Merge branch 'audit.b32' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current
* 'audit.b32' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current:
[PATCH] message types updated
[PATCH] name_count array overrun
[PATCH] PPID filtering fix
[PATCH] arch filter lists with < or > should not be accepted
diff --git a/CREDITS b/CREDITS
index dba3e63..5d75254 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2240,6 +2240,12 @@
S: Freiburg
S: Germany
+N: Paul E. McKenney
+E: paulmck@us.ibm.com
+W: http://www.rdrop.com/users/paulmck/
+D: RCU and variants
+D: rcutorture module
+
N: Mike McLagan
E: mike.mclagan@linux.org
W: http://www.invlogic.com/~mmclagan
@@ -2981,6 +2987,10 @@
S: 75013 Paris
S: France
+N: Dipankar Sarma
+E: dipankar@in.ibm.com
+D: RCU
+
N: Hannu Savolainen
E: hannu@opensound.com
D: Maintainer of the sound drivers until 2.1.x days.
@@ -3293,6 +3303,12 @@
S: MacGregor A.C.T 2615
S: Australia
+N: Josh Triplett
+E: josh@freedesktop.org
+P: 1024D/D0FE7AFB B24A 65C9 1D71 2AC2 DE87 CA26 189B 9946 D0FE 7AFB
+D: rcutorture maintainer
+D: lock annotations, finding and fixing lock bugs
+
N: Winfried Trümper
E: winni@xpilot.org
W: http://www.shop.de/~winni/
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 49c7457..2b5ac60 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -158,6 +158,7 @@
!Emm/filemap.c
!Emm/memory.c
!Emm/vmalloc.c
+!Imm/page_alloc.c
!Emm/mempool.c
!Emm/page-writeback.c
!Emm/truncate.c
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index c684abf..07a6355 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -14,7 +14,7 @@
</authorgroup>
<copyright>
- <year>2003-2005</year>
+ <year>2003-2006</year>
<holder>Jeff Garzik</holder>
</copyright>
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 1d50cf0..f4dffad 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -221,3 +221,41 @@
disable irq on a given acquisition of that lock will result in
deadlock as soon as the RCU callback happens to interrupt that
acquisition's critical section.
+
+13. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu())
+ may only be invoked from process context. Unlike other forms of
+ RCU, it -is- permissible to block in an SRCU read-side critical
+ section (demarked by srcu_read_lock() and srcu_read_unlock()),
+ hence the "SRCU": "sleepable RCU". Please note that if you
+ don't need to sleep in read-side critical sections, you should
+ be using RCU rather than SRCU, because RCU is almost always
+ faster and easier to use than is SRCU.
+
+ Also unlike other forms of RCU, explicit initialization
+ and cleanup is required via init_srcu_struct() and
+ cleanup_srcu_struct(). These are passed a "struct srcu_struct"
+ that defines the scope of a given SRCU domain. Once initialized,
+ the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
+ and synchronize_srcu(). A given synchronize_srcu() waits only
+ for SRCU read-side critical sections governed by srcu_read_lock()
+ and srcu_read_unlock() calls that have been passd the same
+ srcu_struct. This property is what makes sleeping read-side
+ critical sections tolerable -- a given subsystem delays only
+ its own updates, not those of other subsystems using SRCU.
+ Therefore, SRCU is less prone to OOM the system than RCU would
+ be if RCU's read-side critical sections were permitted to
+ sleep.
+
+ The ability to sleep in read-side critical sections does not
+ come for free. First, corresponding srcu_read_lock() and
+ srcu_read_unlock() calls must be passed the same srcu_struct.
+ Second, grace-period-detection overhead is amortized only
+ over those updates sharing a given srcu_struct, rather than
+ being globally amortized as they are for other forms of RCU.
+ Therefore, SRCU should be used in preference to rw_semaphore
+ only in extremely read-intensive situations, or in situations
+ requiring SRCU's read-side deadlock immunity or low read-side
+ realtime latency.
+
+ Note that, rcu_assign_pointer() and rcu_dereference() relate to
+ SRCU just as they do to other forms of RCU.
diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt
index 02e27bf..f84407c 100644
--- a/Documentation/RCU/rcu.txt
+++ b/Documentation/RCU/rcu.txt
@@ -45,7 +45,8 @@
Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
"rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
- "synchronize_rcu", and "synchronize_net".
+ "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu",
+ "synchronize_net", and "synchronize_srcu".
o What guidelines should I follow when writing code that uses RCU?
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index a494859..25a3c3f 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -28,6 +28,15 @@
To properly exercise RCU implementations with preemptible
read-side critical sections.
+nfakewriters This is the number of RCU fake writer threads to run. Fake
+ writer threads repeatedly use the synchronous "wait for
+ current readers" function of the interface selected by
+ torture_type, with a delay between calls to allow for various
+ different numbers of writers running in parallel.
+ nfakewriters defaults to 4, which provides enough parallelism
+ to trigger special cases caused by multiple writers, such as
+ the synchronize_srcu() early return optimization.
+
stat_interval The number of seconds between output of torture
statistics (via printk()). Regardless of the interval,
statistics are printed when the module is unloaded.
@@ -44,9 +53,12 @@
a kernel that disables the scheduling-clock interrupt to
idle CPUs. Boolean parameter, "1" to test, "0" otherwise.
-torture_type The type of RCU to test: "rcu" for the rcu_read_lock()
- API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu"
- for the "srcu_read_lock()" API.
+torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API,
+ "rcu_sync" for rcu_read_lock() with synchronous reclamation,
+ "rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for
+ rcu_read_lock_bh() with synchronous reclamation, "srcu" for
+ the "srcu_read_lock()" API, and "sched" for the use of
+ preempt_disable() together with synchronize_sched().
verbose Enable debug printk()s. Default is disabled.
@@ -118,6 +130,21 @@
as it is only incremented if a torture structure's counter
somehow gets incremented farther than it should.
+Different implementations of RCU can provide implementation-specific
+additional information. For example, SRCU provides the following:
+
+ srcu-torture: rtc: f8cf46a8 ver: 355 tfle: 0 rta: 356 rtaf: 0 rtf: 346 rtmbe: 0
+ srcu-torture: Reader Pipe: 559738 939 0 0 0 0 0 0 0 0 0
+ srcu-torture: Reader Batch: 560434 243 0 0 0 0 0 0 0 0
+ srcu-torture: Free-Block Circulation: 355 354 353 352 351 350 349 348 347 346 0
+ srcu-torture: per-CPU(idx=1): 0(0,1) 1(0,1) 2(0,0) 3(0,1)
+
+The first four lines are similar to those for RCU. The last line shows
+the per-CPU counter state. The numbers in parentheses are the values
+of the "old" and "current" counters for the corresponding CPU. The
+"idx" value maps the "old" and "current" values to the underlying array,
+and is useful for debugging.
+
USAGE
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 820fee2..e0d6d99 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -778,6 +778,8 @@
rcu_read_unlock
rcu_read_lock_bh
rcu_read_unlock_bh
+ srcu_read_lock
+ srcu_read_unlock
RCU pointer/list traversal:
@@ -804,6 +806,7 @@
synchronize_net
synchronize_sched
synchronize_rcu
+ synchronize_srcu
call_rcu
call_rcu_bh
diff --git a/Documentation/ecryptfs.txt b/Documentation/ecryptfs.txt
new file mode 100644
index 0000000..01d8a08
--- /dev/null
+++ b/Documentation/ecryptfs.txt
@@ -0,0 +1,77 @@
+eCryptfs: A stacked cryptographic filesystem for Linux
+
+eCryptfs is free software. Please see the file COPYING for details.
+For documentation, please see the files in the doc/ subdirectory. For
+building and installation instructions please see the INSTALL file.
+
+Maintainer: Phillip Hellewell
+Lead developer: Michael A. Halcrow <mhalcrow@us.ibm.com>
+Developers: Michael C. Thompson
+ Kent Yoder
+Web Site: http://ecryptfs.sf.net
+
+This software is currently undergoing development. Make sure to
+maintain a backup copy of any data you write into eCryptfs.
+
+eCryptfs requires the userspace tools downloadable from the
+SourceForge site:
+
+http://sourceforge.net/projects/ecryptfs/
+
+Userspace requirements include:
+ - David Howells' userspace keyring headers and libraries (version
+ 1.0 or higher), obtainable from
+ http://people.redhat.com/~dhowells/keyutils/
+ - Libgcrypt
+
+
+NOTES
+
+In the beta/experimental releases of eCryptfs, when you upgrade
+eCryptfs, you should copy the files to an unencrypted location and
+then copy the files back into the new eCryptfs mount to migrate the
+files.
+
+
+MOUNT-WIDE PASSPHRASE
+
+Create a new directory into which eCryptfs will write its encrypted
+files (i.e., /root/crypt). Then, create the mount point directory
+(i.e., /mnt/crypt). Now it's time to mount eCryptfs:
+
+mount -t ecryptfs /root/crypt /mnt/crypt
+
+You should be prompted for a passphrase and a salt (the salt may be
+blank).
+
+Try writing a new file:
+
+echo "Hello, World" > /mnt/crypt/hello.txt
+
+The operation will complete. Notice that there is a new file in
+/root/crypt that is at least 12288 bytes in size (depending on your
+host page size). This is the encrypted underlying file for what you
+just wrote. To test reading, from start to finish, you need to clear
+the user session keyring:
+
+keyctl clear @u
+
+Then umount /mnt/crypt and mount again per the instructions given
+above.
+
+cat /mnt/crypt/hello.txt
+
+
+NOTES
+
+eCryptfs version 0.1 should only be mounted on (1) empty directories
+or (2) directories containing files only created by eCryptfs. If you
+mount a directory that has pre-existing files not created by eCryptfs,
+then behavior is undefined. Do not run eCryptfs in higher verbosity
+levels unless you are doing so for the sole purpose of debugging or
+development, since secret values will be written out to the system log
+in that case.
+
+
+Mike Halcrow
+mhalcrow@us.ibm.com
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 42b95e0..24f3c63 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -29,14 +29,6 @@
---------------------------
-What: drivers that were depending on OBSOLETE_OSS_DRIVER
- (config options already removed)
-When: before 2.6.19
-Why: OSS drivers with ALSA replacements
-Who: Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
When: November 2006
Why: Deprecated in favour of the new ioctl-based rawiso interface, which is
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index 7f34778d..125093c 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -1,7 +1,7 @@
Introduction
------------
-The configuration database is collection of configuration options
+The configuration database is a collection of configuration options
organized in a tree structure:
+- Code maturity level options
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index e2cbd59..50f4edd 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -390,7 +390,7 @@
The kernel may be built with several different versions of
$(CC), each supporting a unique set of features and options.
kbuild provide basic support to check for valid options for $(CC).
- $(CC) is useally the gcc compiler, but other alternatives are
+ $(CC) is usually the gcc compiler, but other alternatives are
available.
as-option
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 12b3b24..ff571f9 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -289,9 +289,6 @@
autotest [IA64]
- awe= [HW,OSS] AWE32/SB32/AWE64 wave table synth
- Format: <io>,<memsize>,<isapnp>
-
aztcd= [HW,CD] Aztech CD268 CDROM driver
Format: <io>,0x79 (?)
@@ -536,10 +533,6 @@
Default value is 0.
Value can be changed at runtime via /selinux/enforce.
- es1370= [HW,OSS]
- Format: <lineout>[,<micbias>]
- See also header of sound/oss/es1370.c.
-
es1371= [HW,OSS]
Format: <spdif>,[<nomix>,[<amplifier>]]
See also header of sound/oss/es1371.c.
@@ -580,9 +573,6 @@
gscd= [HW,CD]
Format: <io>
- gus= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma16>
-
gvp11= [HW,SCSI]
hashdist= [KNL,NUMA] Large hashes allocated during boot
@@ -841,12 +831,6 @@
(machvec) in a generic kernel.
Example: machvec=hpzx1_swiotlb
- mad16= [HW,OSS] Format:
- <io>,<irq>,<dma>,<dma16>,<mpu_io>,<mpu_irq>,<joystick>
-
- maui= [HW,OSS]
- Format: <io>,<irq>
-
max_loop= [LOOP] Maximum number of loopback devices that can
be mounted
Format: <1-256>
@@ -1114,9 +1098,6 @@
opl3= [HW,OSS]
Format: <io>
- opl3sa= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma2>,<mpu_io>,<mpu_irq>
-
opl3sa2= [HW,OSS] Format:
<io>,<irq>,<dma>,<dma2>,<mss_io>,<mpu_io>,<ymode>,<loopback>[,<isapnp>,<multiple]
@@ -1357,10 +1338,6 @@
rcu.qlowmark= [KNL,BOOT] Set threshold of queued
RCU callbacks below which batch limiting is re-enabled.
- rcu.rsinterval= [KNL,BOOT,SMP] Set the number of additional
- RCU callbacks to queued before forcing reschedule
- on all cpus.
-
rdinit= [KNL]
Format: <full_path>
Run specified binary instead of /init from the ramdisk,
@@ -1455,9 +1432,6 @@
sg_def_reserved_size= [SCSI]
- sgalaxy= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma2>,<sgbase>
-
shapers= [NET]
Maximal number of shapers.
@@ -1598,9 +1572,6 @@
snd-ymfpci= [HW,ALSA]
- sonicvibes= [HW,OSS]
- Format: <reverb>
-
sonycd535= [HW,CD]
Format: <io>[,<irq>]
diff --git a/Documentation/sound/oss/AWE32 b/Documentation/sound/oss/AWE32
deleted file mode 100644
index b5908a6..0000000
--- a/Documentation/sound/oss/AWE32
+++ /dev/null
@@ -1,76 +0,0 @@
- Installing and using Creative AWE midi sound under Linux.
-
-This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and
-SB32.
-
-1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This
- is important, because the driver works only with real Creative cards.
-
-2) The first thing you need to do is re-compile your kernel with support for
- your sound card. Run your favourite tool to configure the kernel and when
- you get to the "Sound" menu you should enable support for the following:
-
- Sound card support,
- OSS sound modules,
- 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support,
- AWE32 synth
-
- If your card is "Plug and Play" you will also need to enable these two
- options, found under the "Plug and Play configuration" menu:
-
- Plug and Play support
- ISA Plug and Play support
-
- Now compile and install the kernel in normal fashion. If you don't know
- how to do this you can find instructions for this in the README file
- located in the root directory of the kernel source.
-
-3) Before you can start playing midi files you will have to load a sound
- bank file. The utility needed for doing this is called "sfxload", and it
- is one of the utilities found in a package called "awesfx". If this
- package is not available in your distribution you can download the AWE
- snapshot from Creative Labs Open Source website:
-
- http://www.opensource.creative.com/snapshot.html
-
- Once you have unpacked the AWE snapshot you will see a "awesfx"
- directory. Follow the instructions in awesfx/docs/INSTALL to install the
- utilities in this package. After doing this, sfxload should be installed
- as:
-
- /usr/local/bin/sfxload
-
- To enable AWE general midi synthesis you should also get the sound bank
- file for general midi from:
-
- http://members.xoom.com/yar/synthgm.sbk.gz
-
- Copy it to a directory of your choice, and unpack it there.
-
-4) Edit /etc/modprobe.conf, and insert the following lines at the end of the
- file:
-
- alias sound-slot-0 sb
- alias sound-service-0-1 awe_wave
- install awe_wave /sbin/modprobe --first-time -i awe_wave && /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
-
- You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
- path of the sound bank file. That will enable the Sound Blaster and AWE
- wave synthesis. To play midi files you should get one of these programs if
- you don't already have them:
-
- Playmidi: http://playmidi.openprojects.net
-
- AWEMidi Player (drvmidi) Included in the previously mentioned AWE
- snapshot.
-
- You will probably have to pass the "-e" switch to playmidi to have it use
- your midi device. drvmidi should work without switches.
-
- If something goes wrong please e-mail me. All comments and suggestions are
- welcome.
-
- Yaroslav Rosomakho (alons55@dialup.ptt.ru)
- http://www.yar.opennet.ru
-
-Last Updated: Feb 3 2001
diff --git a/Documentation/sound/oss/CMI8338 b/Documentation/sound/oss/CMI8338
deleted file mode 100644
index 387d058..0000000
--- a/Documentation/sound/oss/CMI8338
+++ /dev/null
@@ -1,85 +0,0 @@
-Audio driver for CM8338/CM8738 chips by Chen-Li Tien
-
-
-HARDWARE SUPPORTED
-================================================================================
-C-Media CMI8338
-C-Media CMI8738
-On-board C-Media chips
-
-
-STEPS TO BUILD DRIVER
-================================================================================
-
- 1. Backup the Config.in and Makefile in the sound driver directory
- (/usr/src/linux/driver/sound).
- The Configure.help provide help when you config driver in step
- 4, please backup the original one (/usr/src/linux/Document) and
- copy this file.
- The cmpci is document for the driver in detail, please copy it
- to /usr/src/linux/Document/sound so you can refer it. Backup if
- there is already one.
-
- 2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above
- directory.
-
- 3. Change directory to /usr/src/linux
-
- 4. Config cm8338 driver by 'make menuconfig', 'make config' or
- 'make xconfig' command.
-
- 5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI
- driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
- For driver option, please refer 'DRIVER PARAMETER'
-
- 6. Compile the kernel if necessary.
-
- 7. Compile the modules by 'make modules'.
-
- 8. Install the modules by 'make modules_install'
-
-
-INSTALL DRIVER
-================================================================================
-
- 1. Before first time to run the driver, create module dependency by
- 'depmod -a'
-
- 2. To install the driver manually, enter 'modprobe cmpci'.
-
- 3. Driver installation for various distributions:
-
- a. Slackware 4.0
- Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules
- file.so you can start the driver automatically each time booting.
-
- b. Caldera OpenLinux 2.2
- Use LISA to load the cmpci module.
-
- c. RedHat 6.0 and S.u.S.E. 6.1
- Add following command in /etc/conf.modules:
-
- alias sound cmpci
-
- also visit http://www.cmedia.com.tw for installation instruction.
-
-DRIVER PARAMETER
-================================================================================
-
- Some functions for the cm8738 can be configured in Kernel Configuration
- or modules parameters. Set these parameters to 1 to enable.
-
- mpuio: I/O ports base for MPU-401, 0 if disabled.
- fmio: I/O ports base for OPL-3, 0 if disabled.
- spdif_inverse:Inverse the S/PDIF-in signal, this depends on your
- CD-ROM or DVD-ROM.
- spdif_loop: Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
- directly.
- speakers: Number of speakers used.
- use_line_as_rear:Enable this if you want to use line-in as
- rear-out.
- use_line_as_bass:Enable this if you want to use line-in as
- bass-out.
- joystick: Enable joystick. You will need to install Linux joystick
- driver.
-
diff --git a/Documentation/sound/oss/INSTALL.awe b/Documentation/sound/oss/INSTALL.awe
deleted file mode 100644
index 310f42c..0000000
--- a/Documentation/sound/oss/INSTALL.awe
+++ /dev/null
@@ -1,134 +0,0 @@
-================================================================
- INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX
- Takashi Iwai <iwai@ww.uni-erlangen.de>
-================================================================
-
-----------------------------------------------------------------
-* Attention to SB-PnP Card Users
-
-If you're using PnP cards, the initialization of PnP is required
-before loading this driver. You have now three options:
- 1. Use isapnptools.
- 2. Use in-kernel isapnp support.
- 3. Initialize PnP on DOS/Windows, then boot linux by loadlin.
-In this document, only the case 1 case is treated.
-
-----------------------------------------------------------------
-* Installation on Red Hat 5.0 Sound Driver
-
-Please use install-rh.sh under RedHat5.0 directory.
-DO NOT USE install.sh below.
-See INSTALL.RH for more details.
-
-----------------------------------------------------------------
-* Installation/Update by Shell Script
-
- 1. Become root
-
- % su
-
- 2. If you have never configured the kernel tree yet, run make config
- once (to make dependencies and symlinks).
-
- # cd /usr/src/linux
- # make xconfig
-
- 3. Run install.sh script
-
- # sh ./install.sh
-
- 4. Configure your kernel
-
- (for Linux 2.[01].x user)
- # cd /usr/src/linux
- # make xconfig (or make menuconfig)
-
- (for Linux 1.2.x user)
- # cd /usr/src/linux
- # make config
-
- Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items
- in Sound menu. ("lowlevel drivers" will appear only in 2.x
- kernel.)
-
- 5. Make your kernel (and modules), and install them as usual.
-
- 5a. make kernel image
- # make zImage
-
- 5b. make modules and install them
- # make modules && make modules_install
-
- 5c. If you're using lilo, copy the kernel image and run lilo.
- Otherwise, copy the kernel image to suitable directory or
- media for your system.
-
- 6. Reboot the kernel if necessary.
- - If you updated only the modules, you don't have to reboot
- the system. Just remove the old sound modules here.
- in
- # rmmod sound.o (linux-2.0 or OSS/Free)
- # rmmod awe_wave.o (linux-2.1)
-
- 7. If your AWE card is a PnP and not initialized yet, you'll have to
- do it by isapnp tools. Otherwise, skip to 8.
-
- This section described only a brief explanation. For more
- details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ.
-
- 7a. If you have no isapnp.conf file, generate it by pnpdump.
- Otherwise, skip to 7d.
- # pnpdump > /etc/isapnp.conf
-
- 7b. Edit isapnp.conf file. Comment out the appropriate
- lines containing desirable I/O ports, DMA and IRQs.
- Don't forget to enable (ACT Y) line.
-
- 7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part.
- ex)
- (CONFIGURE CTL0048/58128 (LD 2
- # ANSI string -->WaveTable<--
- (IO 0 (BASE 0x0620))
- (IO 1 (BASE 0x0A20))
- (IO 2 (BASE 0x0E20))
- (ACT Y)
- ))
-
- 7d. Load the config file.
- CAUTION: This will reset all PnP cards!
-
- # isapnp /etc/isapnp.conf
-
- 8. Load the sound module (if you configured it as a module):
-
- for 2.0 kernel or OSS/Free monolithic module:
-
- # modprobe sound.o
-
- for 2.1 kernel:
-
- # modprobe sound
- # insmod uart401
- # insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
- (These values depend on your settings.)
- # insmod awe_wave
- (Be sure to load awe_wave after sb!)
-
- See Documentation/sound/oss/AWE32 for
- more details.
-
- 9. (only for obsolete systems) If you don't have /dev/sequencer
- device file, make it according to Readme.linux file on
- /usr/src/linux/drivers/sound. (Run a shell script included in
- that file). <-- This file no longer exists in the recent kernels!
-
- 10. OK, load your own soundfont file, and enjoy MIDI!
-
- % sfxload synthgm.sbk
- % drvmidi foo.mid
-
- 11. For more advanced use (eg. dynamic loading, virtual bank and
- etc.), please read the awedrv FAQ or the instructions in awesfx
- and awemidi packages.
-
-Good luck!
diff --git a/Documentation/sound/oss/MAD16 b/Documentation/sound/oss/MAD16
deleted file mode 100644
index 865dbd8..0000000
--- a/Documentation/sound/oss/MAD16
+++ /dev/null
@@ -1,56 +0,0 @@
-(This recipe has been edited to update the configuration symbols,
- and change over to modprobe.conf for 2.6)
-
-From: Shaw Carruthers <shaw@shawc.demon.co.uk>
-
-I have been using mad16 sound for some time now with no problems, current
-kernel 2.1.89
-
-lsmod shows:
-
-mad16 5176 0
-sb 22044 0 [mad16]
-uart401 5576 0 [mad16 sb]
-ad1848 14176 1 [mad16]
-sound 61928 0 [mad16 sb uart401 ad1848]
-
-.config has:
-
-CONFIG_SOUND=m
-CONFIG_SOUND_ADLIB=m
-CONFIG_SOUND_MAD16=m
-CONFIG_SOUND_YM3812=m
-
-modprobe.conf has:
-
-alias char-major-14-* mad16
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-
-To get the built in mixer to work this needs to be:
-
-options adlib_card io=0x388 # FM synthesizer
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is
-
-------------------------------------------------------------------------
-The mad16 module in addition supports the following options:
-
-option: meaning: default:
-joystick=0,1 disabled, enabled disabled
-cdtype=0x00,0x02,0x04, disabled, Sony CDU31A, disabled
- 0x06,0x08,0x0a Mitsumi, Panasonic,
- Secondary IDE, Primary IDE
-cdport=0x340,0x320, 0x340
- 0x330,0x360
-cdirq=0,3,5,7,9,10,11 disabled, IRQ3, ... disabled
-cddma=0,5,6,7 disabled, DMA5, ... DMA5 for Mitsumi or IDE
-cddma=0,1,2,3 disabled, DMA1, ... DMA3 for Sony or Panasonic
-opl4=0,1 OPL3, OPL4 OPL3
-
-for more details see linux/drivers/sound/mad16.c
-
-Rui Sousa
diff --git a/Documentation/sound/oss/Maestro b/Documentation/sound/oss/Maestro
deleted file mode 100644
index 4a80eb3..0000000
--- a/Documentation/sound/oss/Maestro
+++ /dev/null
@@ -1,123 +0,0 @@
- An OSS/Lite Driver for the ESS Maestro family of sound cards
-
- Zach Brown, December 1999
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
- http://www.zabbo.net/maestro/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-ESS Maestro Chip Family
------------------------
-
-There are 3 main variants of the ESS Maestro PCI sound chip. The first
-is the Maestro 1. It was originally produced by Platform Tech as the
-'AGOGO'. It can be recognized by Platform Tech's PCI ID 0x1285 with
-0x0100 as the device ID. It was put on some sound boards and a few laptops.
-ESS bought the design and cleaned it up as the Maestro 2. This starts
-their marking with the ESS vendor ID 0x125D and the 'year' device IDs.
-The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978.
-
-The various families of Maestro are mostly identical as far as this
-driver is concerned. It doesn't touch the DSP parts that differ (though
-it could for FM synthesis).
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec. This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves almost as expected. Playback is
-supported in all the various lovely formats. 8/16bit stereo/mono from
-8khz to 48khz, and mmap()ing for playback behaves. Capture/recording
-is limited due to oddities with the Maestro hardware. One can only
-record in 16bit stereo. For recording the maestro uses non interleaved
-stereo buffers so that mmap()ing the incoming data does not result in
-a ring buffer of LRLR data. mmap()ing of the read buffers is therefore
-disallowed until this can be cleaned up.
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro. It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro. Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them.
-
-The driver doesn't support MIDI or FM playback at the moment. Typically
-the Maestro is wired to an MPU MIDI chip, but some hardware implementations
-don't. We need to assemble a white list of hardware implementations that
-have MIDI wired properly before we can claim to support it safely.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers. Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO variable
-in the config system.
-
-It may be modular or statically linked. If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere. 'alias sound maestro'
-should also be added to your module configs (typically /etc/conf.modules)
-if you're using modular OSS/Lite sound and want to default to using a
-maestro chip.
-
-As this is a PCI device, the module does not need to be informed of
-any IO or IRQ resources it should use, it devines these from the
-system. Sometimes, on sucky PCs, the BIOS fails to allocated resources
-for the maestro. This will result in a message like:
- maestro: PCI subsystem reports IRQ 0, this might not be correct.
-from the kernel. Should this happen the sound chip most likely will
-not operate correctly. To solve this one has to dig through their BIOS
-(typically entered by hitting a hot key at boot time) and figure out
-what magic needs to happen so that the BIOS will reward the maestro with
-an IRQ. This operation is incredibly system specific, so you're on your
-own. Sometimes the magic lies in 'PNP Capable Operating System' settings.
-
-There are very few options to the driver. One is 'debug' which will
-tell the driver to print minimal debugging information as it runs. This
-can be collected with 'dmesg' or through the klogd daemon.
-
-The other, more interesting option, is 'dsps_order'. Typically at
-install time the driver will only register one available /dev/dsp device
-for its use. The 'dsps_order' module parameter allows for more devices
-to be allocated, as a power of two. Up to 4 devices can be registered
-( dsps_order=2 ). These devices act as fully distinct units and use
-separate channels in the maestro.
-
-Power Management
-----------------
-
-As of version 0.14, this driver has a minimal understanding of PCI
-Power Management. If it finds a valid power management capability
-on the PCI device it will attempt to use the power management
-functions of the maestro. It will only do this on Maestro 2Es and
-only on machines that are known to function well. You can
-force the use of power management by setting the 'use_pm' module
-option to 1, or can disable it entirely by setting it to 0.
-
-When using power management, the driver does a few things
-differently. It will keep the chip in a lower power mode
-when the module is inserted but /dev/dsp is not open. This
-allows the mixer to function but turns off the clocks
-on other parts of the chip. When /dev/dsp is opened the chip
-is brought into full power mode, and brought back down
-when it is closed. It also powers down the chip entirely
-when the module is removed or the machine is shutdown. This
-can have nonobvious consequences. CD audio may not work
-after a power managing driver is removed. Also, software that
-doesn't understand power management may not be able to talk
-to the powered down chip until the machine goes through a hard
-reboot to bring it back.
-
-.. more details ..
-------------------
-
-drivers/sound/maestro.c contains comments that hopefully explain
-the maestro implementation.
diff --git a/Documentation/sound/oss/Maestro3 b/Documentation/sound/oss/Maestro3
deleted file mode 100644
index a113718..0000000
--- a/Documentation/sound/oss/Maestro3
+++ /dev/null
@@ -1,92 +0,0 @@
- An OSS/Lite Driver for the ESS Maestro3 family of sound chips
-
- Zach Brown, January 2001
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
- http://www.zabbo.net/maestro3/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-Historically I've sucked pretty hard at actually doing that, however.
-
-ESS Maestro3 Chip Family
------------------------
-
-The 'Maestro3' is much like the Maestro2 chip. The noted improvement
-is the removal of the silicon in the '2' that did PCM mixing. All that
-work is now done through a custom DSP called the ASSP, the Asynchronus
-Specific Signal Processor.
-
-The 'Allegro' is a baby version of the Maestro3. I'm not entirely clear
-on the extent of the differences, but the driver supports them both :)
-
-The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
-both under ESS's vendor ID of 0x125D. The Maestro3 can also show up as
-0x199a when hardware strapping is used.
-
-The chip can also act as a multi function device. The modem IDs follow
-the audio multimedia device IDs. (so the modem part of an Allegro shows
-up as 0x1989)
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec. This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves as expected. Playback is
-supported in all the various lovely formats. 8/16bit stereo/mono from
-8khz to 48khz, with both read()/write(), and mmap().
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro3. It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro3. Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them.
-The Allegro has an onchip AC'97.
-
-The driver doesn't support MIDI or FM playback at the moment.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers. Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
-in the config system.
-
-It may be modular or statically linked. If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0
-maestro3' should also be added to your module configs (typically
-/etc/modprobe.conf) if you're using modular OSS/Lite sound and want to
-default to using a maestro3 chip.
-
-There are very few options to the driver. One is 'debug' which will
-tell the driver to print minimal debugging information as it runs. This
-can be collected with 'dmesg' or through the klogd daemon.
-
-One is 'external_amp', which tells the driver to attempt to enable
-an external amplifier. This defaults to '1', you can tell the driver
-not to bother enabling such an amplifier by setting it to '0'.
-
-And the last is 'gpio_pin', which tells the driver which GPIO pin number
-the external amp uses (0-15), The Allegro uses 8 by default, all others 1.
-If everything loads correctly and seems to be working but you get no sound,
-try tweaking this value.
-
-Systems known to need a different value
- Panasonic ToughBook CF-72: gpio_pin=13
-
-Power Management
-----------------
-
-This driver has a minimal understanding of PCI Power Management. It will
-try and power down the chip when the system is suspended, and power
-it up with it is resumed. It will also try and power down the chip
-when the machine is shut down.
diff --git a/Documentation/sound/oss/NEWS b/Documentation/sound/oss/NEWS
deleted file mode 100644
index a81e0ef..0000000
--- a/Documentation/sound/oss/NEWS
+++ /dev/null
@@ -1,42 +0,0 @@
-Linux 2.4 Sound Changes
-2000-September-25
-Christoph Hellwig, <hch@infradead.org>
-
-
-
-=== isapnp support
-
-The Linux 2.4 Kernel does have reliable in-kernel isapnp support.
-Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically
-detecting and configuring isapnp devices.
-If you have a not yet supported isapnp soundcard, mail me the content
-of '/proc/isapnp' on your system and some information about your card
-and its driver(s) so I can try to get isapnp working for it.
-
-
-
-=== soundcard resources on kernel commandline
-
-Before Linux 2.4 you had to specify the resources for sounddrivers
-statically linked into the kernel at compile time
-(in make config/menuconfig/xconfig). In Linux 2.4 the resources are
-now specified at the boot-time kernel commandline (e.g. the lilo
-'append=' line or everything that's after the kernel name in grub).
-Read the Configure.help entry for your card for the parameters.
-
-
-=== softoss is gone
-
-In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable.
-Use a user space software synthesizer like timidity instead.
-
-
-
-=== /dev/sndstat and /proc/sound are gone
-
-In older Linux versions those files exported some information about the
-OSS/Free configuration to userspace. In Linux 2.3 they were removed because
-they did not support the growing number of pci soundcards and there were
-some general problems with this interface.
-
-
diff --git a/Documentation/sound/oss/OPL3-SA b/Documentation/sound/oss/OPL3-SA
deleted file mode 100644
index 66a9183..0000000
--- a/Documentation/sound/oss/OPL3-SA
+++ /dev/null
@@ -1,52 +0,0 @@
-OPL3-SA1 sound driver (opl3sa.o)
-
----
-Note: This howto only describes how to setup the OPL3-SA1 chip; this info
-does not apply to the SA2, SA3, or SA4.
----
-
-The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and
-it's a decent little chip offering a WSS mode, a SB Pro emulation mode, MPU401
-and OPL3 FM Synth capabilities.
-
-You can enable inclusion of the driver via CONFIG_SOUND_OPL3SA1=m, or
-CONFIG_SOUND_OPL3SA1=y through 'make config/xconfig/menuconfig'.
-
-You'll need to know all of the relevant info (irq, dma, and io port) for the
-chip's WSS mode, since that is the mode the kernel sound driver uses, and of
-course you'll also need to know about where the MPU401 and OPL3 ports and
-IRQs are if you want to use those.
-
-Here's the skinny on how to load it as a module:
-
- modprobe opl3sa io=0x530 irq=11 dma=0 dma2=1 mpu_io=0x330 mpu_irq=5
-
-Module options in detail:
-
- io: This is the WSS's port base.
- irq: This is the WSS's IRQ.
- dma: This is the WSS's DMA line. In my BIOS setup screen this was
- listed as "WSS Play DMA"
- dma2: This is the WSS's secondary DMA line. My BIOS calls it the
- "WSS capture DMA"
-
- mpu_io: This is the MPU401's port base.
- mpu_irq: This is the MPU401's IRQ.
-
-If you'd like to use the OPL3 FM Synthesizer, make sure you enable
-CONFIG_SOUND_YM3812 (in 'make config'). That'll build the opl3.o module.
-
-Then a simple 'insmod opl3 io=0x388', and you now have FM Synth.
-
-You can also use the SoftOSS software synthesizer instead of the builtin OPL3.
-Here's how:
-
-Say 'y' or 'm' to "SoftOSS software wave table engine" in make config.
-
-If you said yes, the software synth is available once you boot your new
-kernel.
-
-If you chose to build it as a module, just insmod the resulting softoss2.o
-
-Questions? Comments?
-<stiker@northlink.com>
diff --git a/Documentation/sound/oss/README.awe b/Documentation/sound/oss/README.awe
deleted file mode 100644
index 80054cd..0000000
--- a/Documentation/sound/oss/README.awe
+++ /dev/null
@@ -1,218 +0,0 @@
-================================================================
- AWE32 Sound Driver for Linux / FreeBSD
- version 0.4.3; Nov. 1, 1998
-
- Takashi Iwai <iwai@ww.uni-erlangen.de>
-================================================================
-
-* GENERAL NOTES
-
-This is a sound driver extension for SoundBlaster AWE32 and other
-compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable
-the wave synth operations. The driver is provided for Linux 1.2.x
-and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC
-Alpha systems.
-
-This driver was written by Takashi Iwai <iwai@ww.uni-erlangen.de>,
-and provided "as is". The original source (awedrv-0.4.3.tar.gz) and
-binary packages are available on the following URL:
- http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/
-Note that since the author is apart from this web site, the update is
-not frequent now.
-
-
-* NOTE TO LINUX USERS
-
-To enable this driver on linux-2.[01].x kernels, you need turn on
-"AWE32 synth" options in sound menu when configure your linux kernel
-and modules. The precise installation procedure is described in the
-AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32.
-
-If you're using PnP cards, the card must be initialized before loading
-the sound driver. There're several options to do this:
- - Initialize the card via ISA PnP tools, and load the sound module.
- - Initialize the card on DOS, and load linux by loadlin.exe
- - Use PnP kernel driver (for Linux-2.x.x)
-The detailed instruction for the solution using isapnp tools is found
-in many documents like above. A brief instruction is also included in
-the installation document of this package.
-For PnP driver project, please refer to the following URL:
- http://www-jcr.lmh.ox.ac.uk/~pnp/
-
-
-* USING THE DRIVER
-
-The awedrv has several different playing modes to realize easy channel
-allocation for MIDI songs. To hear the exact sound quality, you need
-to obtain the extended sequencer program, drvmidi or playmidi-2.5.
-
-For playing MIDI files, you *MUST* load the soundfont file on the
-driver previously by sfxload utility. Otherwise you'll here no sounds
-at all! All the utilities and driver source packages are found in the
-above URL. The sfxload program is included in the package
-awesfx-0.4.3.tgz. Binary packages are available there, too. See the
-instruction in each package for installation.
-
-Loading a soundfont file is very simple. Just execute the command
-
- % sfxload synthgm.sbk
-
-Then, sfxload transfers the file "synthgm.sbk" to the driver.
-Both SF1 and SF2 formats are accepted.
-
-Now you can hear midi musics by a midi player.
-
- % drvmidi foo.mid
-
-If you run MIDI player after MOD player, you need to load soundfont
-files again, since MOD player programs clear the previous loaded
-samples by their own data.
-
-If you have only 512kb on the sound card, I recommend to use dynamic
-sample loading via -L option of drvmidi. 2MB GM/GS soundfont file is
-available in most midi files.
-
- % sfxload synthgm
- % drvmidi -L 2mbgmgs foo.mid
-
-This makes a big difference (believe me)! For more details, please
-refer to the FAQ list which is available on the URL above.
-
-The current chorus, reverb and equalizer status can be changed by
-aweset utility program (included in awesfx package). Note that
-some awedrv-native programs (like drvmidi and xmp) will change the
-current settings by themselves. The aweset program is effective
-only for other programs like playmidi.
-
-Enjoy.
-
-
-* COMPILE FLAGS
-
-Compile conditions are defined in awe_config.h.
-
-[Compatibility Conditions]
-The following flags are defined automatically when using installation
-shell script.
-
-- AWE_MODULE_SUPPORT
- indicates your Linux kernel supports module for each sound card
- (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels
- as distributed in the RH5.0 package).
- This flag is automatically set when you're using 2.1.x kernels.
- You can pass the base address and memory size via the following
- module options,
- io = base I/O port address (eg. 0x620)
- memsize = DRAM size in kilobytes (eg. 512)
- As default, AWE driver probes these values automatically.
-
-
-[Hardware Conditions]
-You DON'T have to define the following two values.
-Define them only when the driver couldn't detect the card properly.
-
-- AWE_DEFAULT_BASE_ADDR (default: not defined)
- specifies the base port address of your AWE32 card.
- 0 means to autodetect the address.
-
-- AWE_DEFAULT_MEM_SIZE (default: not defined)
- specifies the memory size of your AWE32 card in kilobytes.
- -1 means to autodetect its size.
-
-
-[Sample Table Size]
-From ver.0.4.0, sample tables are allocated dynamically (except
-Linux-1.2.x system), so you need NOT to touch these parameters.
-Linux-1.2.x users may need to increase these values to appropriate size
-if the sound card is equipped with more DRAM.
-
-- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS
-
-
-[Other Conditions]
-
-- AWE_ALWAYS_INIT_FM (default: not defined)
- indicates the AWE driver always initialize FM passthrough even
- without DRAM on board. Emu8000 chip has a restriction for playing
- samples on DRAM that at least two channels must be occupied as
- passthrough channels.
-
-- AWE_DEBUG_ON (default: defined)
- turns on debugging messages if defined.
-
-- AWE_HAS_GUS_COMPATIBILITY (default: defined)
- Enables GUS compatibility mode if defined, reading GUS patches and
- GUS control commands. Define this option to use GMOD or other
- GUS module players.
-
-- CONFIG_AWE32_MIDIEMU (default: defined)
- Adds a MIDI emulation device by Emu8000 wavetable. The emulation
- device can be accessed as an external MIDI, and sends the MIDI
- control codes directly. XG and GS sysex/NRPN are accepted.
- No MIDI input is supported.
-
-- CONFIG_AWE32_MIXER (default: not defined)
- Adds a mixer device for AWE32 bass/treble equalizer control.
- You can access this device using /dev/mixer?? (usually mixer01).
-
-- AWE_USE_NEW_VOLUME_CALC (default: defined)
- Use the new method to calculate the volume change as compatible
- with DOS/Win drivers. This option can be toggled via aweset
- program, or drvmidi player.
-
-- AWE_CHECK_VTARGET (default: defined)
- Check the current volume target value when searching for an
- empty channel to allocate a new voice. This is experimentally
- implemented in this version. (probably, this option doesn't
- affect the sound quality severely...)
-
-- AWE_ALLOW_SAMPLE_SHARING (default: defined)
- Allow sample sharing for differently loaded patches.
- This function is available only together with awesfx-0.4.3p3.
- Note that this is still an experimental option.
-
-- DEF_FM_CHORUS_DEPTH (default: 0x10)
- The default strength to be sent to the chorus effect engine.
- From 0 to 0xff. Larger numbers may often cause weird sounds.
-
-- DEF_FM_REVERB_DEPTH (default: 0x10)
- The default strength to be sent to the reverb effect engine.
- From 0 to 0xff. Larger numbers may often cause weird sounds.
-
-
-* ACKNOWLEDGMENTS
-
-Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice
-on programming of AWE32. Much code is brought from his AWE32-native
-MOD player, ALMP.
-The port of awedrv to FreeBSD is done by Randall Hopper
-(rhh@ct.picker.com).
-The new volume calculation routine was derived from Mark Weaver's
-ADIP compatible routines.
-I also thank linux-awe-ml members for their efforts
-to reboot their system many times :-)
-
-
-* TODO'S
-
-- Complete DOS/Win compatibility
-- DSP-like output
-
-
-* COPYRIGHT
-
-Copyright (C) 1996-1998 Takashi Iwai
-
-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.
diff --git a/Documentation/sound/oss/Wavefront b/Documentation/sound/oss/Wavefront
deleted file mode 100644
index 16f57ea..0000000
--- a/Documentation/sound/oss/Wavefront
+++ /dev/null
@@ -1,339 +0,0 @@
- An OSS/Free Driver for WaveFront soundcards
- (Turtle Beach Maui, Tropez, Tropez Plus)
-
- Paul Barton-Davis, July 1998
-
- VERSION 0.2.5
-
-Driver Status
--------------
-
-Requires: Kernel 2.1.106 or later (the driver is included with kernels
-2.1.109 and above)
-
-As of 7/22/1998, this driver is currently in *BETA* state. This means
-that it compiles and runs, and that I use it on my system (Linux
-2.1.106) with some reasonably demanding applications and uses. I
-believe the code is approaching an initial "finished" state that
-provides bug-free support for the Tropez Plus.
-
-Please note that to date, the driver has ONLY been tested on a Tropez
-Plus. I would very much like to hear (and help out) people with Tropez
-and Maui cards, since I think the driver can support those cards as
-well.
-
-Finally, the driver has not been tested (or even compiled) as a static
-(non-modular) part of the kernel. Alan Cox's good work in modularizing
-OSS/Free for Linux makes this rather unnecessary.
-
-Some Questions
---------------
-
-**********************************************************************
-0) What does this driver do that the maui driver did not ?
-**********************************************************************
-
-* can fully initialize a WaveFront card from cold boot - no DOS
- utilities needed
-* working patch/sample/program loading and unloading (the maui
- driver didn't document how to make this work, and assumed
- user-level preparation of the patch data for writing
- to the board. ick.)
-* full user-level access to all WaveFront commands
-* for the Tropez Plus, (primitive) control of the YSS225 FX processor
-* Virtual MIDI mode supported - 2 MIDI devices accessible via the
- WaveFront's MPU401/UART emulation. One
- accesses the WaveFront synth, the other accesses the
- external MIDI connector. Full MIDI read/write semantics
- for both devices.
-* OSS-compliant /dev/sequencer interface for the WaveFront synth,
- including native and GUS-format patch downloading.
-* semi-intelligent patch management (prototypical at this point)
-
-**********************************************************************
-1) What to do about MIDI interfaces ?
-**********************************************************************
-
-The Tropez Plus (and perhaps other WF cards) can in theory support up
-to 2 physical MIDI interfaces. One of these is connected to the
-ICS2115 chip (the WaveFront synth itself) and is controlled by
-MPU/UART-401 emulation code running as part of the WaveFront OS. The
-other is controlled by the CS4232 chip present on the board. However,
-physical access to the CS4232 connector is difficult, and it is
-unlikely (though not impossible) that you will want to use it.
-
-An older version of this driver introduced an additional kernel config
-variable which controlled whether or not the CS4232 MIDI interface was
-configured. Because of Alan Cox's work on modularizing the sound
-drivers, and now backporting them to 2.0.34 kernels, there seems to be
-little reason to support "static" configuration variables, and so this
-has been abandoned in favor of *only* module parameters. Specifying
-"mpuio" and "mpuirq" for the cs4232 parameter will result in the
-CS4232 MIDI interface being configured; leaving them unspecified will
-leave it unconfigured (and thus unusable).
-
-BTW, I have heard from one Tropez+ user that the CS4232 interface is
-more reliable than the ICS2115 one. I have had no problems with the
-latter, and I don't have the right cable to test the former one
-out. Reports welcome.
-
-**********************************************************************
-2) Why does line XXX of the code look like this .... ?
-**********************************************************************
-
-Either because it's not finished yet, or because you're a better coder
-than I am, or because you don't understand some aspect of how the card
-or the code works.
-
-I absolutely welcome comments, criticisms and suggestions about the
-design and implementation of the driver.
-
-**********************************************************************
-3) What files are included ?
-**********************************************************************
-
- drivers/sound/README.wavefront -- this file
-
- drivers/sound/wavefront.patch -- patches for the 2.1.106 sound drivers
- needed to make the rest of this work
- DO NOT USE IF YOU'VE APPLIED THEM
- BEFORE, OR HAVE 2.1.109 OR ABOVE
-
- drivers/sound/wavfront.c -- the driver
- drivers/sound/ys225.h -- data declarations for FX config
- drivers/sound/ys225.c -- data definitions for FX config
- drivers/sound/wf_midi.c -- the "uart401" driver
- to support virtual MIDI mode.
- include/wavefront.h -- the header file
- Documentation/sound/oss/Tropez+ -- short docs on configuration
-
-**********************************************************************
-4) How do I compile/install/use it ?
-**********************************************************************
-
-PART ONE: install the source code into your sound driver directory
-
- cd <top-of-your-2.1.106-code-base-e.g.-/usr/src/linux>
- tar -zxvf <where-you-put/wavefront.tar.gz>
-
-PART TWO: apply the patches
-
- DO THIS ONLY IF YOU HAVE A KERNEL VERSION BELOW 2.1.109
- AND HAVE NOT ALREADY INSTALLED THE PATCH(ES).
-
- cd drivers/sound
- patch < wavefront.patch
-
-PART THREE: configure your kernel
-
- cd <top of your kernel tree>
- make xconfig (or whichever config option you use)
-
- - choose YES for Sound Support
- - choose MODULE (M) for OSS Sound Modules
- - choose MODULE(M) to YM3812/OPL3 support
- - choose MODULE(M) for WaveFront support
- - choose MODULE(M) for CS4232 support
-
- - choose "N" for everything else (unless you have other
- soundcards you want support for)
-
-
- make boot
- .
- .
- .
- <whatever you normally do for a kernel install>
- make modules
- .
- .
- .
- make modules_install
-
-Here's my autoconf.h SOUND section:
-
-/*
- * Sound
- */
-#define CONFIG_SOUND 1
-#undef CONFIG_SOUND_OSS
-#define CONFIG_SOUND_OSS_MODULE 1
-#undef CONFIG_SOUND_PAS
-#undef CONFIG_SOUND_SB
-#undef CONFIG_SOUND_ADLIB
-#undef CONFIG_SOUND_GUS
-#undef CONFIG_SOUND_MPU401
-#undef CONFIG_SOUND_PSS
-#undef CONFIG_SOUND_MSS
-#undef CONFIG_SOUND_SSCAPE
-#undef CONFIG_SOUND_TRIX
-#undef CONFIG_SOUND_MAD16
-#undef CONFIG_SOUND_WAVEFRONT
-#define CONFIG_SOUND_WAVEFRONT_MODULE 1
-#undef CONFIG_SOUND_CS4232
-#define CONFIG_SOUND_CS4232_MODULE 1
-#undef CONFIG_SOUND_MAUI
-#undef CONFIG_SOUND_SGALAXY
-#undef CONFIG_SOUND_OPL3SA1
-#undef CONFIG_SOUND_SOFTOSS
-#undef CONFIG_SOUND_YM3812
-#define CONFIG_SOUND_YM3812_MODULE 1
-#undef CONFIG_SOUND_VMIDI
-#undef CONFIG_SOUND_UART6850
-/*
- * Additional low level sound drivers
- */
-#undef CONFIG_LOWLEVEL_SOUND
-
-************************************************************
-6) How do I configure my card ?
-************************************************************
-
-You need to edit /etc/modprobe.conf. Here's mine (edited to show the
-relevant details):
-
- # Sound system
- alias char-major-14-* wavefront
- alias synth0 wavefront
- alias mixer0 cs4232
- alias audio0 cs4232
- install wavefront /sbin/modprobe cs4232 && /sbin/modprobe -i wavefront && /sbin/modprobe opl3
- options wavefront io=0x200 irq=9
- options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
- options opl3 io=0x388
-
-Things to note:
-
- the wavefront options "io" and "irq" ***MUST*** match the "synthio"
- and "synthirq" cs4232 options.
-
- you can do without the opl3 module if you don't
- want to use the OPL/[34] FM synth on the soundcard
-
- the opl3 io parameter is conventionally not adjustable.
- In theory, any not-in-use IO port address would work, but
- just use 0x388 and stick with the crowd.
-
-**********************************************************************
-7) What about firmware ?
-**********************************************************************
-
-Turtle Beach have not given me permission to distribute their firmware
-for the ICS2115. However, if you have a WaveFront card, then you
-almost certainly have the firmware, and if not, its freely available
-on their website, at:
-
- http://www.tbeach.com/tbs/downloads/scardsdown.htm#tropezplus
-
-The file is called WFOS2001.MOT (for the Tropez+).
-
-This driver, however, doesn't use the pure firmware as distributed,
-but instead relies on a somewhat processed form of it. You can
-generate this very easily. Following an idea from Andrew Veliath's
-Pinnacle driver, the following flex program will generate the
-processed version:
-
----- cut here -------------------------
-%option main
-%%
-^S[28].*\r$ printf ("%c%.*s", yyleng-1,yyleng-1,yytext);
-<<EOF>> { fputc ('\0', stdout); return; }
-\n {}
-. {}
----- cut here -------------------------
-
-To use it, put the above in file (say, ws.l) compile it like this:
-
- shell> flex -ows.c ws.l
- shell> cc -o ws ws.c
-
-and then use it like this:
-
- ws < my-copy-of-the-oswf.mot-file > /etc/sound/wavefront.os
-
-If you put it somewhere else, you'll always have to use the wf_ospath
-module parameter (see below) or alter the source code.
-
-**********************************************************************
-7) How do I get it working ?
-**********************************************************************
-
-Optionally, you can reboot with the "new" kernel (even though the only
-changes have really been made to a module).
-
-Then, as root do:
-
- modprobe wavefront
-
-You should get something like this in /var/log/messages:
-
- WaveFront: firmware 1.20 already loaded.
-
-or
-
- WaveFront: no response to firmware probe, assume raw.
-
-then:
-
- WaveFront: waiting for memory configuration ...
- WaveFront: hardware version 1.64
- WaveFront: available DRAM 8191k
- WaveFront: 332 samples used (266 real, 13 aliases, 53 multi), 180 empty
- WaveFront: 128 programs slots in use
- WaveFront: 256 patch slots filled, 142 in use
-
-The whole process takes about 16 seconds, the longest waits being
-after reporting the hardware version (during the firmware download),
-and after reporting program status (during patch status inquiry). Its
-shorter (about 10 secs) if the firmware is already loaded (i.e. only
-warm reboots since the last firmware load).
-
-The "available DRAM" line will vary depending on how much added RAM
-your card has. Mine has 8MB.
-
-To check basically functionality, use play(1) or splay(1) to send a
-.WAV or other audio file through the audio portion. Then use playmidi
-to play a General MIDI file. Try the "-D 0" to hear the
-difference between sending MIDI to the WaveFront and using the OPL/3,
-which is the default (I think ...). If you have an external synth(s)
-hooked to the soundcard, you can use "-e" to route to the
-external synth(s) (in theory, -D 1 should work as well, but I think
-there is a bug in playmidi which prevents this from doing what it
-should).
-
-**********************************************************************
-8) What are the module parameters ?
-**********************************************************************
-
-Its best to read wavefront.c for this, but here is a summary:
-
-integers:
- wf_raw - if set, ignore apparent presence of firmware
- loaded onto the ICS2115, reset the whole
- board, and initialize it from scratch. (default = 0)
-
- fx_raw - if set, always initialize the YSS225 processor
- on the Tropez plus. (default = 1)
-
- < The next 4 are basically for kernel hackers to allow
- tweaking the driver for testing purposes. >
-
- wait_usecs - loop timer used when waiting for
- status conditions on the board.
- The default is 150.
-
- debug_default - debugging flags. See sound/wavefront.h
- for WF_DEBUG_* values. Default is zero.
- Setting this allows you to debug the
- driver during module installation.
-strings:
- ospath - path to get to the pre-processed OS firmware.
- (default: /etc/sound/wavefront.os)
-
-**********************************************************************
-9) Who should I contact if I have problems?
-**********************************************************************
-
-Just me: Paul Barton-Davis <pbd@op.net>
-
-
diff --git a/Documentation/sound/oss/es1370 b/Documentation/sound/oss/es1370
deleted file mode 100644
index 7b38b1a..0000000
--- a/Documentation/sound/oss/es1370
+++ /dev/null
@@ -1,70 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-This soundcard does not have any hardware MIDI synthesizer;
-MIDI synthesis has to be done in software. To allow this
-the driver/soundcard supports two PCM (/dev/dsp) interfaces.
-The second one goes to the mixer "synth" setting and supports
-only a limited set of sampling rates (44100, 22050, 11025, 5512).
-By setting lineout to 1 on the driver command line
-(eg. insmod es1370 lineout=1) it is even possible on some
-cards to convert the LINEIN jack into a second LINEOUT jack, thus
-making it possible to output four independent audio channels!
-
-There is a freely available software package that allows
-MIDI file playback on this soundcard called Timidity.
-See http://www.cgs.fi/~tt/timidity/.
-
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/Documentation/sound/oss/rme96xx b/Documentation/sound/oss/rme96xx
deleted file mode 100644
index 87d7b7b..0000000
--- a/Documentation/sound/oss/rme96xx
+++ /dev/null
@@ -1,767 +0,0 @@
-Beta release of the rme96xx (driver for RME 96XX cards like the
-"Hammerfall" and the "Hammerfall light")
-
-Important: The driver module has to be installed on a freshly rebooted system,
-otherwise the driver might not be able to acquire its buffers.
-
-features:
-
- - OSS programming interface (i.e. runs with standard OSS soundsoftware)
- - OSS/Multichannel interface (OSS multichannel is done by just aquiring
- more than 2 channels). The driver does not use more than one device
- ( yet .. this feature may be implemented later )
- - more than one RME card supported
-
-The driver uses a specific multichannel interface, which I will document
-when the driver gets stable. (take a look at the defines in rme96xx.h,
-which adds blocked multichannel formats i.e instead of
-lrlrlrlr --> llllrrrr etc.
-
-Use the "rmectrl" programm to look at the status of the card ..
-or use xrmectrl, a GUI interface for the ctrl program.
-
-What you can do with the rmectrl program is to set the stereo device for
-OSS emulation (e.g. if you use SPDIF out).
-
-You do:
-
-./ctrl offset 24 24
-
-which makes the stereo device use channels 25 and 26.
-
-Guenter Geiger <geiger@epy.co.at>
-
-copy the first part of the attached source code into rmectrl.c
-and the second part into xrmectrl (or get the program from
-http://gige.xdv.org/pages/soft/pages/rme)
-
-to compile: gcc -o rmectrl rmectrl.c
------------------------------- snip ------------------------------------
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <linux/soundcard.h>
-#include <math.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "rme96xx.h"
-
-/*
- remctrl.c
- (C) 2000 Guenter Geiger <geiger@debian.org>
- HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-*/
-
-/* # define DEVICE_NAME "/dev/mixer" */
-# define DEVICE_NAME "/dev/mixer1"
-
-
-void usage(void)
-{
- fprintf(stderr,"usage: rmectrl [/dev/mixer<n>] [command [options]]\n\n");
- fprintf(stderr,"where command is one of:\n");
- fprintf(stderr," help show this help\n");
- fprintf(stderr," status show status bits\n");
- fprintf(stderr," control show control bits\n");
- fprintf(stderr," mix show mixer/offset status\n");
- fprintf(stderr," master <n> set sync master\n");
- fprintf(stderr," pro <n> set spdif out pro\n");
- fprintf(stderr," emphasis <n> set spdif out emphasis\n");
- fprintf(stderr," dolby <n> set spdif out no audio\n");
- fprintf(stderr," optout <n> set spdif out optical\n");
- fprintf(stderr," wordclock <n> set sync wordclock\n");
- fprintf(stderr," spdifin <n> set spdif in (0=optical,1=coax,2=intern)\n");
- fprintf(stderr," syncref <n> set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n");
- fprintf(stderr," adat1cd <n> set ADAT1 on internal CD\n");
- fprintf(stderr," offset <devnr> <in> <out> set dev (0..3) offset (0..25)\n");
- exit(-1);
-}
-
-
-int main(int argc, char* argv[])
-{
- int cards;
- int ret;
- int i;
- double ft;
- int fd, fdwr;
- int param,orig;
- rme_status_t stat;
- rme_ctrl_t ctrl;
- char *device;
- int argidx;
-
- if (argc < 2)
- usage();
-
- if (*argv[1]=='/') {
- device = argv[1];
- argidx = 2;
- }
- else {
- device = DEVICE_NAME;
- argidx = 1;
- }
-
- fprintf(stdout,"mixer device %s\n",device);
- if ((fd = open(device,O_RDONLY)) < 0) {
- fprintf(stdout,"opening device failed\n");
- exit(-1);
- }
-
- if ((fdwr = open(device,O_WRONLY)) < 0) {
- fprintf(stdout,"opening device failed\n");
- exit(-1);
- }
-
- if (argc < argidx+1)
- usage();
-
- if (!strcmp(argv[argidx],"help"))
- usage();
- if (!strcmp(argv[argidx],"-h"))
- usage();
- if (!strcmp(argv[argidx],"--help"))
- usage();
-
- if (!strcmp(argv[argidx],"status")) {
- ioctl(fd,SOUND_MIXER_PRIVATE2,&stat);
- fprintf(stdout,"stat.irq %d\n",stat.irq);
- fprintf(stdout,"stat.lockmask %d\n",stat.lockmask);
- fprintf(stdout,"stat.sr48 %d\n",stat.sr48);
- fprintf(stdout,"stat.wclock %d\n",stat.wclock);
- fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint);
- fprintf(stdout,"stat.syncmask %d\n",stat.syncmask);
- fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed);
- fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy);
- fprintf(stdout,"stat.tc_out %d\n",stat.tc_out);
- fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate);
- fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error);
- fprintf(stdout,"stat.bufid %d\n",stat.bufid);
- fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"control")) {
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- fprintf(stdout,"ctrl.start %d\n",ctrl.start);
- fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency);
- fprintf(stdout,"ctrl.master %d\n",ctrl.master);
- fprintf(stdout,"ctrl.ie %d\n",ctrl.ie);
- fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48);
- fprintf(stdout,"ctrl.spare %d\n",ctrl.spare);
- fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed);
- fprintf(stdout,"ctrl.pro %d\n",ctrl.pro);
- fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis);
- fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby);
- fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out);
- fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock);
- fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in);
- fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref);
- fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset);
- fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select);
- fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock);
- fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write);
- fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"mix")) {
- rme_mixer mix;
- int i;
-
- for (i=0; i<4; i++) {
- mix.devnr = i;
- ioctl(fd,SOUND_MIXER_PRIVATE1,&mix);
- if (mix.devnr == i) {
- fprintf(stdout,"devnr %d\n",mix.devnr);
- fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset);
- fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset);
- }
- }
- exit (0);
- }
-
-/* the control flags */
-
- if (argc < argidx+2)
- usage();
-
- if (!strcmp(argv[argidx],"master")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("master = %d\n",val);
- ctrl.master = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"pro")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("pro = %d\n",val);
- ctrl.pro = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"emphasis")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("emphasis = %d\n",val);
- ctrl.emphasis = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"dolby")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("dolby = %d\n",val);
- ctrl.dolby = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"optout")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("optout = %d\n",val);
- ctrl.opt_out = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"wordclock")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("wordclock = %d\n",val);
- ctrl.wordclock = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"spdifin")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("spdifin = %d\n",val);
- ctrl.spdif_in = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"syncref")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("syncref = %d\n",val);
- ctrl.sync_ref = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"adat1cd")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("adat1cd = %d\n",val);
- ctrl.adat1_cd = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
-/* setting offset */
-
- if (argc < argidx+4)
- usage();
-
- if (!strcmp(argv[argidx],"offset")) {
- rme_mixer mix;
-
- mix.devnr = atoi(argv[argidx+1]);
-
- mix.i_offset = atoi(argv[argidx+2]);
- mix.o_offset = atoi(argv[argidx+3]);
- ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix);
- fprintf(stdout,"devnr %d\n",mix.devnr);
- fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset);
- fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset);
- exit (0);
- }
-
- usage();
- exit (0); /* to avoid warning */
-}
-
-
----------------------------- <snip> --------------------------------
-#!/usr/bin/wish
-
-# xrmectrl
-# (C) 2000 Guenter Geiger <geiger@debian.org>
-# HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-
-#set defaults "-relief ridged"
-set CTRLPROG "./rmectrl"
-if {$argc} {
- set CTRLPROG "$CTRLPROG $argv"
-}
-puts "CTRLPROG $CTRLPROG"
-
-frame .butts
-button .butts.exit -text "Exit" -command "exit" -relief ridge
-#button .butts.state -text "State" -command "get_all"
-
-pack .butts.exit -side left
-pack .butts -side bottom
-
-
-#
-# STATUS
-#
-
-frame .status
-
-# Sampling Rate
-
-frame .status.sr
-label .status.sr.text -text "Sampling Rate" -justify left
-radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times
-radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times
-radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times
-radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw -variable srate -value 96000 -font times
-
-pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3
-
-# Lock
-
-frame .status.lock
-label .status.lock.text -text "Lock" -justify left
-checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times
-checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times
-checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times
-
-pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3
-
-# Sync
-
-frame .status.sync
-label .status.sync.text -text "Sync" -justify left
-checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times
-checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times
-checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times
-
-pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3
-
-# Timecode
-
-frame .status.tc
-label .status.tc.text -text "Timecode" -justify left
-checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times
-checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times
-checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times
-
-pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3
-
-# SPDIF In
-
-frame .status.spdif
-label .status.spdif.text -text "SPDIF In" -justify left
-label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times
-checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times
-
-pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3
-
-pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1
-
-
-#
-# CONTROL
-#
-
-proc setprof {} {
- global CTRLPROG
- global spprof
- exec $CTRLPROG pro $spprof
-}
-
-proc setemph {} {
- global CTRLPROG
- global spemph
- exec $CTRLPROG emphasis $spemph
-}
-
-proc setnoaud {} {
- global CTRLPROG
- global spnoaud
- exec $CTRLPROG dolby $spnoaud
-}
-
-proc setoptical {} {
- global CTRLPROG
- global spoptical
- exec $CTRLPROG optout $spoptical
-}
-
-proc setspdifin {} {
- global CTRLPROG
- global spdifin
- exec $CTRLPROG spdifin [expr $spdifin - 1]
-}
-
-proc setsyncsource {} {
- global CTRLPROG
- global syncsource
- exec $CTRLPROG syncref [expr $syncsource -1]
-}
-
-
-proc setmaster {} {
- global CTRLPROG
- global master
- exec $CTRLPROG master $master
-}
-
-proc setwordclock {} {
- global CTRLPROG
- global wordclock
- exec $CTRLPROG wordclock $wordclock
-}
-
-proc setadat1cd {} {
- global CTRLPROG
- global adat1cd
- exec $CTRLPROG adat1cd $adat1cd
-}
-
-
-frame .control
-
-# SPDIF In & SPDIF Out
-
-
-frame .control.spdif
-
-frame .control.spdif.in
-label .control.spdif.in.text -text "SPDIF In" -justify left
-radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times
-radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times
-radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times
-
-checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times
-
-pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd
-
-label .control.spdif.space
-
-frame .control.spdif.out
-label .control.spdif.out.text -text "SPDIF Out" -justify left
-checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times
-checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times
-checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times
-checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times
-
-pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom
-
-pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1
-
-# Sync Mode & Sync Source
-
-frame .control.sync
-frame .control.sync.mode
-label .control.sync.mode.text -text "Sync Mode" -justify left
-checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times
-checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times
-
-pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc
-
-label .control.sync.space
-
-frame .control.sync.src
-label .control.sync.src.text -text "Sync Source" -justify left
-radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times
-radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times
-radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times
-radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times
-
-pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom
-
-pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1
-
-label .control.space -text "" -width 10
-
-# Buffer Size
-
-frame .control.buf
-label .control.buf.text -text "Buffer Size (Latency)" -justify left
-radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times
-radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times
-radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times
-radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times
-radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times
-radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times
-radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times
-radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times
-
-pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3
-
-# Offset
-
-frame .control.offset
-
-frame .control.offset.in
-label .control.offset.in.text -text "Offset In" -justify left
-label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
-label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
-label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
-label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
-
-pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3
-
-label .control.offset.space
-
-frame .control.offset.out
-label .control.offset.out.text -text "Offset Out" -justify left
-label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
-label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
-label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
-label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
-
-pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom
-
-pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1
-
-
-pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1
-
-
-label .statustext -text Status -justify center -relief ridge
-label .controltext -text Control -justify center -relief ridge
-
-label .statusspace
-label .controlspace
-
-pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1
-
-
-proc get_bit {output sstr} {
- set idx1 [string last [concat $sstr 1] $output]
- set idx1 [expr $idx1 != -1]
- return $idx1
-}
-
-proc get_val {output sstr} {
- set val [string wordend $output [string last $sstr $output]]
- set val [string range $output $val [expr $val+1]]
- return $val
-}
-
-proc get_val2 {output sstr} {
- set val [string wordend $output [string first $sstr $output]]
- set val [string range $output $val [expr $val+2]]
- return $val
-}
-
-proc get_control {} {
- global spprof
- global spemph
- global spnoaud
- global spoptical
- global spdifin
- global ssrate
- global master
- global wordclock
- global syncsource
- global CTRLPROG
-
- set f [open "| $CTRLPROG control" r+]
- set ooo [read $f 1000]
- close $f
-# puts $ooo
-
- set spprof [ get_bit $ooo "pro"]
- set spemph [ get_bit $ooo "emphasis"]
- set spnoaud [ get_bit $ooo "dolby"]
- set spoptical [ get_bit $ooo "opt_out"]
- set spdifin [ expr [ get_val $ooo "spdif_in"] + 1]
- set ssrate [ expr [ get_val $ooo "latency"] + 1]
- set master [ expr [ get_val $ooo "master"]]
- set wordclock [ expr [ get_val $ooo "wordclock"]]
- set syncsource [ expr [ get_val $ooo "sync_ref"] + 1]
-}
-
-proc get_status {} {
- global srate
- global ctrlcom
-
- global adatlock1
- global adatlock2
- global adatlock3
-
- global adatsync1
- global adatsync2
- global adatsync3
-
- global tcbusy
- global tcout
- global tcvalid
-
- global spdiferr
- global crystal
- global .status.spdif.text
- global CTRLPROG
-
-
- set f [open "| $CTRLPROG status" r+]
- set ooo [read $f 1000]
- close $f
-# puts $ooo
-
-# samplerate
-
- set idx1 [string last "sr48 1" $ooo]
- set idx2 [string last "doublespeed 1" $ooo]
- if {$idx1 >= 0} {
- set fact1 48000
- } else {
- set fact1 44100
- }
-
- if {$idx2 >= 0} {
- set fact2 2
- } else {
- set fact2 1
- }
- set srate [expr $fact1 * $fact2]
-# ADAT lock
-
- set val [get_val $ooo lockmask]
- set adatlock1 0
- set adatlock2 0
- set adatlock3 0
- if {[expr $val & 1]} {
- set adatlock3 1
- }
- if {[expr $val & 2]} {
- set adatlock2 1
- }
- if {[expr $val & 4]} {
- set adatlock1 1
- }
-
-# ADAT sync
- set val [get_val $ooo syncmask]
- set adatsync1 0
- set adatsync2 0
- set adatsync3 0
-
- if {[expr $val & 1]} {
- set adatsync3 1
- }
- if {[expr $val & 2]} {
- set adatsync2 1
- }
- if {[expr $val & 4]} {
- set adatsync1 1
- }
-
-# TC busy
-
- set tcbusy [get_bit $ooo "busy"]
- set tcout [get_bit $ooo "out"]
- set tcvalid [get_bit $ooo "valid"]
- set spdiferr [expr [get_bit $ooo "spdif_error"] == 0]
-
-# 000=64kHz, 100=88.2kHz, 011=96kHz
-# 111=32kHz, 110=44.1kHz, 101=48kHz
-
- set val [get_val $ooo crystalrate]
-
- set crystal "--.- kHz"
- if {$val == 0} {
- set crystal "64 kHz"
- }
- if {$val == 4} {
- set crystal "88.2 kHz"
- }
- if {$val == 3} {
- set crystal "96 kHz"
- }
- if {$val == 7} {
- set crystal "32 kHz"
- }
- if {$val == 6} {
- set crystal "44.1 kHz"
- }
- if {$val == 5} {
- set crystal "48 kHz"
- }
- .status.spdif.sr configure -text $crystal
-}
-
-proc get_offset {} {
- global inoffset
- global outoffset
- global CTRLPROG
-
- set f [open "| $CTRLPROG mix" r+]
- set ooo [read $f 1000]
- close $f
-# puts $ooo
-
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off0 configure -text "dev\#0: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off0 configure -text "dev\#0: $val"
- } else {
- .control.offset.in.off0 configure -text "dev\#0: -"
- .control.offset.out.off0 configure -text "dev\#0: -"
- }
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off1 configure -text "dev\#1: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off1 configure -text "dev\#1: $val"
- } else {
- .control.offset.in.off1 configure -text "dev\#1: -"
- .control.offset.out.off1 configure -text "dev\#1: -"
- }
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off2 configure -text "dev\#2: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off2 configure -text "dev\#2: $val"
- } else {
- .control.offset.in.off2 configure -text "dev\#2: -"
- .control.offset.out.off2 configure -text "dev\#2: -"
- }
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off3 configure -text "dev\#3: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off3 configure -text "dev\#3: $val"
- } else {
- .control.offset.in.off3 configure -text "dev\#3: -"
- .control.offset.out.off3 configure -text "dev\#3: -"
- }
-}
-
-
-proc get_all {} {
-get_status
-get_control
-get_offset
-}
-
-# main
-while {1} {
- after 200
- get_all
- update
-}
diff --git a/Documentation/sound/oss/solo1 b/Documentation/sound/oss/solo1
deleted file mode 100644
index 95c4c834..0000000
--- a/Documentation/sound/oss/solo1
+++ /dev/null
@@ -1,70 +0,0 @@
-Recording
----------
-
-Recording does not work on the author's card, but there
-is at least one report of it working on later silicon.
-The chip behaves differently than described in the data sheet,
-likely due to a chip bug. Working around this would require
-the help of ESS (for example by publishing an errata sheet),
-but ESS has not done so far.
-
-Also, the chip only supports 24 bit addresses for recording,
-which means it cannot work on some Alpha mainboards.
-
-
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (or later, available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card has an OPL compatible FM synthesizer.
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/Documentation/sound/oss/sonicvibes b/Documentation/sound/oss/sonicvibes
deleted file mode 100644
index 84dee2e..0000000
--- a/Documentation/sound/oss/sonicvibes
+++ /dev/null
@@ -1,81 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card both has an OPL compatible FM synthesizer as well as
-a wavetable synthesizer.
-
-I haven't managed so far to get the OPL synth running.
-
-Using the wavetable synthesizer requires allocating
-1-4MB of physically contiguous memory, which isn't possible
-currently on Linux without ugly hacks like the bigphysarea
-patch. Therefore, the driver doesn't support wavetable
-synthesis.
-
-
-No support from S3
-------------------
-
-I do not get any support from S3. Therefore, the driver
-still has many problems. For example, although the manual
-states that the chip should be able to access the sample
-buffer anywhere in 32bit address space, I haven't managed to
-get it working with buffers above 16M. Therefore, the card
-has the same disadvantages as ISA soundcards.
-
-Given that the card is also very noisy, and if you haven't
-already bought it, you should strongly opt for one of the
-comparatively priced Ensoniq products.
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/MAINTAINERS b/MAINTAINERS
index 1c6223d..8c35b3c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -977,6 +977,13 @@
W: http://ebtables.sourceforge.net/
S: Maintained
+ECRYPT FILE SYSTEM
+P: Mike Halcrow, Phillip Hellewell
+M: mhalcrow@us.ibm.com, phillip@hellewell.homeip.net
+L: ecryptfs-devel@lists.sourceforge.net
+W: http://ecryptfs.sourceforge.net/
+S: Supported
+
EDAC-CORE
P: Doug Thompson
M: norsk5@xmission.com
@@ -1893,11 +1900,6 @@
W: http://www.syskonnect.com
S: Supported
-MAESTRO PCI SOUND DRIVERS
-P: Zach Brown
-M: zab@zabbo.net
-S: Odd Fixes
-
MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
P: Michael Kerrisk
M: mtk-manpages@gmx.net
@@ -2434,6 +2436,19 @@
L: linux-kernel@vger.kernel.org
S: Maintained
+READ-COPY UPDATE (RCU)
+P: Dipankar Sarma
+M: dipankar@in.ibm.com
+W: http://www.rdrop.com/users/paulmck/rclock/
+L: linux-kernel@vger.kernel.org
+S: Supported
+
+RCUTORTURE MODULE
+P: Josh Triplett
+M: josh@freedesktop.org
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
REAL TIME CLOCK DRIVER
P: Paul Gortmaker
M: p_gortmaker@yahoo.com
@@ -2854,6 +2869,11 @@
W: http://tcp-lp-mod.sourceforge.net/
S: Maintained
+TI FLASH MEDIA INTERFACE DRIVER
+P: Alex Dubov
+M: oakad@yahoo.com
+S: Maintained
+
TI OMAP RANDOM NUMBER GENERATOR SUPPORT
P: Deepak Saxena
M: dsaxena@plexity.net
@@ -3377,12 +3397,6 @@
L: usbb2k-api-dev@nongnu.org
S: Maintained
-YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
-P: Pete Zaitcev
-M: zaitcev@yahoo.com
-L: linux-kernel@vger.kernel.org
-S: Obsolete
-
Z8530 DRIVER FOR AX.25
P: Joerg Reuter
M: jreuter@yaina.de
diff --git a/Makefile b/Makefile
index 4c6c5e3..adb2c74 100644
--- a/Makefile
+++ b/Makefile
@@ -1321,7 +1321,7 @@
--langdef=kconfig \
--language-force=kconfig \
--regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \
- $(all-defconfigs) | xargs $1 -a \
+ $(all-defconfigs) | xargs -r $1 -a \
--langdef=dotconfig \
--language-force=dotconfig \
--regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \
@@ -1329,7 +1329,7 @@
$(all-sources) | xargs $1 -a; \
$(all-kconfigs) | xargs $1 -a \
--regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \
- $(all-defconfigs) | xargs $1 -a \
+ $(all-defconfigs) | xargs -r $1 -a \
--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
else \
$(all-sources) | xargs $1 -a; \
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 1aaea6a..92f79cd 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -62,8 +62,6 @@
#include <mach_mpparse.h>
#endif /* CONFIG_X86_LOCAL_APIC */
-static inline int gsi_irq_sharing(int gsi) { return gsi; }
-
#endif /* X86 */
#define BAD_MADT_ENTRY(entry, end) ( \
@@ -468,12 +466,7 @@
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
-#ifdef CONFIG_X86_IO_APIC
- if (use_pci_vector() && !platform_legacy_irq(gsi))
- *irq = IO_APIC_VECTOR(gsi);
- else
-#endif
- *irq = gsi_irq_sharing(gsi);
+ *irq = gsi;
return 0;
}
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index ea5f4e7..d07ed31 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -34,35 +34,15 @@
* moves to arch independent land
*/
-DEFINE_SPINLOCK(i8259A_lock);
-
-static void end_8259A_irq (unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
- irq_desc[irq].action)
- enable_8259A_irq(irq);
-}
-
-#define shutdown_8259A_irq disable_8259A_irq
-
static int i8259A_auto_eoi;
-
+DEFINE_SPINLOCK(i8259A_lock);
static void mask_and_ack_8259A(unsigned int);
-unsigned int startup_8259A_irq(unsigned int irq)
-{
- enable_8259A_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type i8259A_irq_type = {
- .typename = "XT-PIC",
- .startup = startup_8259A_irq,
- .shutdown = shutdown_8259A_irq,
- .enable = enable_8259A_irq,
- .disable = disable_8259A_irq,
- .ack = mask_and_ack_8259A,
- .end = end_8259A_irq,
+static struct irq_chip i8259A_chip = {
+ .name = "XT-PIC",
+ .mask = disable_8259A_irq,
+ .unmask = enable_8259A_irq,
+ .mask_ack = mask_and_ack_8259A,
};
/*
@@ -133,7 +113,7 @@
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<<irq);
- irq_desc[irq].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
enable_irq(irq);
}
@@ -327,12 +307,12 @@
outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
if (auto_eoi)
/*
- * in AEOI mode we just have to mask the interrupt
+ * In AEOI mode we just have to mask the interrupt
* when acking.
*/
- i8259A_irq_type.ack = disable_8259A_irq;
+ i8259A_chip.mask_ack = disable_8259A_irq;
else
- i8259A_irq_type.ack = mask_and_ack_8259A;
+ i8259A_chip.mask_ack = mask_and_ack_8259A;
udelay(100); /* wait for 8259A to initialize */
@@ -389,12 +369,13 @@
/*
* 16 old-style INTA-cycle interrupts:
*/
- irq_desc[i].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler(i, &i8259A_chip,
+ handle_level_irq);
} else {
/*
* 'high' PCI IRQs filled in on demand
*/
- irq_desc[i].chip = &no_irq_type;
+ irq_desc[i].chip = &no_irq_chip;
}
}
}
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index fd0df75..b7287fb 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -31,6 +31,9 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/sysdev.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/htirq.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -38,6 +41,8 @@
#include <asm/timer.h>
#include <asm/i8259.h>
#include <asm/nmi.h>
+#include <asm/msidef.h>
+#include <asm/hypertransport.h>
#include <mach_apic.h>
#include <mach_apicdef.h>
@@ -86,15 +91,6 @@
int apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
-#ifdef CONFIG_PCI_MSI
-#define vector_to_irq(vector) \
- (platform_legacy_irq(vector) ? vector : vector_irq[vector])
-#else
-#define vector_to_irq(vector) (vector)
-#endif
-
-
union entry_union {
struct { u32 w1, w2; };
struct IO_APIC_route_entry entry;
@@ -280,7 +276,7 @@
break;
entry = irq_2_pin + entry->next;
}
- set_irq_info(irq, cpumask);
+ set_native_irq_info(irq, cpumask);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -1181,46 +1177,45 @@
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
-int assign_irq_vector(int irq)
+static int __assign_irq_vector(int irq)
{
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
- unsigned long flags;
int vector;
- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
- spin_lock_irqsave(&vector_lock, flags);
-
- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
- spin_unlock_irqrestore(&vector_lock, flags);
+ if (IO_APIC_VECTOR(irq) > 0)
return IO_APIC_VECTOR(irq);
- }
-next:
+
current_vector += 8;
if (current_vector == SYSCALL_VECTOR)
- goto next;
+ current_vector += 8;
if (current_vector >= FIRST_SYSTEM_VECTOR) {
offset++;
- if (!(offset%8)) {
- spin_unlock_irqrestore(&vector_lock, flags);
+ if (!(offset % 8))
return -ENOSPC;
- }
current_vector = FIRST_DEVICE_VECTOR + offset;
}
vector = current_vector;
- vector_irq[vector] = irq;
- if (irq != AUTO_ASSIGN)
- IO_APIC_VECTOR(irq) = vector;
-
- spin_unlock_irqrestore(&vector_lock, flags);
+ IO_APIC_VECTOR(irq) = vector;
return vector;
}
-static struct hw_interrupt_type ioapic_level_type;
-static struct hw_interrupt_type ioapic_edge_type;
+static int assign_irq_vector(int irq)
+{
+ unsigned long flags;
+ int vector;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ vector = __assign_irq_vector(irq);
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ return vector;
+}
+static struct irq_chip ioapic_chip;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
@@ -1228,16 +1223,14 @@
static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
{
- unsigned idx;
-
- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
-
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL)
- irq_desc[idx].chip = &ioapic_level_type;
+ set_irq_chip_and_handler(irq, &ioapic_chip,
+ handle_fasteoi_irq);
else
- irq_desc[idx].chip = &ioapic_edge_type;
- set_intr_gate(vector, interrupt[idx]);
+ set_irq_chip_and_handler(irq, &ioapic_chip,
+ handle_edge_irq);
+ set_intr_gate(vector, interrupt[irq]);
}
static void __init setup_IO_APIC_irqs(void)
@@ -1346,7 +1339,8 @@
* The timer IRQ doesn't have to know that behind the
* scene we have a 8259A-master in AEOI mode ...
*/
- irq_desc[0].chip = &ioapic_edge_type;
+ irq_desc[0].chip = &ioapic_chip;
+ set_irq_handler(0, handle_edge_irq);
/*
* Add it to the IO-APIC irq-routing table:
@@ -1481,17 +1475,12 @@
);
}
}
- if (use_pci_vector())
- printk(KERN_INFO "Using vector-based indexing\n");
printk(KERN_DEBUG "IRQ to pin mappings:\n");
for (i = 0; i < NR_IRQS; i++) {
struct irq_pin_list *entry = irq_2_pin + i;
if (entry->pin < 0)
continue;
- if (use_pci_vector() && !platform_legacy_irq(i))
- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
- else
- printk(KERN_DEBUG "IRQ%d ", i);
+ printk(KERN_DEBUG "IRQ%d ", i);
for (;;) {
printk("-> %d:%d", entry->apic, entry->pin);
if (!entry->next)
@@ -1918,6 +1907,8 @@
*/
/*
+ * Startup quirk:
+ *
* Starting up a edge-triggered IO-APIC interrupt is
* nasty - we need to make sure that we get the edge.
* If it is already asserted for some reason, we need
@@ -1925,8 +1916,10 @@
*
* This is not complete - we should be able to fake
* an edge even if it isn't on the 8259A...
+ *
+ * (We do this for level-triggered IRQs too - it cannot hurt.)
*/
-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
unsigned long flags;
@@ -1943,47 +1936,18 @@
return was_pending;
}
-/*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
-static void ack_edge_ioapic_irq(unsigned int irq)
+static void ack_ioapic_irq(unsigned int irq)
{
- move_irq(irq);
- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
- == (IRQ_PENDING | IRQ_DISABLED))
- mask_IO_APIC_irq(irq);
+ move_native_irq(irq);
ack_APIC_irq();
}
-/*
- * Level triggered interrupts can just be masked,
- * and shutting down and starting up the interrupt
- * is the same as enabling and disabling them -- except
- * with a startup need to return a "was pending" value.
- *
- * Level triggered interrupts are special because we
- * do not touch any IO-APIC register while handling
- * them. We ack the APIC in the end-IRQ handler, not
- * in the start-IRQ-handler. Protection against reentrance
- * from the same interrupt is still provided, both by the
- * generic IRQ layer and by the fact that an unacked local
- * APIC does not accept IRQs.
- */
-static unsigned int startup_level_ioapic_irq (unsigned int irq)
-{
- unmask_IO_APIC_irq(irq);
-
- return 0; /* don't check for pending */
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
+static void ack_ioapic_quirk_irq(unsigned int irq)
{
unsigned long v;
int i;
- move_irq(irq);
+ move_native_irq(irq);
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
@@ -2018,105 +1982,26 @@
}
}
-#ifdef CONFIG_PCI_MSI
-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_edge_ioapic_irq(irq);
-}
-
-static void ack_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- ack_edge_ioapic_irq(irq);
-}
-
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_level_ioapic_irq (irq);
-}
-
-static void end_level_ioapic_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- end_level_ioapic_irq(irq);
-}
-
-static void mask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- mask_IO_APIC_irq(irq);
-}
-
-static void unmask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- unmask_IO_APIC_irq(irq);
-}
-
-#ifdef CONFIG_SMP
-static void set_ioapic_affinity_vector (unsigned int vector,
- cpumask_t cpu_mask)
-{
- int irq = vector_to_irq(vector);
-
- set_native_irq_info(vector, cpu_mask);
- set_ioapic_affinity_irq(irq, cpu_mask);
-}
-#endif
-#endif
-
-static int ioapic_retrigger(unsigned int irq)
+static int ioapic_retrigger_irq(unsigned int irq)
{
send_IPI_self(IO_APIC_VECTOR(irq));
return 1;
}
-/*
- * Level and edge triggered IO-APIC interrupts need different handling,
- * so we use two separate IRQ descriptors. Edge triggered IRQs can be
- * handled with the level-triggered descriptor, but that one has slightly
- * more overhead. Level-triggered interrupts cannot be handled with the
- * edge-triggered handler, without risking IRQ storms and other ugly
- * races.
- */
-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
- .typename = "IO-APIC-edge",
- .startup = startup_edge_ioapic,
- .shutdown = shutdown_edge_ioapic,
- .enable = enable_edge_ioapic,
- .disable = disable_edge_ioapic,
- .ack = ack_edge_ioapic,
- .end = end_edge_ioapic,
+static struct irq_chip ioapic_chip __read_mostly = {
+ .name = "IO-APIC",
+ .startup = startup_ioapic_irq,
+ .mask = mask_IO_APIC_irq,
+ .unmask = unmask_IO_APIC_irq,
+ .ack = ack_ioapic_irq,
+ .eoi = ack_ioapic_quirk_irq,
#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
+ .set_affinity = set_ioapic_affinity_irq,
#endif
- .retrigger = ioapic_retrigger,
+ .retrigger = ioapic_retrigger_irq,
};
-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
- .typename = "IO-APIC-level",
- .startup = startup_level_ioapic,
- .shutdown = shutdown_level_ioapic,
- .enable = enable_level_ioapic,
- .disable = disable_level_ioapic,
- .ack = mask_and_ack_level_ioapic,
- .end = end_level_ioapic,
-#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
-#endif
- .retrigger = ioapic_retrigger,
-};
static inline void init_IO_APIC_traps(void)
{
@@ -2135,11 +2020,6 @@
*/
for (irq = 0; irq < NR_IRQS ; irq++) {
int tmp = irq;
- if (use_pci_vector()) {
- if (!platform_legacy_irq(tmp))
- if ((tmp = vector_to_irq(tmp)) == -1)
- continue;
- }
if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
/*
* Hmm.. We don't have an entry for this,
@@ -2150,20 +2030,21 @@
make_8259A_irq(irq);
else
/* Strange. Oh, well.. */
- irq_desc[irq].chip = &no_irq_type;
+ irq_desc[irq].chip = &no_irq_chip;
}
}
}
-static void enable_lapic_irq (unsigned int irq)
-{
- unsigned long v;
+/*
+ * The local APIC irq-chip implementation:
+ */
- v = apic_read(APIC_LVT0);
- apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+static void ack_apic(unsigned int irq)
+{
+ ack_APIC_irq();
}
-static void disable_lapic_irq (unsigned int irq)
+static void mask_lapic_irq (unsigned int irq)
{
unsigned long v;
@@ -2171,21 +2052,19 @@
apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
}
-static void ack_lapic_irq (unsigned int irq)
+static void unmask_lapic_irq (unsigned int irq)
{
- ack_APIC_irq();
+ unsigned long v;
+
+ v = apic_read(APIC_LVT0);
+ apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
}
-static void end_lapic_irq (unsigned int i) { /* nothing */ }
-
-static struct hw_interrupt_type lapic_irq_type __read_mostly = {
- .typename = "local-APIC-edge",
- .startup = NULL, /* startup_irq() not used for IRQ0 */
- .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
- .enable = enable_lapic_irq,
- .disable = disable_lapic_irq,
- .ack = ack_lapic_irq,
- .end = end_lapic_irq
+static struct irq_chip lapic_chip __read_mostly = {
+ .name = "local-APIC-edge",
+ .mask = mask_lapic_irq,
+ .unmask = unmask_lapic_irq,
+ .eoi = ack_apic,
};
static void setup_nmi (void)
@@ -2356,7 +2235,7 @@
printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
disable_8259A_irq(0);
- irq_desc[0].chip = &lapic_irq_type;
+ set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq);
apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
enable_8259A_irq(0);
@@ -2531,6 +2410,238 @@
device_initcall(ioapic_init_sysfs);
+/*
+ * Dynamic irq allocate and deallocation
+ */
+int create_irq(void)
+{
+ /* Allocate an unused irq */
+ int irq, new, vector;
+ unsigned long flags;
+
+ irq = -ENOSPC;
+ spin_lock_irqsave(&vector_lock, flags);
+ for (new = (NR_IRQS - 1); new >= 0; new--) {
+ if (platform_legacy_irq(new))
+ continue;
+ if (irq_vector[new] != 0)
+ continue;
+ vector = __assign_irq_vector(new);
+ if (likely(vector > 0))
+ irq = new;
+ break;
+ }
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ if (irq >= 0) {
+ set_intr_gate(vector, interrupt[irq]);
+ dynamic_irq_init(irq);
+ }
+ return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ dynamic_irq_cleanup(irq);
+
+ spin_lock_irqsave(&vector_lock, flags);
+ irq_vector[irq] = 0;
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+/*
+ * MSI mesage composition
+ */
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+{
+ int vector;
+ unsigned dest;
+
+ vector = assign_irq_vector(irq);
+ if (vector >= 0) {
+ dest = cpu_mask_to_apicid(TARGET_CPUS);
+
+ msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->address_lo =
+ MSI_ADDR_BASE_LO |
+ ((INT_DEST_MODE == 0) ?
+ MSI_ADDR_DEST_MODE_PHYSICAL:
+ MSI_ADDR_DEST_MODE_LOGICAL) |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_ADDR_REDIRECTION_CPU:
+ MSI_ADDR_REDIRECTION_LOWPRI) |
+ MSI_ADDR_DEST_ID(dest);
+
+ msg->data =
+ MSI_DATA_TRIGGER_EDGE |
+ MSI_DATA_LEVEL_ASSERT |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_DATA_DELIVERY_FIXED:
+ MSI_DATA_DELIVERY_LOWPRI) |
+ MSI_DATA_VECTOR(vector);
+ }
+ return vector;
+}
+
+#ifdef CONFIG_SMP
+static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ struct msi_msg msg;
+ unsigned int dest;
+ cpumask_t tmp;
+ int vector;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ vector = assign_irq_vector(irq);
+ if (vector < 0)
+ return;
+
+ dest = cpu_mask_to_apicid(mask);
+
+ read_msi_msg(irq, &msg);
+
+ msg.data &= ~MSI_DATA_VECTOR_MASK;
+ msg.data |= MSI_DATA_VECTOR(vector);
+ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, mask);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip msi_chip = {
+ .name = "PCI-MSI",
+ .unmask = unmask_msi_irq,
+ .mask = mask_msi_irq,
+ .ack = ack_ioapic_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = set_msi_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+{
+ struct msi_msg msg;
+ int ret;
+ ret = msi_compose_msg(dev, irq, &msg);
+ if (ret < 0)
+ return ret;
+
+ write_msi_msg(irq, &msg);
+
+ set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq);
+
+ return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ return;
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+/*
+ * Hypertransport interrupt support
+ */
+#ifdef CONFIG_HT_IRQ
+
+#ifdef CONFIG_SMP
+
+static void target_ht_irq(unsigned int irq, unsigned int dest)
+{
+ u32 low, high;
+ low = read_ht_irq_low(irq);
+ high = read_ht_irq_high(irq);
+
+ low &= ~(HT_IRQ_LOW_DEST_ID_MASK);
+ high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+
+ low |= HT_IRQ_LOW_DEST_ID(dest);
+ high |= HT_IRQ_HIGH_DEST_ID(dest);
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+}
+
+static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ unsigned int dest;
+ cpumask_t tmp;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+ dest = cpu_mask_to_apicid(mask);
+
+ target_ht_irq(irq, dest);
+ set_native_irq_info(irq, mask);
+}
+#endif
+
+static struct hw_interrupt_type ht_irq_chip = {
+ .name = "PCI-HT",
+ .mask = mask_ht_irq,
+ .unmask = unmask_ht_irq,
+ .ack = ack_ioapic_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = set_ht_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+{
+ int vector;
+
+ vector = assign_irq_vector(irq);
+ if (vector >= 0) {
+ u32 low, high;
+ unsigned dest;
+ cpumask_t tmp;
+
+ cpus_clear(tmp);
+ cpu_set(vector >> 8, tmp);
+ dest = cpu_mask_to_apicid(tmp);
+
+ high = HT_IRQ_HIGH_DEST_ID(dest);
+
+ low = HT_IRQ_LOW_BASE |
+ HT_IRQ_LOW_DEST_ID(dest) |
+ HT_IRQ_LOW_VECTOR(vector) |
+ ((INT_DEST_MODE == 0) ?
+ HT_IRQ_LOW_DM_PHYSICAL :
+ HT_IRQ_LOW_DM_LOGICAL) |
+ HT_IRQ_LOW_RQEOI_EDGE |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ HT_IRQ_LOW_MT_FIXED :
+ HT_IRQ_LOW_MT_ARBITRATED) |
+ HT_IRQ_LOW_IRQ_MASKED;
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+
+ set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq);
+ }
+ return vector;
+}
+#endif /* CONFIG_HT_IRQ */
+
/* --------------------------------------------------------------------------
ACPI-based IOAPIC Configuration
-------------------------------------------------------------------------- */
@@ -2684,7 +2795,7 @@
ioapic_write_entry(ioapic, pin, entry);
spin_lock_irqsave(&ioapic_lock, flags);
- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
+ set_native_irq_info(irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 5fe547c..3dd2e18 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -55,6 +55,7 @@
{
/* high bit used in ret_from_ code */
int irq = ~regs->orig_eax;
+ struct irq_desc *desc = irq_desc + irq;
#ifdef CONFIG_4KSTACKS
union irq_ctx *curctx, *irqctx;
u32 *isp;
@@ -94,7 +95,7 @@
* current stack (which is the irq stack already after all)
*/
if (curctx != irqctx) {
- int arg1, arg2, ebx;
+ int arg1, arg2, arg3, ebx;
/* build the stack frame on the IRQ stack */
isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -110,16 +111,17 @@
(curctx->tinfo.preempt_count & SOFTIRQ_MASK);
asm volatile(
- " xchgl %%ebx,%%esp \n"
- " call __do_IRQ \n"
+ " xchgl %%ebx,%%esp \n"
+ " call *%%edi \n"
" movl %%ebx,%%esp \n"
- : "=a" (arg1), "=d" (arg2), "=b" (ebx)
- : "0" (irq), "1" (regs), "2" (isp)
- : "memory", "cc", "ecx"
+ : "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx)
+ : "0" (irq), "1" (desc), "2" (regs), "3" (isp),
+ "D" (desc->handle_irq)
+ : "memory", "cc"
);
} else
#endif
- __do_IRQ(irq, regs);
+ desc->handle_irq(irq, desc, regs);
irq_exit();
@@ -253,7 +255,8 @@
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- seq_printf(p, " %14s", irq_desc[i].chip->typename);
+ seq_printf(p, " %8s", irq_desc[i].chip->name);
+ seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 4a8995c..47f02af 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -981,10 +981,6 @@
pci_name(bridge), 'A' + pin, irq);
}
if (irq >= 0) {
- if (use_pci_vector() &&
- !platform_legacy_irq(irq))
- irq = IO_APIC_VECTOR(irq);
-
printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
pci_name(dev), 'A' + pin, irq);
dev->irq = irq;
@@ -1169,33 +1165,3 @@
}
return 0;
}
-
-int pci_vector_resources(int last, int nr_released)
-{
- int count = nr_released;
-
- int next = last;
- int offset = (last % 8);
-
- while (next < FIRST_SYSTEM_VECTOR) {
- next += 8;
-#ifdef CONFIG_X86_64
- if (next == IA32_SYSCALL_VECTOR)
- continue;
-#else
- if (next == SYSCALL_VECTOR)
- continue;
-#endif
- count++;
- if (next >= FIRST_SYSTEM_VECTOR) {
- if (offset%8) {
- next = FIRST_DEVICE_VECTOR + offset;
- offset++;
- continue;
- }
- count--;
- }
- }
-
- return count;
-}
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 3149749..cfa099b 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -30,6 +30,7 @@
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
obj-$(CONFIG_AUDIT) += audit.o
+obj-$(CONFIG_PCI_MSI) += msi_ia64.o
mca_recovery-y += mca_drv.o mca_drv_asm.o
obj-$(CONFIG_IA64_ESI) += esi.o
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index aafca18..ab2d19c 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -30,6 +30,7 @@
#include <linux/smp_lock.h>
#include <linux/threads.h>
#include <linux/bitops.h>
+#include <linux/irq.h>
#include <asm/delay.h>
#include <asm/intrinsics.h>
@@ -105,6 +106,25 @@
return test_and_set_bit(pos, ia64_vector_mask);
}
+/*
+ * Dynamic irq allocate and deallocation for MSI
+ */
+int create_irq(void)
+{
+ int vector = assign_irq_vector(AUTO_ASSIGN);
+
+ if (vector >= 0)
+ dynamic_irq_init(vector);
+
+ return vector;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ dynamic_irq_cleanup(irq);
+ free_irq_vector(irq);
+}
+
#ifdef CONFIG_SMP
# define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
#else
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
new file mode 100644
index 0000000..822e59a
--- /dev/null
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -0,0 +1,143 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <asm/smp.h>
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT 0
+#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT 8
+#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
+#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT 14
+#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT 15
+#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_TARGET_CPU_SHIFT 4
+#define MSI_ADDR_HEADER 0xfee00000
+
+#define MSI_ADDR_DESTID_MASK 0xfff0000f
+#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT 2
+#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
+#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT 3
+#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+static struct irq_chip ia64_msi_chip;
+
+#ifdef CONFIG_SMP
+static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
+{
+ struct msi_msg msg;
+ u32 addr;
+
+ read_msi_msg(irq, &msg);
+
+ addr = msg.address_lo;
+ addr &= MSI_ADDR_DESTID_MASK;
+ addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+ msg.address_lo = addr;
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, cpu_mask);
+}
+#endif /* CONFIG_SMP */
+
+int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+ struct msi_msg msg;
+ unsigned long dest_phys_id;
+ unsigned int vector;
+
+ dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+ vector = irq;
+
+ msg.address_hi = 0;
+ msg.address_lo =
+ MSI_ADDR_HEADER |
+ MSI_ADDR_DESTMODE_PHYS |
+ MSI_ADDR_REDIRECTION_CPU |
+ MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+ msg.data =
+ MSI_DATA_TRIGGER_EDGE |
+ MSI_DATA_LEVEL_ASSERT |
+ MSI_DATA_DELIVERY_FIXED |
+ MSI_DATA_VECTOR(vector);
+
+ write_msi_msg(irq, &msg);
+ set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
+
+ return 0;
+}
+
+void ia64_teardown_msi_irq(unsigned int irq)
+{
+ return; /* no-op */
+}
+
+static void ia64_ack_msi_irq(unsigned int irq)
+{
+ move_native_irq(irq);
+ ia64_eoi();
+}
+
+static int ia64_msi_retrigger_irq(unsigned int irq)
+{
+ unsigned int vector = irq;
+ ia64_resend_irq(vector);
+
+ return 1;
+}
+
+/*
+ * Generic ops used on most IA64 platforms.
+ */
+static struct irq_chip ia64_msi_chip = {
+ .name = "PCI-MSI",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .ack = ia64_ack_msi_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = ia64_set_msi_irq_affinity,
+#endif
+ .retrigger = ia64_msi_retrigger_irq,
+};
+
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+ if (platform_setup_msi_irq)
+ return platform_setup_msi_irq(irq, pdev);
+
+ return ia64_setup_msi_irq(irq, pdev);
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ if (platform_teardown_msi_irq)
+ return platform_teardown_msi_irq(irq);
+
+ return ia64_teardown_msi_irq(irq);
+}
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 15c7c67..b30be7c 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -810,12 +810,3 @@
}
return rc;
}
-
-int pci_vector_resources(int last, int nr_released)
-{
- int count = nr_released;
-
- count += (IA64_LAST_DEVICE_VECTOR - last);
-
- return count;
-}
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile
index ab9c48c..2d78f34 100644
--- a/arch/ia64/sn/kernel/Makefile
+++ b/arch/ia64/sn/kernel/Makefile
@@ -19,3 +19,4 @@
obj-$(CONFIG_IA64_SGI_SN_XP) += xpc.o
xpc-y := xpc_main.o xpc_channel.o xpc_partition.o
obj-$(CONFIG_IA64_SGI_SN_XP) += xpnet.o
+obj-$(CONFIG_PCI_MSI) += msi_sn.o
diff --git a/drivers/pci/msi-altix.c b/arch/ia64/sn/kernel/msi_sn.c
similarity index 65%
rename from drivers/pci/msi-altix.c
rename to arch/ia64/sn/kernel/msi_sn.c
index bed4183..6ffd1f8 100644
--- a/drivers/pci/msi-altix.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -7,8 +7,10 @@
*/
#include <linux/types.h>
+#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/cpumask.h>
+#include <linux/msi.h>
#include <asm/sn/addrs.h>
#include <asm/sn/intr.h>
@@ -16,17 +18,16 @@
#include <asm/sn/pcidev.h>
#include <asm/sn/nodepda.h>
-#include "msi.h"
-
struct sn_msi_info {
u64 pci_addr;
struct sn_irq_info *sn_irq_info;
};
-static struct sn_msi_info *sn_msi_info;
+static struct sn_msi_info sn_msi_info[NR_IRQS];
-static void
-sn_msi_teardown(unsigned int vector)
+static struct irq_chip sn_msi_chip;
+
+void sn_teardown_msi_irq(unsigned int irq)
{
nasid_t nasid;
int widget;
@@ -36,7 +37,7 @@
struct pcibus_bussoft *bussoft;
struct sn_pcibus_provider *provider;
- sn_irq_info = sn_msi_info[vector].sn_irq_info;
+ sn_irq_info = sn_msi_info[irq].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return;
@@ -45,9 +46,9 @@
provider = SN_PCIDEV_BUSPROVIDER(pdev);
(*provider->dma_unmap)(pdev,
- sn_msi_info[vector].pci_addr,
+ sn_msi_info[irq].pci_addr,
PCI_DMA_FROMDEVICE);
- sn_msi_info[vector].pci_addr = 0;
+ sn_msi_info[irq].pci_addr = 0;
bussoft = SN_PCIDEV_BUSSOFT(pdev);
nasid = NASID_GET(bussoft->bs_base);
@@ -56,15 +57,15 @@
SWIN_WIDGETNUM(bussoft->bs_base);
sn_intr_free(nasid, widget, sn_irq_info);
- sn_msi_info[vector].sn_irq_info = NULL;
+ sn_msi_info[irq].sn_irq_info = NULL;
return;
}
-int
-sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
- u32 *addr_hi, u32 *addr_lo, u32 *data)
+int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
{
+ struct msi_msg msg;
+ struct msi_desc *entry;
int widget;
int status;
nasid_t nasid;
@@ -73,6 +74,10 @@
struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+ entry = get_irq_data(irq);
+ if (!entry->msi_attrib.is_64)
+ return -EINVAL;
+
if (bussoft == NULL)
return -EINVAL;
@@ -93,7 +98,7 @@
if (! sn_irq_info)
return -ENOMEM;
- status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
+ status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
if (status) {
kfree(sn_irq_info);
return -ENOMEM;
@@ -119,29 +124,32 @@
return -ENOMEM;
}
- sn_msi_info[vector].sn_irq_info = sn_irq_info;
- sn_msi_info[vector].pci_addr = bus_addr;
+ sn_msi_info[irq].sn_irq_info = sn_irq_info;
+ sn_msi_info[irq].pci_addr = bus_addr;
- *addr_hi = (u32)(bus_addr >> 32);
- *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+ msg.address_hi = (u32)(bus_addr >> 32);
+ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
/*
* In the SN platform, bit 16 is a "send vector" bit which
* must be present in order to move the vector through the system.
*/
- *data = 0x100 + (unsigned int)vector;
+ msg.data = 0x100 + irq;
#ifdef CONFIG_SMP
- set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
+ set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
#endif
+ write_msi_msg(irq, &msg);
+ set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
+
return 0;
}
-static void
-sn_msi_target(unsigned int vector, unsigned int cpu,
- u32 *addr_hi, u32 *addr_lo)
+#ifdef CONFIG_SMP
+static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
{
+ struct msi_msg msg;
int slice;
nasid_t nasid;
u64 bus_addr;
@@ -150,8 +158,10 @@
struct sn_irq_info *sn_irq_info;
struct sn_irq_info *new_irq_info;
struct sn_pcibus_provider *provider;
+ unsigned int cpu;
- sn_irq_info = sn_msi_info[vector].sn_irq_info;
+ cpu = first_cpu(cpu_mask);
+ sn_irq_info = sn_msi_info[irq].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return;
@@ -159,19 +169,20 @@
* Release XIO resources for the old MSI PCI address
*/
+ read_msi_msg(irq, &msg);
sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
pdev = sn_pdev->pdi_linux_pcidev;
provider = SN_PCIDEV_BUSPROVIDER(pdev);
- bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
+ bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo);
(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
- sn_msi_info[vector].pci_addr = 0;
+ sn_msi_info[irq].pci_addr = 0;
nasid = cpuid_to_nasid(cpu);
slice = cpuid_to_slice(cpu);
new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
- sn_msi_info[vector].sn_irq_info = new_irq_info;
+ sn_msi_info[irq].sn_irq_info = new_irq_info;
if (new_irq_info == NULL)
return;
@@ -184,27 +195,36 @@
sizeof(new_irq_info->irq_xtalkaddr),
SN_DMA_MSI|SN_DMA_ADDR_XIO);
- sn_msi_info[vector].pci_addr = bus_addr;
- *addr_hi = (u32)(bus_addr >> 32);
- *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+ sn_msi_info[irq].pci_addr = bus_addr;
+ msg.address_hi = (u32)(bus_addr >> 32);
+ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, cpu_mask);
}
+#endif /* CONFIG_SMP */
-struct msi_ops sn_msi_ops = {
- .setup = sn_msi_setup,
- .teardown = sn_msi_teardown,
-#ifdef CONFIG_SMP
- .target = sn_msi_target,
-#endif
-};
-
-int
-sn_msi_init(void)
+static void sn_ack_msi_irq(unsigned int irq)
{
- sn_msi_info =
- kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
- if (! sn_msi_info)
- return -ENOMEM;
-
- msi_register(&sn_msi_ops);
- return 0;
+ move_native_irq(irq);
+ ia64_eoi();
}
+
+static int sn_msi_retrigger_irq(unsigned int irq)
+{
+ unsigned int vector = irq;
+ ia64_resend_irq(vector);
+
+ return 1;
+}
+
+static struct irq_chip sn_msi_chip = {
+ .name = "PCI-MSI",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .ack = sn_ack_msi_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = sn_set_msi_irq_affinity,
+#endif
+ .retrigger = sn_msi_retrigger_irq,
+};
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index c383d56..003520b 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -113,7 +113,7 @@
endif
quiet_cmd_wrap = WRAP $@
- cmd_wrap =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
+ cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
quiet_cmd_wrap_initrd = WRAP $@
cmd_wrap_initrd =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
-i $(obj)/ramdisk.image.gz vmlinux
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 723972b..3ee03a9 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -341,7 +341,7 @@
u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
if (id == PCI_CAP_ID_HT) {
id = readb(devbase + pos + 3);
- if (id == 0x80)
+ if (id == HT_CAPTYPE_IRQ)
break;
}
}
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 2dd51f3..0612a33 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -43,17 +43,10 @@
BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
BI(x,c) BI(x,d) BI(x,e) BI(x,f)
-#define BUILD_15_IRQS(x) \
- BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
- BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
- BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
- BI(x,c) BI(x,d) BI(x,e)
-
/*
* ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
* (these are usually mapped to vectors 0x20-0x2f)
*/
-BUILD_16_IRQS(0x0)
/*
* The IO-APIC gives us many more interrupt sources. Most of these
@@ -65,17 +58,12 @@
*
* (these are usually mapped into the 0x30-0xff vector range)
*/
- BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+ BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
-BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
-
-#ifdef CONFIG_PCI_MSI
- BUILD_15_IRQS(0xe)
-#endif
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
#undef BUILD_16_IRQS
-#undef BUILD_15_IRQS
#undef BI
@@ -88,29 +76,15 @@
IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
-#define IRQLIST_15(x) \
- IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
- IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
- IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
- IRQ(x,c), IRQ(x,d), IRQ(x,e)
-
void (*interrupt[NR_IRQS])(void) = {
- IRQLIST_16(0x0),
-
- IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
+ IRQLIST_16(0x2), IRQLIST_16(0x3),
IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
- IRQLIST_16(0xc), IRQLIST_16(0xd)
-
-#ifdef CONFIG_PCI_MSI
- , IRQLIST_15(0xe)
-#endif
-
+ IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
};
#undef IRQ
#undef IRQLIST_16
-#undef IRQLIST_14
/*
* This is the 'legacy' 8259A Programmable Interrupt Controller,
@@ -121,42 +95,15 @@
* moves to arch independent land
*/
-DEFINE_SPINLOCK(i8259A_lock);
-
static int i8259A_auto_eoi;
-
-static void end_8259A_irq (unsigned int irq)
-{
- if (irq > 256) {
- char var;
- printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current));
-
- BUG();
- }
-
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
- irq_desc[irq].action)
- enable_8259A_irq(irq);
-}
-
-#define shutdown_8259A_irq disable_8259A_irq
-
+DEFINE_SPINLOCK(i8259A_lock);
static void mask_and_ack_8259A(unsigned int);
-static unsigned int startup_8259A_irq(unsigned int irq)
-{
- enable_8259A_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type i8259A_irq_type = {
- .typename = "XT-PIC",
- .startup = startup_8259A_irq,
- .shutdown = shutdown_8259A_irq,
- .enable = enable_8259A_irq,
- .disable = disable_8259A_irq,
- .ack = mask_and_ack_8259A,
- .end = end_8259A_irq,
+static struct irq_chip i8259A_chip = {
+ .name = "XT-PIC",
+ .mask = disable_8259A_irq,
+ .unmask = enable_8259A_irq,
+ .mask_ack = mask_and_ack_8259A,
};
/*
@@ -231,7 +178,7 @@
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<<irq);
- irq_desc[irq].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
enable_irq(irq);
}
@@ -367,9 +314,9 @@
* in AEOI mode we just have to mask the interrupt
* when acking.
*/
- i8259A_irq_type.ack = disable_8259A_irq;
+ i8259A_chip.mask_ack = disable_8259A_irq;
else
- i8259A_irq_type.ack = mask_and_ack_8259A;
+ i8259A_chip.mask_ack = mask_and_ack_8259A;
udelay(100); /* wait for 8259A to initialize */
@@ -447,6 +394,26 @@
*/
static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL};
+DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
+ [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1,
+ [FIRST_EXTERNAL_VECTOR + 0] = 0,
+ [FIRST_EXTERNAL_VECTOR + 1] = 1,
+ [FIRST_EXTERNAL_VECTOR + 2] = 2,
+ [FIRST_EXTERNAL_VECTOR + 3] = 3,
+ [FIRST_EXTERNAL_VECTOR + 4] = 4,
+ [FIRST_EXTERNAL_VECTOR + 5] = 5,
+ [FIRST_EXTERNAL_VECTOR + 6] = 6,
+ [FIRST_EXTERNAL_VECTOR + 7] = 7,
+ [FIRST_EXTERNAL_VECTOR + 8] = 8,
+ [FIRST_EXTERNAL_VECTOR + 9] = 9,
+ [FIRST_EXTERNAL_VECTOR + 10] = 10,
+ [FIRST_EXTERNAL_VECTOR + 11] = 11,
+ [FIRST_EXTERNAL_VECTOR + 12] = 12,
+ [FIRST_EXTERNAL_VECTOR + 13] = 13,
+ [FIRST_EXTERNAL_VECTOR + 14] = 14,
+ [FIRST_EXTERNAL_VECTOR + 15] = 15,
+ [FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1
+};
void __init init_ISA_irqs (void)
{
@@ -464,12 +431,13 @@
/*
* 16 old-style INTA-cycle interrupts:
*/
- irq_desc[i].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler(i, &i8259A_chip,
+ handle_level_irq);
} else {
/*
* 'high' PCI IRQs filled in on demand
*/
- irq_desc[i].chip = &no_irq_type;
+ irq_desc[i].chip = &no_irq_chip;
}
}
}
@@ -543,8 +511,6 @@
*/
for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
int vector = FIRST_EXTERNAL_VECTOR + i;
- if (i >= NR_IRQS)
- break;
if (vector != IA32_SYSCALL_VECTOR)
set_intr_gate(vector, interrupt[i]);
}
@@ -554,7 +520,7 @@
* IRQ0 must be given a fixed assignment and initialized,
* because it's used before the IO-APIC is set up.
*/
- set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
+ __get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0;
/*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 0491019..91728d9 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -26,9 +26,12 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
+#include <linux/pci.h>
#include <linux/mc146818rtc.h>
#include <linux/acpi.h>
#include <linux/sysdev.h>
+#include <linux/msi.h>
+#include <linux/htirq.h>
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
@@ -41,6 +44,10 @@
#include <asm/acpi.h>
#include <asm/dma.h>
#include <asm/nmi.h>
+#include <asm/msidef.h>
+#include <asm/hypertransport.h>
+
+static int assign_irq_vector(int irq, cpumask_t mask);
#define __apicdebuginit __init
@@ -81,14 +88,6 @@
short apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
-#ifdef CONFIG_PCI_MSI
-#define vector_to_irq(vector) \
- (platform_legacy_irq(vector) ? vector : vector_irq[vector])
-#else
-#define vector_to_irq(vector) (vector)
-#endif
-
#define __DO_ACTION(R, ACTION, FINAL) \
\
{ \
@@ -139,11 +138,35 @@
}
#ifdef CONFIG_SMP
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
+{
+ int apic, pin;
+ struct irq_pin_list *entry = irq_2_pin + irq;
+
+ BUG_ON(irq >= NR_IRQS);
+ for (;;) {
+ unsigned int reg;
+ apic = entry->apic;
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+ io_apic_write(apic, 0x11 + pin*2, dest);
+ reg = io_apic_read(apic, 0x10 + pin*2);
+ reg &= ~0x000000ff;
+ reg |= vector;
+ io_apic_modify(apic, reg);
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+}
+
static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
{
unsigned long flags;
unsigned int dest;
cpumask_t tmp;
+ int vector;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
@@ -151,7 +174,13 @@
cpus_and(mask, tmp, CPU_MASK_ALL);
- dest = cpu_mask_to_apicid(mask);
+ vector = assign_irq_vector(irq, mask);
+ if (vector < 0)
+ return;
+
+ cpus_clear(tmp);
+ cpu_set(vector >> 8, tmp);
+ dest = cpu_mask_to_apicid(tmp);
/*
* Only the high 8 bits are valid.
@@ -159,14 +188,12 @@
dest = SET_APIC_LOGICAL_ID(dest);
spin_lock_irqsave(&ioapic_lock, flags);
- __DO_ACTION(1, = dest, )
- set_irq_info(irq, mask);
+ __target_IO_APIC_irq(irq, dest, vector & 0xff);
+ set_native_irq_info(irq, mask);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
#endif
-static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF };
-
/*
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are
* shared ISA-space IRQs, so we have to support them. We are super
@@ -492,64 +519,6 @@
return MPBIOS_trigger(idx);
}
-static int next_irq = 16;
-
-/*
- * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ
- * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number
- * from ACPI, which can reach 800 in large boxen.
- *
- * Compact the sparse GSI space into a sequential IRQ series and reuse
- * vectors if possible.
- */
-int gsi_irq_sharing(int gsi)
-{
- int i, tries, vector;
-
- BUG_ON(gsi >= NR_IRQ_VECTORS);
-
- if (platform_legacy_irq(gsi))
- return gsi;
-
- if (gsi_2_irq[gsi] != 0xFF)
- return (int)gsi_2_irq[gsi];
-
- tries = NR_IRQS;
- try_again:
- vector = assign_irq_vector(gsi);
-
- /*
- * Sharing vectors means sharing IRQs, so scan irq_vectors for previous
- * use of vector and if found, return that IRQ. However, we never want
- * to share legacy IRQs, which usually have a different trigger mode
- * than PCI.
- */
- for (i = 0; i < NR_IRQS; i++)
- if (IO_APIC_VECTOR(i) == vector)
- break;
- if (platform_legacy_irq(i)) {
- if (--tries >= 0) {
- IO_APIC_VECTOR(i) = 0;
- goto try_again;
- }
- panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi);
- }
- if (i < NR_IRQS) {
- gsi_2_irq[gsi] = i;
- printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n",
- gsi, vector, i);
- return i;
- }
-
- i = next_irq++;
- BUG_ON(i >= NR_IRQS);
- gsi_2_irq[gsi] = i;
- IO_APIC_VECTOR(i) = vector;
- printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n",
- gsi, vector, i);
- return i;
-}
-
static int pin_2_irq(int idx, int apic, int pin)
{
int irq, i;
@@ -571,7 +540,6 @@
while (i < apic)
irq += nr_ioapic_registers[i++];
irq += pin;
- irq = gsi_irq_sharing(irq);
}
BUG_ON(irq >= NR_IRQS);
return irq;
@@ -595,46 +563,83 @@
}
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
+unsigned int irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_EXTERNAL_VECTOR, 0 };
-int assign_irq_vector(int irq)
+static int __assign_irq_vector(int irq, cpumask_t mask)
{
- static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
- unsigned long flags;
- int vector;
+ /*
+ * NOTE! The local APIC isn't very good at handling
+ * multiple interrupts at the same interrupt level.
+ * As the interrupt level is determined by taking the
+ * vector number and shifting that right by 4, we
+ * want to spread these out a bit so that they don't
+ * all fall in the same interrupt level.
+ *
+ * Also, we've got to be careful not to trash gate
+ * 0x80, because int 0x80 is hm, kind of importantish. ;)
+ */
+ static struct {
+ int vector;
+ int offset;
+ } pos[NR_CPUS] = { [ 0 ... NR_CPUS - 1] = {FIRST_DEVICE_VECTOR, 0} };
+ int old_vector = -1;
+ int cpu;
- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+
+ if (IO_APIC_VECTOR(irq) > 0)
+ old_vector = IO_APIC_VECTOR(irq);
+ if ((old_vector > 0) && cpu_isset(old_vector >> 8, mask)) {
+ return old_vector;
+ }
+
+ for_each_cpu_mask(cpu, mask) {
+ int vector, offset;
+ vector = pos[cpu].vector;
+ offset = pos[cpu].offset;
+next:
+ vector += 8;
+ if (vector >= FIRST_SYSTEM_VECTOR) {
+ /* If we run out of vectors on large boxen, must share them. */
+ offset = (offset + 1) % 8;
+ vector = FIRST_DEVICE_VECTOR + offset;
+ }
+ if (unlikely(pos[cpu].vector == vector))
+ continue;
+ if (vector == IA32_SYSCALL_VECTOR)
+ goto next;
+ if (per_cpu(vector_irq, cpu)[vector] != -1)
+ goto next;
+ /* Found one! */
+ pos[cpu].vector = vector;
+ pos[cpu].offset = offset;
+ if (old_vector >= 0) {
+ int old_cpu = old_vector >> 8;
+ old_vector &= 0xff;
+ per_cpu(vector_irq, old_cpu)[old_vector] = -1;
+ }
+ per_cpu(vector_irq, cpu)[vector] = irq;
+ vector |= cpu << 8;
+ IO_APIC_VECTOR(irq) = vector;
+ return vector;
+ }
+ return -ENOSPC;
+}
+
+static int assign_irq_vector(int irq, cpumask_t mask)
+{
+ int vector;
+ unsigned long flags;
spin_lock_irqsave(&vector_lock, flags);
-
- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
- spin_unlock_irqrestore(&vector_lock, flags);
- return IO_APIC_VECTOR(irq);
- }
-next:
- current_vector += 8;
- if (current_vector == IA32_SYSCALL_VECTOR)
- goto next;
-
- if (current_vector >= FIRST_SYSTEM_VECTOR) {
- /* If we run out of vectors on large boxen, must share them. */
- offset = (offset + 1) % 8;
- current_vector = FIRST_DEVICE_VECTOR + offset;
- }
-
- vector = current_vector;
- vector_irq[vector] = irq;
- if (irq != AUTO_ASSIGN)
- IO_APIC_VECTOR(irq) = vector;
-
+ vector = __assign_irq_vector(irq, mask);
spin_unlock_irqrestore(&vector_lock, flags);
-
return vector;
}
extern void (*interrupt[NR_IRQS])(void);
-static struct hw_interrupt_type ioapic_level_type;
-static struct hw_interrupt_type ioapic_edge_type;
+
+static struct irq_chip ioapic_chip;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
@@ -642,16 +647,13 @@
static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
{
- unsigned idx;
-
- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
-
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL)
- irq_desc[idx].chip = &ioapic_level_type;
+ set_irq_chip_and_handler(irq, &ioapic_chip,
+ handle_fasteoi_irq);
else
- irq_desc[idx].chip = &ioapic_edge_type;
- set_intr_gate(vector, interrupt[idx]);
+ set_irq_chip_and_handler(irq, &ioapic_chip,
+ handle_edge_irq);
}
static void __init setup_IO_APIC_irqs(void)
@@ -701,8 +703,15 @@
continue;
if (IO_APIC_IRQ(irq)) {
- vector = assign_irq_vector(irq);
- entry.vector = vector;
+ cpumask_t mask;
+ vector = assign_irq_vector(irq, TARGET_CPUS);
+ if (vector < 0)
+ continue;
+
+ cpus_clear(mask);
+ cpu_set(vector >> 8, mask);
+ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
+ entry.vector = vector & 0xff;
ioapic_register_intr(irq, vector, IOAPIC_AUTO);
if (!apic && (irq < 16))
@@ -752,7 +761,7 @@
* The timer IRQ doesn't have to know that behind the
* scene we have a 8259A-master in AEOI mode ...
*/
- irq_desc[0].chip = &ioapic_edge_type;
+ set_irq_chip_and_handler(0, &ioapic_chip, handle_edge_irq);
/*
* Add it to the IO-APIC irq-routing table:
@@ -868,17 +877,12 @@
);
}
}
- if (use_pci_vector())
- printk(KERN_INFO "Using vector-based indexing\n");
printk(KERN_DEBUG "IRQ to pin mappings:\n");
for (i = 0; i < NR_IRQS; i++) {
struct irq_pin_list *entry = irq_2_pin + i;
if (entry->pin < 0)
continue;
- if (use_pci_vector() && !platform_legacy_irq(i))
- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
- else
- printk(KERN_DEBUG "IRQ%d ", i);
+ printk(KERN_DEBUG "IRQ%d ", i);
for (;;) {
printk("-> %d:%d", entry->apic, entry->pin);
if (!entry->next)
@@ -1185,7 +1189,7 @@
* an edge even if it isn't on the 8259A...
*/
-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
unsigned long flags;
@@ -1202,107 +1206,16 @@
return was_pending;
}
-/*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
-static void ack_edge_ioapic_irq(unsigned int irq)
+static int ioapic_retrigger_irq(unsigned int irq)
{
- move_irq(irq);
- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
- == (IRQ_PENDING | IRQ_DISABLED))
- mask_IO_APIC_irq(irq);
- ack_APIC_irq();
-}
+ cpumask_t mask;
+ unsigned vector;
-/*
- * Level triggered interrupts can just be masked,
- * and shutting down and starting up the interrupt
- * is the same as enabling and disabling them -- except
- * with a startup need to return a "was pending" value.
- *
- * Level triggered interrupts are special because we
- * do not touch any IO-APIC register while handling
- * them. We ack the APIC in the end-IRQ handler, not
- * in the start-IRQ-handler. Protection against reentrance
- * from the same interrupt is still provided, both by the
- * generic IRQ layer and by the fact that an unacked local
- * APIC does not accept IRQs.
- */
-static unsigned int startup_level_ioapic_irq (unsigned int irq)
-{
- unmask_IO_APIC_irq(irq);
+ vector = irq_vector[irq];
+ cpus_clear(mask);
+ cpu_set(vector >> 8, mask);
- return 0; /* don't check for pending */
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
-{
- move_irq(irq);
- ack_APIC_irq();
-}
-
-#ifdef CONFIG_PCI_MSI
-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_edge_ioapic_irq(irq);
-}
-
-static void ack_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- ack_edge_ioapic_irq(irq);
-}
-
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_level_ioapic_irq (irq);
-}
-
-static void end_level_ioapic_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- end_level_ioapic_irq(irq);
-}
-
-static void mask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- mask_IO_APIC_irq(irq);
-}
-
-static void unmask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- unmask_IO_APIC_irq(irq);
-}
-
-#ifdef CONFIG_SMP
-static void set_ioapic_affinity_vector (unsigned int vector,
- cpumask_t cpu_mask)
-{
- int irq = vector_to_irq(vector);
-
- set_native_irq_info(vector, cpu_mask);
- set_ioapic_affinity_irq(irq, cpu_mask);
-}
-#endif // CONFIG_SMP
-#endif // CONFIG_PCI_MSI
-
-static int ioapic_retrigger(unsigned int irq)
-{
- send_IPI_self(IO_APIC_VECTOR(irq));
+ send_IPI_mask(mask, vector & 0xff);
return 1;
}
@@ -1316,32 +1229,47 @@
* races.
*/
-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
- .typename = "IO-APIC-edge",
- .startup = startup_edge_ioapic,
- .shutdown = shutdown_edge_ioapic,
- .enable = enable_edge_ioapic,
- .disable = disable_edge_ioapic,
- .ack = ack_edge_ioapic,
- .end = end_edge_ioapic,
-#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
-#endif
- .retrigger = ioapic_retrigger,
-};
+static void ack_apic_edge(unsigned int irq)
+{
+ move_native_irq(irq);
+ ack_APIC_irq();
+}
-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
- .typename = "IO-APIC-level",
- .startup = startup_level_ioapic,
- .shutdown = shutdown_level_ioapic,
- .enable = enable_level_ioapic,
- .disable = disable_level_ioapic,
- .ack = mask_and_ack_level_ioapic,
- .end = end_level_ioapic,
-#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
+static void ack_apic_level(unsigned int irq)
+{
+ int do_unmask_irq = 0;
+
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
+ /* If we are moving the irq we need to mask it */
+ if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+ do_unmask_irq = 1;
+ mask_IO_APIC_irq(irq);
+ }
#endif
- .retrigger = ioapic_retrigger,
+
+ /*
+ * We must acknowledge the irq before we move it or the acknowledge will
+ * not propogate properly.
+ */
+ ack_APIC_irq();
+
+ /* Now we can move and renable the irq */
+ move_masked_irq(irq);
+ if (unlikely(do_unmask_irq))
+ unmask_IO_APIC_irq(irq);
+}
+
+static struct irq_chip ioapic_chip __read_mostly = {
+ .name = "IO-APIC",
+ .startup = startup_ioapic_irq,
+ .mask = mask_IO_APIC_irq,
+ .unmask = unmask_IO_APIC_irq,
+ .ack = ack_apic_edge,
+ .eoi = ack_apic_level,
+#ifdef CONFIG_SMP
+ .set_affinity = set_ioapic_affinity_irq,
+#endif
+ .retrigger = ioapic_retrigger_irq,
};
static inline void init_IO_APIC_traps(void)
@@ -1361,11 +1289,6 @@
*/
for (irq = 0; irq < NR_IRQS ; irq++) {
int tmp = irq;
- if (use_pci_vector()) {
- if (!platform_legacy_irq(tmp))
- if ((tmp = vector_to_irq(tmp)) == -1)
- continue;
- }
if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
/*
* Hmm.. We don't have an entry for this,
@@ -1376,7 +1299,7 @@
make_8259A_irq(irq);
else
/* Strange. Oh, well.. */
- irq_desc[irq].chip = &no_irq_type;
+ irq_desc[irq].chip = &no_irq_chip;
}
}
}
@@ -1495,8 +1418,6 @@
spin_unlock_irqrestore(&ioapic_lock, flags);
}
-int timer_uses_ioapic_pin_0;
-
/*
* This code may look a bit paranoid, but it's supposed to cooperate with
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
@@ -1514,8 +1435,7 @@
* get/set the timer IRQ vector:
*/
disable_8259A_irq(0);
- vector = assign_irq_vector(0);
- set_intr_gate(vector, interrupt[0]);
+ vector = assign_irq_vector(0, TARGET_CPUS);
/*
* Subtle, code in do_timer_interrupt() expects an AEOI
@@ -1534,9 +1454,6 @@
pin2 = ioapic_i8259.pin;
apic2 = ioapic_i8259.apic;
- if (pin1 == 0)
- timer_uses_ioapic_pin_0 = 1;
-
apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
vector, apic1, pin1, apic2, pin2);
@@ -1740,6 +1657,253 @@
device_initcall(ioapic_init_sysfs);
+/*
+ * Dynamic irq allocate and deallocation
+ */
+int create_irq(void)
+{
+ /* Allocate an unused irq */
+ int irq;
+ int new;
+ int vector = 0;
+ unsigned long flags;
+
+ irq = -ENOSPC;
+ spin_lock_irqsave(&vector_lock, flags);
+ for (new = (NR_IRQS - 1); new >= 0; new--) {
+ if (platform_legacy_irq(new))
+ continue;
+ if (irq_vector[new] != 0)
+ continue;
+ vector = __assign_irq_vector(new, TARGET_CPUS);
+ if (likely(vector > 0))
+ irq = new;
+ break;
+ }
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ if (irq >= 0) {
+ dynamic_irq_init(irq);
+ }
+ return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ dynamic_irq_cleanup(irq);
+
+ spin_lock_irqsave(&vector_lock, flags);
+ irq_vector[irq] = 0;
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+/*
+ * MSI mesage composition
+ */
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+{
+ int vector;
+ unsigned dest;
+
+ vector = assign_irq_vector(irq, TARGET_CPUS);
+ if (vector >= 0) {
+ cpumask_t tmp;
+
+ cpus_clear(tmp);
+ cpu_set(vector >> 8, tmp);
+ dest = cpu_mask_to_apicid(tmp);
+
+ msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->address_lo =
+ MSI_ADDR_BASE_LO |
+ ((INT_DEST_MODE == 0) ?
+ MSI_ADDR_DEST_MODE_PHYSICAL:
+ MSI_ADDR_DEST_MODE_LOGICAL) |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_ADDR_REDIRECTION_CPU:
+ MSI_ADDR_REDIRECTION_LOWPRI) |
+ MSI_ADDR_DEST_ID(dest);
+
+ msg->data =
+ MSI_DATA_TRIGGER_EDGE |
+ MSI_DATA_LEVEL_ASSERT |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_DATA_DELIVERY_FIXED:
+ MSI_DATA_DELIVERY_LOWPRI) |
+ MSI_DATA_VECTOR(vector);
+ }
+ return vector;
+}
+
+#ifdef CONFIG_SMP
+static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ struct msi_msg msg;
+ unsigned int dest;
+ cpumask_t tmp;
+ int vector;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+ vector = assign_irq_vector(irq, mask);
+ if (vector < 0)
+ return;
+
+ cpus_clear(tmp);
+ cpu_set(vector >> 8, tmp);
+ dest = cpu_mask_to_apicid(tmp);
+
+ read_msi_msg(irq, &msg);
+
+ msg.data &= ~MSI_DATA_VECTOR_MASK;
+ msg.data |= MSI_DATA_VECTOR(vector);
+ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, mask);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip msi_chip = {
+ .name = "PCI-MSI",
+ .unmask = unmask_msi_irq,
+ .mask = mask_msi_irq,
+ .ack = ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = set_msi_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+{
+ struct msi_msg msg;
+ int ret;
+ ret = msi_compose_msg(dev, irq, &msg);
+ if (ret < 0)
+ return ret;
+
+ write_msi_msg(irq, &msg);
+
+ set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq);
+
+ return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ return;
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+/*
+ * Hypertransport interrupt support
+ */
+#ifdef CONFIG_HT_IRQ
+
+#ifdef CONFIG_SMP
+
+static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
+{
+ u32 low, high;
+ low = read_ht_irq_low(irq);
+ high = read_ht_irq_high(irq);
+
+ low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
+ high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+
+ low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
+ high |= HT_IRQ_HIGH_DEST_ID(dest);
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+}
+
+static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ unsigned int dest;
+ cpumask_t tmp;
+ int vector;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+ vector = assign_irq_vector(irq, mask);
+ if (vector < 0)
+ return;
+
+ cpus_clear(tmp);
+ cpu_set(vector >> 8, tmp);
+ dest = cpu_mask_to_apicid(tmp);
+
+ target_ht_irq(irq, dest, vector & 0xff);
+ set_native_irq_info(irq, mask);
+}
+#endif
+
+static struct hw_interrupt_type ht_irq_chip = {
+ .name = "PCI-HT",
+ .mask = mask_ht_irq,
+ .unmask = unmask_ht_irq,
+ .ack = ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = set_ht_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+{
+ int vector;
+
+ vector = assign_irq_vector(irq, TARGET_CPUS);
+ if (vector >= 0) {
+ u32 low, high;
+ unsigned dest;
+ cpumask_t tmp;
+
+ cpus_clear(tmp);
+ cpu_set(vector >> 8, tmp);
+ dest = cpu_mask_to_apicid(tmp);
+
+ high = HT_IRQ_HIGH_DEST_ID(dest);
+
+ low = HT_IRQ_LOW_BASE |
+ HT_IRQ_LOW_DEST_ID(dest) |
+ HT_IRQ_LOW_VECTOR(vector) |
+ ((INT_DEST_MODE == 0) ?
+ HT_IRQ_LOW_DM_PHYSICAL :
+ HT_IRQ_LOW_DM_LOGICAL) |
+ HT_IRQ_LOW_RQEOI_EDGE |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ HT_IRQ_LOW_MT_FIXED :
+ HT_IRQ_LOW_MT_ARBITRATED);
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+
+ set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq);
+ }
+ return vector;
+}
+#endif /* CONFIG_HT_IRQ */
+
/* --------------------------------------------------------------------------
ACPI-based IOAPIC Configuration
-------------------------------------------------------------------------- */
@@ -1765,6 +1929,8 @@
{
struct IO_APIC_route_entry entry;
unsigned long flags;
+ int vector;
+ cpumask_t mask;
if (!IO_APIC_IRQ(irq)) {
apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
@@ -1773,6 +1939,20 @@
}
/*
+ * IRQs < 16 are already in the irq_2_pin[] map
+ */
+ if (irq >= 16)
+ add_pin_to_irq(irq, ioapic, pin);
+
+
+ vector = assign_irq_vector(irq, TARGET_CPUS);
+ if (vector < 0)
+ return vector;
+
+ cpus_clear(mask);
+ cpu_set(vector >> 8, mask);
+
+ /*
* Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
* Note that we mask (disable) IRQs now -- these get enabled when the
* corresponding device driver registers for this IRQ.
@@ -1782,19 +1962,11 @@
entry.delivery_mode = INT_DELIVERY_MODE;
entry.dest_mode = INT_DEST_MODE;
- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
+ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
entry.trigger = triggering;
entry.polarity = polarity;
entry.mask = 1; /* Disabled (masked) */
-
- irq = gsi_irq_sharing(irq);
- /*
- * IRQs < 16 are already in the irq_2_pin[] map
- */
- if (irq >= 16)
- add_pin_to_irq(irq, ioapic, pin);
-
- entry.vector = assign_irq_vector(irq);
+ entry.vector = vector & 0xff;
apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
"IRQ %d Mode:%i Active:%i)\n", ioapic,
@@ -1809,7 +1981,7 @@
ioapic_write_entry(ioapic, pin, entry);
spin_lock_irqsave(&ioapic_lock, flags);
- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
+ set_native_irq_info(irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index b3677e6..506f27c 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -74,7 +74,8 @@
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- seq_printf(p, " %14s", irq_desc[i].chip->typename);
+ seq_printf(p, " %8s", irq_desc[i].chip->name);
+ seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
@@ -104,7 +105,12 @@
asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
{
/* high bit used in ret_from_ code */
- unsigned irq = ~regs->orig_rax;
+ unsigned vector = ~regs->orig_rax;
+ unsigned irq;
+
+ exit_idle();
+ irq_enter();
+ irq = __get_cpu_var(vector_irq)[vector];
if (unlikely(irq >= NR_IRQS)) {
printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
@@ -112,12 +118,10 @@
BUG();
}
- exit_idle();
- irq_enter();
#ifdef CONFIG_DEBUG_STACKOVERFLOW
stack_overflow_check(regs);
#endif
- __do_IRQ(irq, regs);
+ generic_handle_irq(irq, regs);
irq_exit();
return 1;
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index b8d53df..b147ab1 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -790,20 +790,11 @@
}
}
-#define MAX_GSI_NUM 4096
-
int mp_register_gsi(u32 gsi, int triggering, int polarity)
{
int ioapic = -1;
int ioapic_pin = 0;
int idx, bit = 0;
- static int pci_irq = 16;
- /*
- * Mapping between Global System Interrupts, which
- * represent all possible interrupts, to the IRQs
- * assigned to actual devices.
- */
- static int gsi_to_irq[MAX_GSI_NUM];
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
return gsi;
@@ -836,42 +827,11 @@
if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
- return gsi_to_irq[gsi];
+ return gsi;
}
mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
- if (triggering == ACPI_LEVEL_SENSITIVE) {
- /*
- * For PCI devices assign IRQs in order, avoiding gaps
- * due to unused I/O APIC pins.
- */
- int irq = gsi;
- if (gsi < MAX_GSI_NUM) {
- /*
- * Retain the VIA chipset work-around (gsi > 15), but
- * avoid a problem where the 8254 timer (IRQ0) is setup
- * via an override (so it's not on pin 0 of the ioapic),
- * and at the same time, the pin 0 interrupt is a PCI
- * type. The gsi > 15 test could cause these two pins
- * to be shared as IRQ0, and they are not shareable.
- * So test for this condition, and if necessary, avoid
- * the pin collision.
- */
- if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0))
- gsi = pci_irq++;
- /*
- * Don't assign IRQ used by ACPI SCI
- */
- if (gsi == acpi_fadt.sci_int)
- gsi = pci_irq++;
- gsi_to_irq[irq] = gsi;
- } else {
- printk(KERN_ERR "GSI %u is too high\n", gsi);
- return gsi;
- }
- }
-
io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 1aabc81..54e1f38 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -299,76 +299,46 @@
static const struct pci_device_id ahci_pci_tbl[] = {
/* Intel */
- { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH6 */
- { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH6M */
- { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7 */
- { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7M */
- { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7R */
- { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ULi M5288 */
- { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7-M DH */
- { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8M */
- { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
+ { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
+ { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
+ { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
+ { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
+ { PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */
+ { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
+ { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
+ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
+ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
/* JMicron */
- { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB360 */
- { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB361 */
- { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB363 */
- { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB365 */
- { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB366 */
+ { PCI_VDEVICE(JMICRON, 0x2360), board_ahci }, /* JMicron JMB360 */
+ { PCI_VDEVICE(JMICRON, 0x2361), board_ahci }, /* JMicron JMB361 */
+ { PCI_VDEVICE(JMICRON, 0x2363), board_ahci }, /* JMicron JMB363 */
+ { PCI_VDEVICE(JMICRON, 0x2365), board_ahci }, /* JMicron JMB365 */
+ { PCI_VDEVICE(JMICRON, 0x2366), board_ahci }, /* JMicron JMB366 */
/* ATI */
- { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ATI SB600 non-raid */
- { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ATI SB600 raid */
+ { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
+ { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
/* VIA */
- { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci_vt8251 }, /* VIA VT8251 */
+ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
- { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */
/* SiS */
- { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* SiS 966 */
- { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* SiS 966 */
- { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
{ } /* terminate list */
};
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index b4abd68..dce6565 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2340,7 +2340,8 @@
if (status & ATA_BUSY)
ata_port_printk(ap, KERN_WARNING,
- "port is slow to respond, please be patient\n");
+ "port is slow to respond, please be patient "
+ "(Status 0x%x)\n", status);
timeout = timer_start + tmout;
while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
@@ -2350,7 +2351,8 @@
if (status & ATA_BUSY) {
ata_port_printk(ap, KERN_ERR, "port failed to respond "
- "(%lu secs)\n", tmout / HZ);
+ "(%lu secs, Status 0x%x)\n",
+ tmout / HZ, status);
return 1;
}
@@ -5478,11 +5480,10 @@
int irq_line = ent->irq;
ap = ata_port_add(ent, host, i);
+ host->ports[i] = ap;
if (!ap)
goto err_out;
- host->ports[i] = ap;
-
/* dummy? */
if (ent->dummy_port_mask & (1 << i)) {
ata_port_printk(ap, KERN_INFO, "DUMMY\n");
@@ -5740,7 +5741,7 @@
/**
* ata_scsi_release - SCSI layer callback hook for host unload
- * @host: libata host to be unloaded
+ * @shost: libata host to be unloaded
*
* Performs all duties necessary to shut down a libata port...
* Kill port kthread, disable port, and release resources.
@@ -5786,6 +5787,7 @@
probe_ent->mwdma_mask = port->mwdma_mask;
probe_ent->udma_mask = port->udma_mask;
probe_ent->port_ops = port->port_ops;
+ probe_ent->private_data = port->private_data;
return probe_ent;
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3986ec8..b0d0cc4 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -889,6 +889,7 @@
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev;
+ unsigned long flags;
int max_depth;
if (queue_depth < 1)
@@ -904,6 +905,14 @@
queue_depth = max_depth;
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+
+ spin_lock_irqsave(ap->lock, flags);
+ if (queue_depth > 1)
+ dev->flags &= ~ATA_DFLAG_NCQ_OFF;
+ else
+ dev->flags |= ATA_DFLAG_NCQ_OFF;
+ spin_unlock_irqrestore(ap->lock, flags);
+
return queue_depth;
}
@@ -1293,7 +1302,8 @@
*/
goto nothing_to_do;
- if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+ if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
+ ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
/* yay, NCQ */
if (!lba_48_ok(block, n_block))
goto out_of_range;
@@ -3174,7 +3184,7 @@
/**
* ata_sas_port_alloc - Allocate port for a SAS attached SATA device
- * @pdev: PCI device that the scsi device is attached to
+ * @host: ATA host container for all SAS ports
* @port_info: Information from low-level host driver
* @shost: SCSI host that the scsi device is attached to
*
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 08b3a40..06daaa3 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -828,7 +828,6 @@
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->private_data = port[0]->private_data;
if (ports & ATA_PORT_PRIMARY) {
probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
@@ -878,7 +877,6 @@
return NULL;
probe_ent->n_ports = 2;
- probe_ent->private_data = port[0]->private_data;
if (port_mask & ATA_PORT_PRIMARY) {
probe_ent->irq = ATA_PRIMARY_IRQ;
@@ -908,6 +906,8 @@
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
}
ata_std_ports(&probe_ent->port[1]);
+
+ /* FIXME: could be pointing to stack area; must copy */
probe_ent->pinfo2 = port[1];
} else
probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
@@ -946,35 +946,21 @@
{
struct ata_probe_ent *probe_ent = NULL;
struct ata_port_info *port[2];
- u8 tmp8, mask;
+ u8 mask;
unsigned int legacy_mode = 0;
int disable_dev_on_err = 1;
int rc;
DPRINTK("ENTER\n");
+ BUG_ON(n_ports < 1 || n_ports > 2);
+
port[0] = port_info[0];
if (n_ports > 1)
port[1] = port_info[1];
else
port[1] = port[0];
- if ((port[0]->flags & ATA_FLAG_NO_LEGACY) == 0
- && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- /* TODO: What if one channel is in native mode ... */
- pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
- mask = (1 << 2) | (1 << 0);
- if ((tmp8 & mask) != mask)
- legacy_mode = (1 << 3);
- }
-
- /* FIXME... */
- if ((!legacy_mode) && (n_ports > 2)) {
- printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
- n_ports = 2;
- /* For now */
- }
-
/* FIXME: Really for ATA it isn't safe because the device may be
multi-purpose and we want to leave it alone if it was already
enabled. Secondly for shared use as Arjan says we want refcounting
@@ -987,6 +973,16 @@
if (rc)
return rc;
+ if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ u8 tmp8;
+
+ /* TODO: What if one channel is in native mode ... */
+ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+ mask = (1 << 2) | (1 << 0);
+ if ((tmp8 & mask) != mask)
+ legacy_mode = (1 << 3);
+ }
+
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
disable_dev_on_err = 0;
@@ -1039,7 +1035,7 @@
goto err_out_regions;
}
- /* FIXME: If we get no DMA mask we should fall back to PIO */
+ /* TODO: If we get no DMA mask we should fall back to PIO */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
goto err_out_regions;
@@ -1062,13 +1058,17 @@
pci_set_master(pdev);
- /* FIXME: check ata_device_add return */
- ata_device_add(probe_ent);
+ if (!ata_device_add(probe_ent)) {
+ rc = -ENODEV;
+ goto err_out_ent;
+ }
kfree(probe_ent);
return 0;
+err_out_ent:
+ kfree(probe_ent);
err_out_regions:
if (legacy_mode & ATA_PORT_PRIMARY)
release_region(ATA_PRIMARY_CMD, 8);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 87af3b5..1d695df 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.6.5"
+#define DRV_VERSION "0.6.6"
/*
* Cable special cases
@@ -630,7 +630,7 @@
pci_read_config_byte(pdev, 0x53, &tmp);
if (rev <= 0x20)
tmp &= ~0x02;
- if (rev == 0xc7)
+ if (rev >= 0xc7)
tmp |= 0x03;
else
tmp |= 0x01; /* CD_ROM enable for DMA */
@@ -644,10 +644,11 @@
return ata_pci_init_one(pdev, port_info, 2);
}
-static struct pci_device_id ali[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228), },
- { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229), },
- { 0, },
+static const struct pci_device_id ali[] = {
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), },
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), },
+
+ { },
};
static struct pci_driver ali_pci_driver = {
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 599ee26..29234c8 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -662,27 +662,28 @@
}
static const struct pci_device_id amd[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
- { 0, },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 3 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 4 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 7 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 8 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 },
+
+ { },
};
static struct pci_driver amd_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = amd,
.probe = amd_init_one,
.remove = ata_pci_remove_one
@@ -698,7 +699,6 @@
pci_unregister_driver(&amd_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for AMD PATA IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index c4ccb75..690828e 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -426,7 +426,7 @@
.port_ops = &artop6260_ops,
};
struct ata_port_info *port_info[2];
- struct ata_port_info *info;
+ struct ata_port_info *info = NULL;
int ports = 2;
if (!printed_version++)
@@ -470,16 +470,20 @@
pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
}
+
+ BUG_ON(info == NULL);
+
port_info[0] = port_info[1] = info;
return ata_pci_init_one(pdev, port_info, ports);
}
static const struct pci_device_id artop_pci_tbl[] = {
- { 0x1191, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { 0x1191, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0x1191, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0x1191, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { 0x1191, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VDEVICE(ARTOP, 0x0005), 0 },
+ { PCI_VDEVICE(ARTOP, 0x0006), 1 },
+ { PCI_VDEVICE(ARTOP, 0x0007), 1 },
+ { PCI_VDEVICE(ARTOP, 0x0008), 2 },
+ { PCI_VDEVICE(ARTOP, 0x0009), 2 },
+
{ } /* terminate list */
};
@@ -500,7 +504,6 @@
pci_unregister_driver(&artop_pci_driver);
}
-
module_init(artop_init);
module_exit(artop_exit);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 6c2269b..1ce28d2 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -267,12 +267,13 @@
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id atiixp[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
- { 0, },
+static const struct pci_device_id atiixp[] = {
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
+
+ { },
};
static struct pci_driver atiixp_pci_driver = {
@@ -293,7 +294,6 @@
pci_unregister_driver(&atiixp_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index e92b0ef..b9bbd1d 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -468,16 +468,17 @@
return ata_pci_init_one(pdev, port_info, 2);
}
-static struct pci_device_id cmd64x[] = {
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- { 0, },
+static const struct pci_device_id cmd64x[] = {
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
+
+ { },
};
static struct pci_driver cmd64x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = cmd64x,
.probe = cmd64x_init_one,
.remove = ata_pci_remove_one
@@ -488,13 +489,11 @@
return pci_register_driver(&cmd64x_pci_driver);
}
-
static void __exit cmd64x_exit(void)
{
pci_unregister_driver(&cmd64x_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index a6c6ceb..2cd3c0f 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -299,10 +299,11 @@
/* For now keep DMA off. We can set it for all but A rev CS5510 once the
core ATA code can handle it */
-static struct pci_device_id pata_cs5520[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
- { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
- { 0, },
+static const struct pci_device_id pata_cs5520[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
+
+ { },
};
static struct pci_driver cs5520_pci_driver = {
@@ -312,7 +313,6 @@
.remove = cs5520_remove_one
};
-
static int __init cs5520_init(void)
{
return pci_register_driver(&cs5520_pci_driver);
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 7bba4d95..a07cc81 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -353,13 +353,14 @@
return -ENODEV;
}
-static struct pci_device_id cs5530[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
- { 0, },
+static const struct pci_device_id cs5530[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
+
+ { },
};
static struct pci_driver cs5530_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = cs5530,
.probe = cs5530_init_one,
.remove = ata_pci_remove_one
@@ -370,13 +371,11 @@
return pci_register_driver(&cs5530_pci_driver);
}
-
static void __exit cs5530_exit(void)
{
pci_unregister_driver(&cs5530_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index d64fcdc..f8def3f 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -257,9 +257,10 @@
return ata_pci_init_one(dev, ports, 1);
}
-static struct pci_device_id cs5535[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), },
- { 0, },
+static const struct pci_device_id cs5535[] = {
+ { PCI_VDEVICE(NS, 0x002D), },
+
+ { },
};
static struct pci_driver cs5535_pci_driver = {
@@ -274,13 +275,11 @@
return pci_register_driver(&cs5535_pci_driver);
}
-
static void __exit cs5535_exit(void)
{
pci_unregister_driver(&cs5535_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch");
MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index dfa5ac5..247b436 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -184,8 +184,8 @@
};
static struct ata_port_info *port_info[1] = { &info };
- /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. For the
- moment we don't handle the secondary. FIXME */
+ /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2.
+ For the moment we don't handle the secondary. FIXME */
if (PCI_FUNC(pdev->devfn) != 1)
return -ENODEV;
@@ -193,13 +193,14 @@
return ata_pci_init_one(pdev, port_info, 1);
}
-static struct pci_device_id cy82c693[] = {
- { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { 0, },
+static const struct pci_device_id cy82c693[] = {
+ { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), },
+
+ { },
};
static struct pci_driver cy82c693_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = cy82c693,
.probe = cy82c693_init_one,
.remove = ata_pci_remove_one
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index 95cd1ca..ef18c60 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -305,7 +305,8 @@
}
static const struct pci_device_id efar_pci_tbl[] = {
- { 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VDEVICE(EFAR, 0x9130), },
+
{ } /* terminate list */
};
@@ -326,7 +327,6 @@
pci_unregister_driver(&efar_pci_driver);
}
-
module_init(efar_init);
module_exit(efar_exit);
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 8c75743..6d3e4c0 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -444,13 +444,14 @@
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt36x[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
- { 0, },
+static const struct pci_device_id hpt36x[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+
+ { },
};
static struct pci_driver hpt36x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt36x,
.probe = hpt36x_init_one,
.remove = ata_pci_remove_one
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 10318c0..7350443 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -1219,17 +1219,18 @@
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt37x[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
- { 0, },
+static const struct pci_device_id hpt37x[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
+
+ { },
};
static struct pci_driver hpt37x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt37x,
.probe = hpt37x_init_one,
.remove = ata_pci_remove_one
@@ -1240,13 +1241,11 @@
return pci_register_driver(&hpt37x_pci_driver);
}
-
static void __exit hpt37x_exit(void)
{
pci_unregister_driver(&hpt37x_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 5c5d4f6..58cfb2b 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -560,16 +560,17 @@
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt3x2n[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N), },
- { 0, },
+static const struct pci_device_id hpt3x2n[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
+
+ { },
};
static struct pci_driver hpt3x2n_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt3x2n,
.probe = hpt3x2n_init_one,
.remove = ata_pci_remove_one
@@ -580,13 +581,11 @@
return pci_register_driver(&hpt3x2n_pci_driver);
}
-
static void __exit hpt3x2n_exit(void)
{
pci_unregister_driver(&hpt3x2n_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 1f084ab..3334d72 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -192,13 +192,14 @@
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt3x3[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), },
- { 0, },
+static const struct pci_device_id hpt3x3[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), },
+
+ { },
};
static struct pci_driver hpt3x3_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt3x3,
.probe = hpt3x3_init_one,
.remove = ata_pci_remove_one
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 82a46ff..18ff3e5 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -808,14 +808,15 @@
return ata_pci_init_one(pdev, port_info, 2);
}
-static struct pci_device_id it821x[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211), },
- { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212), },
- { 0, },
+static const struct pci_device_id it821x[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
+
+ { },
};
static struct pci_driver it821x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = it821x,
.probe = it821x_init_one,
.remove = ata_pci_remove_one
@@ -826,13 +827,11 @@
return pci_register_driver(&it821x_pci_driver);
}
-
static void __exit it821x_exit(void)
{
pci_unregister_driver(&it821x_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index be3a866..52a2bdf 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -229,11 +229,12 @@
}
static const struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 3c65393..9dfe3e9 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -274,11 +274,10 @@
dev_set_drvdata(dev, NULL);
}
-
-
static const struct pci_device_id mpiix[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
- { 0, },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
+
+ { },
};
static struct pci_driver mpiix_pci_driver = {
@@ -293,13 +292,11 @@
return pci_register_driver(&mpiix_pci_driver);
}
-
static void __exit mpiix_exit(void)
{
pci_unregister_driver(&mpiix_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Intel MPIIX");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 76eb9c9..f5672de 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -142,7 +142,8 @@
}
static const struct pci_device_id netcell_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+ { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 2005a95..2a3dbee 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -200,12 +200,13 @@
}
static const struct pci_device_id ns87410[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410), },
- { 0, },
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), },
+
+ { },
};
static struct pci_driver ns87410_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = ns87410,
.probe = ns87410_init_one,
.remove = ata_pci_remove_one
@@ -216,13 +217,11 @@
return pci_register_driver(&ns87410_pci_driver);
}
-
static void __exit ns87410_exit(void)
{
pci_unregister_driver(&ns87410_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Nat Semi 87410");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 31a285c..fc947df 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -303,7 +303,8 @@
}
static const struct pci_device_id oldpiix_pci_tbl[] = {
- { PCI_DEVICE(0x8086, 0x1230), },
+ { PCI_VDEVICE(INTEL, 0x1230), },
+
{ } /* terminate list */
};
@@ -324,7 +325,6 @@
pci_unregister_driver(&oldpiix_pci_driver);
}
-
module_init(oldpiix_init);
module_exit(oldpiix_exit);
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 57fe21f..a7320ba 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -256,13 +256,14 @@
}
static const struct pci_device_id opti[] = {
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0, },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
+
+ { },
};
static struct pci_driver opti_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = opti,
.probe = opti_init_one,
.remove = ata_pci_remove_one
@@ -273,7 +274,6 @@
return pci_register_driver(&opti_pci_driver);
}
-
static void __exit opti_exit(void)
{
pci_unregister_driver(&opti_pci_driver);
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 7296a20..c6906b4 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -512,12 +512,13 @@
}
static const struct pci_device_id optidma[] = {
- { PCI_DEVICE(0x1045, 0xD568), }, /* Opti 82C700 */
- { 0, },
+ { PCI_VDEVICE(OPTI, 0xD568), }, /* Opti 82C700 */
+
+ { },
};
static struct pci_driver optidma_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = optidma,
.probe = optidma_init_one,
.remove = ata_pci_remove_one
@@ -528,13 +529,11 @@
return pci_register_driver(&optidma_pci_driver);
}
-
static void __exit optidma_exit(void)
{
pci_unregister_driver(&optidma_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index cb501e1..e93ea27 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.2.9"
+#define DRV_VERSION "0.2.11"
/*
* Private data structure to glue stuff together
@@ -355,6 +355,8 @@
PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+ PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index bd4ed67..d894d99 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -108,13 +108,14 @@
};
static const struct pci_device_id pdc2027x_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), PDC_UDMA_100 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), PDC_UDMA_100 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), PDC_UDMA_133 },
+
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 48f4343..5ba9eb2 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -385,17 +385,18 @@
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id pdc[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2},
- { 0, },
+static const struct pci_device_id pdc[] = {
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
+
+ { },
};
static struct pci_driver pdc_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = pdc,
.probe = pdc_init_one,
.remove = ata_pci_remove_one
@@ -406,13 +407,11 @@
return pci_register_driver(&pdc_pci_driver);
}
-
static void __exit pdc_exit(void)
{
pci_unregister_driver(&pdc_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index c20bcf4..1af83d7 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -300,7 +300,8 @@
}
static const struct pci_device_id radisys_pci_tbl[] = {
- { 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VDEVICE(RADISYS, 0x8201), },
+
{ } /* terminate list */
};
@@ -321,7 +322,6 @@
pci_unregister_driver(&radisys_pci_driver);
}
-
module_init(radisys_init);
module_exit(radisys_exit);
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index eccc6fd..4533b63 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -170,20 +170,20 @@
return -ENODEV;
}
-static struct pci_device_id pata_rz1000[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
- { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
- { 0, },
+static const struct pci_device_id pata_rz1000[] = {
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
+
+ { },
};
static struct pci_driver rz1000_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = pata_rz1000,
.probe = rz1000_init_one,
.remove = ata_pci_remove_one
};
-
static int __init rz1000_init(void)
{
return pci_register_driver(&rz1000_pci_driver);
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 107e6cd..067d9d2 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -253,13 +253,14 @@
return ata_pci_init_one(dev, port_info, 1);
}
-static struct pci_device_id sc1200[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
- { 0, },
+static const struct pci_device_id sc1200[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
+
+ { },
};
static struct pci_driver sc1200_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = sc1200,
.probe = sc1200_init_one,
.remove = ata_pci_remove_one
@@ -270,13 +271,11 @@
return pci_register_driver(&sc1200_pci_driver);
}
-
static void __exit sc1200_exit(void)
{
pci_unregister_driver(&sc1200_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox, Mark Lord");
MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index a5c8d7e..5bbf76e 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -553,13 +553,14 @@
return ata_pci_init_one(pdev, port_info, ports);
}
-static struct pci_device_id serverworks[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
- { 0, },
+static const struct pci_device_id serverworks[] = {
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
+
+ { },
};
static struct pci_driver serverworks_pci_driver = {
@@ -574,13 +575,11 @@
return pci_register_driver(&serverworks_pci_driver);
}
-
static void __exit serverworks_exit(void)
{
pci_unregister_driver(&serverworks_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index c8b2e26..4a2b72b 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -348,12 +348,13 @@
}
static const struct pci_device_id sil680[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), },
- { 0, },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
+
+ { },
};
static struct pci_driver sil680_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = sil680,
.probe = sil680_init_one,
.remove = ata_pci_remove_one
@@ -364,13 +365,11 @@
return pci_register_driver(&sil680_pci_driver);
}
-
static void __exit sil680_exit(void)
{
pci_unregister_driver(&sil680_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for SI680 PATA");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 17791e2..b9ffafb 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -988,8 +988,9 @@
}
static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5513), }, /* SiS 5513 */
- { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5518), }, /* SiS 5518 */
+ { PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */
+ { PCI_VDEVICE(SI, 0x5518), }, /* SiS 5518 */
+
{ }
};
@@ -1010,7 +1011,6 @@
pci_unregister_driver(&sis_pci_driver);
}
-
module_init(sis_init);
module_exit(sis_exit);
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 5b762ac..08a6dc8 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -351,9 +351,10 @@
return ata_pci_init_one(dev, port_info, 1); /* For now */
}
-static struct pci_device_id sl82c105[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
- { 0, },
+static const struct pci_device_id sl82c105[] = {
+ { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
+
+ { },
};
static struct pci_driver sl82c105_pci_driver = {
@@ -368,13 +369,11 @@
return pci_register_driver(&sl82c105_pci_driver);
}
-
static void __exit sl82c105_exit(void)
{
pci_unregister_driver(&sl82c105_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Sl82c105");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index a954ed9..9640f80 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -248,13 +248,13 @@
}
static const struct pci_device_id triflex[] = {
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0, },
+ { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
+
+ { },
};
static struct pci_driver triflex_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = triflex,
.probe = triflex_init_one,
.remove = ata_pci_remove_one
@@ -265,13 +265,11 @@
return pci_register_driver(&triflex_pci_driver);
}
-
static void __exit triflex_exit(void)
{
pci_unregister_driver(&triflex_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 7b5dd23..1e7be9e 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -529,15 +529,16 @@
}
static const struct pci_device_id via[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1), },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1), },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410), },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
- { 0, },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
+
+ { },
};
static struct pci_driver via_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = via,
.probe = via_init_one,
.remove = ata_pci_remove_one
@@ -548,13 +549,11 @@
return pci_register_driver(&via_pci_driver);
}
-
static void __exit via_exit(void)
{
pci_unregister_driver(&via_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for VIA PATA");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 0e23ecb..81f3d21 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -192,8 +192,7 @@
};
static const struct pci_device_id adma_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_1841_idx },
+ { PCI_VDEVICE(PDC, 0x1841), board_1841_idx },
{ } /* terminate list */
};
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index c01496d..e6aa1a8 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -533,19 +533,20 @@
};
static const struct pci_device_id mv_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
+ { PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
+ { PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
+ { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
+ { PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
+ { PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
+ { PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
+ { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
+ { PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
+ { PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
- {} /* terminate list */
+ { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
+
+ { } /* terminate list */
};
static struct pci_driver mv_pci_driver = {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 8cd730f..d09d20a 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -106,45 +106,32 @@
};
static const struct pci_device_id nv_pci_tbl[] = {
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), NFORCE2 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), NFORCE3 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), NFORCE3 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045c), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
- { 0, } /* terminate list */
+
+ { } /* terminate list */
};
static struct pci_driver nv_pci_driver = {
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index d627812..15c9437 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -234,48 +234,31 @@
};
static const struct pci_device_id pdc_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2057x },
- { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2057x },
- { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3371), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3570), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3571), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3373), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3375), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3376), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3574), board_2057x },
+ { PCI_VDEVICE(PROMISE, 0x3d75), board_2057x },
+ { PCI_VDEVICE(PROMISE, 0x3d73), board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_40518 },
+ { PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3d17), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
- { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20619 },
+ { PCI_VDEVICE(PROMISE, 0x6629), board_20619 },
/* TODO: remove all associated board_20771 code, as it completely
* duplicates board_2037x code, unless reason for separation can be
* divined.
*/
#if 0
- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20771 },
+ { PCI_VDEVICE(PROMISE, 0x3570), board_20771 },
#endif
{ } /* terminate list */
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index fa29dfe..7f6cc3c 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -185,8 +185,7 @@
};
static const struct pci_device_id qs_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2068_idx },
+ { PCI_VDEVICE(PDC, 0x2068), board_2068_idx },
{ } /* terminate list */
};
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index c63dbab..3d9fa1c 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -123,13 +123,14 @@
static const struct pci_device_id sil_pci_tbl[] = {
- { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
- { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
- { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
- { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+ { PCI_VDEVICE(CMD, 0x3112), sil_3112 },
+ { PCI_VDEVICE(CMD, 0x0240), sil_3112 },
+ { PCI_VDEVICE(CMD, 0x3512), sil_3512 },
+ { PCI_VDEVICE(CMD, 0x3114), sil_3114 },
+ { PCI_VDEVICE(ATI, 0x436e), sil_3112 },
+ { PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq },
+ { PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq },
+
{ } /* terminate list */
};
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 39cb07b..a951f40 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -344,11 +344,12 @@
#endif
static const struct pci_device_id sil24_pci_tbl[] = {
- { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
- { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
- { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
- { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
- { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+ { PCI_VDEVICE(CMD, 0x3124), BID_SIL3124 },
+ { PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
+ { PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
+ { PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
+ { PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
+
{ } /* terminate list */
};
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 18d49ff..0738f52 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -67,13 +67,13 @@
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
- { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
- { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VDEVICE(SI, 0x180), sis_180 },
+ { PCI_VDEVICE(SI, 0x181), sis_180 },
+ { PCI_VDEVICE(SI, 0x182), sis_180 },
+
{ } /* terminate list */
};
-
static struct pci_driver sis_pci_driver = {
.name = DRV_NAME,
.id_table = sis_pci_tbl,
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index d6d6658..84025a2 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -469,15 +469,15 @@
* controller
* */
static const struct pci_device_id k2_sata_pci_tbl[] = {
- { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x024b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0240), 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0241), 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0242), 8 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024a), 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024b), 4 },
+
{ }
};
-
static struct pci_driver k2_sata_pci_driver = {
.name = DRV_NAME,
.id_table = k2_sata_pci_tbl,
@@ -485,19 +485,16 @@
.remove = ata_pci_remove_one,
};
-
static int __init k2_sata_init(void)
{
return pci_register_driver(&k2_sata_pci_driver);
}
-
static void __exit k2_sata_exit(void)
{
pci_unregister_driver(&k2_sata_pci_driver);
}
-
MODULE_AUTHOR("Benjamin Herrenschmidt");
MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 091867e..8c74f2f 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -230,12 +230,11 @@
};
static const struct pci_device_id pdc_sata_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20621 },
+ { PCI_VDEVICE(PROMISE, 0x6622), board_20621 },
+
{ } /* terminate list */
};
-
static struct pci_driver pdc_sata_pci_driver = {
.name = DRV_NAME,
.id_table = pdc_sata_pci_tbl,
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index dd76f37..5c603ca 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -61,13 +61,13 @@
static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
- { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
- { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
- { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
+ { PCI_VDEVICE(AL, 0x5289), uli_5289 },
+ { PCI_VDEVICE(AL, 0x5287), uli_5287 },
+ { PCI_VDEVICE(AL, 0x5281), uli_5281 },
+
{ } /* terminate list */
};
-
static struct pci_driver uli_pci_driver = {
.name = DRV_NAME,
.id_table = uli_pci_tbl,
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index a72a238..f4455a1 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -77,9 +77,9 @@
static void vt6420_error_handler(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
- { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
- { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
- { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
+ { PCI_VDEVICE(VIA, 0x0591), vt6420 },
+ { PCI_VDEVICE(VIA, 0x3149), vt6420 },
+ { PCI_VDEVICE(VIA, 0x3249), vt6421 },
{ } /* terminate list */
};
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index d0d92f3..273d88f 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -442,16 +442,15 @@
return rc;
}
-
static const struct pci_device_id vsc_sata_pci_tbl[] = {
{ PCI_VENDOR_ID_VITESSE, 0x7174,
PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
{ PCI_VENDOR_ID_INTEL, 0x3200,
PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+
{ } /* terminate list */
};
-
static struct pci_driver vsc_sata_pci_driver = {
.name = DRV_NAME,
.id_table = vsc_sata_pci_tbl,
@@ -459,19 +458,16 @@
.remove = ata_pci_remove_one,
};
-
static int __init vsc_sata_init(void)
{
return pci_register_driver(&vsc_sata_pci_driver);
}
-
static void __exit vsc_sata_exit(void)
{
pci_unregister_driver(&vsc_sata_pci_driver);
}
-
MODULE_AUTHOR("Jeremy Higdon");
MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index a6b2aa6..f2904f6 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -62,6 +62,8 @@
#include <asm/uaccess.h>
+#define DRIVER_NAME "pktcdvd"
+
#if PACKET_DEBUG
#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
#else
@@ -80,7 +82,7 @@
static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
static struct proc_dir_entry *pkt_proc;
-static int pkt_major;
+static int pktdev_major;
static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
static mempool_t *psd_pool;
@@ -89,7 +91,7 @@
{
BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
- VPRINTK("pktcdvd: queue empty\n");
+ VPRINTK(DRIVER_NAME": queue empty\n");
atomic_set(&pd->iosched.attention, 1);
wake_up(&pd->wqueue);
}
@@ -400,7 +402,7 @@
int i;
struct request_sense *sense = cgc->sense;
- printk("pktcdvd:");
+ printk(DRIVER_NAME":");
for (i = 0; i < CDROM_PACKET_SIZE; i++)
printk(" %02x", cgc->cmd[i]);
printk(" - ");
@@ -528,7 +530,7 @@
need_write_seek = 0;
if (need_write_seek && reads_queued) {
if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- VPRINTK("pktcdvd: write, waiting\n");
+ VPRINTK(DRIVER_NAME": write, waiting\n");
break;
}
pkt_flush_cache(pd);
@@ -537,7 +539,7 @@
} else {
if (!reads_queued && writes_queued) {
if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- VPRINTK("pktcdvd: read, waiting\n");
+ VPRINTK(DRIVER_NAME": read, waiting\n");
break;
}
pd->iosched.writing = 1;
@@ -600,7 +602,7 @@
set_bit(PACKET_MERGE_SEGS, &pd->flags);
return 0;
} else {
- printk("pktcdvd: cdrom max_phys_segments too small\n");
+ printk(DRIVER_NAME": cdrom max_phys_segments too small\n");
return -EIO;
}
}
@@ -1049,7 +1051,7 @@
for (f = 0; f < pkt->frames; f++)
if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
BUG();
- VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt);
+ VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt);
atomic_set(&pkt->io_wait, 1);
pkt->w_bio->bi_rw = WRITE;
@@ -1286,7 +1288,7 @@
static void pkt_print_settings(struct pktcdvd_device *pd)
{
- printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
+ printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
printk("%u blocks, ", pd->settings.size >> 2);
printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2');
}
@@ -1471,7 +1473,7 @@
/*
* paranoia
*/
- printk("pktcdvd: write mode wrong %d\n", wp->data_block_type);
+ printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type);
return 1;
}
wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
@@ -1515,7 +1517,7 @@
if (ti->rt == 1 && ti->blank == 0)
return 1;
- printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
+ printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
return 0;
}
@@ -1533,7 +1535,7 @@
case 0x12: /* DVD-RAM */
return 1;
default:
- VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
+ VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile);
return 0;
}
@@ -1542,22 +1544,22 @@
* but i'm not sure, should we leave this to user apps? probably.
*/
if (di->disc_type == 0xff) {
- printk("pktcdvd: Unknown disc. No track?\n");
+ printk(DRIVER_NAME": Unknown disc. No track?\n");
return 0;
}
if (di->disc_type != 0x20 && di->disc_type != 0) {
- printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
+ printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type);
return 0;
}
if (di->erasable == 0) {
- printk("pktcdvd: Disc not erasable\n");
+ printk(DRIVER_NAME": Disc not erasable\n");
return 0;
}
if (di->border_status == PACKET_SESSION_RESERVED) {
- printk("pktcdvd: Can't write to last track (reserved)\n");
+ printk(DRIVER_NAME": Can't write to last track (reserved)\n");
return 0;
}
@@ -1593,12 +1595,12 @@
track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
- printk("pktcdvd: failed get_track\n");
+ printk(DRIVER_NAME": failed get_track\n");
return ret;
}
if (!pkt_writable_track(pd, &ti)) {
- printk("pktcdvd: can't write to this track\n");
+ printk(DRIVER_NAME": can't write to this track\n");
return -EROFS;
}
@@ -1608,11 +1610,11 @@
*/
pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
if (pd->settings.size == 0) {
- printk("pktcdvd: detected zero packet size!\n");
+ printk(DRIVER_NAME": detected zero packet size!\n");
return -ENXIO;
}
if (pd->settings.size > PACKET_MAX_SECTORS) {
- printk("pktcdvd: packet size is too big\n");
+ printk(DRIVER_NAME": packet size is too big\n");
return -EROFS;
}
pd->settings.fp = ti.fp;
@@ -1654,7 +1656,7 @@
pd->settings.block_mode = PACKET_BLOCK_MODE2;
break;
default:
- printk("pktcdvd: unknown data mode\n");
+ printk(DRIVER_NAME": unknown data mode\n");
return -EROFS;
}
return 0;
@@ -1688,10 +1690,10 @@
cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
ret = pkt_mode_select(pd, &cgc);
if (ret) {
- printk("pktcdvd: write caching control failed\n");
+ printk(DRIVER_NAME": write caching control failed\n");
pkt_dump_sense(&cgc);
} else if (!ret && set)
- printk("pktcdvd: enabled write caching on %s\n", pd->name);
+ printk(DRIVER_NAME": enabled write caching on %s\n", pd->name);
return ret;
}
@@ -1805,11 +1807,11 @@
}
if (!buf[6] & 0x40) {
- printk("pktcdvd: Disc type is not CD-RW\n");
+ printk(DRIVER_NAME": Disc type is not CD-RW\n");
return 1;
}
if (!buf[6] & 0x4) {
- printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n");
+ printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
return 1;
}
@@ -1829,14 +1831,14 @@
*speed = us_clv_to_speed[sp];
break;
default:
- printk("pktcdvd: Unknown disc sub-type %d\n",st);
+ printk(DRIVER_NAME": Unknown disc sub-type %d\n",st);
return 1;
}
if (*speed) {
- printk("pktcdvd: Max. media speed: %d\n",*speed);
+ printk(DRIVER_NAME": Max. media speed: %d\n",*speed);
return 0;
} else {
- printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st);
+ printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st);
return 1;
}
}
@@ -1847,7 +1849,7 @@
struct request_sense sense;
int ret;
- VPRINTK("pktcdvd: Performing OPC\n");
+ VPRINTK(DRIVER_NAME": Performing OPC\n");
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.sense = &sense;
@@ -1865,12 +1867,12 @@
unsigned int write_speed, media_write_speed, read_speed;
if ((ret = pkt_probe_settings(pd))) {
- VPRINTK("pktcdvd: %s failed probe\n", pd->name);
+ VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name);
return ret;
}
if ((ret = pkt_set_write_settings(pd))) {
- DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name);
return -EIO;
}
@@ -1882,26 +1884,26 @@
case 0x13: /* DVD-RW */
case 0x1a: /* DVD+RW */
case 0x12: /* DVD-RAM */
- DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);
+ DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed);
break;
default:
if ((ret = pkt_media_speed(pd, &media_write_speed)))
media_write_speed = 16;
write_speed = min(write_speed, media_write_speed * 177);
- DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176);
+ DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176);
break;
}
read_speed = write_speed;
if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
- DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name);
return -EIO;
}
pd->write_speed = write_speed;
pd->read_speed = read_speed;
if ((ret = pkt_perform_opc(pd))) {
- DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name);
}
return 0;
@@ -1929,7 +1931,7 @@
goto out_putdev;
if ((ret = pkt_get_last_written(pd, &lba))) {
- printk("pktcdvd: pkt_get_last_written failed\n");
+ printk(DRIVER_NAME": pkt_get_last_written failed\n");
goto out_unclaim;
}
@@ -1959,11 +1961,11 @@
if (write) {
if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
- printk("pktcdvd: not enough memory for buffers\n");
+ printk(DRIVER_NAME": not enough memory for buffers\n");
ret = -ENOMEM;
goto out_unclaim;
}
- printk("pktcdvd: %lukB available on disc\n", lba << 1);
+ printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
}
return 0;
@@ -1983,7 +1985,7 @@
static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
{
if (flush && pkt_flush_cache(pd))
- DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name);
pkt_lock_door(pd, 0);
@@ -2006,7 +2008,7 @@
struct pktcdvd_device *pd = NULL;
int ret;
- VPRINTK("pktcdvd: entering open\n");
+ VPRINTK(DRIVER_NAME": entering open\n");
mutex_lock(&ctl_mutex);
pd = pkt_find_dev_from_minor(iminor(inode));
@@ -2040,7 +2042,7 @@
out_dec:
pd->refcnt--;
out:
- VPRINTK("pktcdvd: failed open (%d)\n", ret);
+ VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
mutex_unlock(&ctl_mutex);
return ret;
}
@@ -2088,7 +2090,7 @@
pd = q->queuedata;
if (!pd) {
- printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
+ printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
goto end_io;
}
@@ -2110,13 +2112,13 @@
}
if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
- printk("pktcdvd: WRITE for ro device %s (%llu)\n",
+ printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n",
pd->name, (unsigned long long)bio->bi_sector);
goto end_io;
}
if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
- printk("pktcdvd: wrong bio size\n");
+ printk(DRIVER_NAME": wrong bio size\n");
goto end_io;
}
@@ -2319,7 +2321,7 @@
struct block_device *bdev;
if (pd->pkt_dev == dev) {
- printk("pktcdvd: Recursive setup not allowed\n");
+ printk(DRIVER_NAME": Recursive setup not allowed\n");
return -EBUSY;
}
for (i = 0; i < MAX_WRITERS; i++) {
@@ -2327,11 +2329,11 @@
if (!pd2)
continue;
if (pd2->bdev->bd_dev == dev) {
- printk("pktcdvd: %s already setup\n", bdevname(pd2->bdev, b));
+ printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b));
return -EBUSY;
}
if (pd2->pkt_dev == dev) {
- printk("pktcdvd: Can't chain pktcdvd devices\n");
+ printk(DRIVER_NAME": Can't chain pktcdvd devices\n");
return -EBUSY;
}
}
@@ -2354,7 +2356,7 @@
atomic_set(&pd->cdrw.pending_bios, 0);
pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
if (IS_ERR(pd->cdrw.thread)) {
- printk("pktcdvd: can't start kernel thread\n");
+ printk(DRIVER_NAME": can't start kernel thread\n");
ret = -ENOMEM;
goto out_mem;
}
@@ -2364,7 +2366,7 @@
proc->data = pd;
proc->proc_fops = &pkt_proc_fops;
}
- DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
+ DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
return 0;
out_mem:
@@ -2401,7 +2403,7 @@
return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
default:
- VPRINTK("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
+ VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
return -ENOTTY;
}
@@ -2446,7 +2448,7 @@
if (!pkt_devs[idx])
break;
if (idx == MAX_WRITERS) {
- printk("pktcdvd: max %d writers supported\n", MAX_WRITERS);
+ printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
return -EBUSY;
}
@@ -2470,15 +2472,15 @@
spin_lock_init(&pd->lock);
spin_lock_init(&pd->iosched.lock);
- sprintf(pd->name, "pktcdvd%d", idx);
+ sprintf(pd->name, DRIVER_NAME"%d", idx);
init_waitqueue_head(&pd->wqueue);
pd->bio_queue = RB_ROOT;
- disk->major = pkt_major;
+ disk->major = pktdev_major;
disk->first_minor = idx;
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
- sprintf(disk->disk_name, "pktcdvd%d", idx);
+ sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
disk->private_data = pd;
disk->queue = blk_alloc_queue(GFP_KERNEL);
if (!disk->queue)
@@ -2520,7 +2522,7 @@
break;
}
if (idx == MAX_WRITERS) {
- DPRINTK("pktcdvd: dev not setup\n");
+ DPRINTK(DRIVER_NAME": dev not setup\n");
return -ENXIO;
}
@@ -2533,7 +2535,7 @@
blkdev_put(pd->bdev);
remove_proc_entry(pd->name, pkt_proc);
- DPRINTK("pktcdvd: writer %s unmapped\n", pd->name);
+ DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name);
del_gendisk(pd->disk);
blk_cleanup_queue(pd->disk->queue);
@@ -2610,7 +2612,7 @@
static struct miscdevice pkt_misc = {
.minor = MISC_DYNAMIC_MINOR,
- .name = "pktcdvd",
+ .name = DRIVER_NAME,
.fops = &pkt_ctl_fops
};
@@ -2623,28 +2625,28 @@
if (!psd_pool)
return -ENOMEM;
- ret = register_blkdev(pkt_major, "pktcdvd");
+ ret = register_blkdev(pktdev_major, DRIVER_NAME);
if (ret < 0) {
- printk("pktcdvd: Unable to register block device\n");
+ printk(DRIVER_NAME": Unable to register block device\n");
goto out2;
}
- if (!pkt_major)
- pkt_major = ret;
+ if (!pktdev_major)
+ pktdev_major = ret;
ret = misc_register(&pkt_misc);
if (ret) {
- printk("pktcdvd: Unable to register misc device\n");
+ printk(DRIVER_NAME": Unable to register misc device\n");
goto out;
}
mutex_init(&ctl_mutex);
- pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
+ pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
return 0;
out:
- unregister_blkdev(pkt_major, "pktcdvd");
+ unregister_blkdev(pktdev_major, DRIVER_NAME);
out2:
mempool_destroy(psd_pool);
return ret;
@@ -2652,9 +2654,9 @@
static void __exit pkt_exit(void)
{
- remove_proc_entry("pktcdvd", proc_root_driver);
+ remove_proc_entry(DRIVER_NAME, proc_root_driver);
misc_deregister(&pkt_misc);
- unregister_blkdev(pkt_major, "pktcdvd");
+ unregister_blkdev(pktdev_major, DRIVER_NAME);
mempool_destroy(psd_pool);
}
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index d0e92ed..486f97c 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -112,17 +112,6 @@
#define NR_PORTS ARRAY_SIZE(rs_table)
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-
#include <asm/uaccess.h>
#define serial_isroot() (capable(CAP_SYS_ADMIN))
@@ -912,7 +901,7 @@
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
- if (!info->xmit.buf || !tmp_buf)
+ if (!info->xmit.buf)
return 0;
local_save_flags(flags);
@@ -1778,7 +1767,6 @@
{
struct async_struct *info;
int retval, line;
- unsigned long page;
line = tty->index;
if ((line < 0) || (line >= NR_PORTS)) {
@@ -1798,17 +1786,6 @@
#endif
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page) {
- return -ENOMEM;
- }
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
-
/*
* If the port is the middle of closing, bail out now
*/
@@ -2090,11 +2067,6 @@
kfree(info);
}
- if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
- tmp_buf = NULL;
- }
-
release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index f85b4eb..87b2fb5 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -748,18 +748,6 @@
static int cy_next_channel; /* next minor available */
/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open. This buffer is
- * allocated when the first cy_open occurs.
- */
-static unsigned char *tmp_buf;
-
-/*
* This is used to look up the divisor speeds and the timeouts
* We're normally limited to 15 distinct baud rates. The extra
* are accessed via settings in info->flags.
@@ -2466,7 +2454,6 @@
{
struct cyclades_port *info;
int retval, line;
- unsigned long page;
line = tty->index;
if ((line < 0) || (NR_PORTS <= line)){
@@ -2545,15 +2532,6 @@
printk("cyc:cy_open (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
/*
* If the port is the middle of closing, bail out now
@@ -2832,7 +2810,7 @@
return 0;
}
- if (!info->xmit_buf || !tmp_buf)
+ if (!info->xmit_buf)
return 0;
CY_LOCK(info, flags);
@@ -5490,10 +5468,6 @@
#endif
}
}
- if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
- tmp_buf = NULL;
- }
} /* cy_cleanup_module */
module_init(cy_init);
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 3baa2ab..c3f9558 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1113,11 +1113,8 @@
ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++)
{ /* Begin for each port */
- if (ch) {
- if (ch->tty)
- tty_hangup(ch->tty);
- kfree(ch->tmp_buf);
- }
+ if (ch && ch->tty)
+ tty_hangup(ch->tty);
} /* End for each port */
} /* End for each card */
pci_unregister_driver (&epca_driver);
@@ -1635,16 +1632,6 @@
init_waitqueue_head(&ch->close_wait);
spin_unlock_irqrestore(&epca_lock, flags);
-
- ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
- if (!ch->tmp_buf) {
- printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
- release_region((int)bd->port, 4);
- while(i-- > 0)
- kfree((ch--)->tmp_buf);
- return;
- } else
- memset((void *)ch->tmp_buf,0,ch->txbufsize);
} /* End for each port */
printk(KERN_INFO
diff --git a/drivers/char/epca.h b/drivers/char/epca.h
index 456d6c8..a297238 100644
--- a/drivers/char/epca.h
+++ b/drivers/char/epca.h
@@ -130,7 +130,6 @@
unsigned long c_oflag;
unsigned char __iomem *txptr;
unsigned char __iomem *rxptr;
- unsigned char *tmp_buf;
struct board_info *board;
struct board_chan __iomem *brdchan;
struct digi_struct digiext;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 4711d9b..87127e4 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -33,8 +33,6 @@
#define DEBUG
-static char * tmp_buf;
-
static int gs_debug;
#ifdef DEBUG
@@ -205,7 +203,7 @@
if (!tty) return -EIO;
port = tty->driver_data;
- if (!port || !port->xmit_buf || !tmp_buf)
+ if (!port || !port->xmit_buf)
return -EIO;
local_save_flags(flags);
@@ -837,24 +835,9 @@
int gs_init_port(struct gs_port *port)
{
unsigned long flags;
- unsigned long page;
func_enter ();
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- spin_unlock_irqrestore (&port->driver_lock, flags);
- if (!tmp_buf) {
- func_exit ();
- return -ENOMEM;
- }
- }
-
if (port->flags & ASYNC_INITIALIZED) {
func_exit ();
return 0;
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 214d8501..b0ab3f2 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -81,7 +81,6 @@
static struct riscom_board * IRQ_to_board[16];
static struct tty_driver *riscom_driver;
-static unsigned char * tmp_buf;
static unsigned long baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
@@ -1124,7 +1123,7 @@
bp = port_Board(port);
- if (!tty || !port->xmit_buf || !tmp_buf)
+ if (!tty || !port->xmit_buf)
return 0;
save_flags(flags);
@@ -1612,11 +1611,6 @@
if (!riscom_driver)
return -ENOMEM;
- if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
- printk(KERN_ERR "rc: Couldn't get free page.\n");
- put_tty_driver(riscom_driver);
- return 1;
- }
memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
riscom_driver->owner = THIS_MODULE;
riscom_driver->name = "ttyL";
@@ -1629,7 +1623,6 @@
riscom_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(riscom_driver, &riscom_ops);
if ((error = tty_register_driver(riscom_driver))) {
- free_page((unsigned long)tmp_buf);
put_tty_driver(riscom_driver);
printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
"error = %d\n",
@@ -1657,7 +1650,6 @@
save_flags(flags);
cli();
- free_page((unsigned long)tmp_buf);
tty_unregister_driver(riscom_driver);
put_tty_driver(riscom_driver);
restore_flags(flags);
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index b4ea126..f4809c8 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -119,17 +119,6 @@
#define NR_PORTS ARRAY_SIZE(cy_port)
/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf = 0;
-
-/*
* This is used to look up the divisor speeds and the timeouts
* We're normally limited to 15 distinct baud rates. The extra
* are accessed via settings in info->flags.
@@ -1132,7 +1121,7 @@
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
local_irq_save(flags);
@@ -1198,7 +1187,7 @@
return 0;
}
- if (!tty || !info->xmit_buf || !tmp_buf){
+ if (!info->xmit_buf){
return 0;
}
@@ -1983,13 +1972,6 @@
tty->driver_data = info;
info->tty = tty;
- if (!tmp_buf) {
- tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (!tmp_buf){
- return -ENOMEM;
- }
- }
-
/*
* Start up serial port
*/
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
index d418b82..22915cc 100644
--- a/drivers/clocksource/scx200_hrt.c
+++ b/drivers/clocksource/scx200_hrt.c
@@ -63,7 +63,7 @@
static int __init init_hrt_clocksource(void)
{
- /* Make sure scx200 has initializedd the configuration block */
+ /* Make sure scx200 has initialized the configuration block */
if (!scx200_cb_present())
return -ENODEV;
@@ -76,7 +76,7 @@
}
/* write timer config */
- outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0,
+ outb(HR_TMEN | (mhz27 ? HR_TMCLKSEL : 0),
scx200_cb_base + SCx200_TMCNFG_OFFSET);
if (mhz27) {
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2caaf71..86e69b7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -52,8 +52,14 @@
* The mutex locks both lists.
*/
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
-static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list);
+static struct srcu_notifier_head cpufreq_transition_notifier_list;
+static int __init init_cpufreq_transition_notifier_list(void)
+{
+ srcu_init_notifier_head(&cpufreq_transition_notifier_list);
+ return 0;
+}
+core_initcall(init_cpufreq_transition_notifier_list);
static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX (cpufreq_governor_mutex);
@@ -262,14 +268,14 @@
freqs->old = policy->cur;
}
}
- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break;
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu))
policy->cur = freqs->new;
@@ -1049,7 +1055,7 @@
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_SUSPENDCHANGE, &freqs);
adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
@@ -1130,7 +1136,7 @@
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- blocking_notifier_call_chain(
+ srcu_notifier_call_chain(
&cpufreq_transition_notifier_list,
CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
@@ -1176,7 +1182,7 @@
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
- ret = blocking_notifier_chain_register(
+ ret = srcu_notifier_chain_register(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
@@ -1208,7 +1214,7 @@
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
- ret = blocking_notifier_chain_unregister(
+ ret = srcu_notifier_chain_unregister(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 489022b..0945336 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -13,7 +13,6 @@
*
*/
-
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -45,33 +44,31 @@
#define PCI_IRQ_DISABLE 0xff0000
#define PCI_IRQ_ASSERT 0x800000
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
+static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
- return (ret);
+ return ret;
}
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+static inline void readfifo(unsigned int ale, unsigned int adr, u_char off,
+ u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+static inline void writereg(unsigned int ale, unsigned int adr, u_char off,
+ u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+static inline void writefifo(unsigned int ale, unsigned int adr, u_char off,
+ u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
@@ -79,39 +76,34 @@
/* Interface functions */
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
+static u_char ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
+ return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset);
}
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
}
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+static void ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
}
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+static void WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
}
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- return (readreg(cs->hw.niccy.hscx_ale,
- cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
+ return readreg(cs->hw.niccy.hscx_ale,
+ cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0));
}
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset,
+ u_char value)
{
writereg(cs->hw.niccy.hscx_ale,
cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
@@ -130,8 +122,8 @@
#include "hscx_irq.c"
-static irqreturn_t
-niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t niccy_interrupt(int intno, void *dev_id,
+ struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val;
@@ -141,21 +133,23 @@
if (cs->subtyp == NICCY_PCI) {
int ival;
ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
+ if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
}
- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
- Start_HSCX:
+ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
+ HSCX_ISTA + 0x40);
+Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
- Start_ISAC:
+Start_ISAC:
if (val)
isac_interrupt(cs, val);
- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
+ HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
@@ -168,21 +162,21 @@
goto Start_ISAC;
}
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,
+ 0xFF);
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
-static void
-release_io_niccy(struct IsdnCardState *cs)
+static void release_io_niccy(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
int val;
-
+
val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
val &= PCI_IRQ_DISABLE;
outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
@@ -194,8 +188,7 @@
}
}
-static void
-niccy_reset(struct IsdnCardState *cs)
+static void niccy_reset(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
int val;
@@ -207,29 +200,28 @@
inithscxisac(cs, 3);
}
-static int
-niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- niccy_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return(0);
- case CARD_RELEASE:
- release_io_niccy(cs);
- return(0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- niccy_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return(0);
- case CARD_TEST:
- return(0);
+ case CARD_RESET:
+ spin_lock_irqsave(&cs->lock, flags);
+ niccy_reset(cs);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return 0;
+ case CARD_RELEASE:
+ release_io_niccy(cs);
+ return 0;
+ case CARD_INIT:
+ spin_lock_irqsave(&cs->lock, flags);
+ niccy_reset(cs);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return 0;
+ case CARD_TEST:
+ return 0;
}
- return(0);
+ return 0;
}
static struct pci_dev *niccy_dev __devinitdata = NULL;
@@ -237,8 +229,7 @@
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __devinit
-setup_niccy(struct IsdnCard *card)
+int __devinit setup_niccy(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
@@ -246,40 +237,44 @@
strcpy(tmp, niccy_revision);
printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_NICCY)
- return (0);
+ return 0;
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d = NULL;
int err;
- if ((pnp_c = pnp_find_card(
- ISAPNP_VENDOR('S', 'D', 'A'),
- ISAPNP_FUNCTION(0x0150), pnp_c))) {
- if (!(pnp_d = pnp_find_dev(pnp_c,
- ISAPNP_VENDOR('S', 'D', 'A'),
- ISAPNP_FUNCTION(0x0150), pnp_d))) {
- printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
- return (0);
+ pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'),
+ ISAPNP_FUNCTION(0x0150), pnp_c);
+ if (pnp_c) {
+ pnp_d = pnp_find_dev(pnp_c,
+ ISAPNP_VENDOR('S', 'D', 'A'),
+ ISAPNP_FUNCTION(0x0150), pnp_d);
+ if (!pnp_d) {
+ printk(KERN_ERR "NiccyPnP: PnP error card "
+ "found, no device\n");
+ return 0;
}
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
+ if (err < 0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev "
+ "ret(%d)\n", __FUNCTION__, err);
+ return 0;
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[2] = pnp_port_start(pnp_d, 1);
card->para[0] = pnp_irq(pnp_d, 0);
- if (!card->para[0] || !card->para[1] || !card->para[2]) {
- printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
- card->para[0], card->para[1], card->para[2]);
+ if (!card->para[0] || !card->para[1] ||
+ !card->para[2]) {
+ printk(KERN_ERR "NiccyPnP:some resources are "
+ "missing %ld/%lx/%lx\n",
+ card->para[0], card->para[1],
+ card->para[2]);
pnp_disable_dev(pnp_d);
- return(0);
+ return 0;
}
- } else {
+ } else
printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
- }
}
#endif
if (card->para[1]) {
@@ -291,50 +286,51 @@
cs->subtyp = NICCY_PNP;
cs->irq = card->para[0];
if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
- printk(KERN_WARNING
- "HiSax: %s data port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.niccy.isac,
- cs->hw.niccy.isac + 1);
- return (0);
+ printk(KERN_WARNING "HiSax: %s data port %x-%x "
+ "already in use\n", CardType[card->typ],
+ cs->hw.niccy.isac, cs->hw.niccy.isac + 1);
+ return 0;
}
if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
- printk(KERN_WARNING
- "HiSax: %s address port %x-%x already in use\n",
- CardType[card->typ],
+ printk(KERN_WARNING "HiSax: %s address port %x-%x "
+ "already in use\n", CardType[card->typ],
cs->hw.niccy.isac_ale,
cs->hw.niccy.isac_ale + 1);
release_region(cs->hw.niccy.isac, 2);
- return (0);
+ return 0;
}
} else {
#ifdef CONFIG_PCI
u_int pci_ioaddr;
cs->subtyp = 0;
if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
- PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
+ PCI_DEVICE_ID_SATSAGEM_NICCY,
+ niccy_dev))) {
if (pci_enable_device(niccy_dev))
- return(0);
+ return 0;
/* get IRQ */
if (!niccy_dev->irq) {
- printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
- return(0);
+ printk(KERN_WARNING
+ "Niccy: No IRQ for PCI card found\n");
+ return 0;
}
cs->irq = niccy_dev->irq;
cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
if (!cs->hw.niccy.cfg_reg) {
- printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
- return(0);
+ printk(KERN_WARNING
+ "Niccy: No IO-Adr for PCI cfg found\n");
+ return 0;
}
pci_ioaddr = pci_resource_start(niccy_dev, 1);
if (!pci_ioaddr) {
- printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
- return(0);
+ printk(KERN_WARNING
+ "Niccy: No IO-Adr for PCI card found\n");
+ return 0;
}
cs->subtyp = NICCY_PCI;
} else {
printk(KERN_WARNING "Niccy: No PCI card found\n");
- return(0);
+ return 0;
}
cs->irq_flags |= IRQF_SHARED;
cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
@@ -343,29 +339,28 @@
cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
printk(KERN_WARNING
- "HiSax: %s data port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.niccy.isac,
- cs->hw.niccy.isac + 4);
- return (0);
+ "HiSax: %s data port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.niccy.isac, cs->hw.niccy.isac + 4);
+ return 0;
}
if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
printk(KERN_WARNING
"HiSax: %s pci port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.niccy.cfg_reg,
- cs->hw.niccy.cfg_reg + 0x40);
+ CardType[card->typ],
+ cs->hw.niccy.cfg_reg,
+ cs->hw.niccy.cfg_reg + 0x40);
release_region(cs->hw.niccy.isac, 4);
- return (0);
+ return 0;
}
#else
printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
- return (0);
-#endif /* CONFIG_PCI */
+ return 0;
+#endif /* CONFIG_PCI */
}
printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
- CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
+ CardType[cs->typ], (cs->subtyp == 1) ? "PnP" : "PCI",
cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
setup_isac(cs);
cs->readisac = &ReadISAC;
@@ -379,10 +374,10 @@
cs->irq_func = &niccy_interrupt;
ISACVersion(cs, "Niccy:");
if (HscxVersion(cs, "Niccy:")) {
- printk(KERN_WARNING
- "Niccy: wrong HSCX versions check IO address\n");
+ printk(KERN_WARNING "Niccy: wrong HSCX versions check IO "
+ "address\n");
release_io_niccy(cs);
- return (0);
+ return 0;
}
- return (1);
+ return 1;
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7fc692a..3df0e7a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -18,7 +18,7 @@
service processor board as a regular serial port. To make use of
this feature serial driver support (CONFIG_SERIAL_8250) must be
enabled.
-
+
WARNING: This software may not be supported or function
correctly on your IBM server. Please consult the IBM ServerProven
website <http://www.pc.ibm.com/ww/eserver/xseries/serverproven> for
@@ -28,5 +28,33 @@
If unsure, say N.
-endmenu
+config TIFM_CORE
+ tristate "TI Flash Media interface support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ If you want support for Texas Instruments(R) Flash Media adapters
+ you should select this option and then also choose an appropriate
+ host adapter, such as 'TI Flash Media PCI74xx/PCI76xx host adapter
+ support', if you have a TI PCI74xx compatible card reader, for
+ example.
+ You will also have to select some flash card format drivers. MMC/SD
+ cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD
+ Interface support (MMC_TIFM_SD)'.
+ To compile this driver as a module, choose M here: the module will
+ be called tifm_core.
+
+config TIFM_7XX1
+ tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)"
+ depends on PCI && TIFM_CORE && EXPERIMENTAL
+ default TIFM_CORE
+ help
+ This option enables support for Texas Instruments(R) PCI74xx and
+ PCI76xx families of Flash Media adapters, found in many laptops.
+ To make actual use of the device, you will have to select some
+ flash card format drivers, as outlined in the TIFM_CORE Help.
+
+ To compile this driver as a module, choose M here: the module will
+ be called tifm_7xx1.
+
+endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c1bf1fb..d65ece7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,3 +6,5 @@
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_LKDTM) += lkdtm.o
+obj-$(CONFIG_TIFM_CORE) += tifm_core.o
+obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
new file mode 100644
index 0000000..a7ed304
--- /dev/null
+++ b/drivers/misc/tifm_7xx1.c
@@ -0,0 +1,437 @@
+/*
+ * tifm_7xx1.c - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/tifm.h>
+#include <linux/dma-mapping.h>
+
+#define DRIVER_NAME "tifm_7xx1"
+#define DRIVER_VERSION "0.6"
+
+static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
+{
+ int cnt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->inhibit_new_cards) {
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ if (fm->sockets[cnt] == sock) {
+ fm->remove_mask |= (1 << cnt);
+ queue_work(fm->wq, &fm->media_remover);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+}
+
+static void tifm_7xx1_remove_media(void *adapter)
+{
+ struct tifm_adapter *fm = adapter;
+ unsigned long flags;
+ int cnt;
+ struct tifm_dev *sock;
+
+ if (!class_device_get(&fm->cdev))
+ return;
+ spin_lock_irqsave(&fm->lock, flags);
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
+ printk(KERN_INFO DRIVER_NAME
+ ": demand removing card from socket %d\n", cnt);
+ sock = fm->sockets[cnt];
+ fm->sockets[cnt] = 0;
+ fm->remove_mask &= ~(1 << cnt);
+
+ writel(0x0e00, sock->addr + SOCK_CONTROL);
+
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+ spin_unlock_irqrestore(&fm->lock, flags);
+ device_unregister(&sock->dev);
+ spin_lock_irqsave(&fm->lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ class_device_put(&fm->cdev);
+}
+
+static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct tifm_adapter *fm = dev_id;
+ unsigned int irq_status;
+ unsigned int sock_irq_status, cnt;
+
+ spin_lock(&fm->lock);
+ irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
+ if (irq_status == 0 || irq_status == (~0)) {
+ spin_unlock(&fm->lock);
+ return IRQ_NONE;
+ }
+
+ if (irq_status & TIFM_IRQ_ENABLE) {
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ sock_irq_status = (irq_status >> cnt) &
+ (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
+
+ if (fm->sockets[cnt]) {
+ if (sock_irq_status &&
+ fm->sockets[cnt]->signal_irq)
+ sock_irq_status = fm->sockets[cnt]->
+ signal_irq(fm->sockets[cnt],
+ sock_irq_status);
+
+ if (irq_status & (1 << cnt))
+ fm->remove_mask |= 1 << cnt;
+ } else {
+ if (irq_status & (1 << cnt))
+ fm->insert_mask |= 1 << cnt;
+ }
+ }
+ }
+ writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
+
+ if (!fm->inhibit_new_cards) {
+ if (!fm->remove_mask && !fm->insert_mask) {
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ } else {
+ queue_work(fm->wq, &fm->media_remover);
+ queue_work(fm->wq, &fm->media_inserter);
+ }
+ }
+
+ spin_unlock(&fm->lock);
+ return IRQ_HANDLED;
+}
+
+static tifm_media_id tifm_7xx1_toggle_sock_power(char *sock_addr, int is_x2)
+{
+ unsigned int s_state;
+ int cnt;
+
+ writel(0x0e00, sock_addr + SOCK_CONTROL);
+
+ for (cnt = 0; cnt < 100; cnt++) {
+ if (!(TIFM_SOCK_STATE_POWERED &
+ readl(sock_addr + SOCK_PRESENT_STATE)))
+ break;
+ msleep(10);
+ }
+
+ s_state = readl(sock_addr + SOCK_PRESENT_STATE);
+ if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
+ return FM_NULL;
+
+ if (is_x2) {
+ writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+ } else {
+ // SmartMedia cards need extra 40 msec
+ if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
+ msleep(40);
+ writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
+ sock_addr + SOCK_CONTROL);
+ msleep(10);
+ writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
+ sock_addr + SOCK_CONTROL);
+ }
+
+ for (cnt = 0; cnt < 100; cnt++) {
+ if ((TIFM_SOCK_STATE_POWERED &
+ readl(sock_addr + SOCK_PRESENT_STATE)))
+ break;
+ msleep(10);
+ }
+
+ if (!is_x2)
+ writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
+ sock_addr + SOCK_CONTROL);
+
+ return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
+}
+
+inline static char *tifm_7xx1_sock_addr(char *base_addr, unsigned int sock_num)
+{
+ return base_addr + ((sock_num + 1) << 10);
+}
+
+static void tifm_7xx1_insert_media(void *adapter)
+{
+ struct tifm_adapter *fm = adapter;
+ unsigned long flags;
+ tifm_media_id media_id;
+ char *card_name = "xx";
+ int cnt, ok_to_register;
+ unsigned int insert_mask;
+ struct tifm_dev *new_sock = 0;
+
+ if (!class_device_get(&fm->cdev))
+ return;
+ spin_lock_irqsave(&fm->lock, flags);
+ insert_mask = fm->insert_mask;
+ fm->insert_mask = 0;
+ if (fm->inhibit_new_cards) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ class_device_put(&fm->cdev);
+ return;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ if (!(insert_mask & (1 << cnt)))
+ continue;
+
+ media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->max_sockets == 2);
+ if (media_id) {
+ ok_to_register = 0;
+ new_sock = tifm_alloc_device(fm, cnt);
+ if (new_sock) {
+ new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
+ cnt);
+ new_sock->media_id = media_id;
+ switch (media_id) {
+ case 1:
+ card_name = "xd";
+ break;
+ case 2:
+ card_name = "ms";
+ break;
+ case 3:
+ card_name = "sd";
+ break;
+ default:
+ break;
+ }
+ snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
+ "tifm_%s%u:%u", card_name, fm->id, cnt);
+ printk(KERN_INFO DRIVER_NAME
+ ": %s card detected in socket %d\n",
+ card_name, cnt);
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->sockets[cnt]) {
+ fm->sockets[cnt] = new_sock;
+ ok_to_register = 1;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ if (!ok_to_register ||
+ device_register(&new_sock->dev)) {
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->sockets[cnt] = 0;
+ spin_unlock_irqrestore(&fm->lock,
+ flags);
+ tifm_free_device(&new_sock->dev);
+ }
+ }
+ }
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ }
+
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+ class_device_put(&fm->cdev);
+}
+
+static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ struct tifm_adapter *fm = pci_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->inhibit_new_cards = 1;
+ fm->remove_mask = 0xf;
+ fm->insert_mask = 0;
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+ flush_workqueue(fm->wq);
+
+ tifm_7xx1_remove_media(fm);
+
+ pci_set_power_state(dev, PCI_D3hot);
+ pci_disable_device(dev);
+ pci_save_state(dev);
+ return 0;
+}
+
+static int tifm_7xx1_resume(struct pci_dev *dev)
+{
+ struct tifm_adapter *fm = pci_get_drvdata(dev);
+ unsigned long flags;
+
+ pci_restore_state(dev);
+ pci_enable_device(dev);
+ pci_set_power_state(dev, PCI_D0);
+ pci_set_master(dev);
+
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->inhibit_new_cards = 0;
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ fm->insert_mask = 0xf;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+}
+
+static int tifm_7xx1_probe(struct pci_dev *dev,
+ const struct pci_device_id *dev_id)
+{
+ struct tifm_adapter *fm;
+ int pci_dev_busy = 0;
+ int rc;
+
+ rc = pci_set_dma_mask(dev, DMA_32BIT_MASK);
+ if (rc)
+ return rc;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ pci_set_master(dev);
+
+ rc = pci_request_regions(dev, DRIVER_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ pci_intx(dev, 1);
+
+ fm = tifm_alloc_adapter();
+ if (!fm) {
+ rc = -ENOMEM;
+ goto err_out_int;
+ }
+
+ fm->dev = &dev->dev;
+ fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
+ fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
+ GFP_KERNEL);
+ if (!fm->sockets)
+ goto err_out_free;
+
+ INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media, fm);
+ INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media, fm);
+ fm->eject = tifm_7xx1_eject;
+ pci_set_drvdata(dev, fm);
+
+ fm->addr = ioremap(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+ if (!fm->addr)
+ goto err_out_free;
+
+ rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
+ if (rc)
+ goto err_out_unmap;
+
+ rc = tifm_add_adapter(fm);
+ if (rc)
+ goto err_out_irq;
+
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+ fm->insert_mask = 0xf;
+
+ return 0;
+
+err_out_irq:
+ free_irq(dev->irq, fm);
+err_out_unmap:
+ iounmap(fm->addr);
+err_out_free:
+ pci_set_drvdata(dev, NULL);
+ tifm_free_adapter(fm);
+err_out_int:
+ pci_intx(dev, 0);
+ pci_release_regions(dev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(dev);
+ return rc;
+}
+
+static void tifm_7xx1_remove(struct pci_dev *dev)
+{
+ struct tifm_adapter *fm = pci_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->inhibit_new_cards = 1;
+ fm->remove_mask = 0xf;
+ fm->insert_mask = 0;
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+
+ flush_workqueue(fm->wq);
+
+ tifm_7xx1_remove_media(fm);
+
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ free_irq(dev->irq, fm);
+
+ tifm_remove_adapter(fm);
+
+ pci_set_drvdata(dev, 0);
+
+ iounmap(fm->addr);
+ pci_intx(dev, 0);
+ pci_release_regions(dev);
+
+ pci_disable_device(dev);
+ tifm_free_adapter(fm);
+}
+
+static struct pci_device_id tifm_7xx1_pci_tbl [] = {
+ { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ 0 }, /* xx21 - the one I have */
+ { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ 0 }, /* xx12 - should be also supported */
+ { }
+};
+
+static struct pci_driver tifm_7xx1_driver = {
+ .name = DRIVER_NAME,
+ .id_table = tifm_7xx1_pci_tbl,
+ .probe = tifm_7xx1_probe,
+ .remove = tifm_7xx1_remove,
+ .suspend = tifm_7xx1_suspend,
+ .resume = tifm_7xx1_resume,
+};
+
+static int __init tifm_7xx1_init(void)
+{
+ return pci_register_driver(&tifm_7xx1_driver);
+}
+
+static void __exit tifm_7xx1_exit(void)
+{
+ pci_unregister_driver(&tifm_7xx1_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia host driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_7xx1_init);
+module_exit(tifm_7xx1_exit);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
new file mode 100644
index 0000000..cca5f85
--- /dev/null
+++ b/drivers/misc/tifm_core.c
@@ -0,0 +1,272 @@
+/*
+ * tifm_core.c - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/tifm.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+
+#define DRIVER_NAME "tifm_core"
+#define DRIVER_VERSION "0.6"
+
+static DEFINE_IDR(tifm_adapter_idr);
+static DEFINE_SPINLOCK(tifm_adapter_lock);
+
+static tifm_media_id *tifm_device_match(tifm_media_id *ids,
+ struct tifm_dev *dev)
+{
+ while (*ids) {
+ if (dev->media_id == *ids)
+ return ids;
+ ids++;
+ }
+ return NULL;
+}
+
+static int tifm_match(struct device *dev, struct device_driver *drv)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *fm_drv;
+
+ fm_drv = container_of(drv, struct tifm_driver, driver);
+ if (!fm_drv->id_table)
+ return -EINVAL;
+ if (tifm_device_match(fm_drv->id_table, fm_dev))
+ return 1;
+ return -ENODEV;
+}
+
+static int tifm_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct tifm_dev *fm_dev;
+ int i = 0;
+ int length = 0;
+ const char *card_type_name[] = {"INV", "SM", "MS", "SD"};
+
+ if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev)))
+ return -ENODEV;
+ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id]))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static struct bus_type tifm_bus_type = {
+ .name = "tifm",
+ .match = tifm_match,
+ .uevent = tifm_uevent,
+};
+
+static void tifm_free(struct class_device *cdev)
+{
+ struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
+
+ kfree(fm->sockets);
+ if (fm->wq)
+ destroy_workqueue(fm->wq);
+ kfree(fm);
+}
+
+static struct class tifm_adapter_class = {
+ .name = "tifm_adapter",
+ .release = tifm_free
+};
+
+struct tifm_adapter *tifm_alloc_adapter(void)
+{
+ struct tifm_adapter *fm;
+
+ fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL);
+ if (fm) {
+ fm->cdev.class = &tifm_adapter_class;
+ spin_lock_init(&fm->lock);
+ class_device_initialize(&fm->cdev);
+ }
+ return fm;
+}
+EXPORT_SYMBOL(tifm_alloc_adapter);
+
+void tifm_free_adapter(struct tifm_adapter *fm)
+{
+ class_device_put(&fm->cdev);
+}
+EXPORT_SYMBOL(tifm_free_adapter);
+
+int tifm_add_adapter(struct tifm_adapter *fm)
+{
+ int rc;
+
+ if (!idr_pre_get(&tifm_adapter_idr, GFP_KERNEL))
+ return -ENOMEM;
+
+ spin_lock(&tifm_adapter_lock);
+ rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id);
+ spin_unlock(&tifm_adapter_lock);
+ if (!rc) {
+ snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
+ strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+
+ fm->wq = create_singlethread_workqueue(fm->wq_name);
+ if (fm->wq)
+ return class_device_add(&fm->cdev);
+
+ spin_lock(&tifm_adapter_lock);
+ idr_remove(&tifm_adapter_idr, fm->id);
+ spin_unlock(&tifm_adapter_lock);
+ rc = -ENOMEM;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(tifm_add_adapter);
+
+void tifm_remove_adapter(struct tifm_adapter *fm)
+{
+ class_device_del(&fm->cdev);
+
+ spin_lock(&tifm_adapter_lock);
+ idr_remove(&tifm_adapter_idr, fm->id);
+ spin_unlock(&tifm_adapter_lock);
+}
+EXPORT_SYMBOL(tifm_remove_adapter);
+
+void tifm_free_device(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ if (fm_dev->wq)
+ destroy_workqueue(fm_dev->wq);
+ kfree(fm_dev);
+}
+EXPORT_SYMBOL(tifm_free_device);
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+{
+ struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
+
+ if (dev) {
+ spin_lock_init(&dev->lock);
+ snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
+ dev->wq = create_singlethread_workqueue(dev->wq_name);
+ if (!dev->wq) {
+ kfree(dev);
+ return 0;
+ }
+ dev->dev.parent = fm->dev;
+ dev->dev.bus = &tifm_bus_type;
+ dev->dev.release = tifm_free_device;
+ }
+ return dev;
+}
+EXPORT_SYMBOL(tifm_alloc_device);
+
+void tifm_eject(struct tifm_dev *sock)
+{
+ struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
+ fm->eject(fm, sock);
+}
+EXPORT_SYMBOL(tifm_eject);
+
+int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction)
+{
+ return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
+}
+EXPORT_SYMBOL(tifm_map_sg);
+
+void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction)
+{
+ pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
+}
+EXPORT_SYMBOL(tifm_unmap_sg);
+
+static int tifm_device_probe(struct device *dev)
+{
+ struct tifm_driver *drv;
+ struct tifm_dev *fm_dev;
+ int rc = 0;
+ const tifm_media_id *id;
+
+ drv = container_of(dev->driver, struct tifm_driver, driver);
+ fm_dev = container_of(dev, struct tifm_dev, dev);
+ get_device(dev);
+ if (!fm_dev->drv && drv->probe && drv->id_table) {
+ rc = -ENODEV;
+ id = tifm_device_match(drv->id_table, fm_dev);
+ if (id)
+ rc = drv->probe(fm_dev);
+ if (rc >= 0) {
+ rc = 0;
+ fm_dev->drv = drv;
+ }
+ }
+ if (rc)
+ put_device(dev);
+ return rc;
+}
+
+static int tifm_device_remove(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv) {
+ if (drv->remove) drv->remove(fm_dev);
+ fm_dev->drv = 0;
+ }
+
+ put_device(dev);
+ return 0;
+}
+
+int tifm_register_driver(struct tifm_driver *drv)
+{
+ drv->driver.bus = &tifm_bus_type;
+ drv->driver.probe = tifm_device_probe;
+ drv->driver.remove = tifm_device_remove;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(tifm_register_driver);
+
+void tifm_unregister_driver(struct tifm_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(tifm_unregister_driver);
+
+static int __init tifm_init(void)
+{
+ int rc = bus_register(&tifm_bus_type);
+
+ if (!rc) {
+ rc = class_register(&tifm_adapter_class);
+ if (rc)
+ bus_unregister(&tifm_bus_type);
+ }
+
+ return rc;
+}
+
+static void __exit tifm_exit(void)
+{
+ class_unregister(&tifm_adapter_class);
+ bus_unregister(&tifm_bus_type);
+}
+
+subsys_initcall(tifm_init);
+module_exit(tifm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia core driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index f540bd8..ea41852 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -109,4 +109,20 @@
If unsure, say N.
+config MMC_TIFM_SD
+ tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
+ depends on MMC && EXPERIMENTAL
+ select TIFM_CORE
+ help
+ Say Y here if you want to be able to access MMC/SD cards with
+ the Texas Instruments(R) Flash Media card reader, found in many
+ laptops.
+ This option 'selects' (turns on, enables) 'TIFM_CORE', but you
+ probably also need appropriate card reader host adapter, such as
+ 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
+ (TIFM_7XX1)'.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tifm_sd.
+
endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index b1f6e03..acfd4de 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -23,6 +23,7 @@
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o
+obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
mmc_core-y := mmc.o mmc_sysfs.o
mmc_core-$(CONFIG_BLOCK) += mmc_queue.o
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 5b9caa7..ee8863c 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1166,9 +1166,9 @@
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
if (delay)
- schedule_delayed_work(&host->detect, delay);
+ mmc_schedule_delayed_work(&host->detect, delay);
else
- schedule_work(&host->detect);
+ mmc_schedule_work(&host->detect);
}
EXPORT_SYMBOL(mmc_detect_change);
@@ -1311,7 +1311,7 @@
*/
void mmc_free_host(struct mmc_host *host)
{
- flush_scheduled_work();
+ mmc_flush_scheduled_work();
mmc_free_host_sysfs(host);
}
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
index 97bae00..cd5e0ab 100644
--- a/drivers/mmc/mmc.h
+++ b/drivers/mmc/mmc.h
@@ -18,4 +18,8 @@
int mmc_add_host_sysfs(struct mmc_host *host);
void mmc_remove_host_sysfs(struct mmc_host *host);
void mmc_free_host_sysfs(struct mmc_host *host);
+
+int mmc_schedule_work(struct work_struct *work);
+int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay);
+void mmc_flush_scheduled_work(void);
#endif
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index db0e8ad..c1293f1 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -158,13 +158,13 @@
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
+ struct mmc_blk_request brq;
int ret;
if (mmc_card_claim_host(card))
goto cmd_err;
do {
- struct mmc_blk_request brq;
struct mmc_command cmd;
u32 readcmd, writecmd;
@@ -278,17 +278,27 @@
cmd_err:
mmc_card_release_host(card);
+ ret = 1;
+
/*
- * This is a little draconian, but until we get proper
- * error handling sorted out here, its the best we can
- * do - especially as some hosts have no idea how much
- * data was transferred before the error occurred.
+ * For writes and where the host claims to support proper
+ * error reporting, we first ok the successful blocks.
+ *
+ * For reads we just fail the entire chunk as that should
+ * be safe in all cases.
*/
+ if (rq_data_dir(req) != READ &&
+ (card->host->caps & MMC_CAP_MULTIWRITE)) {
+ spin_lock_irq(&md->lock);
+ ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+ spin_unlock_irq(&md->lock);
+ }
+
spin_lock_irq(&md->lock);
- do {
+ while (ret) {
ret = end_that_request_chunk(req, 0,
req->current_nr_sectors << 9);
- } while (ret);
+ }
add_disk_randomness(req->rq_disk);
blkdev_dequeue_request(req);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index a2a35fd..10cc973 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/idr.h>
+#include <linux/workqueue.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -317,10 +318,41 @@
class_device_put(&host->class_dev);
}
+static struct workqueue_struct *workqueue;
+
+/*
+ * Internal function. Schedule work in the MMC work queue.
+ */
+int mmc_schedule_work(struct work_struct *work)
+{
+ return queue_work(workqueue, work);
+}
+
+/*
+ * Internal function. Schedule delayed work in the MMC work queue.
+ */
+int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay)
+{
+ return queue_delayed_work(workqueue, work, delay);
+}
+
+/*
+ * Internal function. Flush all scheduled work from the MMC work queue.
+ */
+void mmc_flush_scheduled_work(void)
+{
+ flush_workqueue(workqueue);
+}
static int __init mmc_init(void)
{
- int ret = bus_register(&mmc_bus_type);
+ int ret;
+
+ workqueue = create_singlethread_workqueue("kmmcd");
+ if (!workqueue)
+ return -ENOMEM;
+
+ ret = bus_register(&mmc_bus_type);
if (ret == 0) {
ret = class_register(&mmc_host_class);
if (ret)
@@ -333,6 +365,7 @@
{
class_unregister(&mmc_host_class);
bus_unregister(&mmc_bus_type);
+ destroy_workqueue(workqueue);
}
module_init(mmc_init);
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 4dab5ec..20711ac 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -35,6 +35,8 @@
#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
+/* Controller doesn't like some resets when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -51,7 +53,8 @@
.device = PCI_DEVICE_ID_RICOH_R5C822,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = SDHCI_QUIRK_FORCE_DMA,
+ .driver_data = SDHCI_QUIRK_FORCE_DMA |
+ SDHCI_QUIRK_NO_CARD_NO_RESET,
},
{
@@ -125,6 +128,12 @@
{
unsigned long timeout;
+ if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+ if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+ SDHCI_CARD_PRESENT))
+ return;
+ }
+
writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
if (mask & SDHCI_RESET_ALL)
@@ -717,6 +726,7 @@
} else
sdhci_send_command(host, mrq->cmd);
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -753,6 +763,7 @@
ctrl &= ~SDHCI_CTRL_4BITBUS;
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -860,6 +871,7 @@
sdhci_deactivate_led(host);
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq);
@@ -893,6 +905,7 @@
}
}
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -1030,6 +1043,7 @@
result = IRQ_HANDLED;
+ mmiowb();
out:
spin_unlock(&host->lock);
@@ -1095,6 +1109,7 @@
if (chip->hosts[i]->flags & SDHCI_USE_DMA)
pci_set_master(pdev);
sdhci_init(chip->hosts[i]);
+ mmiowb();
ret = mmc_resume_host(chip->hosts[i]->mmc);
if (ret)
return ret;
@@ -1168,6 +1183,9 @@
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->chip = chip;
+ chip->hosts[slot] = host;
+
host->bar = first_bar + slot;
host->addr = pci_resource_start(pdev, host->bar);
@@ -1324,8 +1342,7 @@
sdhci_dumpregs(host);
#endif
- host->chip = chip;
- chip->hosts[slot] = host;
+ mmiowb();
mmc_add_host(mmc);
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
new file mode 100644
index 0000000..6d23dc0
--- /dev/null
+++ b/drivers/mmc/tifm_sd.c
@@ -0,0 +1,933 @@
+/*
+ * tifm_sd.c - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
+ *
+ * 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.
+ *
+ */
+
+
+#include <linux/tifm.h>
+#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
+#include <linux/highmem.h>
+
+#define DRIVER_NAME "tifm_sd"
+#define DRIVER_VERSION "0.6"
+
+static int no_dma = 0;
+static int fixed_timeout = 0;
+module_param(no_dma, bool, 0644);
+module_param(fixed_timeout, bool, 0644);
+
+/* Constants here are mostly from OMAP5912 datasheet */
+#define TIFM_MMCSD_RESET 0x0002
+#define TIFM_MMCSD_CLKMASK 0x03ff
+#define TIFM_MMCSD_POWER 0x0800
+#define TIFM_MMCSD_4BBUS 0x8000
+#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */
+#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */
+#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */
+#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */
+#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
+#define TIFM_MMCSD_READ 0x8000
+
+#define TIFM_MMCSD_DATAMASK 0x001d /* set bits: EOFB, BRS, CB, EOC */
+#define TIFM_MMCSD_ERRMASK 0x41e0 /* set bits: CERR, CCRC, CTO, DCRC, DTO */
+#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
+#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
+#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
+#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */
+#define TIFM_MMCSD_DTO 0x0020 /* data time-out */
+#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */
+#define TIFM_MMCSD_CTO 0x0080 /* command time-out */
+#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */
+#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */
+#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */
+#define TIFM_MMCSD_CERR 0x4000 /* card status error */
+
+#define TIFM_MMCSD_FIFO_SIZE 0x0020
+
+#define TIFM_MMCSD_RSP_R0 0x0000
+#define TIFM_MMCSD_RSP_R1 0x0100
+#define TIFM_MMCSD_RSP_R2 0x0200
+#define TIFM_MMCSD_RSP_R3 0x0300
+#define TIFM_MMCSD_RSP_R4 0x0400
+#define TIFM_MMCSD_RSP_R5 0x0500
+#define TIFM_MMCSD_RSP_R6 0x0600
+
+#define TIFM_MMCSD_RSP_BUSY 0x0800
+
+#define TIFM_MMCSD_CMD_BC 0x0000
+#define TIFM_MMCSD_CMD_BCR 0x1000
+#define TIFM_MMCSD_CMD_AC 0x2000
+#define TIFM_MMCSD_CMD_ADTC 0x3000
+
+typedef enum {
+ IDLE = 0,
+ CMD, /* main command ended */
+ BRS, /* block transfer finished */
+ SCMD, /* stop command ended */
+ CARD, /* card left busy state */
+ FIFO, /* FIFO operation completed (uncertain) */
+ READY
+} card_state_t;
+
+enum {
+ FIFO_RDY = 0x0001, /* hardware dependent value */
+ HOST_REG = 0x0002,
+ EJECT = 0x0004,
+ EJECT_DONE = 0x0008,
+ CARD_BUSY = 0x0010,
+ OPENDRAIN = 0x0040, /* hardware dependent value */
+ CARD_EVENT = 0x0100, /* hardware dependent value */
+ CARD_RO = 0x0200, /* hardware dependent value */
+ FIFO_EVENT = 0x10000 }; /* hardware dependent value */
+
+struct tifm_sd {
+ struct tifm_dev *dev;
+
+ unsigned int flags;
+ card_state_t state;
+ unsigned int clk_freq;
+ unsigned int clk_div;
+ unsigned long timeout_jiffies; // software timeout - 2 sec
+
+ struct mmc_request *req;
+ struct work_struct cmd_handler;
+ struct work_struct abort_handler;
+ wait_queue_head_t can_eject;
+
+ size_t written_blocks;
+ char *buffer;
+ size_t buffer_size;
+ size_t buffer_pos;
+
+};
+
+static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
+ unsigned int host_status)
+{
+ struct mmc_command *cmd = host->req->cmd;
+ unsigned int t_val = 0, cnt = 0;
+
+ if (host_status & TIFM_MMCSD_BRS) {
+ /* in non-dma rx mode BRS fires when fifo is still not empty */
+ if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
+ while (host->buffer_size > host->buffer_pos) {
+ t_val = readl(sock->addr + SOCK_MMCSD_DATA);
+ host->buffer[host->buffer_pos++] = t_val & 0xff;
+ host->buffer[host->buffer_pos++] =
+ (t_val >> 8) & 0xff;
+ }
+ }
+ return 1;
+ } else if (host->buffer) {
+ if ((cmd->data->flags & MMC_DATA_READ) &&
+ (host_status & TIFM_MMCSD_AF)) {
+ for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
+ t_val = readl(sock->addr + SOCK_MMCSD_DATA);
+ if (host->buffer_size > host->buffer_pos) {
+ host->buffer[host->buffer_pos++] =
+ t_val & 0xff;
+ host->buffer[host->buffer_pos++] =
+ (t_val >> 8) & 0xff;
+ }
+ }
+ } else if ((cmd->data->flags & MMC_DATA_WRITE)
+ && (host_status & TIFM_MMCSD_AE)) {
+ for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
+ if (host->buffer_size > host->buffer_pos) {
+ t_val = host->buffer[host->buffer_pos++] & 0x00ff;
+ t_val |= ((host->buffer[host->buffer_pos++]) << 8)
+ & 0xff00;
+ writel(t_val,
+ sock->addr + SOCK_MMCSD_DATA);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
+{
+ unsigned int rc = 0;
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ rc |= TIFM_MMCSD_RSP_R0;
+ break;
+ case MMC_RSP_R1B:
+ rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
+ case MMC_RSP_R1:
+ rc |= TIFM_MMCSD_RSP_R1;
+ break;
+ case MMC_RSP_R2:
+ rc |= TIFM_MMCSD_RSP_R2;
+ break;
+ case MMC_RSP_R3:
+ rc |= TIFM_MMCSD_RSP_R3;
+ break;
+ case MMC_RSP_R6:
+ rc |= TIFM_MMCSD_RSP_R6;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (mmc_cmd_type(cmd)) {
+ case MMC_CMD_BC:
+ rc |= TIFM_MMCSD_CMD_BC;
+ break;
+ case MMC_CMD_BCR:
+ rc |= TIFM_MMCSD_CMD_BCR;
+ break;
+ case MMC_CMD_AC:
+ rc |= TIFM_MMCSD_CMD_AC;
+ break;
+ case MMC_CMD_ADTC:
+ rc |= TIFM_MMCSD_CMD_ADTC;
+ break;
+ default:
+ BUG();
+ }
+ return rc;
+}
+
+static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned int cmd_mask = tifm_sd_op_flags(cmd) |
+ (host->flags & OPENDRAIN);
+
+ if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
+ cmd_mask |= TIFM_MMCSD_READ;
+
+ dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
+ cmd->opcode, cmd->arg, cmd_mask);
+
+ writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
+ writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
+ writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
+}
+
+static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
+{
+ cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
+ cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
+ cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
+ cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
+}
+
+static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
+ unsigned int host_status)
+{
+ struct mmc_command *cmd = host->req->cmd;
+
+change_state:
+ switch (host->state) {
+ case IDLE:
+ return;
+ case CMD:
+ if (host_status & TIFM_MMCSD_EOC) {
+ tifm_sd_fetch_resp(cmd, sock);
+ if (cmd->data) {
+ host->state = BRS;
+ } else
+ host->state = READY;
+ goto change_state;
+ }
+ break;
+ case BRS:
+ if (tifm_sd_transfer_data(sock, host, host_status)) {
+ if (!host->req->stop) {
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ host->state = CARD;
+ } else {
+ host->state =
+ host->buffer ? READY : FIFO;
+ }
+ goto change_state;
+ }
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ }
+ break;
+ case SCMD:
+ if (host_status & TIFM_MMCSD_EOC) {
+ tifm_sd_fetch_resp(host->req->stop, sock);
+ if (cmd->error) {
+ host->state = READY;
+ } else if (cmd->data->flags & MMC_DATA_WRITE) {
+ host->state = CARD;
+ } else {
+ host->state = host->buffer ? READY : FIFO;
+ }
+ goto change_state;
+ }
+ break;
+ case CARD:
+ if (!(host->flags & CARD_BUSY)
+ && (host->written_blocks == cmd->data->blocks)) {
+ host->state = host->buffer ? READY : FIFO;
+ goto change_state;
+ }
+ break;
+ case FIFO:
+ if (host->flags & FIFO_RDY) {
+ host->state = READY;
+ host->flags &= ~FIFO_RDY;
+ goto change_state;
+ }
+ break;
+ case READY:
+ queue_work(sock->wq, &host->cmd_handler);
+ return;
+ }
+
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+}
+
+/* Called from interrupt handler */
+static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
+{
+ struct tifm_sd *host;
+ unsigned int host_status = 0, fifo_status = 0;
+ int error_code = 0;
+
+ spin_lock(&sock->lock);
+ host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+ cancel_delayed_work(&host->abort_handler);
+
+ if (sock_irq_status & FIFO_EVENT) {
+ fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
+ writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+
+ host->flags |= fifo_status & FIFO_RDY;
+ }
+
+ if (sock_irq_status & CARD_EVENT) {
+ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+
+ if (!(host->flags & HOST_REG))
+ queue_work(sock->wq, &host->cmd_handler);
+ if (!host->req)
+ goto done;
+
+ if (host_status & TIFM_MMCSD_ERRMASK) {
+ if (host_status & TIFM_MMCSD_CERR)
+ error_code = MMC_ERR_FAILED;
+ else if (host_status &
+ (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
+ error_code = MMC_ERR_TIMEOUT;
+ else if (host_status &
+ (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
+ error_code = MMC_ERR_BADCRC;
+
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
+
+ if (host->req->stop) {
+ if (host->state == SCMD) {
+ host->req->stop->error = error_code;
+ } else if(host->state == BRS) {
+ host->req->cmd->error = error_code;
+ tifm_sd_exec(host, host->req->stop);
+ queue_delayed_work(sock->wq,
+ &host->abort_handler,
+ host->timeout_jiffies);
+ host->state = SCMD;
+ goto done;
+ } else {
+ host->req->cmd->error = error_code;
+ }
+ } else {
+ host->req->cmd->error = error_code;
+ }
+ host->state = READY;
+ }
+
+ if (host_status & TIFM_MMCSD_CB)
+ host->flags |= CARD_BUSY;
+ if ((host_status & TIFM_MMCSD_EOFB) &&
+ (host->flags & CARD_BUSY)) {
+ host->written_blocks++;
+ host->flags &= ~CARD_BUSY;
+ }
+ }
+
+ if (host->req)
+ tifm_sd_process_cmd(sock, host, host_status);
+done:
+ dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
+ host_status, fifo_status);
+ spin_unlock(&sock->lock);
+ return sock_irq_status;
+}
+
+static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
+{
+ struct tifm_dev *sock = card->dev;
+ unsigned int dest_cnt;
+
+ /* DMA style IO */
+
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(long_log2(cmd->data->blksz) - 2,
+ sock->addr + SOCK_FIFO_PAGE_SIZE);
+ writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
+ writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+ dest_cnt = (cmd->data->blocks) << 8;
+
+ writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS);
+
+ writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
+
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+ writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
+ sock->addr + SOCK_DMA_CONTROL);
+ } else {
+ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+ writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
+ }
+}
+
+static void tifm_sd_set_data_timeout(struct tifm_sd *host,
+ struct mmc_data *data)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned int data_timeout = data->timeout_clks;
+
+ if (fixed_timeout)
+ return;
+
+ data_timeout += data->timeout_ns /
+ ((1000000000 / host->clk_freq) * host->clk_div);
+ data_timeout *= 10; // call it fudge factor for now
+
+ if (data_timeout < 0xffff) {
+ writel((~TIFM_MMCSD_DPE) &
+ readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ } else {
+ writel(TIFM_MMCSD_DPE |
+ readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+ data_timeout = (data_timeout >> 10) + 1;
+ if(data_timeout > 0xffff)
+ data_timeout = 0; /* set to unlimited */
+ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ }
+}
+
+static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+ int sg_count = 0;
+ struct mmc_data *r_data = mrq->cmd->data;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ if (host->flags & EJECT) {
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (host->req) {
+ printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (r_data) {
+ tifm_sd_set_data_timeout(host, r_data);
+
+ sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len,
+ mrq->cmd->flags & MMC_DATA_WRITE
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ if (sg_count != 1) {
+ printk(KERN_ERR DRIVER_NAME
+ ": scatterlist map failed\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ host->written_blocks = 0;
+ host->flags &= ~CARD_BUSY;
+ tifm_sd_prepare_data(host, mrq->cmd);
+ }
+
+ host->req = mrq;
+ host->state = CMD;
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+ writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ tifm_sd_exec(host, mrq->cmd);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+
+err_out:
+ if (sg_count > 0)
+ tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+ (r_data->flags & MMC_DATA_WRITE)
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+ mrq->cmd->error = MMC_ERR_TIMEOUT;
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd(void *data)
+{
+ struct tifm_sd *host = data;
+ struct tifm_dev *sock = host->dev;
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct mmc_request *mrq;
+ struct mmc_data *r_data = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ mrq = host->req;
+ host->req = 0;
+ host->state = IDLE;
+
+ if (!mrq) {
+ printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+ }
+
+ r_data = mrq->cmd->data;
+ if (r_data) {
+ if (r_data->flags & MMC_DATA_WRITE) {
+ r_data->bytes_xfered = host->written_blocks *
+ r_data->blksz;
+ } else {
+ r_data->bytes_xfered = r_data->blocks -
+ readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+ r_data->bytes_xfered *= r_data->blksz;
+ r_data->bytes_xfered += r_data->blksz -
+ readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+ }
+ tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+ (r_data->flags & MMC_DATA_WRITE)
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ }
+
+ writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+ struct mmc_data *r_data = mrq->cmd->data;
+ char *t_buffer = 0;
+
+ if (r_data) {
+ t_buffer = kmap(r_data->sg->page);
+ if (!t_buffer) {
+ printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
+ goto err_out;
+ }
+ }
+
+ spin_lock_irqsave(&sock->lock, flags);
+ if (host->flags & EJECT) {
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (host->req) {
+ printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (r_data) {
+ tifm_sd_set_data_timeout(host, r_data);
+
+ host->buffer = t_buffer + r_data->sg->offset;
+ host->buffer_size = mrq->cmd->data->blocks *
+ mrq->cmd->data->blksz;
+
+ writel(TIFM_MMCSD_BUFINT |
+ readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
+ (TIFM_MMCSD_FIFO_SIZE - 1),
+ sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+ host->written_blocks = 0;
+ host->flags &= ~CARD_BUSY;
+ host->buffer_pos = 0;
+ writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
+ }
+
+ host->req = mrq;
+ host->state = CMD;
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+ writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ tifm_sd_exec(host, mrq->cmd);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+
+err_out:
+ if (t_buffer)
+ kunmap(r_data->sg->page);
+
+ mrq->cmd->error = MMC_ERR_TIMEOUT;
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd_nodma(void *data)
+{
+ struct tifm_sd *host = (struct tifm_sd*)data;
+ struct tifm_dev *sock = host->dev;
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct mmc_request *mrq;
+ struct mmc_data *r_data = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ mrq = host->req;
+ host->req = 0;
+ host->state = IDLE;
+
+ if (!mrq) {
+ printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+ }
+
+ r_data = mrq->cmd->data;
+ if (r_data) {
+ writel((~TIFM_MMCSD_BUFINT) &
+ readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+ if (r_data->flags & MMC_DATA_WRITE) {
+ r_data->bytes_xfered = host->written_blocks *
+ r_data->blksz;
+ } else {
+ r_data->bytes_xfered = r_data->blocks -
+ readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+ r_data->bytes_xfered *= r_data->blksz;
+ r_data->bytes_xfered += r_data->blksz -
+ readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+ }
+ host->buffer = 0;
+ host->buffer_pos = 0;
+ host->buffer_size = 0;
+ }
+
+ writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+
+ if (r_data)
+ kunmap(r_data->sg->page);
+
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_abort(void *data)
+{
+ printk(KERN_ERR DRIVER_NAME
+ ": card failed to respond for a long period of time");
+ tifm_eject(((struct tifm_sd*)data)->dev);
+}
+
+static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned int clk_div1, clk_div2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width,
+ ios->power_mode);
+ if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
+ } else {
+ writel((~TIFM_MMCSD_4BBUS) &
+ readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
+ }
+
+ if (ios->clock) {
+ clk_div1 = 20000000 / ios->clock;
+ if (!clk_div1)
+ clk_div1 = 1;
+
+ clk_div2 = 24000000 / ios->clock;
+ if (!clk_div2)
+ clk_div2 = 1;
+
+ if ((20000000 / clk_div1) > ios->clock)
+ clk_div1++;
+ if ((24000000 / clk_div2) > ios->clock)
+ clk_div2++;
+ if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
+ host->clk_freq = 20000000;
+ host->clk_div = clk_div1;
+ writel((~TIFM_CTRL_FAST_CLK) &
+ readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ } else {
+ host->clk_freq = 24000000;
+ host->clk_div = clk_div2;
+ writel(TIFM_CTRL_FAST_CLK |
+ readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ }
+ } else {
+ host->clk_div = 0;
+ }
+ host->clk_div &= TIFM_MMCSD_CLKMASK;
+ writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
+ readl(sock->addr + SOCK_MMCSD_CONFIG)),
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ host->flags |= OPENDRAIN;
+ else
+ host->flags &= ~OPENDRAIN;
+
+ /* chip_select : maybe later */
+ //vdd
+ //power is set before probe / after remove
+ //I believe, power_off when already marked for eject is sufficient to
+ // allow removal.
+ if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
+ host->flags |= EJECT_DONE;
+ wake_up_all(&host->can_eject);
+ }
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static int tifm_sd_ro(struct mmc_host *mmc)
+{
+ int rc;
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE));
+ rc = (host->flags & CARD_RO) ? 1 : 0;
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return rc;
+}
+
+static struct mmc_host_ops tifm_sd_ops = {
+ .request = tifm_sd_request,
+ .set_ios = tifm_sd_ios,
+ .get_ro = tifm_sd_ro
+};
+
+static void tifm_sd_register_host(void *data)
+{
+ struct tifm_sd *host = (struct tifm_sd*)data;
+ struct tifm_dev *sock = host->dev;
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ host->flags |= HOST_REG;
+ PREPARE_WORK(&host->cmd_handler,
+ no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+ data);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ dev_dbg(&sock->dev, "adding host\n");
+ mmc_add_host(mmc);
+}
+
+static int tifm_sd_probe(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc;
+ struct tifm_sd *host;
+ int rc = -EIO;
+
+ if (!(TIFM_SOCK_STATE_OCCUPIED &
+ readl(sock->addr + SOCK_PRESENT_STATE))) {
+ printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
+ return rc;
+ }
+
+ mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ host = mmc_priv(mmc);
+ host->dev = sock;
+ host->clk_div = 61;
+ init_waitqueue_head(&host->can_eject);
+ INIT_WORK(&host->cmd_handler, tifm_sd_register_host, host);
+ INIT_WORK(&host->abort_handler, tifm_sd_abort, host);
+
+ tifm_set_drvdata(sock, mmc);
+ sock->signal_irq = tifm_sd_signal_irq;
+
+ host->clk_freq = 20000000;
+ host->timeout_jiffies = msecs_to_jiffies(1000);
+
+ tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
+ mmc->ops = &tifm_sd_ops;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->f_min = 20000000 / 60;
+ mmc->f_max = 24000000;
+ mmc->max_hw_segs = 1;
+ mmc->max_phys_segs = 1;
+ mmc->max_sectors = 127;
+ mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
+
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ for (rc = 0; rc < 50; rc++) {
+ /* Wait for reset ack */
+ if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+ rc = 0;
+ break;
+ }
+ msleep(10);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": card not ready - probe failed\n");
+ mmc_free_host(mmc);
+ return -ENODEV;
+ }
+
+ writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+ writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+ writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
+ writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+
+ return 0;
+}
+
+static int tifm_sd_host_is_down(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ rc = (host->flags & EJECT_DONE);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return rc;
+}
+
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ host->flags |= EJECT;
+ if (host->req)
+ queue_work(sock->wq, &host->cmd_handler);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
+ host->timeout_jiffies);
+
+ if (host->flags & HOST_REG)
+ mmc_remove_host(mmc);
+
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+ tifm_set_drvdata(sock, 0);
+ mmc_free_host(mmc);
+}
+
+static tifm_media_id tifm_sd_id_tbl[] = {
+ FM_SD, 0
+};
+
+static struct tifm_driver tifm_sd_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE
+ },
+ .id_table = tifm_sd_id_tbl,
+ .probe = tifm_sd_probe,
+ .remove = tifm_sd_remove
+};
+
+static int __init tifm_sd_init(void)
+{
+ return tifm_register_driver(&tifm_sd_driver);
+}
+
+static void __exit tifm_sd_exit(void)
+{
+ tifm_unregister_driver(&tifm_sd_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia SD driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_sd_init);
+module_exit(tifm_sd_exit);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index c27e782..3029412 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -52,3 +52,11 @@
When in doubt, say N.
+config HT_IRQ
+ bool "Interrupts on hypertransport devices"
+ default y
+ depends on X86_LOCAL_APIC && X86_IO_APIC
+ help
+ This allows native hypertransport devices to use interrupts.
+
+ If unsure say Y.
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index f2d152b..e3beb78 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -14,6 +14,12 @@
# Build the PCI Hotplug drivers if we were asked to
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
+# Build the PCI MSI interrupt support
+obj-$(CONFIG_PCI_MSI) += msi.o
+
+# Build the Hypertransport interrupt support
+obj-$(CONFIG_HT_IRQ) += htirq.o
+
#
# Some architectures use the generic PCI setup functions
#
@@ -27,11 +33,6 @@
obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
-obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
-
#
# ACPI Related PCI FW Functions
#
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
new file mode 100644
index 0000000..0e27f24
--- /dev/null
+++ b/drivers/pci/htirq.c
@@ -0,0 +1,190 @@
+/*
+ * File: htirq.c
+ * Purpose: Hypertransport Interrupt Capability
+ *
+ * Copyright (C) 2006 Linux Networx
+ * Copyright (C) Eric Biederman <ebiederman@lnxi.com>
+ */
+
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/htirq.h>
+
+/* Global ht irq lock.
+ *
+ * This is needed to serialize access to the data port in hypertransport
+ * irq capability.
+ *
+ * With multiple simultaneous hypertransport irq devices it might pay
+ * to make this more fine grained. But start with simple, stupid, and correct.
+ */
+static DEFINE_SPINLOCK(ht_irq_lock);
+
+struct ht_irq_cfg {
+ struct pci_dev *dev;
+ unsigned pos;
+ unsigned idx;
+};
+
+void write_ht_irq_low(unsigned int irq, u32 data)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+void write_ht_irq_high(unsigned int irq, u32 data)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+u32 read_ht_irq_low(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ u32 data;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+ return data;
+}
+
+u32 read_ht_irq_high(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ u32 data;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+ return data;
+}
+
+void mask_ht_irq(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg;
+ unsigned long flags;
+ u32 data;
+
+ cfg = get_irq_data(irq);
+
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ data |= 1;
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+void unmask_ht_irq(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg;
+ unsigned long flags;
+ u32 data;
+
+ cfg = get_irq_data(irq);
+
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ data &= ~1;
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+/**
+ * ht_create_irq - create an irq and attach it to a device.
+ * @dev: The hypertransport device to find the irq capability on.
+ * @idx: Which of the possible irqs to attach to.
+ *
+ * ht_create_irq is needs to be called for all hypertransport devices
+ * that generate irqs.
+ *
+ * The irq number of the new irq or a negative error value is returned.
+ */
+int ht_create_irq(struct pci_dev *dev, int idx)
+{
+ struct ht_irq_cfg *cfg;
+ unsigned long flags;
+ u32 data;
+ int max_irq;
+ int pos;
+ int irq;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_HT);
+ while (pos) {
+ u8 subtype;
+ pci_read_config_byte(dev, pos + 3, &subtype);
+ if (subtype == HT_CAPTYPE_IRQ)
+ break;
+ pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT);
+ }
+ if (!pos)
+ return -EINVAL;
+
+ /* Verify the idx I want to use is in range */
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(dev, pos + 2, 1);
+ pci_read_config_dword(dev, pos + 4, &data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+
+ max_irq = (data >> 16) & 0xff;
+ if ( idx > max_irq)
+ return -EINVAL;
+
+ cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ cfg->dev = dev;
+ cfg->pos = pos;
+ cfg->idx = 0x10 + (idx * 2);
+
+ irq = create_irq();
+ if (irq < 0) {
+ kfree(cfg);
+ return -EBUSY;
+ }
+ set_irq_data(irq, cfg);
+
+ if (arch_setup_ht_irq(irq, dev) < 0) {
+ ht_destroy_irq(irq);
+ return -EBUSY;
+ }
+
+ return irq;
+}
+
+/**
+ * ht_destroy_irq - destroy an irq created with ht_create_irq
+ *
+ * This reverses ht_create_irq removing the specified irq from
+ * existence. The irq should be free before this happens.
+ */
+void ht_destroy_irq(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg;
+
+ cfg = get_irq_data(irq);
+ set_irq_chip(irq, NULL);
+ set_irq_data(irq, NULL);
+ destroy_irq(irq);
+
+ kfree(cfg);
+}
+
+EXPORT_SYMBOL(ht_create_irq);
+EXPORT_SYMBOL(ht_destroy_irq);
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
deleted file mode 100644
index 5ed798b3..0000000
--- a/drivers/pci/msi-apic.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * MSI hooks for standard x86 apic
- */
-
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <asm/smp.h>
-
-#include "msi.h"
-
-/*
- * Shifts for APIC-based data
- */
-
-#define MSI_DATA_VECTOR_SHIFT 0
-#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
-
-#define MSI_DATA_DELIVERY_SHIFT 8
-#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
-#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
-
-#define MSI_DATA_LEVEL_SHIFT 14
-#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
-#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
-
-#define MSI_DATA_TRIGGER_SHIFT 15
-#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
-#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
-
-/*
- * Shift/mask fields for APIC-based bus address
- */
-
-#define MSI_ADDR_HEADER 0xfee00000
-
-#define MSI_ADDR_DESTID_MASK 0xfff0000f
-#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
-
-#define MSI_ADDR_DESTMODE_SHIFT 2
-#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
-#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
-
-#define MSI_ADDR_REDIRECTION_SHIFT 3
-#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
-#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
-
-
-static void
-msi_target_apic(unsigned int vector,
- unsigned int dest_cpu,
- u32 *address_hi, /* in/out */
- u32 *address_lo) /* in/out */
-{
- u32 addr = *address_lo;
-
- addr &= MSI_ADDR_DESTID_MASK;
- addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
-
- *address_lo = addr;
-}
-
-static int
-msi_setup_apic(struct pci_dev *pdev, /* unused in generic */
- unsigned int vector,
- u32 *address_hi,
- u32 *address_lo,
- u32 *data)
-{
- unsigned long dest_phys_id;
-
- dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
-
- *address_hi = 0;
- *address_lo = MSI_ADDR_HEADER |
- MSI_ADDR_DESTMODE_PHYS |
- MSI_ADDR_REDIRECTION_CPU |
- MSI_ADDR_DESTID_CPU(dest_phys_id);
-
- *data = MSI_DATA_TRIGGER_EDGE |
- MSI_DATA_LEVEL_ASSERT |
- MSI_DATA_DELIVERY_FIXED |
- MSI_DATA_VECTOR(vector);
-
- return 0;
-}
-
-static void
-msi_teardown_apic(unsigned int vector)
-{
- return; /* no-op */
-}
-
-/*
- * Generic ops used on most IA archs/platforms. Set with msi_register()
- */
-
-struct msi_ops msi_apic_ops = {
- .setup = msi_setup_apic,
- .teardown = msi_teardown_apic,
- .target = msi_target_apic,
-};
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 27a0574..f9fdc54 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -6,6 +6,7 @@
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
+#include <linux/err.h>
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -14,6 +15,7 @@
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
+#include <linux/msi.h>
#include <asm/errno.h>
#include <asm/io.h>
@@ -27,23 +29,6 @@
static kmem_cache_t* msi_cachep;
static int pci_msi_enable = 1;
-static int last_alloc_vector;
-static int nr_released_vectors;
-static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
-static int nr_msix_devices;
-
-#ifndef CONFIG_X86_IO_APIC
-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-#endif
-
-static struct msi_ops *msi_ops;
-
-int
-msi_register(struct msi_ops *ops)
-{
- msi_ops = ops;
- return 0;
-}
static int msi_cache_init(void)
{
@@ -55,26 +40,25 @@
return 0;
}
-static void msi_set_mask_bit(unsigned int vector, int flag)
+static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
- entry = (struct msi_desc *)msi_desc[vector];
- if (!entry || !entry->dev || !entry->mask_base)
- return;
+ entry = msi_desc[irq];
+ BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
- {
- int pos;
- u32 mask_bits;
+ if (entry->msi_attrib.maskbit) {
+ int pos;
+ u32 mask_bits;
- pos = (long)entry->mask_base;
- pci_read_config_dword(entry->dev, pos, &mask_bits);
- mask_bits &= ~(1);
- mask_bits |= flag;
- pci_write_config_dword(entry->dev, pos, mask_bits);
+ pos = (long)entry->mask_base;
+ pci_read_config_dword(entry->dev, pos, &mask_bits);
+ mask_bits &= ~(1);
+ mask_bits |= flag;
+ pci_write_config_dword(entry->dev, pos, mask_bits);
+ }
break;
- }
case PCI_CAP_ID_MSIX:
{
int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -83,261 +67,101 @@
break;
}
default:
+ BUG();
break;
}
}
-#ifdef CONFIG_SMP
-static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
+void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry;
- u32 address_hi, address_lo;
- unsigned int irq = vector;
- unsigned int dest_cpu = first_cpu(cpu_mask);
-
- entry = (struct msi_desc *)msi_desc[vector];
- if (!entry || !entry->dev)
- return;
-
- switch (entry->msi_attrib.type) {
+ struct msi_desc *entry = get_irq_data(irq);
+ switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
- int pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI);
+ struct pci_dev *dev = entry->dev;
+ int pos = entry->msi_attrib.pos;
+ u16 data;
- if (!pos)
- return;
-
- pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
- &address_hi);
- pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
- &address_lo);
-
- msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
-
- pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
- address_hi);
- pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
- address_lo);
- set_native_irq_info(irq, cpu_mask);
+ pci_read_config_dword(dev, msi_lower_address_reg(pos),
+ &msg->address_lo);
+ if (entry->msi_attrib.is_64) {
+ pci_read_config_dword(dev, msi_upper_address_reg(pos),
+ &msg->address_hi);
+ pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ } else {
+ msg->address_hi = 0;
+ pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ }
+ msg->data = data;
break;
}
case PCI_CAP_ID_MSIX:
{
- int offset_hi =
- entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
- int offset_lo =
- entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+ void __iomem *base;
+ base = entry->mask_base +
+ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
- address_hi = readl(entry->mask_base + offset_hi);
- address_lo = readl(entry->mask_base + offset_lo);
+ msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+ msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+ msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
+ break;
+ }
+ default:
+ BUG();
+ }
+}
- msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+void write_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+ struct msi_desc *entry = get_irq_data(irq);
+ switch (entry->msi_attrib.type) {
+ case PCI_CAP_ID_MSI:
+ {
+ struct pci_dev *dev = entry->dev;
+ int pos = entry->msi_attrib.pos;
- writel(address_hi, entry->mask_base + offset_hi);
- writel(address_lo, entry->mask_base + offset_lo);
- set_native_irq_info(irq, cpu_mask);
+ pci_write_config_dword(dev, msi_lower_address_reg(pos),
+ msg->address_lo);
+ if (entry->msi_attrib.is_64) {
+ pci_write_config_dword(dev, msi_upper_address_reg(pos),
+ msg->address_hi);
+ pci_write_config_word(dev, msi_data_reg(pos, 1),
+ msg->data);
+ } else {
+ pci_write_config_word(dev, msi_data_reg(pos, 0),
+ msg->data);
+ }
+ break;
+ }
+ case PCI_CAP_ID_MSIX:
+ {
+ void __iomem *base;
+ base = entry->mask_base +
+ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+ writel(msg->address_lo,
+ base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+ writel(msg->address_hi,
+ base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+ writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
break;
}
default:
- break;
+ BUG();
}
}
-#else
-#define set_msi_affinity NULL
-#endif /* CONFIG_SMP */
-static void mask_MSI_irq(unsigned int vector)
+void mask_msi_irq(unsigned int irq)
{
- msi_set_mask_bit(vector, 1);
+ msi_set_mask_bit(irq, 1);
}
-static void unmask_MSI_irq(unsigned int vector)
+void unmask_msi_irq(unsigned int irq)
{
- msi_set_mask_bit(vector, 0);
+ msi_set_mask_bit(irq, 0);
}
-static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
-{
- struct msi_desc *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[vector];
- if (!entry || !entry->dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
- return 0;
- }
- entry->msi_attrib.state = 1; /* Mark it active */
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return 0; /* never anything pending */
-}
-
-static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
-{
- startup_msi_irq_wo_maskbit(vector);
- unmask_MSI_irq(vector);
- return 0; /* never anything pending */
-}
-
-static void shutdown_msi_irq(unsigned int vector)
-{
- struct msi_desc *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[vector];
- if (entry && entry->dev)
- entry->msi_attrib.state = 0; /* Mark it not active */
- spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static void end_msi_irq_wo_maskbit(unsigned int vector)
-{
- move_native_irq(vector);
- ack_APIC_irq();
-}
-
-static void end_msi_irq_w_maskbit(unsigned int vector)
-{
- move_native_irq(vector);
- unmask_MSI_irq(vector);
- ack_APIC_irq();
-}
-
-static void do_nothing(unsigned int vector)
-{
-}
-
-/*
- * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI-X Capability Structure.
- */
-static struct hw_interrupt_type msix_irq_type = {
- .typename = "PCI-MSI-X",
- .startup = startup_msi_irq_w_maskbit,
- .shutdown = shutdown_msi_irq,
- .enable = unmask_MSI_irq,
- .disable = mask_MSI_irq,
- .ack = mask_MSI_irq,
- .end = end_msi_irq_w_maskbit,
- .set_affinity = set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure with
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_w_maskbit_type = {
- .typename = "PCI-MSI",
- .startup = startup_msi_irq_w_maskbit,
- .shutdown = shutdown_msi_irq,
- .enable = unmask_MSI_irq,
- .disable = mask_MSI_irq,
- .ack = mask_MSI_irq,
- .end = end_msi_irq_w_maskbit,
- .set_affinity = set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure without
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
- .typename = "PCI-MSI",
- .startup = startup_msi_irq_wo_maskbit,
- .shutdown = shutdown_msi_irq,
- .enable = do_nothing,
- .disable = do_nothing,
- .ack = do_nothing,
- .end = end_msi_irq_wo_maskbit,
- .set_affinity = set_msi_affinity
-};
-
-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
-static int assign_msi_vector(void)
-{
- static int new_vector_avail = 1;
- int vector;
- unsigned long flags;
-
- /*
- * msi_lock is provided to ensure that successful allocation of MSI
- * vector is assigned unique among drivers.
- */
- spin_lock_irqsave(&msi_lock, flags);
-
- if (!new_vector_avail) {
- int free_vector = 0;
-
- /*
- * vector_irq[] = -1 indicates that this specific vector is:
- * - assigned for MSI (since MSI have no associated IRQ) or
- * - assigned for legacy if less than 16, or
- * - having no corresponding 1:1 vector-to-IOxAPIC IRQ mapping
- * vector_irq[] = 0 indicates that this vector, previously
- * assigned for MSI, is freed by hotplug removed operations.
- * This vector will be reused for any subsequent hotplug added
- * operations.
- * vector_irq[] > 0 indicates that this vector is assigned for
- * IOxAPIC IRQs. This vector and its value provides a 1-to-1
- * vector-to-IOxAPIC IRQ mapping.
- */
- for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
- if (vector_irq[vector] != 0)
- continue;
- free_vector = vector;
- if (!msi_desc[vector])
- break;
- else
- continue;
- }
- if (!free_vector) {
- spin_unlock_irqrestore(&msi_lock, flags);
- return -EBUSY;
- }
- vector_irq[free_vector] = -1;
- nr_released_vectors--;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (msi_desc[free_vector] != NULL) {
- struct pci_dev *dev;
- int tail;
-
- /* free all linked vectors before re-assign */
- do {
- spin_lock_irqsave(&msi_lock, flags);
- dev = msi_desc[free_vector]->dev;
- tail = msi_desc[free_vector]->link.tail;
- spin_unlock_irqrestore(&msi_lock, flags);
- msi_free_vector(dev, tail, 1);
- } while (free_vector != tail);
- }
-
- return free_vector;
- }
- vector = assign_irq_vector(AUTO_ASSIGN);
- last_alloc_vector = vector;
- if (vector == LAST_DEVICE_VECTOR)
- new_vector_avail = 0;
-
- spin_unlock_irqrestore(&msi_lock, flags);
- return vector;
-}
-
-static int get_new_vector(void)
-{
- int vector = assign_msi_vector();
-
- if (vector > 0)
- set_intr_gate(vector, interrupt[vector]);
-
- return vector;
-}
-
+static int msi_free_irq(struct pci_dev* dev, int irq);
static int msi_init(void)
{
static int status = -ENOMEM;
@@ -352,22 +176,6 @@
return status;
}
- status = msi_arch_init();
- if (status < 0) {
- pci_msi_enable = 0;
- printk(KERN_WARNING
- "PCI: MSI arch init failed. MSI disabled.\n");
- return status;
- }
-
- if (! msi_ops) {
- printk(KERN_WARNING
- "PCI: MSI ops not registered. MSI disabled.\n");
- status = -EINVAL;
- return status;
- }
-
- last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
@@ -375,23 +183,9 @@
return status;
}
- if (last_alloc_vector < 0) {
- pci_msi_enable = 0;
- printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
- status = -EBUSY;
- return status;
- }
- vector_irq[last_alloc_vector] = 0;
- nr_released_vectors++;
-
return status;
}
-static int get_msi_vector(struct pci_dev *dev)
-{
- return get_new_vector();
-}
-
static struct msi_desc* alloc_msi_entry(void)
{
struct msi_desc *entry;
@@ -406,29 +200,44 @@
return entry;
}
-static void attach_msi_entry(struct msi_desc *entry, int vector)
+static void attach_msi_entry(struct msi_desc *entry, int irq)
{
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
- msi_desc[vector] = entry;
+ msi_desc[irq] = entry;
spin_unlock_irqrestore(&msi_lock, flags);
}
-static void irq_handler_init(int cap_id, int pos, int mask)
+static int create_msi_irq(void)
{
- unsigned long flags;
+ struct msi_desc *entry;
+ int irq;
- spin_lock_irqsave(&irq_desc[pos].lock, flags);
- if (cap_id == PCI_CAP_ID_MSIX)
- irq_desc[pos].chip = &msix_irq_type;
- else {
- if (!mask)
- irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
- else
- irq_desc[pos].chip = &msi_irq_w_maskbit_type;
+ entry = alloc_msi_entry();
+ if (!entry)
+ return -ENOMEM;
+
+ irq = create_irq();
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ return -EBUSY;
}
- spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
+
+ set_irq_data(irq, entry);
+
+ return irq;
+}
+
+static void destroy_msi_irq(unsigned int irq)
+{
+ struct msi_desc *entry;
+
+ entry = get_irq_data(irq);
+ set_irq_chip(irq, NULL);
+ set_irq_data(irq, NULL);
+ destroy_irq(irq);
+ kmem_cache_free(msi_cachep, entry);
}
static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
@@ -473,21 +282,21 @@
}
}
-static int msi_lookup_vector(struct pci_dev *dev, int type)
+static int msi_lookup_irq(struct pci_dev *dev, int type)
{
- int vector;
+ int irq;
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
- for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
- if (!msi_desc[vector] || msi_desc[vector]->dev != dev ||
- msi_desc[vector]->msi_attrib.type != type ||
- msi_desc[vector]->msi_attrib.default_vector != dev->irq)
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
+ msi_desc[irq]->msi_attrib.type != type ||
+ msi_desc[irq]->msi_attrib.default_irq != dev->irq)
continue;
spin_unlock_irqrestore(&msi_lock, flags);
- /* This pre-assigned MSI vector for this device
- already exits. Override dev->irq with this vector */
- dev->irq = vector;
+ /* This pre-assigned MSI irq for this device
+ already exits. Override dev->irq with this irq */
+ dev->irq = irq;
return 0;
}
spin_unlock_irqrestore(&msi_lock, flags);
@@ -499,11 +308,6 @@
{
if (!dev)
return;
-
- if (pci_find_capability(dev, PCI_CAP_ID_MSIX) > 0)
- nr_msix_devices++;
- else if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0)
- nr_reserved_vectors++;
}
#ifdef CONFIG_PM
@@ -577,7 +381,7 @@
{
int pos;
int temp;
- int vector, head, tail = 0;
+ int irq, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
@@ -599,33 +403,20 @@
/* save the table */
temp = dev->irq;
- if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+ if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
kfree(save_state);
return -EINVAL;
}
- vector = head = dev->irq;
+ irq = head = dev->irq;
while (head != tail) {
- int j;
- void __iomem *base;
struct msi_desc *entry;
- entry = msi_desc[vector];
- base = entry->mask_base;
- j = entry->msi_attrib.entry_nr;
+ entry = msi_desc[irq];
+ read_msi_msg(irq, &entry->msg_save);
- entry->address_lo_save =
- readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- entry->address_hi_save =
- readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- entry->data_save =
- readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
-
- tail = msi_desc[vector]->link.tail;
- vector = tail;
+ tail = msi_desc[irq]->link.tail;
+ irq = tail;
}
dev->irq = temp;
@@ -638,9 +429,7 @@
{
u16 save;
int pos;
- int vector, head, tail = 0;
- void __iomem *base;
- int j;
+ int irq, head, tail = 0;
struct msi_desc *entry;
int temp;
struct pci_cap_saved_state *save_state;
@@ -658,26 +447,15 @@
/* route the table */
temp = dev->irq;
- if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX))
+ if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
return;
- vector = head = dev->irq;
+ irq = head = dev->irq;
while (head != tail) {
- entry = msi_desc[vector];
- base = entry->mask_base;
- j = entry->msi_attrib.entry_nr;
+ entry = msi_desc[irq];
+ write_msi_msg(irq, &entry->msg_save);
- writel(entry->address_lo_save,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel(entry->address_hi_save,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel(entry->data_save,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
-
- tail = msi_desc[vector]->link.tail;
- vector = tail;
+ tail = msi_desc[irq]->link.tail;
+ irq = tail;
}
dev->irq = temp;
@@ -686,32 +464,43 @@
}
#endif
-static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
+/**
+ * msi_capability_init - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device function with a single
+ * MSI irq, regardless of device function is capable of handling
+ * multiple messages. A return of zero indicates the successful setup
+ * of an entry zero with the new MSI irq or non-zero for otherwise.
+ **/
+static int msi_capability_init(struct pci_dev *dev)
{
int status;
- u32 address_hi;
- u32 address_lo;
- u32 data;
- int pos, vector = dev->irq;
+ struct msi_desc *entry;
+ int pos, irq;
u16 control;
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
+ /* MSI Entry Initialization */
+ irq = create_msi_irq();
+ if (irq < 0)
+ return irq;
- /* Configure MSI capability structure */
- status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data);
- if (status < 0)
- return status;
-
- pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
- if (is_64bit_address(control)) {
- pci_write_config_dword(dev,
- msi_upper_address_reg(pos), address_hi);
- pci_write_config_word(dev,
- msi_data_reg(pos, 1), data);
- } else
- pci_write_config_word(dev,
- msi_data_reg(pos, 0), data);
+ entry = get_irq_data(irq);
+ entry->link.head = irq;
+ entry->link.tail = irq;
+ entry->msi_attrib.type = PCI_CAP_ID_MSI;
+ entry->msi_attrib.is_64 = is_64bit_address(control);
+ entry->msi_attrib.entry_nr = 0;
+ entry->msi_attrib.maskbit = is_mask_bit_support(control);
+ entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
+ entry->msi_attrib.pos = pos;
+ if (is_mask_bit_support(control)) {
+ entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
+ is_64bit_address(control));
+ }
+ entry->dev = dev;
if (entry->msi_attrib.maskbit) {
unsigned int maskbits, temp;
/* All MSIs are unmasked by default, Mask them all */
@@ -725,65 +514,18 @@
msi_mask_bits_reg(pos, is_64bit_address(control)),
maskbits);
}
-
- return 0;
-}
-
-/**
- * msi_capability_init - configure device's MSI capability structure
- * @dev: pointer to the pci_dev data structure of MSI device function
- *
- * Setup the MSI capability structure of device function with a single
- * MSI vector, regardless of device function is capable of handling
- * multiple messages. A return of zero indicates the successful setup
- * of an entry zero with the new MSI vector or non-zero for otherwise.
- **/
-static int msi_capability_init(struct pci_dev *dev)
-{
- int status;
- struct msi_desc *entry;
- int pos, vector;
- u16 control;
-
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- /* MSI Entry Initialization */
- entry = alloc_msi_entry();
- if (!entry)
- return -ENOMEM;
-
- vector = get_msi_vector(dev);
- if (vector < 0) {
- kmem_cache_free(msi_cachep, entry);
- return -EBUSY;
- }
- entry->link.head = vector;
- entry->link.tail = vector;
- entry->msi_attrib.type = PCI_CAP_ID_MSI;
- entry->msi_attrib.state = 0; /* Mark it not active */
- entry->msi_attrib.entry_nr = 0;
- entry->msi_attrib.maskbit = is_mask_bit_support(control);
- entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */
- dev->irq = vector;
- entry->dev = dev;
- if (is_mask_bit_support(control)) {
- entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
- is_64bit_address(control));
- }
- /* Replace with MSI handler */
- irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
/* Configure MSI capability structure */
- status = msi_register_init(dev, entry);
- if (status != 0) {
- dev->irq = entry->msi_attrib.default_vector;
- kmem_cache_free(msi_cachep, entry);
+ status = arch_setup_msi_irq(irq, dev);
+ if (status < 0) {
+ destroy_msi_irq(irq);
return status;
}
- attach_msi_entry(entry, vector);
+ attach_msi_entry(entry, irq);
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+ dev->irq = irq;
return 0;
}
@@ -794,18 +536,15 @@
* @nvec: number of @entries
*
* Setup the MSI-X capability structure of device function with a
- * single MSI-X vector. A return of zero indicates the successful setup of
- * requested MSI-X entries with allocated vectors or non-zero for otherwise.
+ * single MSI-X irq. A return of zero indicates the successful setup of
+ * requested MSI-X entries with allocated irqs or non-zero for otherwise.
**/
static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- u32 address_hi;
- u32 address_lo;
- u32 data;
int status;
- int vector, pos, i, j, nr_entries, temp = 0;
+ int irq, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
u16 control;
@@ -827,65 +566,56 @@
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- entry = alloc_msi_entry();
- if (!entry)
+ irq = create_msi_irq();
+ if (irq < 0)
break;
- vector = get_msi_vector(dev);
- if (vector < 0) {
- kmem_cache_free(msi_cachep, entry);
- break;
- }
+ entry = get_irq_data(irq);
j = entries[i].entry;
- entries[i].vector = vector;
+ entries[i].vector = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
- entry->msi_attrib.state = 0; /* Mark it not active */
+ entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = j;
entry->msi_attrib.maskbit = 1;
- entry->msi_attrib.default_vector = dev->irq;
+ entry->msi_attrib.default_irq = dev->irq;
+ entry->msi_attrib.pos = pos;
entry->dev = dev;
entry->mask_base = base;
if (!head) {
- entry->link.head = vector;
- entry->link.tail = vector;
+ entry->link.head = irq;
+ entry->link.tail = irq;
head = entry;
} else {
entry->link.head = temp;
entry->link.tail = tail->link.tail;
- tail->link.tail = vector;
- head->link.head = vector;
+ tail->link.tail = irq;
+ head->link.head = irq;
}
- temp = vector;
+ temp = irq;
tail = entry;
- /* Replace with MSI-X handler */
- irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
/* Configure MSI-X capability structure */
- status = msi_ops->setup(dev, vector,
- &address_hi,
- &address_lo,
- &data);
- if (status < 0)
+ status = arch_setup_msi_irq(irq, dev);
+ if (status < 0) {
+ destroy_msi_irq(irq);
break;
+ }
- writel(address_lo,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel(address_hi,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel(data,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
- attach_msi_entry(entry, vector);
+ attach_msi_entry(entry, irq);
}
if (i != nvec) {
+ int avail = i - 1;
i--;
for (; i >= 0; i--) {
- vector = (entries + i)->vector;
- msi_free_vector(dev, vector, 0);
+ irq = (entries + i)->vector;
+ msi_free_irq(dev, irq);
(entries + i)->vector = 0;
}
- return -EBUSY;
+ /* If we had some success report the number of irqs
+ * we succeeded in setting up.
+ */
+ if (avail <= 0)
+ avail = -EBUSY;
+ return avail;
}
/* Set MSI-X enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -925,15 +655,14 @@
* @dev: pointer to the pci_dev data structure of MSI device function
*
* Setup the MSI capability structure of device function with
- * a single MSI vector upon its software driver call to request for
+ * a single MSI irq upon its software driver call to request for
* MSI mode enabled on its hardware device function. A return of zero
* indicates the successful setup of an entry zero with the new MSI
- * vector or non-zero for otherwise.
+ * irq or non-zero for otherwise.
**/
int pci_enable_msi(struct pci_dev* dev)
{
int pos, temp, status;
- u16 control;
if (pci_msi_supported(dev) < 0)
return -EINVAL;
@@ -948,52 +677,25 @@
if (!pos)
return -EINVAL;
- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
- /* Lookup Sucess */
- unsigned long flags;
+ WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (control & PCI_MSI_FLAGS_ENABLE)
- return 0; /* Already in MSI mode */
- spin_lock_irqsave(&msi_lock, flags);
- if (!vector_irq[dev->irq]) {
- msi_desc[dev->irq]->msi_attrib.state = 0;
- vector_irq[dev->irq] = -1;
- nr_released_vectors--;
- spin_unlock_irqrestore(&msi_lock, flags);
- status = msi_register_init(dev, msi_desc[dev->irq]);
- if (status == 0)
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
- return status;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
- dev->irq = temp;
- }
- /* Check whether driver already requested for MSI-X vectors */
+ /* Check whether driver already requested for MSI-X irqs */
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X vectors assigned\n",
+ "Device already has MSI-X irq assigned\n",
pci_name(dev));
dev->irq = temp;
return -EINVAL;
}
status = msi_capability_init(dev);
- if (!status) {
- if (!pos)
- nr_reserved_vectors--; /* Only MSI capable */
- else if (nr_msix_devices > 0)
- nr_msix_devices--; /* Both MSI and MSI-X capable,
- but choose enabling MSI */
- }
-
return status;
}
void pci_disable_msi(struct pci_dev* dev)
{
struct msi_desc *entry;
- int pos, default_vector;
+ int pos, default_irq;
u16 control;
unsigned long flags;
@@ -1010,41 +712,41 @@
if (!(control & PCI_MSI_FLAGS_ENABLE))
return;
+ disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+
spin_lock_irqsave(&msi_lock, flags);
entry = msi_desc[dev->irq];
if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
spin_unlock_irqrestore(&msi_lock, flags);
return;
}
- if (entry->msi_attrib.state) {
+ if (irq_has_action(dev->irq)) {
spin_unlock_irqrestore(&msi_lock, flags);
printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
- "free_irq() on MSI vector %d\n",
+ "free_irq() on MSI irq %d\n",
pci_name(dev), dev->irq);
- BUG_ON(entry->msi_attrib.state > 0);
+ BUG_ON(irq_has_action(dev->irq));
} else {
- vector_irq[dev->irq] = 0; /* free it */
- nr_released_vectors++;
- default_vector = entry->msi_attrib.default_vector;
+ default_irq = entry->msi_attrib.default_irq;
spin_unlock_irqrestore(&msi_lock, flags);
- /* Restore dev->irq to its default pin-assertion vector */
- dev->irq = default_vector;
- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
- PCI_CAP_ID_MSI);
+ msi_free_irq(dev, dev->irq);
+
+ /* Restore dev->irq to its default pin-assertion irq */
+ dev->irq = default_irq;
}
}
-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
+static int msi_free_irq(struct pci_dev* dev, int irq)
{
struct msi_desc *entry;
int head, entry_nr, type;
void __iomem *base;
unsigned long flags;
- msi_ops->teardown(vector);
+ arch_teardown_msi_irq(irq);
spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[vector];
+ entry = msi_desc[irq];
if (!entry || entry->dev != dev) {
spin_unlock_irqrestore(&msi_lock, flags);
return -EINVAL;
@@ -1056,100 +758,42 @@
msi_desc[entry->link.head]->link.tail = entry->link.tail;
msi_desc[entry->link.tail]->link.head = entry->link.head;
entry->dev = NULL;
- if (!reassign) {
- vector_irq[vector] = 0;
- nr_released_vectors++;
- }
- msi_desc[vector] = NULL;
+ msi_desc[irq] = NULL;
spin_unlock_irqrestore(&msi_lock, flags);
- kmem_cache_free(msi_cachep, entry);
+ destroy_msi_irq(irq);
if (type == PCI_CAP_ID_MSIX) {
- if (!reassign)
- writel(1, base +
- entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+ writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
- if (head == vector)
+ if (head == irq)
iounmap(base);
}
return 0;
}
-static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
-{
- int vector = head, tail = 0;
- int i, j = 0, nr_entries = 0;
- void __iomem *base;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- while (head != tail) {
- nr_entries++;
- tail = msi_desc[vector]->link.tail;
- if (entries[0].entry == msi_desc[vector]->msi_attrib.entry_nr)
- j = vector;
- vector = tail;
- }
- if (*nvec > nr_entries) {
- spin_unlock_irqrestore(&msi_lock, flags);
- *nvec = nr_entries;
- return -EINVAL;
- }
- vector = ((j > 0) ? j : head);
- for (i = 0; i < *nvec; i++) {
- j = msi_desc[vector]->msi_attrib.entry_nr;
- msi_desc[vector]->msi_attrib.state = 0; /* Mark it not active */
- vector_irq[vector] = -1; /* Mark it busy */
- nr_released_vectors--;
- entries[i].vector = vector;
- if (j != (entries + i)->entry) {
- base = msi_desc[vector]->mask_base;
- msi_desc[vector]->msi_attrib.entry_nr =
- (entries + i)->entry;
- writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET), base +
- (entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET), base +
- (entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel( (readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET) & 0xff00) | vector,
- base + (entries+i)->entry*PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
- }
- vector = msi_desc[vector]->link.tail;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return 0;
-}
-
/**
* pci_enable_msix - configure device's MSI-X capability structure
* @dev: pointer to the pci_dev data structure of MSI-X device function
* @entries: pointer to an array of MSI-X entries
- * @nvec: number of MSI-X vectors requested for allocation by device driver
+ * @nvec: number of MSI-X irqs requested for allocation by device driver
*
* Setup the MSI-X capability structure of device function with the number
- * of requested vectors upon its software driver call to request for
+ * of requested irqs upon its software driver call to request for
* MSI-X mode enabled on its hardware device function. A return of zero
* indicates the successful configuration of MSI-X capability structure
- * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
+ * with new allocated MSI-X irqs. A return of < 0 indicates a failure.
* Or a return of > 0 indicates that driver request is exceeding the number
- * of vectors available. Driver should use the returned value to re-send
+ * of irqs available. Driver should use the returned value to re-send
* its request.
**/
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
- int status, pos, nr_entries, free_vectors;
+ int status, pos, nr_entries;
int i, j, temp;
u16 control;
- unsigned long flags;
if (!entries || pci_msi_supported(dev) < 0)
return -EINVAL;
@@ -1163,9 +807,6 @@
return -EINVAL;
pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (control & PCI_MSIX_FLAGS_ENABLE)
- return -EINVAL; /* Already in MSI-X mode */
-
nr_entries = multi_msix_capable(control);
if (nvec > nr_entries)
return -EINVAL;
@@ -1180,56 +821,18 @@
}
}
temp = dev->irq;
- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
- /* Lookup Sucess */
- nr_entries = nvec;
- /* Reroute MSI-X table */
- if (reroute_msix_table(dev->irq, entries, &nr_entries)) {
- /* #requested > #previous-assigned */
- dev->irq = temp;
- return nr_entries;
- }
- dev->irq = temp;
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
- return 0;
- }
- /* Check whether driver already requested for MSI vector */
+ WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+
+ /* Check whether driver already requested for MSI irq */
if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+ !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
- "Device already has an MSI vector assigned\n",
+ "Device already has an MSI irq assigned\n",
pci_name(dev));
dev->irq = temp;
return -EINVAL;
}
-
- spin_lock_irqsave(&msi_lock, flags);
- /*
- * msi_lock is provided to ensure that enough vectors resources are
- * available before granting.
- */
- free_vectors = pci_vector_resources(last_alloc_vector,
- nr_released_vectors);
- /* Ensure that each MSI/MSI-X device has one vector reserved by
- default to avoid any MSI-X driver to take all available
- resources */
- free_vectors -= nr_reserved_vectors;
- /* Find the average of free vectors among MSI-X devices */
- if (nr_msix_devices > 0)
- free_vectors /= nr_msix_devices;
- spin_unlock_irqrestore(&msi_lock, flags);
-
- if (nvec > free_vectors) {
- if (free_vectors > 0)
- return free_vectors;
- else
- return -EBUSY;
- }
-
status = msix_capability_init(dev, entries, nvec);
- if (!status && nr_msix_devices > 0)
- nr_msix_devices--;
-
return status;
}
@@ -1251,53 +854,47 @@
if (!(control & PCI_MSIX_FLAGS_ENABLE))
return;
+ disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+
temp = dev->irq;
- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
- int state, vector, head, tail = 0, warning = 0;
+ if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ int irq, head, tail = 0, warning = 0;
unsigned long flags;
- vector = head = dev->irq;
- spin_lock_irqsave(&msi_lock, flags);
+ irq = head = dev->irq;
+ dev->irq = temp; /* Restore pin IRQ */
while (head != tail) {
- state = msi_desc[vector]->msi_attrib.state;
- if (state)
+ spin_lock_irqsave(&msi_lock, flags);
+ tail = msi_desc[irq]->link.tail;
+ spin_unlock_irqrestore(&msi_lock, flags);
+ if (irq_has_action(irq))
warning = 1;
- else {
- vector_irq[vector] = 0; /* free it */
- nr_released_vectors++;
- }
- tail = msi_desc[vector]->link.tail;
- vector = tail;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
}
- spin_unlock_irqrestore(&msi_lock, flags);
+ msi_free_irq(dev, irq);
if (warning) {
- dev->irq = temp;
printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X vectors\n",
+ "free_irq() on all MSI-X irqs\n",
pci_name(dev));
BUG_ON(warning > 0);
- } else {
- dev->irq = temp;
- disable_msi_mode(dev,
- pci_find_capability(dev, PCI_CAP_ID_MSIX),
- PCI_CAP_ID_MSIX);
-
}
}
}
/**
- * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
+ * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
* @dev: pointer to the pci_dev data structure of MSI(X) device function
*
* Being called during hotplug remove, from which the device function
- * is hot-removed. All previous assigned MSI/MSI-X vectors, if
+ * is hot-removed. All previous assigned MSI/MSI-X irqs, if
* allocated for this device function, are reclaimed to unused state,
* which may be used later on.
**/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
- int state, pos, temp;
+ int pos, temp;
unsigned long flags;
if (!pci_msi_enable || !dev)
@@ -1305,42 +902,38 @@
temp = dev->irq; /* Save IOAPIC IRQ */
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
- spin_lock_irqsave(&msi_lock, flags);
- state = msi_desc[dev->irq]->msi_attrib.state;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (state) {
+ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ if (irq_has_action(dev->irq)) {
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on MSI vector %d\n",
+ "called without free_irq() on MSI irq %d\n",
pci_name(dev), dev->irq);
- BUG_ON(state > 0);
- } else /* Release MSI vector assigned to this device */
- msi_free_vector(dev, dev->irq, 0);
+ BUG_ON(irq_has_action(dev->irq));
+ } else /* Release MSI irq assigned to this device */
+ msi_free_irq(dev, dev->irq);
dev->irq = temp; /* Restore IOAPIC IRQ */
}
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
- int vector, head, tail = 0, warning = 0;
+ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ int irq, head, tail = 0, warning = 0;
void __iomem *base = NULL;
- vector = head = dev->irq;
+ irq = head = dev->irq;
while (head != tail) {
spin_lock_irqsave(&msi_lock, flags);
- state = msi_desc[vector]->msi_attrib.state;
- tail = msi_desc[vector]->link.tail;
- base = msi_desc[vector]->mask_base;
+ tail = msi_desc[irq]->link.tail;
+ base = msi_desc[irq]->mask_base;
spin_unlock_irqrestore(&msi_lock, flags);
- if (state)
+ if (irq_has_action(irq))
warning = 1;
- else if (vector != head) /* Release MSI-X vector */
- msi_free_vector(dev, vector, 0);
- vector = tail;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
}
- msi_free_vector(dev, vector, 0);
+ msi_free_irq(dev, irq);
if (warning) {
iounmap(base);
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on all MSI-X vectors\n",
+ "called without free_irq() on all MSI-X irqs\n",
pci_name(dev));
BUG_ON(warning > 0);
}
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index 56951c3..f0cca17 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -7,84 +7,6 @@
#define MSI_H
/*
- * MSI operation vector. Used by the msi core code (drivers/pci/msi.c)
- * to abstract platform-specific tasks relating to MSI address generation
- * and resource management.
- */
-struct msi_ops {
- /**
- * setup - generate an MSI bus address and data for a given vector
- * @pdev: PCI device context (in)
- * @vector: vector allocated by the msi core (in)
- * @addr_hi: upper 32 bits of PCI bus MSI address (out)
- * @addr_lo: lower 32 bits of PCI bus MSI address (out)
- * @data: MSI data payload (out)
- *
- * Description: The setup op is used to generate a PCI bus addres and
- * data which the msi core will program into the card MSI capability
- * registers. The setup routine is responsible for picking an initial
- * cpu to target the MSI at. The setup routine is responsible for
- * examining pdev to determine the MSI capabilities of the card and
- * generating a suitable address/data. The setup routine is
- * responsible for allocating and tracking any system resources it
- * needs to route the MSI to the cpu it picks, and for associating
- * those resources with the passed in vector.
- *
- * Returns 0 if the MSI address/data was successfully setup.
- **/
-
- int (*setup) (struct pci_dev *pdev, unsigned int vector,
- u32 *addr_hi, u32 *addr_lo, u32 *data);
-
- /**
- * teardown - release resources allocated by setup
- * @vector: vector context for resources (in)
- *
- * Description: The teardown op is used to release any resources
- * that were allocated in the setup routine associated with the passed
- * in vector.
- **/
-
- void (*teardown) (unsigned int vector);
-
- /**
- * target - retarget an MSI at a different cpu
- * @vector: vector context for resources (in)
- * @cpu: new cpu to direct vector at (in)
- * @addr_hi: new value of PCI bus upper 32 bits (in/out)
- * @addr_lo: new value of PCI bus lower 32 bits (in/out)
- *
- * Description: The target op is used to redirect an MSI vector
- * at a different cpu. addr_hi/addr_lo coming in are the existing
- * values that the MSI core has programmed into the card. The
- * target code is responsible for freeing any resources (if any)
- * associated with the old address, and generating a new PCI bus
- * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
- **/
-
- void (*target) (unsigned int vector, unsigned int cpu,
- u32 *addr_hi, u32 *addr_lo);
-};
-
-extern int msi_register(struct msi_ops *ops);
-
-#include <asm/msi.h>
-
-/*
- * Assume the maximum number of hot plug slots supported by the system is about
- * ten. The worstcase is that each of these slots is hot-added with a device,
- * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
- * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
- * as below to ensure at least one message is assigned to each detected MSI/
- * MSI-X device function.
- */
-#define NR_HP_RESERVED_VECTORS 20
-
-extern int vector_irq[NR_VECTORS];
-extern void (*interrupt[NR_IRQS])(void);
-extern int pci_vector_resources(int last, int nr_released);
-
-/*
* MSI-X Address Register
*/
#define PCI_MSIX_FLAGS_QSIZE 0x7FF
@@ -110,8 +32,8 @@
(1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
#define multi_msi_enable(control, num) \
control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
-#define is_64bit_address(control) (control & PCI_MSI_FLAGS_64BIT)
-#define is_mask_bit_support(control) (control & PCI_MSI_FLAGS_MASKBIT)
+#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
+#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
#define msi_enable(control, num) multi_msi_enable(control, num); \
control |= PCI_MSI_FLAGS_ENABLE
@@ -125,32 +47,4 @@
#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
-struct msi_desc {
- struct {
- __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
- __u8 maskbit : 1; /* mask-pending bit supported ? */
- __u8 state : 1; /* {0: free, 1: busy} */
- __u8 reserved: 1; /* reserved */
- __u8 entry_nr; /* specific enabled entry */
- __u8 default_vector; /* default pre-assigned vector */
- __u8 unused; /* formerly unused destination cpu*/
- }msi_attrib;
-
- struct {
- __u16 head;
- __u16 tail;
- }link;
-
- void __iomem *mask_base;
- struct pci_dev *dev;
-
-#ifdef CONFIG_PM
- /* PM save area for MSIX address/data */
-
- u32 address_hi_save;
- u32 address_lo_save;
- u32 data_save;
-#endif
-};
-
#endif /* MSI_H */
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 5440491..8f7bcf5 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -55,16 +55,16 @@
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 class = dev->class >> 8;
- /* Don't touch classless devices or host bridges. */
+ /* Don't touch classless devices or host bridges or ioapics. */
if (class == PCI_CLASS_NOT_DEFINED ||
class == PCI_CLASS_BRIDGE_HOST)
continue;
- /* Don't touch ioapics if it has the assigned resources. */
+ /* Don't touch ioapic devices already enabled by firmware */
if (class == PCI_CLASS_SYSTEM_PIC) {
- res = &dev->resource[0];
- if (res[0].start || res[1].start || res[2].start ||
- res[3].start || res[4].start || res[5].start)
+ u16 command;
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
continue;
}
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index cc5032b..3f0f7b8 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -141,9 +141,9 @@
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
- "write", dt->tm_sec, dt->tm_min,
- dt->tm_hour, dt->tm_mday,
- dt->tm_mon, dt->tm_year, dt->tm_wday);
+ "write", t->tm_sec, t->tm_min,
+ t->tm_hour, t->tm_mday,
+ t->tm_mon, t->tm_year, t->tm_wday);
*buf++ = 0; /* first register addr */
buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 9c68ec9..67e816a 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -55,7 +55,7 @@
}
dev_dbg(&client->dev,
- "%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
+ "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
__FUNCTION__, buf[0], buf[1], buf[2], buf[3]);
time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
@@ -96,7 +96,7 @@
unsigned long secs;
dev_dbg(&client->dev,
- "%s: secs=%d, mins=%d, hours=%d, ",
+ "%s: secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index bbdad09..2a86632 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -91,7 +91,7 @@
unsigned char buf[8] = { RS5C372_REG_BASE };
dev_dbg(&client->dev,
- "%s: secs=%d, mins=%d, hours=%d ",
+ "%s: secs=%d, mins=%d, hours=%d "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -126,7 +126,7 @@
return -EIO;
}
- dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim);
+ dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim);
if (osc)
*osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768;
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index b120896..a433cc7 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -1843,7 +1843,7 @@
for (i = 0; propnames[i] != NULL; ++i) {
pedid = get_property(dp, propnames[i], NULL);
if (pedid != NULL) {
- par->EDID = pedid;
+ par->EDID = (unsigned char *)pedid;
NVTRACE("LCD found.\n");
return 1;
}
diff --git a/fs/Kconfig b/fs/Kconfig
index 68f4561..674cfbb 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -995,6 +995,18 @@
To compile this file system support as a module, choose M here: the
module will be called affs. If unsure, say N.
+config ECRYPT_FS
+ tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && KEYS && CRYPTO
+ help
+ Encrypted filesystem that operates on the VFS layer. See
+ <file:Documentation/ecryptfs.txt> to learn more about
+ eCryptfs. Userspace components are required and can be
+ obtained from <http://ecryptfs.sf.net>.
+
+ To compile this file system support as a module, choose M here: the
+ module will be called ecryptfs.
+
config HFS_FS
tristate "Apple Macintosh file system support (EXPERIMENTAL)"
depends on BLOCK && EXPERIMENTAL
diff --git a/fs/Makefile b/fs/Makefile
index 819b2a9..fd24d67 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -75,6 +75,7 @@
obj-$(CONFIG_ISO9660_FS) += isofs/
obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+
obj-$(CONFIG_HFS_FS) += hfs/
+obj-$(CONFIG_ECRYPT_FS) += ecryptfs/
obj-$(CONFIG_VXFS_FS) += freevxfs/
obj-$(CONFIG_NFS_FS) += nfs/
obj-$(CONFIG_EXPORTFS) += exportfs/
diff --git a/fs/dcache.c b/fs/dcache.c
index fc2faa4..2355bdd 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -291,9 +291,9 @@
* it can be unhashed only if it has no children, or if it is the root
* of a filesystem.
*
- * If the inode has a DCACHE_DISCONNECTED alias, then prefer
+ * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
* any other hashed alias over that one unless @want_discon is set,
- * in which case only return a DCACHE_DISCONNECTED alias.
+ * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
*/
static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
@@ -309,7 +309,8 @@
prefetch(next);
alias = list_entry(tmp, struct dentry, d_alias);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
- if (alias->d_flags & DCACHE_DISCONNECTED)
+ if (IS_ROOT(alias) &&
+ (alias->d_flags & DCACHE_DISCONNECTED))
discon_alias = alias;
else if (!want_discon) {
__dget_locked(alias);
@@ -1004,7 +1005,7 @@
{
struct dentry *new = NULL;
- if (inode) {
+ if (inode && S_ISDIR(inode->i_mode)) {
spin_lock(&dcache_lock);
new = __d_find_alias(inode, 1);
if (new) {
diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
new file mode 100644
index 0000000..ca65624
--- /dev/null
+++ b/fs/ecryptfs/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux 2.6 eCryptfs
+#
+
+obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
+
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o debug.o
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
new file mode 100644
index 0000000..ed35a9712
--- /dev/null
+++ b/fs/ecryptfs/crypto.c
@@ -0,0 +1,1659 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/key.h>
+#include <linux/namei.h>
+#include <linux/crypto.h>
+#include <linux/file.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+static int
+ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv);
+static int
+ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv);
+
+/**
+ * ecryptfs_to_hex
+ * @dst: Buffer to take hex character representation of contents of
+ * src; must be at least of size (src_size * 2)
+ * @src: Buffer to be converted to a hex string respresentation
+ * @src_size: number of bytes to convert
+ */
+void ecryptfs_to_hex(char *dst, char *src, size_t src_size)
+{
+ int x;
+
+ for (x = 0; x < src_size; x++)
+ sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);
+}
+
+/**
+ * ecryptfs_from_hex
+ * @dst: Buffer to take the bytes from src hex; must be at least of
+ * size (src_size / 2)
+ * @src: Buffer to be converted from a hex string respresentation to raw value
+ * @dst_size: size of dst buffer, or number of hex characters pairs to convert
+ */
+void ecryptfs_from_hex(char *dst, char *src, int dst_size)
+{
+ int x;
+ char tmp[3] = { 0, };
+
+ for (x = 0; x < dst_size; x++) {
+ tmp[0] = src[x * 2];
+ tmp[1] = src[x * 2 + 1];
+ dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16);
+ }
+}
+
+/**
+ * ecryptfs_calculate_md5 - calculates the md5 of @src
+ * @dst: Pointer to 16 bytes of allocated memory
+ * @crypt_stat: Pointer to crypt_stat struct for the current inode
+ * @src: Data to be md5'd
+ * @len: Length of @src
+ *
+ * Uses the allocated crypto context that crypt_stat references to
+ * generate the MD5 sum of the contents of src.
+ */
+static int ecryptfs_calculate_md5(char *dst,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ char *src, int len)
+{
+ int rc = 0;
+ struct scatterlist sg;
+
+ mutex_lock(&crypt_stat->cs_md5_tfm_mutex);
+ sg_init_one(&sg, (u8 *)src, len);
+ if (!crypt_stat->md5_tfm) {
+ crypt_stat->md5_tfm =
+ crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (!crypt_stat->md5_tfm) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "allocate crypto context\n");
+ goto out;
+ }
+ }
+ crypto_digest_init(crypt_stat->md5_tfm);
+ crypto_digest_update(crypt_stat->md5_tfm, &sg, 1);
+ crypto_digest_final(crypt_stat->md5_tfm, dst);
+ mutex_unlock(&crypt_stat->cs_md5_tfm_mutex);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_derive_iv
+ * @iv: destination for the derived iv vale
+ * @crypt_stat: Pointer to crypt_stat struct for the current inode
+ * @offset: Offset of the page whose's iv we are to derive
+ *
+ * Generate the initialization vector from the given root IV and page
+ * offset.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
+ pgoff_t offset)
+{
+ int rc = 0;
+ char dst[MD5_DIGEST_SIZE];
+ char src[ECRYPTFS_MAX_IV_BYTES + 16];
+
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "root iv:\n");
+ ecryptfs_dump_hex(crypt_stat->root_iv, crypt_stat->iv_bytes);
+ }
+ /* TODO: It is probably secure to just cast the least
+ * significant bits of the root IV into an unsigned long and
+ * add the offset to that rather than go through all this
+ * hashing business. -Halcrow */
+ memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);
+ memset((src + crypt_stat->iv_bytes), 0, 16);
+ snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "source:\n");
+ ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));
+ }
+ rc = ecryptfs_calculate_md5(dst, crypt_stat, src,
+ (crypt_stat->iv_bytes + 16));
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
+ "MD5 while generating IV for a page\n");
+ goto out;
+ }
+ memcpy(iv, dst, crypt_stat->iv_bytes);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "derived iv:\n");
+ ecryptfs_dump_hex(iv, crypt_stat->iv_bytes);
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_init_crypt_stat
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ *
+ * Initialize the crypt_stat structure.
+ */
+void
+ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
+ mutex_init(&crypt_stat->cs_mutex);
+ mutex_init(&crypt_stat->cs_tfm_mutex);
+ mutex_init(&crypt_stat->cs_md5_tfm_mutex);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_STRUCT_INITIALIZED);
+}
+
+/**
+ * ecryptfs_destruct_crypt_stat
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ *
+ * Releases all memory associated with a crypt_stat struct.
+ */
+void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ if (crypt_stat->tfm)
+ crypto_free_tfm(crypt_stat->tfm);
+ if (crypt_stat->md5_tfm)
+ crypto_free_tfm(crypt_stat->md5_tfm);
+ memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
+}
+
+void ecryptfs_destruct_mount_crypt_stat(
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
+{
+ if (mount_crypt_stat->global_auth_tok_key)
+ key_put(mount_crypt_stat->global_auth_tok_key);
+ if (mount_crypt_stat->global_key_tfm)
+ crypto_free_tfm(mount_crypt_stat->global_key_tfm);
+ memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));
+}
+
+/**
+ * virt_to_scatterlist
+ * @addr: Virtual address
+ * @size: Size of data; should be an even multiple of the block size
+ * @sg: Pointer to scatterlist array; set to NULL to obtain only
+ * the number of scatterlist structs required in array
+ * @sg_size: Max array size
+ *
+ * Fills in a scatterlist array with page references for a passed
+ * virtual address.
+ *
+ * Returns the number of scatterlist structs in array used
+ */
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+ int sg_size)
+{
+ int i = 0;
+ struct page *pg;
+ int offset;
+ int remainder_of_page;
+
+ while (size > 0 && i < sg_size) {
+ pg = virt_to_page(addr);
+ offset = offset_in_page(addr);
+ if (sg) {
+ sg[i].page = pg;
+ sg[i].offset = offset;
+ }
+ remainder_of_page = PAGE_CACHE_SIZE - offset;
+ if (size >= remainder_of_page) {
+ if (sg)
+ sg[i].length = remainder_of_page;
+ addr += remainder_of_page;
+ size -= remainder_of_page;
+ } else {
+ if (sg)
+ sg[i].length = size;
+ addr += size;
+ size = 0;
+ }
+ i++;
+ }
+ if (size > 0)
+ return -ENOMEM;
+ return i;
+}
+
+/**
+ * encrypt_scatterlist
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ * @dest_sg: Destination of encrypted data
+ * @src_sg: Data to be encrypted
+ * @size: Length of data to be encrypted
+ * @iv: iv to use during encryption
+ *
+ * Returns the number of bytes encrypted; negative value on error
+ */
+static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
+ struct scatterlist *dest_sg,
+ struct scatterlist *src_sg, int size,
+ unsigned char *iv)
+{
+ int rc = 0;
+
+ BUG_ON(!crypt_stat || !crypt_stat->tfm
+ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_STRUCT_INITIALIZED));
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n",
+ crypt_stat->key_size);
+ ecryptfs_dump_hex(crypt_stat->key,
+ crypt_stat->key_size);
+ }
+ /* Consider doing this once, when the file is opened */
+ mutex_lock(&crypt_stat->cs_tfm_mutex);
+ rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
+ crypt_stat->key_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
+ rc);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ rc = -EINVAL;
+ goto out;
+ }
+ ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
+ crypto_cipher_encrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size, iv);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+out:
+ return rc;
+}
+
+static void
+ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx,
+ int *byte_offset,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned long extent_num)
+{
+ unsigned long lower_extent_num;
+ int extents_occupied_by_headers_at_front;
+ int bytes_occupied_by_headers_at_front;
+ int extent_offset;
+ int extents_per_page;
+
+ bytes_occupied_by_headers_at_front =
+ ( crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front );
+ extents_occupied_by_headers_at_front =
+ ( bytes_occupied_by_headers_at_front
+ / crypt_stat->extent_size );
+ lower_extent_num = extents_occupied_by_headers_at_front + extent_num;
+ extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+ (*lower_page_idx) = lower_extent_num / extents_per_page;
+ extent_offset = lower_extent_num % extents_per_page;
+ (*byte_offset) = extent_offset * crypt_stat->extent_size;
+ ecryptfs_printk(KERN_DEBUG, " * crypt_stat->header_extent_size = "
+ "[%d]\n", crypt_stat->header_extent_size);
+ ecryptfs_printk(KERN_DEBUG, " * crypt_stat->"
+ "num_header_extents_at_front = [%d]\n",
+ crypt_stat->num_header_extents_at_front);
+ ecryptfs_printk(KERN_DEBUG, " * extents_occupied_by_headers_at_"
+ "front = [%d]\n", extents_occupied_by_headers_at_front);
+ ecryptfs_printk(KERN_DEBUG, " * lower_extent_num = [0x%.16x]\n",
+ lower_extent_num);
+ ecryptfs_printk(KERN_DEBUG, " * extents_per_page = [%d]\n",
+ extents_per_page);
+ ecryptfs_printk(KERN_DEBUG, " * (*lower_page_idx) = [0x%.16x]\n",
+ (*lower_page_idx));
+ ecryptfs_printk(KERN_DEBUG, " * extent_offset = [%d]\n",
+ extent_offset);
+ ecryptfs_printk(KERN_DEBUG, " * (*byte_offset) = [%d]\n",
+ (*byte_offset));
+}
+
+static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx,
+ struct page *lower_page,
+ struct inode *lower_inode,
+ int byte_offset_in_page, int bytes_to_write)
+{
+ int rc = 0;
+
+ if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
+ rc = ecryptfs_commit_lower_page(lower_page, lower_inode,
+ ctx->param.lower_file,
+ byte_offset_in_page,
+ bytes_to_write);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error calling lower "
+ "commit; rc = [%d]\n", rc);
+ goto out;
+ }
+ } else {
+ rc = ecryptfs_writepage_and_release_lower_page(lower_page,
+ lower_inode,
+ ctx->param.wbc);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error calling lower "
+ "writepage(); rc = [%d]\n", rc);
+ goto out;
+ }
+ }
+out:
+ return rc;
+}
+
+static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx,
+ struct page **lower_page,
+ struct inode *lower_inode,
+ unsigned long lower_page_idx,
+ int byte_offset_in_page)
+{
+ int rc = 0;
+
+ if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
+ /* TODO: Limit this to only the data extents that are
+ * needed */
+ rc = ecryptfs_get_lower_page(lower_page, lower_inode,
+ ctx->param.lower_file,
+ lower_page_idx,
+ byte_offset_in_page,
+ (PAGE_CACHE_SIZE
+ - byte_offset_in_page));
+ if (rc) {
+ ecryptfs_printk(
+ KERN_ERR, "Error attempting to grab, map, "
+ "and prepare_write lower page with index "
+ "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc);
+ goto out;
+ }
+ } else {
+ rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL,
+ lower_inode,
+ lower_page_idx);
+ if (rc) {
+ ecryptfs_printk(
+ KERN_ERR, "Error attempting to grab and map "
+ "lower page with index [0x%.16x]; rc = [%d]\n",
+ lower_page_idx, rc);
+ goto out;
+ }
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_encrypt_page
+ * @ctx: The context of the page
+ *
+ * Encrypt an eCryptfs page. This is done on a per-extent basis. Note
+ * that eCryptfs pages may straddle the lower pages -- for instance,
+ * if the file was created on a machine with an 8K page size
+ * (resulting in an 8K header), and then the file is copied onto a
+ * host with a 32K page size, then when reading page 0 of the eCryptfs
+ * file, 24K of page 0 of the lower file will be read and decrypted,
+ * and then 8K of page 1 of the lower file will be read and decrypted.
+ *
+ * The actual operations performed on each page depends on the
+ * contents of the ecryptfs_page_crypt_context struct.
+ *
+ * Returns zero on success; negative on error
+ */
+int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx)
+{
+ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+ unsigned long base_extent;
+ unsigned long extent_offset = 0;
+ unsigned long lower_page_idx = 0;
+ unsigned long prior_lower_page_idx = 0;
+ struct page *lower_page;
+ struct inode *lower_inode;
+ struct ecryptfs_inode_info *inode_info;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ int rc = 0;
+ int lower_byte_offset = 0;
+ int orig_byte_offset = 0;
+ int num_extents_per_page;
+#define ECRYPTFS_PAGE_STATE_UNREAD 0
+#define ECRYPTFS_PAGE_STATE_READ 1
+#define ECRYPTFS_PAGE_STATE_MODIFIED 2
+#define ECRYPTFS_PAGE_STATE_WRITTEN 3
+ int page_state;
+
+ lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host);
+ inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host);
+ crypt_stat = &inode_info->crypt_stat;
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
+ rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode,
+ ctx->param.lower_file);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error attempting to copy "
+ "page at index [0x%.16x]\n",
+ ctx->page->index);
+ goto out;
+ }
+ num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+ base_extent = (ctx->page->index * num_extents_per_page);
+ page_state = ECRYPTFS_PAGE_STATE_UNREAD;
+ while (extent_offset < num_extents_per_page) {
+ ecryptfs_extent_to_lwr_pg_idx_and_offset(
+ &lower_page_idx, &lower_byte_offset, crypt_stat,
+ (base_extent + extent_offset));
+ if (prior_lower_page_idx != lower_page_idx
+ && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) {
+ rc = ecryptfs_write_out_page(ctx, lower_page,
+ lower_inode,
+ orig_byte_offset,
+ (PAGE_CACHE_SIZE
+ - orig_byte_offset));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting "
+ "to write out page; rc = [%d]"
+ "\n", rc);
+ goto out;
+ }
+ page_state = ECRYPTFS_PAGE_STATE_WRITTEN;
+ }
+ if (page_state == ECRYPTFS_PAGE_STATE_UNREAD
+ || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) {
+ rc = ecryptfs_read_in_page(ctx, &lower_page,
+ lower_inode, lower_page_idx,
+ lower_byte_offset);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting "
+ "to read in lower page with "
+ "index [0x%.16x]; rc = [%d]\n",
+ lower_page_idx, rc);
+ goto out;
+ }
+ orig_byte_offset = lower_byte_offset;
+ prior_lower_page_idx = lower_page_idx;
+ page_state = ECRYPTFS_PAGE_STATE_READ;
+ }
+ BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED
+ || page_state == ECRYPTFS_PAGE_STATE_READ));
+ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+ (base_extent + extent_offset));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "derive IV for extent [0x%.16x]; "
+ "rc = [%d]\n",
+ (base_extent + extent_offset), rc);
+ goto out;
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
+ "with iv:\n");
+ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+ "encryption:\n");
+ ecryptfs_dump_hex((char *)
+ (page_address(ctx->page)
+ + (extent_offset
+ * crypt_stat->extent_size)), 8);
+ }
+ rc = ecryptfs_encrypt_page_offset(
+ crypt_stat, lower_page, lower_byte_offset, ctx->page,
+ (extent_offset * crypt_stat->extent_size),
+ crypt_stat->extent_size, extent_iv);
+ ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
+ "rc = [%d]\n",
+ (base_extent + extent_offset), rc);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+ "encryption:\n");
+ ecryptfs_dump_hex((char *)(page_address(lower_page)
+ + lower_byte_offset), 8);
+ }
+ page_state = ECRYPTFS_PAGE_STATE_MODIFIED;
+ extent_offset++;
+ }
+ BUG_ON(orig_byte_offset != 0);
+ rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0,
+ (lower_byte_offset
+ + crypt_stat->extent_size));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to write out "
+ "page; rc = [%d]\n", rc);
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_decrypt_page
+ * @file: The ecryptfs file
+ * @page: The page in ecryptfs to decrypt
+ *
+ * Decrypt an eCryptfs page. This is done on a per-extent basis. Note
+ * that eCryptfs pages may straddle the lower pages -- for instance,
+ * if the file was created on a machine with an 8K page size
+ * (resulting in an 8K header), and then the file is copied onto a
+ * host with a 32K page size, then when reading page 0 of the eCryptfs
+ * file, 24K of page 0 of the lower file will be read and decrypted,
+ * and then 8K of page 1 of the lower file will be read and decrypted.
+ *
+ * Returns zero on success; negative on error
+ */
+int ecryptfs_decrypt_page(struct file *file, struct page *page)
+{
+ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+ unsigned long base_extent;
+ unsigned long extent_offset = 0;
+ unsigned long lower_page_idx = 0;
+ unsigned long prior_lower_page_idx = 0;
+ struct page *lower_page;
+ char *lower_page_virt = NULL;
+ struct inode *lower_inode;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ int rc = 0;
+ int byte_offset;
+ int num_extents_per_page;
+ int page_state;
+
+ crypt_stat = &(ecryptfs_inode_to_private(
+ page->mapping->host)->crypt_stat);
+ lower_inode = ecryptfs_inode_to_lower(page->mapping->host);
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
+ rc = ecryptfs_do_readpage(file, page, page->index);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error attempting to copy "
+ "page at index [0x%.16x]\n",
+ page->index);
+ goto out;
+ }
+ num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+ base_extent = (page->index * num_extents_per_page);
+ lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache,
+ SLAB_KERNEL);
+ if (!lower_page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error getting page for encrypted "
+ "lower page(s)\n");
+ goto out;
+ }
+ lower_page = virt_to_page(lower_page_virt);
+ page_state = ECRYPTFS_PAGE_STATE_UNREAD;
+ while (extent_offset < num_extents_per_page) {
+ ecryptfs_extent_to_lwr_pg_idx_and_offset(
+ &lower_page_idx, &byte_offset, crypt_stat,
+ (base_extent + extent_offset));
+ if (prior_lower_page_idx != lower_page_idx
+ || page_state == ECRYPTFS_PAGE_STATE_UNREAD) {
+ rc = ecryptfs_do_readpage(file, lower_page,
+ lower_page_idx);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error reading "
+ "lower encrypted page; rc = "
+ "[%d]\n", rc);
+ goto out;
+ }
+ prior_lower_page_idx = lower_page_idx;
+ page_state = ECRYPTFS_PAGE_STATE_READ;
+ }
+ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+ (base_extent + extent_offset));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "derive IV for extent [0x%.16x]; rc = "
+ "[%d]\n",
+ (base_extent + extent_offset), rc);
+ goto out;
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
+ "with iv:\n");
+ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+ "decryption:\n");
+ ecryptfs_dump_hex((lower_page_virt + byte_offset), 8);
+ }
+ rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
+ (extent_offset
+ * crypt_stat->extent_size),
+ lower_page, byte_offset,
+ crypt_stat->extent_size,
+ extent_iv);
+ if (rc != crypt_stat->extent_size) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "decrypt extent [0x%.16x]\n",
+ (base_extent + extent_offset));
+ goto out;
+ }
+ rc = 0;
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+ "decryption:\n");
+ ecryptfs_dump_hex((char *)(page_address(page)
+ + byte_offset), 8);
+ }
+ extent_offset++;
+ }
+out:
+ if (lower_page_virt)
+ kmem_cache_free(ecryptfs_lower_page_cache, lower_page_virt);
+ return rc;
+}
+
+/**
+ * decrypt_scatterlist
+ *
+ * Returns the number of bytes decrypted; negative value on error
+ */
+static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
+ struct scatterlist *dest_sg,
+ struct scatterlist *src_sg, int size,
+ unsigned char *iv)
+{
+ int rc = 0;
+
+ /* Consider doing this once, when the file is opened */
+ mutex_lock(&crypt_stat->cs_tfm_mutex);
+ rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
+ crypt_stat->key_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
+ rc);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ rc = -EINVAL;
+ goto out;
+ }
+ ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
+ rc = crypto_cipher_decrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size,
+ iv);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n",
+ rc);
+ goto out;
+ }
+ rc = size;
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_encrypt_page_offset
+ *
+ * Returns the number of bytes encrypted
+ */
+static int
+ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv)
+{
+ struct scatterlist src_sg, dst_sg;
+
+ src_sg.page = src_page;
+ src_sg.offset = src_offset;
+ src_sg.length = size;
+ dst_sg.page = dst_page;
+ dst_sg.offset = dst_offset;
+ dst_sg.length = size;
+ return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
+}
+
+/**
+ * ecryptfs_decrypt_page_offset
+ *
+ * Returns the number of bytes decrypted
+ */
+static int
+ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv)
+{
+ struct scatterlist src_sg, dst_sg;
+
+ src_sg.page = src_page;
+ src_sg.offset = src_offset;
+ src_sg.length = size;
+ dst_sg.page = dst_page;
+ dst_sg.offset = dst_offset;
+ dst_sg.length = size;
+ return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
+}
+
+#define ECRYPTFS_MAX_SCATTERLIST_LEN 4
+
+/**
+ * ecryptfs_init_crypt_ctx
+ * @crypt_stat: Uninitilized crypt stats structure
+ *
+ * Initialize the crypto context.
+ *
+ * TODO: Performance: Keep a cache of initialized cipher contexts;
+ * only init if needed
+ */
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int rc = -EINVAL;
+
+ if (!crypt_stat->cipher) {
+ ecryptfs_printk(KERN_ERR, "No cipher specified\n");
+ goto out;
+ }
+ ecryptfs_printk(KERN_DEBUG,
+ "Initializing cipher [%s]; strlen = [%d]; "
+ "key_size_bits = [%d]\n",
+ crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
+ crypt_stat->key_size << 3);
+ if (crypt_stat->tfm) {
+ rc = 0;
+ goto out;
+ }
+ mutex_lock(&crypt_stat->cs_tfm_mutex);
+ crypt_stat->tfm = crypto_alloc_tfm(crypt_stat->cipher,
+ ECRYPTFS_DEFAULT_CHAINING_MODE
+ | CRYPTO_TFM_REQ_WEAK_KEY);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ if (!crypt_stat->tfm) {
+ ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): "
+ "Error initializing cipher [%s]\n",
+ crypt_stat->cipher);
+ goto out;
+ }
+ rc = 0;
+out:
+ return rc;
+}
+
+static void set_extent_mask_and_shift(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int extent_size_tmp;
+
+ crypt_stat->extent_mask = 0xFFFFFFFF;
+ crypt_stat->extent_shift = 0;
+ if (crypt_stat->extent_size == 0)
+ return;
+ extent_size_tmp = crypt_stat->extent_size;
+ while ((extent_size_tmp & 0x01) == 0) {
+ extent_size_tmp >>= 1;
+ crypt_stat->extent_mask <<= 1;
+ crypt_stat->extent_shift++;
+ }
+}
+
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ /* Default values; may be overwritten as we are parsing the
+ * packets. */
+ crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;
+ set_extent_mask_and_shift(crypt_stat);
+ crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
+ if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+ crypt_stat->header_extent_size =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
+ } else
+ crypt_stat->header_extent_size = PAGE_CACHE_SIZE;
+ crypt_stat->num_header_extents_at_front = 1;
+}
+
+/**
+ * ecryptfs_compute_root_iv
+ * @crypt_stats
+ *
+ * On error, sets the root IV to all 0's.
+ */
+int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int rc = 0;
+ char dst[MD5_DIGEST_SIZE];
+
+ BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE);
+ BUG_ON(crypt_stat->iv_bytes <= 0);
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING, "Session key not valid; "
+ "cannot generate root IV\n");
+ goto out;
+ }
+ rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key,
+ crypt_stat->key_size);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
+ "MD5 while generating root IV\n");
+ goto out;
+ }
+ memcpy(crypt_stat->root_iv, dst, crypt_stat->iv_bytes);
+out:
+ if (rc) {
+ memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags,
+ ECRYPTFS_SECURITY_WARNING);
+ }
+ return rc;
+}
+
+static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ get_random_bytes(crypt_stat->key, crypt_stat->key_size);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ ecryptfs_compute_root_iv(crypt_stat);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n");
+ ecryptfs_dump_hex(crypt_stat->key,
+ crypt_stat->key_size);
+ }
+}
+
+/**
+ * ecryptfs_set_default_crypt_stat_vals
+ * @crypt_stat
+ *
+ * Default values in the event that policy does not override them.
+ */
+static void ecryptfs_set_default_crypt_stat_vals(
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
+{
+ ecryptfs_set_default_sizes(crypt_stat);
+ strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER);
+ crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES;
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ crypt_stat->file_version = ECRYPTFS_FILE_VERSION;
+ crypt_stat->mount_crypt_stat = mount_crypt_stat;
+}
+
+/**
+ * ecryptfs_new_file_context
+ * @ecryptfs_dentry
+ *
+ * If the crypto context for the file has not yet been established,
+ * this is where we do that. Establishing a new crypto context
+ * involves the following decisions:
+ * - What cipher to use?
+ * - What set of authentication tokens to use?
+ * Here we just worry about getting enough information into the
+ * authentication tokens so that we know that they are available.
+ * We associate the available authentication tokens with the new file
+ * via the set of signatures in the crypt_stat struct. Later, when
+ * the headers are actually written out, we may again defer to
+ * userspace to perform the encryption of the session key; for the
+ * foreseeable future, this will be the case with public key packets.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+/* Associate an authentication token(s) with the file */
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry)
+{
+ int rc = 0;
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ int cipher_name_len;
+
+ ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat);
+ /* See if there are mount crypt options */
+ if (mount_crypt_stat->global_auth_tok) {
+ ecryptfs_printk(KERN_DEBUG, "Initializing context for new "
+ "file using mount_crypt_stat\n");
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++],
+ mount_crypt_stat->global_auth_tok_sig,
+ ECRYPTFS_SIG_SIZE_HEX);
+ cipher_name_len =
+ strlen(mount_crypt_stat->global_default_cipher_name);
+ memcpy(crypt_stat->cipher,
+ mount_crypt_stat->global_default_cipher_name,
+ cipher_name_len);
+ crypt_stat->cipher[cipher_name_len] = '\0';
+ crypt_stat->key_size =
+ mount_crypt_stat->global_default_cipher_key_size;
+ ecryptfs_generate_new_key(crypt_stat);
+ } else
+ /* We should not encounter this scenario since we
+ * should detect lack of global_auth_tok at mount time
+ * TODO: Applies to 0.1 release only; remove in future
+ * release */
+ BUG();
+ rc = ecryptfs_init_crypt_ctx(crypt_stat);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "
+ "context for cipher [%s]: rc = [%d]\n",
+ crypt_stat->cipher, rc);
+ return rc;
+}
+
+/**
+ * contains_ecryptfs_marker - check for the ecryptfs marker
+ * @data: The data block in which to check
+ *
+ * Returns one if marker found; zero if not found
+ */
+int contains_ecryptfs_marker(char *data)
+{
+ u32 m_1, m_2;
+
+ memcpy(&m_1, data, 4);
+ m_1 = be32_to_cpu(m_1);
+ memcpy(&m_2, (data + 4), 4);
+ m_2 = be32_to_cpu(m_2);
+ if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2)
+ return 1;
+ ecryptfs_printk(KERN_DEBUG, "m_1 = [0x%.8x]; m_2 = [0x%.8x]; "
+ "MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n", m_1, m_2,
+ MAGIC_ECRYPTFS_MARKER);
+ ecryptfs_printk(KERN_DEBUG, "(m_1 ^ MAGIC_ECRYPTFS_MARKER) = "
+ "[0x%.8x]\n", (m_1 ^ MAGIC_ECRYPTFS_MARKER));
+ return 0;
+}
+
+struct ecryptfs_flag_map_elem {
+ u32 file_flag;
+ u32 local_flag;
+};
+
+/* Add support for additional flags by adding elements here. */
+static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = {
+ {0x00000001, ECRYPTFS_ENABLE_HMAC},
+ {0x00000002, ECRYPTFS_ENCRYPTED}
+};
+
+/**
+ * ecryptfs_process_flags
+ * @crypt_stat
+ * @page_virt: Source data to be parsed
+ * @bytes_read: Updated with the number of bytes read
+ *
+ * Returns zero on success; non-zero if the flag set is invalid
+ */
+static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat,
+ char *page_virt, int *bytes_read)
+{
+ int rc = 0;
+ int i;
+ u32 flags;
+
+ memcpy(&flags, page_virt, 4);
+ flags = be32_to_cpu(flags);
+ for (i = 0; i < ((sizeof(ecryptfs_flag_map)
+ / sizeof(struct ecryptfs_flag_map_elem))); i++)
+ if (flags & ecryptfs_flag_map[i].file_flag) {
+ ECRYPTFS_SET_FLAG(crypt_stat->flags,
+ ecryptfs_flag_map[i].local_flag);
+ } else
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
+ ecryptfs_flag_map[i].local_flag);
+ /* Version is in top 8 bits of the 32-bit flag vector */
+ crypt_stat->file_version = ((flags >> 24) & 0xFF);
+ (*bytes_read) = 4;
+ return rc;
+}
+
+/**
+ * write_ecryptfs_marker
+ * @page_virt: The pointer to in a page to begin writing the marker
+ * @written: Number of bytes written
+ *
+ * Marker = 0x3c81b7f5
+ */
+static void write_ecryptfs_marker(char *page_virt, size_t *written)
+{
+ u32 m_1, m_2;
+
+ get_random_bytes(&m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+ m_2 = (m_1 ^ MAGIC_ECRYPTFS_MARKER);
+ m_1 = cpu_to_be32(m_1);
+ memcpy(page_virt, &m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+ m_2 = cpu_to_be32(m_2);
+ memcpy(page_virt + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2), &m_2,
+ (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+ (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+}
+
+static void
+write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
+ size_t *written)
+{
+ u32 flags = 0;
+ int i;
+
+ for (i = 0; i < ((sizeof(ecryptfs_flag_map)
+ / sizeof(struct ecryptfs_flag_map_elem))); i++)
+ if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ecryptfs_flag_map[i].local_flag))
+ flags |= ecryptfs_flag_map[i].file_flag;
+ /* Version is in top 8 bits of the 32-bit flag vector */
+ flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000);
+ flags = cpu_to_be32(flags);
+ memcpy(page_virt, &flags, 4);
+ (*written) = 4;
+}
+
+struct ecryptfs_cipher_code_str_map_elem {
+ char cipher_str[16];
+ u16 cipher_code;
+};
+
+/* Add support for additional ciphers by adding elements here. The
+ * cipher_code is whatever OpenPGP applicatoins use to identify the
+ * ciphers. List in order of probability. */
+static struct ecryptfs_cipher_code_str_map_elem
+ecryptfs_cipher_code_str_map[] = {
+ {"aes",RFC2440_CIPHER_AES_128 },
+ {"blowfish", RFC2440_CIPHER_BLOWFISH},
+ {"des3_ede", RFC2440_CIPHER_DES3_EDE},
+ {"cast5", RFC2440_CIPHER_CAST_5},
+ {"twofish", RFC2440_CIPHER_TWOFISH},
+ {"cast6", RFC2440_CIPHER_CAST_6},
+ {"aes", RFC2440_CIPHER_AES_192},
+ {"aes", RFC2440_CIPHER_AES_256}
+};
+
+/**
+ * ecryptfs_code_for_cipher_string
+ * @str: The string representing the cipher name
+ *
+ * Returns zero on no match, or the cipher code on match
+ */
+u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int i;
+ u16 code = 0;
+ struct ecryptfs_cipher_code_str_map_elem *map =
+ ecryptfs_cipher_code_str_map;
+
+ if (strcmp(crypt_stat->cipher, "aes") == 0) {
+ switch (crypt_stat->key_size) {
+ case 16:
+ code = RFC2440_CIPHER_AES_128;
+ break;
+ case 24:
+ code = RFC2440_CIPHER_AES_192;
+ break;
+ case 32:
+ code = RFC2440_CIPHER_AES_256;
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
+ if (strcmp(crypt_stat->cipher, map[i].cipher_str) == 0){
+ code = map[i].cipher_code;
+ break;
+ }
+ }
+ return code;
+}
+
+/**
+ * ecryptfs_cipher_code_to_string
+ * @str: Destination to write out the cipher name
+ * @cipher_code: The code to convert to cipher name string
+ *
+ * Returns zero on success
+ */
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
+{
+ int rc = 0;
+ int i;
+
+ str[0] = '\0';
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
+ if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code)
+ strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str);
+ if (str[0] == '\0') {
+ ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: "
+ "[%d]\n", cipher_code);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+/**
+ * ecryptfs_read_header_region
+ * @data
+ * @dentry
+ * @nd
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ struct file *file;
+ mm_segment_t oldfs;
+ int rc;
+
+ mnt = mntget(mnt);
+ file = dentry_open(dentry, mnt, O_RDONLY);
+ if (IS_ERR(file)) {
+ ecryptfs_printk(KERN_DEBUG, "Error opening file to "
+ "read header region\n");
+ mntput(mnt);
+ rc = PTR_ERR(file);
+ goto out;
+ }
+ file->f_pos = 0;
+ oldfs = get_fs();
+ set_fs(get_ds());
+ /* For releases 0.1 and 0.2, all of the header information
+ * fits in the first data extent-sized region. */
+ rc = file->f_op->read(file, (char __user *)data,
+ ECRYPTFS_DEFAULT_EXTENT_SIZE, &file->f_pos);
+ set_fs(oldfs);
+ fput(file);
+ rc = 0;
+out:
+ return rc;
+}
+
+static void
+write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat,
+ size_t *written)
+{
+ u32 header_extent_size;
+ u16 num_header_extents_at_front;
+
+ header_extent_size = (u32)crypt_stat->header_extent_size;
+ num_header_extents_at_front =
+ (u16)crypt_stat->num_header_extents_at_front;
+ header_extent_size = cpu_to_be32(header_extent_size);
+ memcpy(virt, &header_extent_size, 4);
+ virt += 4;
+ num_header_extents_at_front = cpu_to_be16(num_header_extents_at_front);
+ memcpy(virt, &num_header_extents_at_front, 2);
+ (*written) = 6;
+}
+
+struct kmem_cache *ecryptfs_header_cache_0;
+struct kmem_cache *ecryptfs_header_cache_1;
+struct kmem_cache *ecryptfs_header_cache_2;
+
+/**
+ * ecryptfs_write_headers_virt
+ * @page_virt
+ * @crypt_stat
+ * @ecryptfs_dentry
+ *
+ * Format version: 1
+ *
+ * Header Extent:
+ * Octets 0-7: Unencrypted file size (big-endian)
+ * Octets 8-15: eCryptfs special marker
+ * Octets 16-19: Flags
+ * Octet 16: File format version number (between 0 and 255)
+ * Octets 17-18: Reserved
+ * Octet 19: Bit 1 (lsb): Reserved
+ * Bit 2: Encrypted?
+ * Bits 3-8: Reserved
+ * Octets 20-23: Header extent size (big-endian)
+ * Octets 24-25: Number of header extents at front of file
+ * (big-endian)
+ * Octet 26: Begin RFC 2440 authentication token packet set
+ * Data Extent 0:
+ * Lower data (CBC encrypted)
+ * Data Extent 1:
+ * Lower data (CBC encrypted)
+ * ...
+ *
+ * Returns zero on success
+ */
+int ecryptfs_write_headers_virt(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry)
+{
+ int rc;
+ size_t written;
+ size_t offset;
+
+ offset = ECRYPTFS_FILE_SIZE_BYTES;
+ write_ecryptfs_marker((page_virt + offset), &written);
+ offset += written;
+ write_ecryptfs_flags((page_virt + offset), crypt_stat, &written);
+ offset += written;
+ write_header_metadata((page_virt + offset), crypt_stat, &written);
+ offset += written;
+ rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat,
+ ecryptfs_dentry, &written,
+ PAGE_CACHE_SIZE - offset);
+ if (rc)
+ ecryptfs_printk(KERN_WARNING, "Error generating key packet "
+ "set; rc = [%d]\n", rc);
+ return rc;
+}
+
+/**
+ * ecryptfs_write_headers
+ * @lower_file: The lower file struct, which was returned from dentry_open
+ *
+ * Write the file headers out. This will likely involve a userspace
+ * callout, in which the session key is encrypted with one or more
+ * public keys and/or the passphrase necessary to do the encryption is
+ * retrieved via a prompt. Exactly what happens at this point should
+ * be policy-dependent.
+ *
+ * Returns zero on success; non-zero on error
+ */
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file)
+{
+ mm_segment_t oldfs;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ char *page_virt;
+ int current_header_page;
+ int header_pages;
+ int rc = 0;
+
+ crypt_stat = &ecryptfs_inode_to_private(
+ ecryptfs_dentry->d_inode)->crypt_stat;
+ if (likely(ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_ENCRYPTED))) {
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_KEY_VALID)) {
+ ecryptfs_printk(KERN_DEBUG, "Key is "
+ "invalid; bailing out\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ } else {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING,
+ "Called with crypt_stat->encrypted == 0\n");
+ goto out;
+ }
+ /* Released in this function */
+ page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER);
+ if (!page_virt) {
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ rc = ecryptfs_write_headers_virt(page_virt, crypt_stat,
+ ecryptfs_dentry);
+ if (unlikely(rc)) {
+ ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ goto out_free;
+ }
+ ecryptfs_printk(KERN_DEBUG,
+ "Writing key packet set to underlying file\n");
+ lower_file->f_pos = 0;
+ oldfs = get_fs();
+ set_fs(get_ds());
+ ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
+ "write() w/ header page; lower_file->f_pos = "
+ "[0x%.16x]\n", lower_file->f_pos);
+ lower_file->f_op->write(lower_file, (char __user *)page_virt,
+ PAGE_CACHE_SIZE, &lower_file->f_pos);
+ header_pages = ((crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front)
+ / PAGE_CACHE_SIZE);
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ current_header_page = 1;
+ while (current_header_page < header_pages) {
+ ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
+ "write() w/ zero'd page; lower_file->f_pos = "
+ "[0x%.16x]\n", lower_file->f_pos);
+ lower_file->f_op->write(lower_file, (char __user *)page_virt,
+ PAGE_CACHE_SIZE, &lower_file->f_pos);
+ current_header_page++;
+ }
+ set_fs(oldfs);
+ ecryptfs_printk(KERN_DEBUG,
+ "Done writing key packet set to underlying file.\n");
+out_free:
+ kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+out:
+ return rc;
+}
+
+static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
+ char *virt, int *bytes_read)
+{
+ int rc = 0;
+ u32 header_extent_size;
+ u16 num_header_extents_at_front;
+
+ memcpy(&header_extent_size, virt, 4);
+ header_extent_size = be32_to_cpu(header_extent_size);
+ virt += 4;
+ memcpy(&num_header_extents_at_front, virt, 2);
+ num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
+ crypt_stat->header_extent_size = (int)header_extent_size;
+ crypt_stat->num_header_extents_at_front =
+ (int)num_header_extents_at_front;
+ (*bytes_read) = 6;
+ if ((crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front)
+ < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING, "Invalid header extent size: "
+ "[%d]\n", crypt_stat->header_extent_size);
+ }
+ return rc;
+}
+
+/**
+ * set_default_header_data
+ *
+ * For version 0 file format; this function is only for backwards
+ * compatibility for files created with the prior versions of
+ * eCryptfs.
+ */
+static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ crypt_stat->header_extent_size = 4096;
+ crypt_stat->num_header_extents_at_front = 1;
+}
+
+/**
+ * ecryptfs_read_headers_virt
+ *
+ * Read/parse the header data. The header format is detailed in the
+ * comment block for the ecryptfs_write_headers_virt() function.
+ *
+ * Returns zero on success
+ */
+static int ecryptfs_read_headers_virt(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry)
+{
+ int rc = 0;
+ int offset;
+ int bytes_read;
+
+ ecryptfs_set_default_sizes(crypt_stat);
+ crypt_stat->mount_crypt_stat = &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ offset = ECRYPTFS_FILE_SIZE_BYTES;
+ rc = contains_ecryptfs_marker(page_virt + offset);
+ if (rc == 0) {
+ rc = -EINVAL;
+ goto out;
+ }
+ offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+ rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),
+ &bytes_read);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error processing flags\n");
+ goto out;
+ }
+ if (crypt_stat->file_version > ECRYPTFS_SUPPORTED_FILE_VERSION) {
+ ecryptfs_printk(KERN_WARNING, "File version is [%d]; only "
+ "file version [%d] is supported by this "
+ "version of eCryptfs\n",
+ crypt_stat->file_version,
+ ECRYPTFS_SUPPORTED_FILE_VERSION);
+ rc = -EINVAL;
+ goto out;
+ }
+ offset += bytes_read;
+ if (crypt_stat->file_version >= 1) {
+ rc = parse_header_metadata(crypt_stat, (page_virt + offset),
+ &bytes_read);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error reading header "
+ "metadata; rc = [%d]\n", rc);
+ }
+ offset += bytes_read;
+ } else
+ set_default_header_data(crypt_stat);
+ rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset),
+ ecryptfs_dentry);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_read_headers
+ *
+ * Returns zero if valid headers found and parsed; non-zero otherwise
+ */
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file)
+{
+ int rc = 0;
+ char *page_virt = NULL;
+ mm_segment_t oldfs;
+ ssize_t bytes_read;
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
+
+ /* Read the first page from the underlying file */
+ page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, SLAB_USER);
+ if (!page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n");
+ goto out;
+ }
+ lower_file->f_pos = 0;
+ oldfs = get_fs();
+ set_fs(get_ds());
+ bytes_read = lower_file->f_op->read(lower_file,
+ (char __user *)page_virt,
+ ECRYPTFS_DEFAULT_EXTENT_SIZE,
+ &lower_file->f_pos);
+ set_fs(oldfs);
+ if (bytes_read != ECRYPTFS_DEFAULT_EXTENT_SIZE) {
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,
+ ecryptfs_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG, "Valid eCryptfs headers not "
+ "found\n");
+ rc = -EINVAL;
+ }
+out:
+ if (page_virt) {
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ kmem_cache_free(ecryptfs_header_cache_1, page_virt);
+ }
+ return rc;
+}
+
+/**
+ * ecryptfs_encode_filename - converts a plaintext file name to cipher text
+ * @crypt_stat: The crypt_stat struct associated with the file anem to encode
+ * @name: The plaintext name
+ * @length: The length of the plaintext
+ * @encoded_name: The encypted name
+ *
+ * Encrypts and encodes a filename into something that constitutes a
+ * valid filename for a filesystem, with printable characters.
+ *
+ * We assume that we have a properly initialized crypto context,
+ * pointed to by crypt_stat->tfm.
+ *
+ * TODO: Implement filename decoding and decryption here, in place of
+ * memcpy. We are keeping the framework around for now to (1)
+ * facilitate testing of the components needed to implement filename
+ * encryption and (2) to provide a code base from which other
+ * developers in the community can easily implement this feature.
+ *
+ * Returns the length of encoded filename; negative if error
+ */
+int
+ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length, char **encoded_name)
+{
+ int error = 0;
+
+ (*encoded_name) = kmalloc(length + 2, GFP_KERNEL);
+ if (!(*encoded_name)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ /* TODO: Filename encryption is a scheduled feature for a
+ * future version of eCryptfs. This function is here only for
+ * the purpose of providing a framework for other developers
+ * to easily implement filename encryption. Hint: Replace this
+ * memcpy() with a call to encrypt and encode the
+ * filename, the set the length accordingly. */
+ memcpy((void *)(*encoded_name), (void *)name, length);
+ (*encoded_name)[length] = '\0';
+ error = length + 1;
+out:
+ return error;
+}
+
+/**
+ * ecryptfs_decode_filename - converts the cipher text name to plaintext
+ * @crypt_stat: The crypt_stat struct associated with the file
+ * @name: The filename in cipher text
+ * @length: The length of the cipher text name
+ * @decrypted_name: The plaintext name
+ *
+ * Decodes and decrypts the filename.
+ *
+ * We assume that we have a properly initialized crypto context,
+ * pointed to by crypt_stat->tfm.
+ *
+ * TODO: Implement filename decoding and decryption here, in place of
+ * memcpy. We are keeping the framework around for now to (1)
+ * facilitate testing of the components needed to implement filename
+ * encryption and (2) to provide a code base from which other
+ * developers in the community can easily implement this feature.
+ *
+ * Returns the length of decoded filename; negative if error
+ */
+int
+ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length, char **decrypted_name)
+{
+ int error = 0;
+
+ (*decrypted_name) = kmalloc(length + 2, GFP_KERNEL);
+ if (!(*decrypted_name)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ /* TODO: Filename encryption is a scheduled feature for a
+ * future version of eCryptfs. This function is here only for
+ * the purpose of providing a framework for other developers
+ * to easily implement filename encryption. Hint: Replace this
+ * memcpy() with a call to decode and decrypt the
+ * filename, the set the length accordingly. */
+ memcpy((void *)(*decrypted_name), (void *)name, length);
+ (*decrypted_name)[length + 1] = '\0'; /* Only for convenience
+ * in printing out the
+ * string in debug
+ * messages */
+ error = length;
+out:
+ return error;
+}
+
+/**
+ * ecryptfs_process_cipher - Perform cipher initialization.
+ * @tfm: Crypto context set by this function
+ * @key_tfm: Crypto context for key material, set by this function
+ * @cipher_name: Name of the cipher.
+ * @key_size: Size of the key in bytes.
+ *
+ * Returns zero on success. Any crypto_tfm structs allocated here
+ * should be released by other functions, such as on a superblock put
+ * event, regardless of whether this function succeeds for fails.
+ */
+int
+ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm,
+ char *cipher_name, size_t key_size)
+{
+ char dummy_key[ECRYPTFS_MAX_KEY_BYTES];
+ int rc;
+
+ *tfm = *key_tfm = NULL;
+ if (key_size > ECRYPTFS_MAX_KEY_BYTES) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Requested key size is [%Zd] bytes; maximum "
+ "allowable is [%d]\n", key_size, ECRYPTFS_MAX_KEY_BYTES);
+ goto out;
+ }
+ *tfm = crypto_alloc_tfm(cipher_name, (ECRYPTFS_DEFAULT_CHAINING_MODE
+ | CRYPTO_TFM_REQ_WEAK_KEY));
+ if (!(*tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Unable to allocate crypto cipher with name "
+ "[%s]\n", cipher_name);
+ goto out;
+ }
+ *key_tfm = crypto_alloc_tfm(cipher_name, CRYPTO_TFM_REQ_WEAK_KEY);
+ if (!(*key_tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Unable to allocate crypto cipher with name "
+ "[%s]\n", cipher_name);
+ goto out;
+ }
+ if (key_size < crypto_tfm_alg_min_keysize(*tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; minimum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*tfm));
+ goto out;
+ }
+ if (key_size < crypto_tfm_alg_min_keysize(*key_tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; minimum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*key_tfm));
+ goto out;
+ }
+ if (key_size > crypto_tfm_alg_max_keysize(*tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; maximum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*tfm));
+ goto out;
+ }
+ if (key_size > crypto_tfm_alg_max_keysize(*key_tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; maximum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*key_tfm));
+ goto out;
+ }
+ get_random_bytes(dummy_key, key_size);
+ rc = crypto_cipher_setkey(*tfm, dummy_key, key_size);
+ if (rc) {
+ printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
+ "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = crypto_cipher_setkey(*key_tfm, dummy_key, key_size);
+ if (rc) {
+ printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
+ "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc);
+ rc = -EINVAL;
+ goto out;
+ }
+out:
+ return rc;
+}
diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c
new file mode 100644
index 0000000..61f8e89
--- /dev/null
+++ b/fs/ecryptfs/debug.c
@@ -0,0 +1,123 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * Functions only useful for debugging.
+ *
+ * Copyright (C) 2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_dump_auth_tok - debug function to print auth toks
+ *
+ * This function will print the contents of an ecryptfs authentication
+ * token.
+ */
+void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok)
+{
+ char salt[ECRYPTFS_SALT_SIZE * 2 + 1];
+ char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+
+ ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n",
+ auth_tok);
+ if (ECRYPTFS_CHECK_FLAG(auth_tok->flags, ECRYPTFS_PRIVATE_KEY)) {
+ ecryptfs_printk(KERN_DEBUG, " * private key type\n");
+ ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT "
+ "IN ECRYPTFS VERSION 0.1)\n");
+ } else {
+ ecryptfs_printk(KERN_DEBUG, " * passphrase type\n");
+ ecryptfs_to_hex(salt, auth_tok->token.password.salt,
+ ECRYPTFS_SALT_SIZE);
+ salt[ECRYPTFS_SALT_SIZE * 2] = '\0';
+ ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt);
+ if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
+ ECRYPTFS_PERSISTENT_PASSWORD)) {
+ ecryptfs_printk(KERN_DEBUG, " * persistent\n");
+ }
+ memcpy(sig, auth_tok->token.password.signature,
+ ECRYPTFS_SIG_SIZE_HEX);
+ sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+ ecryptfs_printk(KERN_DEBUG, " * signature = [%s]\n", sig);
+ }
+ ecryptfs_printk(KERN_DEBUG, " * session_key.flags = [0x%x]\n",
+ auth_tok->session_key.flags);
+ if (auth_tok->session_key.flags
+ & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT)
+ ecryptfs_printk(KERN_DEBUG,
+ " * Userspace decrypt request set\n");
+ if (auth_tok->session_key.flags
+ & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT)
+ ecryptfs_printk(KERN_DEBUG,
+ " * Userspace encrypt request set\n");
+ if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) {
+ ecryptfs_printk(KERN_DEBUG, " * Contains decrypted key\n");
+ ecryptfs_printk(KERN_DEBUG,
+ " * session_key.decrypted_key_size = [0x%x]\n",
+ auth_tok->session_key.decrypted_key_size);
+ ecryptfs_printk(KERN_DEBUG, " * Decrypted session key "
+ "dump:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(auth_tok->session_key.decrypted_key,
+ ECRYPTFS_DEFAULT_KEY_BYTES);
+ }
+ if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) {
+ ecryptfs_printk(KERN_DEBUG, " * Contains encrypted key\n");
+ ecryptfs_printk(KERN_DEBUG,
+ " * session_key.encrypted_key_size = [0x%x]\n",
+ auth_tok->session_key.encrypted_key_size);
+ ecryptfs_printk(KERN_DEBUG, " * Encrypted session key "
+ "dump:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.
+ encrypted_key_size);
+ }
+}
+
+/**
+ * ecryptfs_dump_hex - debug hex printer
+ * @data: string of bytes to be printed
+ * @bytes: number of bytes to print
+ *
+ * Dump hexadecimal representation of char array
+ */
+void ecryptfs_dump_hex(char *data, int bytes)
+{
+ int i = 0;
+ int add_newline = 1;
+
+ if (ecryptfs_verbosity < 1)
+ return;
+ if (bytes != 0) {
+ printk(KERN_DEBUG "0x%.2x.", (unsigned char)data[i]);
+ i++;
+ }
+ while (i < bytes) {
+ printk("0x%.2x.", (unsigned char)data[i]);
+ i++;
+ if (i % 16 == 0) {
+ printk("\n");
+ add_newline = 0;
+ } else
+ add_newline = 1;
+ }
+ if (add_newline)
+ printk("\n");
+}
+
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
new file mode 100644
index 0000000..f0d2a43
--- /dev/null
+++ b/fs/ecryptfs/dentry.c
@@ -0,0 +1,87 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_d_revalidate - revalidate an ecryptfs dentry
+ * @dentry: The ecryptfs dentry
+ * @nd: The associated nameidata
+ *
+ * Called when the VFS needs to revalidate a dentry. This
+ * is called whenever a name lookup finds a dentry in the
+ * dcache. Most filesystems leave this as NULL, because all their
+ * dentries in the dcache are valid.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ *
+ */
+static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+ struct dentry *dentry_save;
+ struct vfsmount *vfsmount_save;
+ int rc = 1;
+
+ if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
+ goto out;
+ dentry_save = nd->dentry;
+ vfsmount_save = nd->mnt;
+ nd->dentry = lower_dentry;
+ nd->mnt = lower_mnt;
+ rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
+ nd->dentry = dentry_save;
+ nd->mnt = vfsmount_save;
+out:
+ return rc;
+}
+
+struct kmem_cache *ecryptfs_dentry_info_cache;
+
+/**
+ * ecryptfs_d_release
+ * @dentry: The ecryptfs dentry
+ *
+ * Called when a dentry is really deallocated.
+ */
+static void ecryptfs_d_release(struct dentry *dentry)
+{
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (ecryptfs_dentry_to_private(dentry))
+ kmem_cache_free(ecryptfs_dentry_info_cache,
+ ecryptfs_dentry_to_private(dentry));
+ if (lower_dentry)
+ dput(lower_dentry);
+ return;
+}
+
+struct dentry_operations ecryptfs_dops = {
+ .d_revalidate = ecryptfs_d_revalidate,
+ .d_release = ecryptfs_d_release,
+};
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
new file mode 100644
index 0000000..872c995
--- /dev/null
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -0,0 +1,482 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * Kernel declarations.
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef ECRYPTFS_KERNEL_H
+#define ECRYPTFS_KERNEL_H
+
+#include <keys/user-type.h>
+#include <linux/fs.h>
+#include <linux/scatterlist.h>
+
+/* Version verification for shared data structures w/ userspace */
+#define ECRYPTFS_VERSION_MAJOR 0x00
+#define ECRYPTFS_VERSION_MINOR 0x04
+#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x01
+/* These flags indicate which features are supported by the kernel
+ * module; userspace tools such as the mount helper read
+ * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
+ * how to behave. */
+#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001
+#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002
+#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
+#define ECRYPTFS_VERSIONING_POLICY 0x00000008
+#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
+ | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH)
+
+#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
+#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
+#define ECRYPTFS_SALT_SIZE 8
+#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
+/* The original signature size is only for what is stored on disk; all
+ * in-memory representations are expanded hex, so it better adapted to
+ * be passed around or referenced on the command line */
+#define ECRYPTFS_SIG_SIZE 8
+#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
+#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
+#define ECRYPTFS_MAX_KEY_BYTES 64
+#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
+#define ECRYPTFS_DEFAULT_IV_BYTES 16
+#define ECRYPTFS_FILE_VERSION 0x01
+#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192
+#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
+#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192
+
+#define RFC2440_CIPHER_DES3_EDE 0x02
+#define RFC2440_CIPHER_CAST_5 0x03
+#define RFC2440_CIPHER_BLOWFISH 0x04
+#define RFC2440_CIPHER_AES_128 0x07
+#define RFC2440_CIPHER_AES_192 0x08
+#define RFC2440_CIPHER_AES_256 0x09
+#define RFC2440_CIPHER_TWOFISH 0x0a
+#define RFC2440_CIPHER_CAST_6 0x0b
+
+#define ECRYPTFS_SET_FLAG(flag_bit_vector, flag) (flag_bit_vector |= (flag))
+#define ECRYPTFS_CLEAR_FLAG(flag_bit_vector, flag) (flag_bit_vector &= ~(flag))
+#define ECRYPTFS_CHECK_FLAG(flag_bit_vector, flag) (flag_bit_vector & (flag))
+
+/**
+ * For convenience, we may need to pass around the encrypted session
+ * key between kernel and userspace because the authentication token
+ * may not be extractable. For example, the TPM may not release the
+ * private key, instead requiring the encrypted data and returning the
+ * decrypted data.
+ */
+struct ecryptfs_session_key {
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
+#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
+#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
+ u32 flags;
+ u32 encrypted_key_size;
+ u32 decrypted_key_size;
+ u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+ u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
+};
+
+struct ecryptfs_password {
+ u32 password_bytes;
+ s32 hash_algo;
+ u32 hash_iterations;
+ u32 session_key_encryption_key_bytes;
+#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
+#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
+ u32 flags;
+ /* Iterated-hash concatenation of salt and passphrase */
+ u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+ u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+ /* Always in expanded hex */
+ u8 salt[ECRYPTFS_SALT_SIZE];
+};
+
+enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
+
+/* May be a password or a private key */
+struct ecryptfs_auth_tok {
+ u16 version; /* 8-bit major and 8-bit minor */
+ u16 token_type;
+ u32 flags;
+ struct ecryptfs_session_key session_key;
+ u8 reserved[32];
+ union {
+ struct ecryptfs_password password;
+ /* Private key is in future eCryptfs releases */
+ } token;
+} __attribute__ ((packed));
+
+void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
+extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);
+extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
+
+struct ecryptfs_key_record {
+ unsigned char type;
+ size_t enc_key_size;
+ unsigned char sig[ECRYPTFS_SIG_SIZE];
+ unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+};
+
+struct ecryptfs_auth_tok_list {
+ struct ecryptfs_auth_tok *auth_tok;
+ struct list_head list;
+};
+
+struct ecryptfs_crypt_stat;
+struct ecryptfs_mount_crypt_stat;
+
+struct ecryptfs_page_crypt_context {
+ struct page *page;
+#define ECRYPTFS_PREPARE_COMMIT_MODE 0
+#define ECRYPTFS_WRITEPAGE_MODE 1
+ unsigned int mode;
+ union {
+ struct file *lower_file;
+ struct writeback_control *wbc;
+ } param;
+};
+
+static inline struct ecryptfs_auth_tok *
+ecryptfs_get_key_payload_data(struct key *key)
+{
+ return (struct ecryptfs_auth_tok *)
+ (((struct user_key_payload*)key->payload.data)->data);
+}
+
+#define ECRYPTFS_SUPER_MAGIC 0xf15f
+#define ECRYPTFS_MAX_KEYSET_SIZE 1024
+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
+#define ECRYPTFS_MAX_NUM_ENC_KEYS 64
+#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */
+#define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */
+#define ECRYPTFS_SALT_BYTES 2
+#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
+#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */
+#define ECRYPTFS_FILE_SIZE_BYTES 8
+#define ECRYPTFS_DEFAULT_CIPHER "aes"
+#define ECRYPTFS_DEFAULT_KEY_BYTES 16
+#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC
+#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
+#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
+#define MD5_DIGEST_SIZE 16
+
+/**
+ * This is the primary struct associated with each encrypted file.
+ *
+ * TODO: cache align/pack?
+ */
+struct ecryptfs_crypt_stat {
+#define ECRYPTFS_STRUCT_INITIALIZED 0x00000001
+#define ECRYPTFS_POLICY_APPLIED 0x00000002
+#define ECRYPTFS_NEW_FILE 0x00000004
+#define ECRYPTFS_ENCRYPTED 0x00000008
+#define ECRYPTFS_SECURITY_WARNING 0x00000010
+#define ECRYPTFS_ENABLE_HMAC 0x00000020
+#define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000040
+#define ECRYPTFS_KEY_VALID 0x00000080
+ u32 flags;
+ unsigned int file_version;
+ size_t iv_bytes;
+ size_t num_keysigs;
+ size_t header_extent_size;
+ size_t num_header_extents_at_front;
+ size_t extent_size; /* Data extent size; default is 4096 */
+ size_t key_size;
+ size_t extent_shift;
+ unsigned int extent_mask;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+ struct crypto_tfm *tfm;
+ struct crypto_tfm *md5_tfm; /* Crypto context for generating
+ * the initialization vectors */
+ unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+ unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
+ unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
+ unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX];
+ struct mutex cs_tfm_mutex;
+ struct mutex cs_md5_tfm_mutex;
+ struct mutex cs_mutex;
+};
+
+/* inode private data. */
+struct ecryptfs_inode_info {
+ struct inode vfs_inode;
+ struct inode *wii_inode;
+ struct ecryptfs_crypt_stat crypt_stat;
+};
+
+/* dentry private data. Each dentry must keep track of a lower
+ * vfsmount too. */
+struct ecryptfs_dentry_info {
+ struct dentry *wdi_dentry;
+ struct vfsmount *lower_mnt;
+ struct ecryptfs_crypt_stat *crypt_stat;
+};
+
+/**
+ * This struct is to enable a mount-wide passphrase/salt combo. This
+ * is more or less a stopgap to provide similar functionality to other
+ * crypto filesystems like EncFS or CFS until full policy support is
+ * implemented in eCryptfs.
+ */
+struct ecryptfs_mount_crypt_stat {
+ /* Pointers to memory we do not own, do not free these */
+#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001
+ u32 flags;
+ struct ecryptfs_auth_tok *global_auth_tok;
+ struct key *global_auth_tok_key;
+ size_t global_default_cipher_key_size;
+ struct crypto_tfm *global_key_tfm;
+ struct mutex global_key_tfm_mutex;
+ unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
+ + 1];
+ unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+};
+
+/* superblock private data. */
+struct ecryptfs_sb_info {
+ struct super_block *wsi_sb;
+ struct ecryptfs_mount_crypt_stat mount_crypt_stat;
+};
+
+/* file private data. */
+struct ecryptfs_file_info {
+ struct file *wfi_file;
+ struct ecryptfs_crypt_stat *crypt_stat;
+};
+
+/* auth_tok <=> encrypted_session_key mappings */
+struct ecryptfs_auth_tok_list_item {
+ unsigned char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES];
+ struct list_head list;
+ struct ecryptfs_auth_tok auth_tok;
+};
+
+static inline struct ecryptfs_file_info *
+ecryptfs_file_to_private(struct file *file)
+{
+ return (struct ecryptfs_file_info *)file->private_data;
+}
+
+static inline void
+ecryptfs_set_file_private(struct file *file,
+ struct ecryptfs_file_info *file_info)
+{
+ file->private_data = file_info;
+}
+
+static inline struct file *ecryptfs_file_to_lower(struct file *file)
+{
+ return ((struct ecryptfs_file_info *)file->private_data)->wfi_file;
+}
+
+static inline void
+ecryptfs_set_file_lower(struct file *file, struct file *lower_file)
+{
+ ((struct ecryptfs_file_info *)file->private_data)->wfi_file =
+ lower_file;
+}
+
+static inline struct ecryptfs_inode_info *
+ecryptfs_inode_to_private(struct inode *inode)
+{
+ return container_of(inode, struct ecryptfs_inode_info, vfs_inode);
+}
+
+static inline struct inode *ecryptfs_inode_to_lower(struct inode *inode)
+{
+ return ecryptfs_inode_to_private(inode)->wii_inode;
+}
+
+static inline void
+ecryptfs_set_inode_lower(struct inode *inode, struct inode *lower_inode)
+{
+ ecryptfs_inode_to_private(inode)->wii_inode = lower_inode;
+}
+
+static inline struct ecryptfs_sb_info *
+ecryptfs_superblock_to_private(struct super_block *sb)
+{
+ return (struct ecryptfs_sb_info *)sb->s_fs_info;
+}
+
+static inline void
+ecryptfs_set_superblock_private(struct super_block *sb,
+ struct ecryptfs_sb_info *sb_info)
+{
+ sb->s_fs_info = sb_info;
+}
+
+static inline struct super_block *
+ecryptfs_superblock_to_lower(struct super_block *sb)
+{
+ return ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb;
+}
+
+static inline void
+ecryptfs_set_superblock_lower(struct super_block *sb,
+ struct super_block *lower_sb)
+{
+ ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb = lower_sb;
+}
+
+static inline struct ecryptfs_dentry_info *
+ecryptfs_dentry_to_private(struct dentry *dentry)
+{
+ return (struct ecryptfs_dentry_info *)dentry->d_fsdata;
+}
+
+static inline void
+ecryptfs_set_dentry_private(struct dentry *dentry,
+ struct ecryptfs_dentry_info *dentry_info)
+{
+ dentry->d_fsdata = dentry_info;
+}
+
+static inline struct dentry *
+ecryptfs_dentry_to_lower(struct dentry *dentry)
+{
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry;
+}
+
+static inline void
+ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)
+{
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry =
+ lower_dentry;
+}
+
+static inline struct vfsmount *
+ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)
+{
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt;
+}
+
+static inline void
+ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
+{
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt =
+ lower_mnt;
+}
+
+#define ecryptfs_printk(type, fmt, arg...) \
+ __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
+void __ecryptfs_printk(const char *fmt, ...);
+
+extern const struct file_operations ecryptfs_main_fops;
+extern const struct file_operations ecryptfs_dir_fops;
+extern struct inode_operations ecryptfs_main_iops;
+extern struct inode_operations ecryptfs_dir_iops;
+extern struct inode_operations ecryptfs_symlink_iops;
+extern struct super_operations ecryptfs_sops;
+extern struct dentry_operations ecryptfs_dops;
+extern struct address_space_operations ecryptfs_aops;
+extern int ecryptfs_verbosity;
+
+extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
+extern struct kmem_cache *ecryptfs_file_info_cache;
+extern struct kmem_cache *ecryptfs_dentry_info_cache;
+extern struct kmem_cache *ecryptfs_inode_info_cache;
+extern struct kmem_cache *ecryptfs_sb_info_cache;
+extern struct kmem_cache *ecryptfs_header_cache_0;
+extern struct kmem_cache *ecryptfs_header_cache_1;
+extern struct kmem_cache *ecryptfs_header_cache_2;
+extern struct kmem_cache *ecryptfs_lower_page_cache;
+
+int ecryptfs_interpose(struct dentry *hidden_dentry,
+ struct dentry *this_dentry, struct super_block *sb,
+ int flag);
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
+int ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length,
+ char **decrypted_name);
+int ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length,
+ char **encoded_name);
+struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src);
+void ecryptfs_dump_hex(char *data, int bytes);
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+ int sg_size);
+int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_rotate_iv(unsigned char *iv);
+void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_destruct_mount_crypt_stat(
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_write_inode_size_to_header(struct file *lower_file,
+ struct inode *lower_inode,
+ struct inode *inode);
+int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
+ struct file *lower_file,
+ unsigned long lower_page_index, int byte_offset,
+ int region_bytes);
+int
+ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
+ struct file *lower_file, int byte_offset,
+ int region_size);
+int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
+ struct file *lower_file);
+int ecryptfs_do_readpage(struct file *file, struct page *page,
+ pgoff_t lower_page_index);
+int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
+ char **lower_virt,
+ struct inode *lower_inode,
+ unsigned long lower_page_index);
+int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
+ struct inode *lower_inode,
+ struct writeback_control *wbc);
+int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx);
+int ecryptfs_decrypt_page(struct file *file, struct page *page);
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file);
+int ecryptfs_write_headers_virt(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry);
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file);
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
+int contains_ecryptfs_marker(char *data);
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+ struct vfsmount *mnt);
+u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_generate_key_packet_set(char *dest_base,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry,
+ size_t *len, size_t max);
+int process_request_key_err(long err_code);
+int
+ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned char *src, struct dentry *ecryptfs_dentry);
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
+int
+ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm,
+ char *cipher_name, size_t key_size);
+int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
+int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
+void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
+
+#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
new file mode 100644
index 0000000..c8550c9
--- /dev/null
+++ b/fs/ecryptfs/file.c
@@ -0,0 +1,440 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/security.h>
+#include <linux/smp_lock.h>
+#include <linux/compat.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_llseek
+ * @file: File we are seeking in
+ * @offset: The offset to seek to
+ * @origin: 2 - offset from i_size; 1 - offset from f_pos
+ *
+ * Returns the position we have seeked to, or negative on error
+ */
+static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
+{
+ loff_t rv;
+ loff_t new_end_pos;
+ int rc;
+ int expanding_file = 0;
+ struct inode *inode = file->f_mapping->host;
+
+ /* If our offset is past the end of our file, we're going to
+ * need to grow it so we have a valid length of 0's */
+ new_end_pos = offset;
+ switch (origin) {
+ case 2:
+ new_end_pos += i_size_read(inode);
+ expanding_file = 1;
+ break;
+ case 1:
+ new_end_pos += file->f_pos;
+ if (new_end_pos > i_size_read(inode)) {
+ ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
+ "> i_size_read(inode)(=[0x%.16x])\n",
+ new_end_pos, i_size_read(inode));
+ expanding_file = 1;
+ }
+ break;
+ default:
+ if (new_end_pos > i_size_read(inode)) {
+ ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
+ "> i_size_read(inode)(=[0x%.16x])\n",
+ new_end_pos, i_size_read(inode));
+ expanding_file = 1;
+ }
+ }
+ ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
+ if (expanding_file) {
+ rc = ecryptfs_truncate(file->f_dentry, new_end_pos);
+ if (rc) {
+ rv = rc;
+ ecryptfs_printk(KERN_ERR, "Error on attempt to "
+ "truncate to (higher) offset [0x%.16x];"
+ " rc = [%d]\n", new_end_pos, rc);
+ goto out;
+ }
+ }
+ rv = generic_file_llseek(file, offset, origin);
+out:
+ return rv;
+}
+
+/**
+ * ecryptfs_read_update_atime
+ *
+ * generic_file_read updates the atime of upper layer inode. But, it
+ * doesn't give us a chance to update the atime of the lower layer
+ * inode. This function is a wrapper to generic_file_read. It
+ * updates the atime of the lower level inode if generic_file_read
+ * returns without any errors. This is to be used only for file reads.
+ * The function to be used for directory reads is ecryptfs_read.
+ */
+static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
+ const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct vfsmount *lower_vfsmount;
+ struct file *file = iocb->ki_filp;
+
+ rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
+ /*
+ * Even though this is a async interface, we need to wait
+ * for IO to finish to update atime
+ */
+ if (-EIOCBQUEUED == rc)
+ rc = wait_on_sync_kiocb(iocb);
+ if (rc >= 0) {
+ lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry);
+ lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry);
+ touch_atime(lower_vfsmount, lower_dentry);
+ }
+ return rc;
+}
+
+struct ecryptfs_getdents_callback {
+ void *dirent;
+ struct dentry *dentry;
+ filldir_t filldir;
+ int err;
+ int filldir_called;
+ int entries_written;
+};
+
+/* Inspired by generic filldir in fs/readir.c */
+static int
+ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
+ u64 ino, unsigned int d_type)
+{
+ struct ecryptfs_crypt_stat *crypt_stat;
+ struct ecryptfs_getdents_callback *buf =
+ (struct ecryptfs_getdents_callback *)dirent;
+ int rc;
+ int decoded_length;
+ char *decoded_name;
+
+ crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat;
+ buf->filldir_called++;
+ decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen,
+ &decoded_name);
+ if (decoded_length < 0) {
+ rc = decoded_length;
+ goto out;
+ }
+ rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset,
+ ino, d_type);
+ kfree(decoded_name);
+ if (rc >= 0)
+ buf->entries_written++;
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_readdir
+ * @file: The ecryptfs file struct
+ * @dirent: Directory entry
+ * @filldir: The filldir callback function
+ */
+static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+ int rc;
+ struct file *lower_file;
+ struct inode *inode;
+ struct ecryptfs_getdents_callback buf;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ lower_file->f_pos = file->f_pos;
+ inode = file->f_dentry->d_inode;
+ memset(&buf, 0, sizeof(buf));
+ buf.dirent = dirent;
+ buf.dentry = file->f_dentry;
+ buf.filldir = filldir;
+retry:
+ buf.filldir_called = 0;
+ buf.entries_written = 0;
+ buf.err = 0;
+ rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
+ if (buf.err)
+ rc = buf.err;
+ if (buf.filldir_called && !buf.entries_written)
+ goto retry;
+ file->f_pos = lower_file->f_pos;
+ if (rc >= 0)
+ ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
+ return rc;
+}
+
+struct kmem_cache *ecryptfs_file_info_cache;
+
+/**
+ * ecryptfs_open
+ * @inode: inode speciying file to open
+ * @file: Structure to return filled in
+ *
+ * Opens the file specified by inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ struct ecryptfs_crypt_stat *crypt_stat = NULL;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+ struct dentry *ecryptfs_dentry = file->f_dentry;
+ /* Private value of ecryptfs_dentry allocated in
+ * ecryptfs_lookup() */
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ struct inode *lower_inode = NULL;
+ struct file *lower_file = NULL;
+ struct vfsmount *lower_mnt;
+ struct ecryptfs_file_info *file_info;
+ int lower_flags;
+
+ /* Released in ecryptfs_release or end of function if failure */
+ file_info = kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL);
+ ecryptfs_set_file_private(file, file_info);
+ if (!file_info) {
+ ecryptfs_printk(KERN_ERR,
+ "Error attempting to allocate memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(file_info, 0, sizeof(*file_info));
+ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+ mount_crypt_stat = &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ mutex_lock(&crypt_stat->cs_mutex);
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) {
+ ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
+ /* Policy code enabled in future release */
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ }
+ mutex_unlock(&crypt_stat->cs_mutex);
+ /* This mntget & dget is undone via fput when the file is released */
+ dget(lower_dentry);
+ lower_flags = file->f_flags;
+ if ((lower_flags & O_ACCMODE) == O_WRONLY)
+ lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
+ if (file->f_flags & O_APPEND)
+ lower_flags &= ~O_APPEND;
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+ mntget(lower_mnt);
+ /* Corresponding fput() in ecryptfs_release() */
+ lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags);
+ if (IS_ERR(lower_file)) {
+ rc = PTR_ERR(lower_file);
+ ecryptfs_printk(KERN_ERR, "Error opening lower file\n");
+ goto out_puts;
+ }
+ ecryptfs_set_file_lower(file, lower_file);
+ /* Isn't this check the same as the one in lookup? */
+ lower_inode = lower_dentry->d_inode;
+ if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ rc = 0;
+ goto out;
+ }
+ mutex_lock(&crypt_stat->cs_mutex);
+ if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+ if (!(mount_crypt_stat->flags
+ & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+ rc = -EIO;
+ printk(KERN_WARNING "Attempt to read file that is "
+ "not in a valid eCryptfs format, and plaintext "
+ "passthrough mode is not enabled; returning "
+ "-EIO\n");
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out_puts;
+ }
+ crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+ rc = 0;
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out;
+ } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_POLICY_APPLIED)
+ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_KEY_VALID)) {
+ rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG,
+ "Valid headers not found\n");
+ if (!(mount_crypt_stat->flags
+ & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+ rc = -EIO;
+ printk(KERN_WARNING "Attempt to read file that "
+ "is not in a valid eCryptfs format, "
+ "and plaintext passthrough mode is not "
+ "enabled; returning -EIO\n");
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out_puts;
+ }
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
+ ECRYPTFS_ENCRYPTED);
+ rc = 0;
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out;
+ }
+ }
+ mutex_unlock(&crypt_stat->cs_mutex);
+ ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
+ "size: [0x%.16x]\n", inode, inode->i_ino,
+ i_size_read(inode));
+ ecryptfs_set_file_lower(file, lower_file);
+ goto out;
+out_puts:
+ mntput(lower_mnt);
+ dput(lower_dentry);
+ kmem_cache_free(ecryptfs_file_info_cache,
+ ecryptfs_file_to_private(file));
+out:
+ return rc;
+}
+
+static int ecryptfs_flush(struct file *file, fl_owner_t td)
+{
+ int rc = 0;
+ struct file *lower_file = NULL;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file->f_op && lower_file->f_op->flush)
+ rc = lower_file->f_op->flush(lower_file, td);
+ return rc;
+}
+
+static int ecryptfs_release(struct inode *inode, struct file *file)
+{
+ struct file *lower_file = ecryptfs_file_to_lower(file);
+ struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file);
+ struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
+
+ fput(lower_file);
+ inode->i_blocks = lower_inode->i_blocks;
+ kmem_cache_free(ecryptfs_file_info_cache, file_info);
+ return 0;
+}
+
+static int
+ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ struct file *lower_file = ecryptfs_file_to_lower(file);
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct inode *lower_inode = lower_dentry->d_inode;
+ int rc = -EINVAL;
+
+ if (lower_inode->i_fop->fsync) {
+ mutex_lock(&lower_inode->i_mutex);
+ rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
+ datasync);
+ mutex_unlock(&lower_inode->i_mutex);
+ }
+ return rc;
+}
+
+static int ecryptfs_fasync(int fd, struct file *file, int flag)
+{
+ int rc = 0;
+ struct file *lower_file = NULL;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file->f_op && lower_file->f_op->fasync)
+ rc = lower_file->f_op->fasync(fd, lower_file, flag);
+ return rc;
+}
+
+static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos,
+ size_t count, read_actor_t actor, void *target)
+{
+ struct file *lower_file = NULL;
+ int rc = -EINVAL;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file->f_op && lower_file->f_op->sendfile)
+ rc = lower_file->f_op->sendfile(lower_file, ppos, count,
+ actor, target);
+
+ return rc;
+}
+
+static int ecryptfs_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+const struct file_operations ecryptfs_dir_fops = {
+ .readdir = ecryptfs_readdir,
+ .ioctl = ecryptfs_ioctl,
+ .mmap = generic_file_mmap,
+ .open = ecryptfs_open,
+ .flush = ecryptfs_flush,
+ .release = ecryptfs_release,
+ .fsync = ecryptfs_fsync,
+ .fasync = ecryptfs_fasync,
+ .sendfile = ecryptfs_sendfile,
+};
+
+const struct file_operations ecryptfs_main_fops = {
+ .llseek = ecryptfs_llseek,
+ .read = do_sync_read,
+ .aio_read = ecryptfs_read_update_atime,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
+ .readdir = ecryptfs_readdir,
+ .ioctl = ecryptfs_ioctl,
+ .mmap = generic_file_mmap,
+ .open = ecryptfs_open,
+ .flush = ecryptfs_flush,
+ .release = ecryptfs_release,
+ .fsync = ecryptfs_fsync,
+ .fasync = ecryptfs_fasync,
+ .sendfile = ecryptfs_sendfile,
+};
+
+static int
+ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+ struct file *lower_file = NULL;
+
+ if (ecryptfs_file_to_private(file))
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
+ rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode),
+ lower_file, cmd, arg);
+ else
+ rc = -ENOTTY;
+ return rc;
+}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
new file mode 100644
index 0000000..efdd2b7
--- /dev/null
+++ b/fs/ecryptfs/inode.c
@@ -0,0 +1,1079 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompsion <mcthomps@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/file.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/crypto.h>
+#include "ecryptfs_kernel.h"
+
+static struct dentry *lock_parent(struct dentry *dentry)
+{
+ struct dentry *dir;
+
+ dir = dget(dentry->d_parent);
+ mutex_lock(&(dir->d_inode->i_mutex));
+ return dir;
+}
+
+static void unlock_parent(struct dentry *dentry)
+{
+ mutex_unlock(&(dentry->d_parent->d_inode->i_mutex));
+ dput(dentry->d_parent);
+}
+
+static void unlock_dir(struct dentry *dir)
+{
+ mutex_unlock(&dir->d_inode->i_mutex);
+ dput(dir);
+}
+
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src)
+{
+ i_size_write(dst, i_size_read((struct inode *)src));
+ dst->i_blocks = src->i_blocks;
+}
+
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+}
+
+static void ecryptfs_copy_attr_times(struct inode *dest,
+ const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+}
+
+static void ecryptfs_copy_attr_timesizes(struct inode *dest,
+ const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+ ecryptfs_copy_inode_size(dest, src);
+}
+
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src)
+{
+ dest->i_mode = src->i_mode;
+ dest->i_nlink = src->i_nlink;
+ dest->i_uid = src->i_uid;
+ dest->i_gid = src->i_gid;
+ dest->i_rdev = src->i_rdev;
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+ dest->i_blkbits = src->i_blkbits;
+ dest->i_flags = src->i_flags;
+}
+
+/**
+ * ecryptfs_create_underlying_file
+ * @lower_dir_inode: inode of the parent in the lower fs of the new file
+ * @lower_dentry: New file's dentry in the lower fs
+ * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @mode: The mode of the new file
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
+ *
+ * Creates the file in the lower file system.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
+ struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+ struct dentry *dentry_save;
+ struct vfsmount *vfsmount_save;
+ int rc;
+
+ dentry_save = nd->dentry;
+ vfsmount_save = nd->mnt;
+ nd->dentry = lower_dentry;
+ nd->mnt = lower_mnt;
+ rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
+ nd->dentry = dentry_save;
+ nd->mnt = vfsmount_save;
+ return rc;
+}
+
+/**
+ * ecryptfs_do_create
+ * @directory_inode: inode of the new file's dentry's parent in ecryptfs
+ * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @mode: The mode of the new file
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
+ *
+ * Creates the underlying file and the eCryptfs inode which will link to
+ * it. It will also update the eCryptfs directory inode to mimic the
+ * stat of the lower directory inode.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_do_create(struct inode *directory_inode,
+ struct dentry *ecryptfs_dentry, int mode,
+ struct nameidata *nd)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ if (unlikely(IS_ERR(lower_dir_dentry))) {
+ ecryptfs_printk(KERN_ERR, "Error locking directory of "
+ "dentry\n");
+ rc = PTR_ERR(lower_dir_dentry);
+ goto out;
+ }
+ rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
+ ecryptfs_dentry, mode, nd);
+ if (unlikely(rc)) {
+ ecryptfs_printk(KERN_ERR,
+ "Failure to create underlying file\n");
+ goto out_lock;
+ }
+ rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
+ directory_inode->i_sb, 0);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
+ goto out_lock;
+ }
+ ecryptfs_copy_attr_timesizes(directory_inode,
+ lower_dir_dentry->d_inode);
+out_lock:
+ unlock_dir(lower_dir_dentry);
+out:
+ return rc;
+}
+
+/**
+ * grow_file
+ * @ecryptfs_dentry: the ecryptfs dentry
+ * @lower_file: The lower file
+ * @inode: The ecryptfs inode
+ * @lower_inode: The lower inode
+ *
+ * This is the code which will grow the file to its correct size.
+ */
+static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
+ struct inode *inode, struct inode *lower_inode)
+{
+ int rc = 0;
+ struct file fake_file;
+ struct ecryptfs_file_info tmp_file_info;
+
+ memset(&fake_file, 0, sizeof(fake_file));
+ fake_file.f_dentry = ecryptfs_dentry;
+ memset(&tmp_file_info, 0, sizeof(tmp_file_info));
+ ecryptfs_set_file_private(&fake_file, &tmp_file_info);
+ ecryptfs_set_file_lower(&fake_file, lower_file);
+ rc = ecryptfs_fill_zeros(&fake_file, 1);
+ if (rc) {
+ ECRYPTFS_SET_FLAG(
+ ecryptfs_inode_to_private(inode)->crypt_stat.flags,
+ ECRYPTFS_SECURITY_WARNING);
+ ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros "
+ "in file; rc = [%d]\n", rc);
+ goto out;
+ }
+ i_size_write(inode, 0);
+ ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+ ECRYPTFS_SET_FLAG(ecryptfs_inode_to_private(inode)->crypt_stat.flags,
+ ECRYPTFS_NEW_FILE);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_initialize_file
+ *
+ * Cause the file to be changed from a basic empty file to an ecryptfs
+ * file with a header and first data page.
+ *
+ * Returns zero on success
+ */
+static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
+{
+ int rc = 0;
+ int lower_flags;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ struct dentry *lower_dentry;
+ struct dentry *tlower_dentry = NULL;
+ struct file *lower_file;
+ struct inode *inode, *lower_inode;
+ struct vfsmount *lower_mnt;
+
+ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ ecryptfs_printk(KERN_DEBUG, "lower_dentry->d_name.name = [%s]\n",
+ lower_dentry->d_name.name);
+ inode = ecryptfs_dentry->d_inode;
+ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+ tlower_dentry = dget(lower_dentry);
+ if (!tlower_dentry) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry\n");
+ goto out;
+ }
+ lower_flags = ((O_CREAT | O_WRONLY | O_TRUNC) & O_ACCMODE) | O_RDWR;
+#if BITS_PER_LONG != 32
+ lower_flags |= O_LARGEFILE;
+#endif
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+ mntget(lower_mnt);
+ /* Corresponding fput() at end of this function */
+ lower_file = dentry_open(tlower_dentry, lower_mnt, lower_flags);
+ if (IS_ERR(lower_file)) {
+ rc = PTR_ERR(lower_file);
+ ecryptfs_printk(KERN_ERR,
+ "Error opening dentry; rc = [%i]\n", rc);
+ goto out;
+ }
+ /* fput(lower_file) should handle the puts if we do this */
+ lower_file->f_dentry = tlower_dentry;
+ lower_file->f_vfsmnt = lower_mnt;
+ lower_inode = tlower_dentry->d_inode;
+ if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ goto out_fput;
+ }
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
+ ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n");
+ rc = ecryptfs_new_file_context(ecryptfs_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG, "Error creating new file "
+ "context\n");
+ goto out_fput;
+ }
+ rc = ecryptfs_write_headers(ecryptfs_dentry, lower_file);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG, "Error writing headers\n");
+ goto out_fput;
+ }
+ rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode);
+out_fput:
+ fput(lower_file);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_create
+ * @dir: The inode of the directory in which to create the file.
+ * @dentry: The eCryptfs dentry
+ * @mode: The mode of the new file.
+ * @nd: nameidata
+ *
+ * Creates a new file.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
+ int mode, struct nameidata *nd)
+{
+ int rc;
+
+ rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);
+ if (unlikely(rc)) {
+ ecryptfs_printk(KERN_WARNING, "Failed to create file in"
+ "lower filesystem\n");
+ goto out;
+ }
+ /* At this point, a file exists on "disk"; we need to make sure
+ * that this on disk file is prepared to be an ecryptfs file */
+ rc = ecryptfs_initialize_file(ecryptfs_dentry);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_lookup
+ * @dir: inode
+ * @dentry: The dentry
+ * @nd: nameidata, may be NULL
+ *
+ * Find a file on disk. If the file does not exist, then we'll add it to the
+ * dentry cache and continue on to read it from the disk.
+ */
+static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ int rc = 0;
+ struct dentry *lower_dir_dentry;
+ struct dentry *lower_dentry;
+ struct vfsmount *lower_mnt;
+ struct dentry *tlower_dentry = NULL;
+ char *encoded_name;
+ unsigned int encoded_namelen;
+ struct ecryptfs_crypt_stat *crypt_stat = NULL;
+ char *page_virt = NULL;
+ struct inode *lower_inode;
+ u64 file_size;
+
+ lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
+ dentry->d_op = &ecryptfs_dops;
+ if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, "."))
+ || (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, "..")))
+ goto out_drop;
+ encoded_namelen = ecryptfs_encode_filename(crypt_stat,
+ dentry->d_name.name,
+ dentry->d_name.len,
+ &encoded_name);
+ if (encoded_namelen < 0) {
+ rc = encoded_namelen;
+ goto out_drop;
+ }
+ ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen "
+ "= [%d]\n", encoded_name, encoded_namelen);
+ lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry,
+ encoded_namelen - 1);
+ kfree(encoded_name);
+ lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
+ if (IS_ERR(lower_dentry)) {
+ ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n");
+ rc = PTR_ERR(lower_dentry);
+ goto out_drop;
+ }
+ ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->"
+ "d_name.name = [%s]\n", lower_dentry,
+ lower_dentry->d_name.name);
+ lower_inode = lower_dentry->d_inode;
+ ecryptfs_copy_attr_atime(dir, lower_dir_dentry->d_inode);
+ BUG_ON(!atomic_read(&lower_dentry->d_count));
+ ecryptfs_set_dentry_private(dentry,
+ kmem_cache_alloc(ecryptfs_dentry_info_cache,
+ SLAB_KERNEL));
+ if (!ecryptfs_dentry_to_private(dentry)) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Out of memory whilst attempting "
+ "to allocate ecryptfs_dentry_info struct\n");
+ goto out_dput;
+ }
+ ecryptfs_set_dentry_lower(dentry, lower_dentry);
+ ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt);
+ if (!lower_dentry->d_inode) {
+ /* We want to add because we couldn't find in lower */
+ d_add(dentry, NULL);
+ goto out;
+ }
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 1);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error interposing\n");
+ goto out_dput;
+ }
+ if (S_ISDIR(lower_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "Is a directory; returning\n");
+ goto out;
+ }
+ if (S_ISLNK(lower_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "Is a symlink; returning\n");
+ goto out;
+ }
+ if (!nd) {
+ ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave"
+ "as we *think* we are about to unlink\n");
+ goto out;
+ }
+ tlower_dentry = dget(lower_dentry);
+ if (!tlower_dentry || IS_ERR(tlower_dentry)) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Cannot dget lower_dentry\n");
+ goto out_dput;
+ }
+ /* Released in this function */
+ page_virt =
+ (char *)kmem_cache_alloc(ecryptfs_header_cache_2,
+ SLAB_USER);
+ if (!page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR,
+ "Cannot ecryptfs_kmalloc a page\n");
+ goto out_dput;
+ }
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd->mnt);
+ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED))
+ ecryptfs_set_default_sizes(crypt_stat);
+ if (rc) {
+ rc = 0;
+ ecryptfs_printk(KERN_WARNING, "Error reading header region;"
+ " assuming unencrypted\n");
+ } else {
+ if (!contains_ecryptfs_marker(page_virt
+ + ECRYPTFS_FILE_SIZE_BYTES)) {
+ kmem_cache_free(ecryptfs_header_cache_2, page_virt);
+ goto out;
+ }
+ memcpy(&file_size, page_virt, sizeof(file_size));
+ file_size = be64_to_cpu(file_size);
+ i_size_write(dentry->d_inode, (loff_t)file_size);
+ }
+ kmem_cache_free(ecryptfs_header_cache_2, page_virt);
+ goto out;
+
+out_dput:
+ dput(lower_dentry);
+ if (tlower_dentry)
+ dput(tlower_dentry);
+out_drop:
+ d_drop(dentry);
+out:
+ return ERR_PTR(rc);
+}
+
+static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *new_dentry)
+{
+ struct dentry *lower_old_dentry;
+ struct dentry *lower_new_dentry;
+ struct dentry *lower_dir_dentry;
+ u64 file_size_save;
+ int rc;
+
+ file_size_save = i_size_read(old_dentry->d_inode);
+ lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+ lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+ dget(lower_old_dentry);
+ dget(lower_new_dentry);
+ lower_dir_dentry = lock_parent(lower_new_dentry);
+ rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
+ lower_new_dentry);
+ if (rc || !lower_new_dentry->d_inode)
+ goto out_lock;
+ rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
+ if (rc)
+ goto out_lock;
+ ecryptfs_copy_attr_timesizes(dir, lower_new_dentry->d_inode);
+ old_dentry->d_inode->i_nlink =
+ ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
+ i_size_write(new_dentry->d_inode, file_size_save);
+out_lock:
+ unlock_dir(lower_dir_dentry);
+ dput(lower_new_dentry);
+ dput(lower_old_dentry);
+ if (!new_dentry->d_inode)
+ d_drop(new_dentry);
+ return rc;
+}
+
+static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ int rc = 0;
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
+
+ lock_parent(lower_dentry);
+ rc = vfs_unlink(lower_dir_inode, lower_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error in vfs_unlink\n");
+ goto out_unlock;
+ }
+ ecryptfs_copy_attr_times(dir, lower_dir_inode);
+ dentry->d_inode->i_nlink =
+ ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;
+ dentry->d_inode->i_ctime = dir->i_ctime;
+out_unlock:
+ unlock_parent(lower_dentry);
+ return rc;
+}
+
+static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+ umode_t mode;
+ char *encoded_symname;
+ unsigned int encoded_symlen;
+ struct ecryptfs_crypt_stat *crypt_stat = NULL;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ dget(lower_dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ mode = S_IALLUGO;
+ encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
+ strlen(symname),
+ &encoded_symname);
+ if (encoded_symlen < 0) {
+ rc = encoded_symlen;
+ goto out_lock;
+ }
+ rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
+ encoded_symname, mode);
+ kfree(encoded_symname);
+ if (rc || !lower_dentry->d_inode)
+ goto out_lock;
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+ if (rc)
+ goto out_lock;
+ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out_lock:
+ unlock_dir(lower_dir_dentry);
+ dput(lower_dentry);
+ if (!dentry->d_inode)
+ d_drop(dentry);
+ return rc;
+}
+
+static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
+ if (rc || !lower_dentry->d_inode)
+ goto out;
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+ if (rc)
+ goto out;
+ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+ dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+out:
+ unlock_dir(lower_dir_dentry);
+ if (!dentry->d_inode)
+ d_drop(dentry);
+ return rc;
+}
+
+static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ int rc = 0;
+ struct dentry *tdentry = NULL;
+ struct dentry *lower_dentry;
+ struct dentry *tlower_dentry = NULL;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!(tdentry = dget(dentry))) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "Error dget'ing dentry [%p]\n",
+ dentry);
+ goto out;
+ }
+ lower_dir_dentry = lock_parent(lower_dentry);
+ if (!(tlower_dentry = dget(lower_dentry))) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry "
+ "[%p]\n", lower_dentry);
+ goto out;
+ }
+ rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
+ if (!rc) {
+ d_delete(tlower_dentry);
+ tlower_dentry = NULL;
+ }
+ ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+ unlock_dir(lower_dir_dentry);
+ if (!rc)
+ d_drop(dentry);
+out:
+ if (tdentry)
+ dput(tdentry);
+ if (tlower_dentry)
+ dput(tlower_dentry);
+ return rc;
+}
+
+static int
+ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
+ if (rc || !lower_dentry->d_inode)
+ goto out;
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+ if (rc)
+ goto out;
+ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out:
+ unlock_dir(lower_dir_dentry);
+ if (!dentry->d_inode)
+ d_drop(dentry);
+ return rc;
+}
+
+static int
+ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ int rc;
+ struct dentry *lower_old_dentry;
+ struct dentry *lower_new_dentry;
+ struct dentry *lower_old_dir_dentry;
+ struct dentry *lower_new_dir_dentry;
+
+ lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+ lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+ dget(lower_old_dentry);
+ dget(lower_new_dentry);
+ lower_old_dir_dentry = dget_parent(lower_old_dentry);
+ lower_new_dir_dentry = dget_parent(lower_new_dentry);
+ lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+ rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
+ lower_new_dir_dentry->d_inode, lower_new_dentry);
+ if (rc)
+ goto out_lock;
+ ecryptfs_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
+ if (new_dir != old_dir)
+ ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
+out_lock:
+ unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+ dput(lower_new_dentry);
+ dput(lower_old_dentry);
+ return rc;
+}
+
+static int
+ecryptfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ char *decoded_name;
+ char *lower_buf;
+ mm_segment_t old_fs;
+ struct ecryptfs_crypt_stat *crypt_stat;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op ||
+ !lower_dentry->d_inode->i_op->readlink) {
+ rc = -EINVAL;
+ goto out;
+ }
+ /* Released in this function */
+ lower_buf = kmalloc(bufsiz, GFP_KERNEL);
+ if (lower_buf == NULL) {
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
+ "lower_dentry->d_name.name = [%s]\n",
+ lower_dentry->d_name.name);
+ rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
+ (char __user *)lower_buf,
+ bufsiz);
+ set_fs(old_fs);
+ if (rc >= 0) {
+ crypt_stat = NULL;
+ rc = ecryptfs_decode_filename(crypt_stat, lower_buf, rc,
+ &decoded_name);
+ if (rc == -ENOMEM)
+ goto out_free_lower_buf;
+ if (rc > 0) {
+ ecryptfs_printk(KERN_DEBUG, "Copying [%d] bytes "
+ "to userspace: [%*s]\n", rc,
+ decoded_name);
+ if (copy_to_user(buf, decoded_name, rc))
+ rc = -EFAULT;
+ }
+ kfree(decoded_name);
+ ecryptfs_copy_attr_atime(dentry->d_inode,
+ lower_dentry->d_inode);
+ }
+out_free_lower_buf:
+ kfree(lower_buf);
+out:
+ return rc;
+}
+
+static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ char *buf;
+ int len = PAGE_SIZE, rc;
+ mm_segment_t old_fs;
+
+ /* Released in ecryptfs_put_link(); only release here on error */
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
+ "dentry->d_name.name = [%s]\n", dentry->d_name.name);
+ rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
+ buf[rc] = '\0';
+ set_fs(old_fs);
+ if (rc < 0)
+ goto out_free;
+ rc = 0;
+ nd_set_link(nd, buf);
+ goto out;
+out_free:
+ kfree(buf);
+out:
+ return ERR_PTR(rc);
+}
+
+static void
+ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+{
+ /* Free the char* */
+ kfree(nd_get_link(nd));
+}
+
+/**
+ * upper_size_to_lower_size
+ * @crypt_stat: Crypt_stat associated with file
+ * @upper_size: Size of the upper file
+ *
+ * Calculate the requried size of the lower file based on the
+ * specified size of the upper file. This calculation is based on the
+ * number of headers in the underlying file and the extent size.
+ *
+ * Returns Calculated size of the lower file.
+ */
+static loff_t
+upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
+ loff_t upper_size)
+{
+ loff_t lower_size;
+
+ lower_size = ( crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front );
+ if (upper_size != 0) {
+ loff_t num_extents;
+
+ num_extents = upper_size >> crypt_stat->extent_shift;
+ if (upper_size & ~crypt_stat->extent_mask)
+ num_extents++;
+ lower_size += (num_extents * crypt_stat->extent_size);
+ }
+ return lower_size;
+}
+
+/**
+ * ecryptfs_truncate
+ * @dentry: The ecryptfs layer dentry
+ * @new_length: The length to expand the file to
+ *
+ * Function to handle truncations modifying the size of the file. Note
+ * that the file sizes are interpolated. When expanding, we are simply
+ * writing strings of 0's out. When truncating, we need to modify the
+ * underlying file size according to the page index interpolations.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
+{
+ int rc = 0;
+ struct inode *inode = dentry->d_inode;
+ struct dentry *lower_dentry;
+ struct vfsmount *lower_mnt;
+ struct file fake_ecryptfs_file, *lower_file = NULL;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ loff_t i_size = i_size_read(inode);
+ loff_t lower_size_before_truncate;
+ loff_t lower_size_after_truncate;
+
+ if (unlikely((new_length == i_size)))
+ goto out;
+ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+ /* Set up a fake ecryptfs file, this is used to interface with
+ * the file in the underlying filesystem so that the
+ * truncation has an effect there as well. */
+ memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file));
+ fake_ecryptfs_file.f_dentry = dentry;
+ /* Released at out_free: label */
+ ecryptfs_set_file_private(&fake_ecryptfs_file,
+ kmem_cache_alloc(ecryptfs_file_info_cache,
+ SLAB_KERNEL));
+ if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ /* This dget & mntget is released through fput at out_fput: */
+ dget(lower_dentry);
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+ mntget(lower_mnt);
+ lower_file = dentry_open(lower_dentry, lower_mnt, O_RDWR);
+ if (unlikely(IS_ERR(lower_file))) {
+ rc = PTR_ERR(lower_file);
+ goto out_free;
+ }
+ ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file);
+ /* Switch on growing or shrinking file */
+ if (new_length > i_size) {
+ rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR,
+ "Problem with fill_zeros\n");
+ goto out_fput;
+ }
+ i_size_write(inode, new_length);
+ rc = ecryptfs_write_inode_size_to_header(lower_file,
+ lower_dentry->d_inode,
+ inode);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR,
+ "Problem with ecryptfs_write"
+ "_inode_size\n");
+ goto out_fput;
+ }
+ } else { /* new_length < i_size_read(inode) */
+ vmtruncate(inode, new_length);
+ ecryptfs_write_inode_size_to_header(lower_file,
+ lower_dentry->d_inode,
+ inode);
+ /* We are reducing the size of the ecryptfs file, and need to
+ * know if we need to reduce the size of the lower file. */
+ lower_size_before_truncate =
+ upper_size_to_lower_size(crypt_stat, i_size);
+ lower_size_after_truncate =
+ upper_size_to_lower_size(crypt_stat, new_length);
+ if (lower_size_after_truncate < lower_size_before_truncate)
+ vmtruncate(lower_dentry->d_inode,
+ lower_size_after_truncate);
+ }
+ /* Update the access times */
+ lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime
+ = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+out_fput:
+ fput(lower_file);
+out_free:
+ if (ecryptfs_file_to_private(&fake_ecryptfs_file))
+ kmem_cache_free(ecryptfs_file_info_cache,
+ ecryptfs_file_to_private(&fake_ecryptfs_file));
+out:
+ return rc;
+}
+
+static int
+ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ int rc;
+
+ if (nd) {
+ struct vfsmount *vfsmnt_save = nd->mnt;
+ struct dentry *dentry_save = nd->dentry;
+
+ nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry);
+ nd->dentry = ecryptfs_dentry_to_lower(nd->dentry);
+ rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
+ nd->mnt = vfsmnt_save;
+ nd->dentry = dentry_save;
+ } else
+ rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
+ return rc;
+}
+
+/**
+ * ecryptfs_setattr
+ * @dentry: dentry handle to the inode to modify
+ * @ia: Structure with flags of what to change and values
+ *
+ * Updates the metadata of an inode. If the update is to the size
+ * i.e. truncation, then ecryptfs_truncate will handle the size modification
+ * of both the ecryptfs inode and the lower inode.
+ *
+ * All other metadata changes will be passed right to the lower filesystem,
+ * and we will just update our inode to look like the lower.
+ */
+static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+ struct inode *inode;
+ struct inode *lower_inode;
+ struct ecryptfs_crypt_stat *crypt_stat;
+
+ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ inode = dentry->d_inode;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ if (ia->ia_valid & ATTR_SIZE) {
+ ecryptfs_printk(KERN_DEBUG,
+ "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",
+ ia->ia_valid, ATTR_SIZE);
+ rc = ecryptfs_truncate(dentry, ia->ia_size);
+ /* ecryptfs_truncate handles resizing of the lower file */
+ ia->ia_valid &= ~ATTR_SIZE;
+ ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n",
+ ia->ia_valid);
+ if (rc < 0)
+ goto out;
+ }
+ rc = notify_change(lower_dentry, ia);
+out:
+ ecryptfs_copy_attr_all(inode, lower_inode);
+ return rc;
+}
+
+static int
+ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+ size_t size, int flags)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->setxattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value,
+ size, flags);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+static ssize_t
+ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
+ size_t size)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->getxattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value,
+ size);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+static ssize_t
+ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->listxattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+static int ecryptfs_removexattr(struct dentry *dentry, const char *name)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->removexattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode)
+{
+ if ((ecryptfs_inode_to_lower(inode)
+ == (struct inode *)candidate_lower_inode))
+ return 1;
+ else
+ return 0;
+}
+
+int ecryptfs_inode_set(struct inode *inode, void *lower_inode)
+{
+ ecryptfs_init_inode(inode, (struct inode *)lower_inode);
+ return 0;
+}
+
+struct inode_operations ecryptfs_symlink_iops = {
+ .readlink = ecryptfs_readlink,
+ .follow_link = ecryptfs_follow_link,
+ .put_link = ecryptfs_put_link,
+ .permission = ecryptfs_permission,
+ .setattr = ecryptfs_setattr,
+ .setxattr = ecryptfs_setxattr,
+ .getxattr = ecryptfs_getxattr,
+ .listxattr = ecryptfs_listxattr,
+ .removexattr = ecryptfs_removexattr
+};
+
+struct inode_operations ecryptfs_dir_iops = {
+ .create = ecryptfs_create,
+ .lookup = ecryptfs_lookup,
+ .link = ecryptfs_link,
+ .unlink = ecryptfs_unlink,
+ .symlink = ecryptfs_symlink,
+ .mkdir = ecryptfs_mkdir,
+ .rmdir = ecryptfs_rmdir,
+ .mknod = ecryptfs_mknod,
+ .rename = ecryptfs_rename,
+ .permission = ecryptfs_permission,
+ .setattr = ecryptfs_setattr,
+ .setxattr = ecryptfs_setxattr,
+ .getxattr = ecryptfs_getxattr,
+ .listxattr = ecryptfs_listxattr,
+ .removexattr = ecryptfs_removexattr
+};
+
+struct inode_operations ecryptfs_main_iops = {
+ .permission = ecryptfs_permission,
+ .setattr = ecryptfs_setattr,
+ .setxattr = ecryptfs_setxattr,
+ .getxattr = ecryptfs_getxattr,
+ .listxattr = ecryptfs_listxattr,
+ .removexattr = ecryptfs_removexattr
+};
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
new file mode 100644
index 0000000..ba45478
--- /dev/null
+++ b/fs/ecryptfs/keystore.c
@@ -0,0 +1,1061 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * In-kernel key management code. Includes functions to parse and
+ * write authentication token-related packets with the underlying
+ * file.
+ *
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * request_key returned an error instead of a valid key address;
+ * determine the type of error, make appropriate log entries, and
+ * return an error code.
+ */
+int process_request_key_err(long err_code)
+{
+ int rc = 0;
+
+ switch (err_code) {
+ case ENOKEY:
+ ecryptfs_printk(KERN_WARNING, "No key\n");
+ rc = -ENOENT;
+ break;
+ case EKEYEXPIRED:
+ ecryptfs_printk(KERN_WARNING, "Key expired\n");
+ rc = -ETIME;
+ break;
+ case EKEYREVOKED:
+ ecryptfs_printk(KERN_WARNING, "Key revoked\n");
+ rc = -EINVAL;
+ break;
+ default:
+ ecryptfs_printk(KERN_WARNING, "Unknown error code: "
+ "[0x%.16x]\n", err_code);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static void wipe_auth_tok_list(struct list_head *auth_tok_list_head)
+{
+ struct list_head *walker;
+ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+
+ walker = auth_tok_list_head->next;
+ while (walker != auth_tok_list_head) {
+ auth_tok_list_item =
+ list_entry(walker, struct ecryptfs_auth_tok_list_item,
+ list);
+ walker = auth_tok_list_item->list.next;
+ memset(auth_tok_list_item, 0,
+ sizeof(struct ecryptfs_auth_tok_list_item));
+ kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+ auth_tok_list_item);
+ }
+}
+
+struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
+
+/**
+ * parse_packet_length
+ * @data: Pointer to memory containing length at offset
+ * @size: This function writes the decoded size to this memory
+ * address; zero on error
+ * @length_size: The number of bytes occupied by the encoded length
+ *
+ * Returns Zero on success
+ */
+static int parse_packet_length(unsigned char *data, size_t *size,
+ size_t *length_size)
+{
+ int rc = 0;
+
+ (*length_size) = 0;
+ (*size) = 0;
+ if (data[0] < 192) {
+ /* One-byte length */
+ (*size) = data[0];
+ (*length_size) = 1;
+ } else if (data[0] < 224) {
+ /* Two-byte length */
+ (*size) = ((data[0] - 192) * 256);
+ (*size) += (data[1] + 192);
+ (*length_size) = 2;
+ } else if (data[0] == 255) {
+ /* Five-byte length; we're not supposed to see this */
+ ecryptfs_printk(KERN_ERR, "Five-byte packet length not "
+ "supported\n");
+ rc = -EINVAL;
+ goto out;
+ } else {
+ ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");
+ rc = -EINVAL;
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * write_packet_length
+ * @dest: The byte array target into which to write the
+ * length. Must have at least 5 bytes allocated.
+ * @size: The length to write.
+ * @packet_size_length: The number of bytes used to encode the
+ * packet length is written to this address.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int write_packet_length(char *dest, size_t size,
+ size_t *packet_size_length)
+{
+ int rc = 0;
+
+ if (size < 192) {
+ dest[0] = size;
+ (*packet_size_length) = 1;
+ } else if (size < 65536) {
+ dest[0] = (((size - 192) / 256) + 192);
+ dest[1] = ((size - 192) % 256);
+ (*packet_size_length) = 2;
+ } else {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING,
+ "Unsupported packet size: [%d]\n", size);
+ }
+ return rc;
+}
+
+/**
+ * parse_tag_3_packet
+ * @crypt_stat: The cryptographic context to modify based on packet
+ * contents.
+ * @data: The raw bytes of the packet.
+ * @auth_tok_list: eCryptfs parses packets into authentication tokens;
+ * a new authentication token will be placed at the end
+ * of this list for this packet.
+ * @new_auth_tok: Pointer to a pointer to memory that this function
+ * allocates; sets the memory address of the pointer to
+ * NULL on error. This object is added to the
+ * auth_tok_list.
+ * @packet_size: This function writes the size of the parsed packet
+ * into this memory location; zero on error.
+ * @max_packet_size: maximum number of bytes to parse
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned char *data, struct list_head *auth_tok_list,
+ struct ecryptfs_auth_tok **new_auth_tok,
+ size_t *packet_size, size_t max_packet_size)
+{
+ int rc = 0;
+ size_t body_size;
+ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+ size_t length_size;
+
+ (*packet_size) = 0;
+ (*new_auth_tok) = NULL;
+
+ /* we check that:
+ * one byte for the Tag 3 ID flag
+ * two bytes for the body size
+ * do not exceed the maximum_packet_size
+ */
+ if (unlikely((*packet_size) + 3 > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* check for Tag 3 identifyer - one byte */
+ if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {
+ ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n",
+ ECRYPTFS_TAG_3_PACKET_TYPE);
+ rc = -EINVAL;
+ goto out;
+ }
+ /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
+ * at end of function upon failure */
+ auth_tok_list_item =
+ kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, SLAB_KERNEL);
+ if (!auth_tok_list_item) {
+ ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(auth_tok_list_item, 0,
+ sizeof(struct ecryptfs_auth_tok_list_item));
+ (*new_auth_tok) = &auth_tok_list_item->auth_tok;
+
+ /* check for body size - one to two bytes */
+ rc = parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
+ "rc = [%d]\n", rc);
+ goto out_free;
+ }
+ if (unlikely(body_size < (0x05 + ECRYPTFS_SALT_SIZE))) {
+ ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
+ body_size);
+ rc = -EINVAL;
+ goto out_free;
+ }
+ (*packet_size) += length_size;
+
+ /* now we know the length of the remainting Tag 3 packet size:
+ * 5 fix bytes for: version string, cipher, S2K ID, hash algo,
+ * number of hash iterations
+ * ECRYPTFS_SALT_SIZE bytes for salt
+ * body_size bytes minus the stuff above is the encrypted key size
+ */
+ if (unlikely((*packet_size) + body_size > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out_free;
+ }
+
+ /* There are 5 characters of additional information in the
+ * packet */
+ (*new_auth_tok)->session_key.encrypted_key_size =
+ body_size - (0x05 + ECRYPTFS_SALT_SIZE);
+ ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n",
+ (*new_auth_tok)->session_key.encrypted_key_size);
+
+ /* Version 4 (from RFC2440) - one byte */
+ if (unlikely(data[(*packet_size)++] != 0x04)) {
+ ecryptfs_printk(KERN_DEBUG, "Unknown version number "
+ "[%d]\n", data[(*packet_size) - 1]);
+ rc = -EINVAL;
+ goto out_free;
+ }
+
+ /* cipher - one byte */
+ ecryptfs_cipher_code_to_string(crypt_stat->cipher,
+ (u16)data[(*packet_size)]);
+ /* A little extra work to differentiate among the AES key
+ * sizes; see RFC2440 */
+ switch(data[(*packet_size)++]) {
+ case RFC2440_CIPHER_AES_192:
+ crypt_stat->key_size = 24;
+ break;
+ default:
+ crypt_stat->key_size =
+ (*new_auth_tok)->session_key.encrypted_key_size;
+ }
+ ecryptfs_init_crypt_ctx(crypt_stat);
+ /* S2K identifier 3 (from RFC2440) */
+ if (unlikely(data[(*packet_size)++] != 0x03)) {
+ ecryptfs_printk(KERN_ERR, "Only S2K ID 3 is currently "
+ "supported\n");
+ rc = -ENOSYS;
+ goto out_free;
+ }
+
+ /* TODO: finish the hash mapping */
+ /* hash algorithm - one byte */
+ switch (data[(*packet_size)++]) {
+ case 0x01: /* See RFC2440 for these numbers and their mappings */
+ /* Choose MD5 */
+ /* salt - ECRYPTFS_SALT_SIZE bytes */
+ memcpy((*new_auth_tok)->token.password.salt,
+ &data[(*packet_size)], ECRYPTFS_SALT_SIZE);
+ (*packet_size) += ECRYPTFS_SALT_SIZE;
+
+ /* This conversion was taken straight from RFC2440 */
+ /* number of hash iterations - one byte */
+ (*new_auth_tok)->token.password.hash_iterations =
+ ((u32) 16 + (data[(*packet_size)] & 15))
+ << ((data[(*packet_size)] >> 4) + 6);
+ (*packet_size)++;
+
+ /* encrypted session key -
+ * (body_size-5-ECRYPTFS_SALT_SIZE) bytes */
+ memcpy((*new_auth_tok)->session_key.encrypted_key,
+ &data[(*packet_size)],
+ (*new_auth_tok)->session_key.encrypted_key_size);
+ (*packet_size) +=
+ (*new_auth_tok)->session_key.encrypted_key_size;
+ (*new_auth_tok)->session_key.flags &=
+ ~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+ (*new_auth_tok)->session_key.flags |=
+ ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
+ (*new_auth_tok)->token.password.hash_algo = 0x01;
+ break;
+ default:
+ ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: "
+ "[%d]\n", data[(*packet_size) - 1]);
+ rc = -ENOSYS;
+ goto out_free;
+ }
+ (*new_auth_tok)->token_type = ECRYPTFS_PASSWORD;
+ /* TODO: Parametarize; we might actually want userspace to
+ * decrypt the session key. */
+ ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
+ ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
+ ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
+ ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
+ list_add(&auth_tok_list_item->list, auth_tok_list);
+ goto out;
+out_free:
+ (*new_auth_tok) = NULL;
+ memset(auth_tok_list_item, 0,
+ sizeof(struct ecryptfs_auth_tok_list_item));
+ kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+ auth_tok_list_item);
+out:
+ if (rc)
+ (*packet_size) = 0;
+ return rc;
+}
+
+/**
+ * parse_tag_11_packet
+ * @data: The raw bytes of the packet
+ * @contents: This function writes the data contents of the literal
+ * packet into this memory location
+ * @max_contents_bytes: The maximum number of bytes that this function
+ * is allowed to write into contents
+ * @tag_11_contents_size: This function writes the size of the parsed
+ * contents into this memory location; zero on
+ * error
+ * @packet_size: This function writes the size of the parsed packet
+ * into this memory location; zero on error
+ * @max_packet_size: maximum number of bytes to parse
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+parse_tag_11_packet(unsigned char *data, unsigned char *contents,
+ size_t max_contents_bytes, size_t *tag_11_contents_size,
+ size_t *packet_size, size_t max_packet_size)
+{
+ int rc = 0;
+ size_t body_size;
+ size_t length_size;
+
+ (*packet_size) = 0;
+ (*tag_11_contents_size) = 0;
+
+ /* check that:
+ * one byte for the Tag 11 ID flag
+ * two bytes for the Tag 11 length
+ * do not exceed the maximum_packet_size
+ */
+ if (unlikely((*packet_size) + 3 > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* check for Tag 11 identifyer - one byte */
+ if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) {
+ ecryptfs_printk(KERN_WARNING,
+ "Invalid tag 11 packet format\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* get Tag 11 content length - one or two bytes */
+ rc = parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING,
+ "Invalid tag 11 packet format\n");
+ goto out;
+ }
+ (*packet_size) += length_size;
+
+ if (body_size < 13) {
+ ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
+ body_size);
+ rc = -EINVAL;
+ goto out;
+ }
+ /* We have 13 bytes of surrounding packet values */
+ (*tag_11_contents_size) = (body_size - 13);
+
+ /* now we know the length of the remainting Tag 11 packet size:
+ * 14 fix bytes for: special flag one, special flag two,
+ * 12 skipped bytes
+ * body_size bytes minus the stuff above is the Tag 11 content
+ */
+ /* FIXME why is the body size one byte smaller than the actual
+ * size of the body?
+ * this seems to be an error here as well as in
+ * write_tag_11_packet() */
+ if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* special flag one - one byte */
+ if (data[(*packet_size)++] != 0x62) {
+ ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* special flag two - one byte */
+ if (data[(*packet_size)++] != 0x08) {
+ ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* skip the next 12 bytes */
+ (*packet_size) += 12; /* We don't care about the filename or
+ * the timestamp */
+
+ /* get the Tag 11 contents - tag_11_contents_size bytes */
+ memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size));
+ (*packet_size) += (*tag_11_contents_size);
+
+out:
+ if (rc) {
+ (*packet_size) = 0;
+ (*tag_11_contents_size) = 0;
+ }
+ return rc;
+}
+
+/**
+ * decrypt_session_key - Decrypt the session key with the given auth_tok.
+ *
+ * Returns Zero on success; non-zero error otherwise.
+ */
+static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
+ struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int rc = 0;
+ struct ecryptfs_password *password_s_ptr;
+ struct crypto_tfm *tfm = NULL;
+ struct scatterlist src_sg[2], dst_sg[2];
+ struct mutex *tfm_mutex = NULL;
+ /* TODO: Use virt_to_scatterlist for these */
+ char *encrypted_session_key;
+ char *session_key;
+
+ password_s_ptr = &auth_tok->token.password;
+ if (ECRYPTFS_CHECK_FLAG(password_s_ptr->flags,
+ ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET))
+ ecryptfs_printk(KERN_DEBUG, "Session key encryption key "
+ "set; skipping key generation\n");
+ ecryptfs_printk(KERN_DEBUG, "Session key encryption key (size [%d])"
+ ":\n",
+ password_s_ptr->session_key_encryption_key_bytes);
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(password_s_ptr->session_key_encryption_key,
+ password_s_ptr->
+ session_key_encryption_key_bytes);
+ if (!strcmp(crypt_stat->cipher,
+ crypt_stat->mount_crypt_stat->global_default_cipher_name)
+ && crypt_stat->mount_crypt_stat->global_key_tfm) {
+ tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
+ tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
+ } else {
+ tfm = crypto_alloc_tfm(crypt_stat->cipher,
+ CRYPTO_TFM_REQ_WEAK_KEY);
+ if (!tfm) {
+ printk(KERN_ERR "Error allocating crypto context\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ }
+ if (password_s_ptr->session_key_encryption_key_bytes
+ < crypto_tfm_alg_min_keysize(tfm)) {
+ printk(KERN_WARNING "Session key encryption key is [%d] bytes; "
+ "minimum keysize for selected cipher is [%d] bytes.\n",
+ password_s_ptr->session_key_encryption_key_bytes,
+ crypto_tfm_alg_min_keysize(tfm));
+ rc = -EINVAL;
+ goto out;
+ }
+ if (tfm_mutex)
+ mutex_lock(tfm_mutex);
+ crypto_cipher_setkey(tfm, password_s_ptr->session_key_encryption_key,
+ crypt_stat->key_size);
+ /* TODO: virt_to_scatterlist */
+ encrypted_session_key = (char *)__get_free_page(GFP_KERNEL);
+ if (!encrypted_session_key) {
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out_free_tfm;
+ }
+ session_key = (char *)__get_free_page(GFP_KERNEL);
+ if (!session_key) {
+ kfree(encrypted_session_key);
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out_free_tfm;
+ }
+ memcpy(encrypted_session_key, auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.encrypted_key_size);
+ src_sg[0].page = virt_to_page(encrypted_session_key);
+ src_sg[0].offset = 0;
+ BUG_ON(auth_tok->session_key.encrypted_key_size > PAGE_CACHE_SIZE);
+ src_sg[0].length = auth_tok->session_key.encrypted_key_size;
+ dst_sg[0].page = virt_to_page(session_key);
+ dst_sg[0].offset = 0;
+ auth_tok->session_key.decrypted_key_size =
+ auth_tok->session_key.encrypted_key_size;
+ dst_sg[0].length = auth_tok->session_key.encrypted_key_size;
+ /* TODO: Handle error condition */
+ crypto_cipher_decrypt(tfm, dst_sg, src_sg,
+ auth_tok->session_key.encrypted_key_size);
+ auth_tok->session_key.decrypted_key_size =
+ auth_tok->session_key.encrypted_key_size;
+ memcpy(auth_tok->session_key.decrypted_key, session_key,
+ auth_tok->session_key.decrypted_key_size);
+ auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+ memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
+ auth_tok->session_key.decrypted_key_size);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(crypt_stat->key,
+ crypt_stat->key_size);
+ memset(encrypted_session_key, 0, PAGE_CACHE_SIZE);
+ free_page((unsigned long)encrypted_session_key);
+ memset(session_key, 0, PAGE_CACHE_SIZE);
+ free_page((unsigned long)session_key);
+out_free_tfm:
+ if (tfm_mutex)
+ mutex_unlock(tfm_mutex);
+ else
+ crypto_free_tfm(tfm);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_parse_packet_set
+ * @dest: The header page in memory
+ * @version: Version of file format, to guide parsing behavior
+ *
+ * Get crypt_stat to have the file's session key if the requisite key
+ * is available to decrypt the session key.
+ *
+ * Returns Zero if a valid authentication token was retrieved and
+ * processed; negative value for file not encrypted or for error
+ * conditions.
+ */
+int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned char *src,
+ struct dentry *ecryptfs_dentry)
+{
+ size_t i = 0;
+ int rc = 0;
+ size_t found_auth_tok = 0;
+ size_t next_packet_is_auth_tok_packet;
+ char sig[ECRYPTFS_SIG_SIZE_HEX];
+ struct list_head auth_tok_list;
+ struct list_head *walker;
+ struct ecryptfs_auth_tok *chosen_auth_tok = NULL;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ struct ecryptfs_auth_tok *candidate_auth_tok = NULL;
+ size_t packet_size;
+ struct ecryptfs_auth_tok *new_auth_tok;
+ unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE];
+ size_t tag_11_contents_size;
+ size_t tag_11_packet_size;
+
+ INIT_LIST_HEAD(&auth_tok_list);
+ /* Parse the header to find as many packets as we can, these will be
+ * added the our &auth_tok_list */
+ next_packet_is_auth_tok_packet = 1;
+ while (next_packet_is_auth_tok_packet) {
+ size_t max_packet_size = ((PAGE_CACHE_SIZE - 8) - i);
+
+ switch (src[i]) {
+ case ECRYPTFS_TAG_3_PACKET_TYPE:
+ rc = parse_tag_3_packet(crypt_stat,
+ (unsigned char *)&src[i],
+ &auth_tok_list, &new_auth_tok,
+ &packet_size, max_packet_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error parsing "
+ "tag 3 packet\n");
+ rc = -EIO;
+ goto out_wipe_list;
+ }
+ i += packet_size;
+ rc = parse_tag_11_packet((unsigned char *)&src[i],
+ sig_tmp_space,
+ ECRYPTFS_SIG_SIZE,
+ &tag_11_contents_size,
+ &tag_11_packet_size,
+ max_packet_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "No valid "
+ "(ecryptfs-specific) literal "
+ "packet containing "
+ "authentication token "
+ "signature found after "
+ "tag 3 packet\n");
+ rc = -EIO;
+ goto out_wipe_list;
+ }
+ i += tag_11_packet_size;
+ if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
+ ecryptfs_printk(KERN_ERR, "Expected "
+ "signature of size [%d]; "
+ "read size [%d]\n",
+ ECRYPTFS_SIG_SIZE,
+ tag_11_contents_size);
+ rc = -EIO;
+ goto out_wipe_list;
+ }
+ ecryptfs_to_hex(new_auth_tok->token.password.signature,
+ sig_tmp_space, tag_11_contents_size);
+ new_auth_tok->token.password.signature[
+ ECRYPTFS_PASSWORD_SIG_SIZE] = '\0';
+ ECRYPTFS_SET_FLAG(crypt_stat->flags,
+ ECRYPTFS_ENCRYPTED);
+ break;
+ case ECRYPTFS_TAG_11_PACKET_TYPE:
+ ecryptfs_printk(KERN_WARNING, "Invalid packet set "
+ "(Tag 11 not allowed by itself)\n");
+ rc = -EIO;
+ goto out_wipe_list;
+ break;
+ default:
+ ecryptfs_printk(KERN_DEBUG, "No packet at offset "
+ "[%d] of the file header; hex value of "
+ "character is [0x%.2x]\n", i, src[i]);
+ next_packet_is_auth_tok_packet = 0;
+ }
+ }
+ if (list_empty(&auth_tok_list)) {
+ rc = -EINVAL; /* Do not support non-encrypted files in
+ * the 0.1 release */
+ goto out;
+ }
+ /* If we have a global auth tok, then we should try to use
+ * it */
+ if (mount_crypt_stat->global_auth_tok) {
+ memcpy(sig, mount_crypt_stat->global_auth_tok_sig,
+ ECRYPTFS_SIG_SIZE_HEX);
+ chosen_auth_tok = mount_crypt_stat->global_auth_tok;
+ } else
+ BUG(); /* We should always have a global auth tok in
+ * the 0.1 release */
+ /* Scan list to see if our chosen_auth_tok works */
+ list_for_each(walker, &auth_tok_list) {
+ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+ auth_tok_list_item =
+ list_entry(walker, struct ecryptfs_auth_tok_list_item,
+ list);
+ candidate_auth_tok = &auth_tok_list_item->auth_tok;
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG,
+ "Considering cadidate auth tok:\n");
+ ecryptfs_dump_auth_tok(candidate_auth_tok);
+ }
+ /* TODO: Replace ECRYPTFS_SIG_SIZE_HEX w/ dynamic value */
+ if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD
+ && !strncmp(candidate_auth_tok->token.password.signature,
+ sig, ECRYPTFS_SIG_SIZE_HEX)) {
+ found_auth_tok = 1;
+ goto leave_list;
+ /* TODO: Transfer the common salt into the
+ * crypt_stat salt */
+ }
+ }
+leave_list:
+ if (!found_auth_tok) {
+ ecryptfs_printk(KERN_ERR, "Could not find authentication "
+ "token on temporary list for sig [%.*s]\n",
+ ECRYPTFS_SIG_SIZE_HEX, sig);
+ rc = -EIO;
+ goto out_wipe_list;
+ } else {
+ memcpy(&(candidate_auth_tok->token.password),
+ &(chosen_auth_tok->token.password),
+ sizeof(struct ecryptfs_password));
+ rc = decrypt_session_key(candidate_auth_tok, crypt_stat);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error decrypting the "
+ "session key\n");
+ goto out_wipe_list;
+ }
+ rc = ecryptfs_compute_root_iv(crypt_stat);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error computing "
+ "the root IV\n");
+ goto out_wipe_list;
+ }
+ }
+ rc = ecryptfs_init_crypt_ctx(crypt_stat);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error initializing crypto "
+ "context for cipher [%s]; rc = [%d]\n",
+ crypt_stat->cipher, rc);
+ }
+out_wipe_list:
+ wipe_auth_tok_list(&auth_tok_list);
+out:
+ return rc;
+}
+
+/**
+ * write_tag_11_packet
+ * @dest: Target into which Tag 11 packet is to be written
+ * @max: Maximum packet length
+ * @contents: Byte array of contents to copy in
+ * @contents_length: Number of bytes in contents
+ * @packet_length: Length of the Tag 11 packet written; zero on error
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length,
+ size_t *packet_length)
+{
+ int rc = 0;
+ size_t packet_size_length;
+
+ (*packet_length) = 0;
+ if ((13 + contents_length) > max) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "Packet length larger than "
+ "maximum allowable\n");
+ goto out;
+ }
+ /* General packet header */
+ /* Packet tag */
+ dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
+ /* Packet length */
+ rc = write_packet_length(&dest[(*packet_length)],
+ (13 + contents_length), &packet_size_length);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating tag 11 packet "
+ "header; cannot generate packet length\n");
+ goto out;
+ }
+ (*packet_length) += packet_size_length;
+ /* Tag 11 specific */
+ /* One-octet field that describes how the data is formatted */
+ dest[(*packet_length)++] = 0x62; /* binary data */
+ /* One-octet filename length followed by filename */
+ dest[(*packet_length)++] = 8;
+ memcpy(&dest[(*packet_length)], "_CONSOLE", 8);
+ (*packet_length) += 8;
+ /* Four-octet number indicating modification date */
+ memset(&dest[(*packet_length)], 0x00, 4);
+ (*packet_length) += 4;
+ /* Remainder is literal data */
+ memcpy(&dest[(*packet_length)], contents, contents_length);
+ (*packet_length) += contents_length;
+ out:
+ if (rc)
+ (*packet_length) = 0;
+ return rc;
+}
+
+/**
+ * write_tag_3_packet
+ * @dest: Buffer into which to write the packet
+ * @max: Maximum number of bytes that can be written
+ * @auth_tok: Authentication token
+ * @crypt_stat: The cryptographic context
+ * @key_rec: encrypted key
+ * @packet_size: This function will write the number of bytes that end
+ * up constituting the packet; set to zero on error
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct ecryptfs_key_record *key_rec, size_t *packet_size)
+{
+ int rc = 0;
+
+ size_t i;
+ size_t signature_is_valid = 0;
+ size_t encrypted_session_key_valid = 0;
+ char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+ struct scatterlist dest_sg[2];
+ struct scatterlist src_sg[2];
+ struct crypto_tfm *tfm = NULL;
+ struct mutex *tfm_mutex = NULL;
+ size_t key_rec_size;
+ size_t packet_size_length;
+ size_t cipher_code;
+
+ (*packet_size) = 0;
+ /* Check for a valid signature on the auth_tok */
+ for (i = 0; i < ECRYPTFS_SIG_SIZE_HEX; i++)
+ signature_is_valid |= auth_tok->token.password.signature[i];
+ if (!signature_is_valid)
+ BUG();
+ ecryptfs_from_hex((*key_rec).sig, auth_tok->token.password.signature,
+ ECRYPTFS_SIG_SIZE);
+ encrypted_session_key_valid = 0;
+ for (i = 0; i < crypt_stat->key_size; i++)
+ encrypted_session_key_valid |=
+ auth_tok->session_key.encrypted_key[i];
+ if (encrypted_session_key_valid) {
+ memcpy((*key_rec).enc_key,
+ auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.encrypted_key_size);
+ goto encrypted_session_key_set;
+ }
+ if (auth_tok->session_key.encrypted_key_size == 0)
+ auth_tok->session_key.encrypted_key_size =
+ crypt_stat->key_size;
+ if (crypt_stat->key_size == 24
+ && strcmp("aes", crypt_stat->cipher) == 0) {
+ memset((crypt_stat->key + 24), 0, 8);
+ auth_tok->session_key.encrypted_key_size = 32;
+ }
+ (*key_rec).enc_key_size =
+ auth_tok->session_key.encrypted_key_size;
+ if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
+ ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) {
+ ecryptfs_printk(KERN_DEBUG, "Using previously generated "
+ "session key encryption key of size [%d]\n",
+ auth_tok->token.password.
+ session_key_encryption_key_bytes);
+ memcpy(session_key_encryption_key,
+ auth_tok->token.password.session_key_encryption_key,
+ crypt_stat->key_size);
+ ecryptfs_printk(KERN_DEBUG,
+ "Cached session key " "encryption key: \n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(session_key_encryption_key, 16);
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n");
+ ecryptfs_dump_hex(session_key_encryption_key, 16);
+ }
+ rc = virt_to_scatterlist(crypt_stat->key,
+ (*key_rec).enc_key_size, src_sg, 2);
+ if (!rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+ "for crypt_stat session key\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ rc = virt_to_scatterlist((*key_rec).enc_key,
+ (*key_rec).enc_key_size, dest_sg, 2);
+ if (!rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+ "for crypt_stat encrypted session key\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ if (!strcmp(crypt_stat->cipher,
+ crypt_stat->mount_crypt_stat->global_default_cipher_name)
+ && crypt_stat->mount_crypt_stat->global_key_tfm) {
+ tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
+ tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
+ } else
+ tfm = crypto_alloc_tfm(crypt_stat->cipher, 0);
+ if (!tfm) {
+ ecryptfs_printk(KERN_ERR, "Could not initialize crypto "
+ "context for cipher [%s]\n",
+ crypt_stat->cipher);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (tfm_mutex)
+ mutex_lock(tfm_mutex);
+ rc = crypto_cipher_setkey(tfm, session_key_encryption_key,
+ crypt_stat->key_size);
+ if (rc < 0) {
+ if (tfm_mutex)
+ mutex_unlock(tfm_mutex);
+ ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
+ "context\n");
+ goto out;
+ }
+ rc = 0;
+ ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
+ crypt_stat->key_size);
+ crypto_cipher_encrypt(tfm, dest_sg, src_sg,
+ (*key_rec).enc_key_size);
+ if (tfm_mutex)
+ mutex_unlock(tfm_mutex);
+ ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex((*key_rec).enc_key,
+ (*key_rec).enc_key_size);
+encrypted_session_key_set:
+ /* Now we have a valid key_rec. Append it to the
+ * key_rec set. */
+ key_rec_size = (sizeof(struct ecryptfs_key_record)
+ - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES
+ + ((*key_rec).enc_key_size));
+ /* TODO: Include a packet size limit as a parameter to this
+ * function once we have multi-packet headers (for versions
+ * later than 0.1 */
+ if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) {
+ ecryptfs_printk(KERN_ERR, "Keyset too large\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ /* TODO: Packet size limit */
+ /* We have 5 bytes of surrounding packet data */
+ if ((0x05 + ECRYPTFS_SALT_SIZE
+ + (*key_rec).enc_key_size) >= max) {
+ ecryptfs_printk(KERN_ERR, "Authentication token is too "
+ "large\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ /* This format is inspired by OpenPGP; see RFC 2440
+ * packet tag 3 */
+ dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
+ /* ver+cipher+s2k+hash+salt+iter+enc_key */
+ rc = write_packet_length(&dest[(*packet_size)],
+ (0x05 + ECRYPTFS_SALT_SIZE
+ + (*key_rec).enc_key_size),
+ &packet_size_length);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating tag 3 packet "
+ "header; cannot generate packet length\n");
+ goto out;
+ }
+ (*packet_size) += packet_size_length;
+ dest[(*packet_size)++] = 0x04; /* version 4 */
+ cipher_code = ecryptfs_code_for_cipher_string(crypt_stat);
+ if (cipher_code == 0) {
+ ecryptfs_printk(KERN_WARNING, "Unable to generate code for "
+ "cipher [%s]\n", crypt_stat->cipher);
+ rc = -EINVAL;
+ goto out;
+ }
+ dest[(*packet_size)++] = cipher_code;
+ dest[(*packet_size)++] = 0x03; /* S2K */
+ dest[(*packet_size)++] = 0x01; /* MD5 (TODO: parameterize) */
+ memcpy(&dest[(*packet_size)], auth_tok->token.password.salt,
+ ECRYPTFS_SALT_SIZE);
+ (*packet_size) += ECRYPTFS_SALT_SIZE; /* salt */
+ dest[(*packet_size)++] = 0x60; /* hash iterations (65536) */
+ memcpy(&dest[(*packet_size)], (*key_rec).enc_key,
+ (*key_rec).enc_key_size);
+ (*packet_size) += (*key_rec).enc_key_size;
+out:
+ if (tfm && !tfm_mutex)
+ crypto_free_tfm(tfm);
+ if (rc)
+ (*packet_size) = 0;
+ return rc;
+}
+
+/**
+ * ecryptfs_generate_key_packet_set
+ * @dest: Virtual address from which to write the key record set
+ * @crypt_stat: The cryptographic context from which the
+ * authentication tokens will be retrieved
+ * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat
+ * for the global parameters
+ * @len: The amount written
+ * @max: The maximum amount of data allowed to be written
+ *
+ * Generates a key packet set and writes it to the virtual address
+ * passed in.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+int
+ecryptfs_generate_key_packet_set(char *dest_base,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry, size_t *len,
+ size_t max)
+{
+ int rc = 0;
+ struct ecryptfs_auth_tok *auth_tok;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ size_t written;
+ struct ecryptfs_key_record key_rec;
+
+ (*len) = 0;
+ if (mount_crypt_stat->global_auth_tok) {
+ auth_tok = mount_crypt_stat->global_auth_tok;
+ if (auth_tok->token_type == ECRYPTFS_PASSWORD) {
+ rc = write_tag_3_packet((dest_base + (*len)),
+ max, auth_tok,
+ crypt_stat, &key_rec,
+ &written);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error "
+ "writing tag 3 packet\n");
+ goto out;
+ }
+ (*len) += written;
+ /* Write auth tok signature packet */
+ rc = write_tag_11_packet(
+ (dest_base + (*len)),
+ (max - (*len)),
+ key_rec.sig, ECRYPTFS_SIG_SIZE, &written);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error writing "
+ "auth tok signature packet\n");
+ goto out;
+ }
+ (*len) += written;
+ } else {
+ ecryptfs_printk(KERN_WARNING, "Unsupported "
+ "authentication token type\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error writing "
+ "authentication token packet with sig "
+ "= [%s]\n",
+ mount_crypt_stat->global_auth_tok_sig);
+ rc = -EIO;
+ goto out;
+ }
+ } else
+ BUG();
+ if (likely((max - (*len)) > 0)) {
+ dest_base[(*len)] = 0x00;
+ } else {
+ ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n");
+ rc = -EIO;
+ }
+out:
+ if (rc)
+ (*len) = 0;
+ return rc;
+}
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
new file mode 100644
index 0000000..7a11b8a
--- /dev/null
+++ b/fs/ecryptfs/main.c
@@ -0,0 +1,831 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/skbuff.h>
+#include <linux/crypto.h>
+#include <linux/netlink.h>
+#include <linux/mount.h>
+#include <linux/dcache.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/parser.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * Module parameter that defines the ecryptfs_verbosity level.
+ */
+int ecryptfs_verbosity = 0;
+
+module_param(ecryptfs_verbosity, int, 0);
+MODULE_PARM_DESC(ecryptfs_verbosity,
+ "Initial verbosity level (0 or 1; defaults to "
+ "0, which is Quiet)");
+
+void __ecryptfs_printk(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (fmt[1] == '7') { /* KERN_DEBUG */
+ if (ecryptfs_verbosity >= 1)
+ vprintk(fmt, args);
+ } else
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+/**
+ * ecryptfs_interpose
+ * @lower_dentry: Existing dentry in the lower filesystem
+ * @dentry: ecryptfs' dentry
+ * @sb: ecryptfs's super_block
+ * @flag: If set to true, then d_add is called, else d_instantiate is called
+ *
+ * Interposes upper and lower dentries.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
+ struct super_block *sb, int flag)
+{
+ struct inode *lower_inode;
+ struct inode *inode;
+ int rc = 0;
+
+ lower_inode = lower_dentry->d_inode;
+ if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
+ rc = -EXDEV;
+ goto out;
+ }
+ if (!igrab(lower_inode)) {
+ rc = -ESTALE;
+ goto out;
+ }
+ inode = iget5_locked(sb, (unsigned long)lower_inode,
+ ecryptfs_inode_test, ecryptfs_inode_set,
+ lower_inode);
+ if (!inode) {
+ rc = -EACCES;
+ iput(lower_inode);
+ goto out;
+ }
+ if (inode->i_state & I_NEW)
+ unlock_new_inode(inode);
+ else
+ iput(lower_inode);
+ if (S_ISLNK(lower_inode->i_mode))
+ inode->i_op = &ecryptfs_symlink_iops;
+ else if (S_ISDIR(lower_inode->i_mode))
+ inode->i_op = &ecryptfs_dir_iops;
+ if (S_ISDIR(lower_inode->i_mode))
+ inode->i_fop = &ecryptfs_dir_fops;
+ /* TODO: Is there a better way to identify if the inode is
+ * special? */
+ if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) ||
+ S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode))
+ init_special_inode(inode, lower_inode->i_mode,
+ lower_inode->i_rdev);
+ dentry->d_op = &ecryptfs_dops;
+ if (flag)
+ d_add(dentry, inode);
+ else
+ d_instantiate(dentry, inode);
+ ecryptfs_copy_attr_all(inode, lower_inode);
+ /* This size will be overwritten for real files w/ headers and
+ * other metadata */
+ ecryptfs_copy_inode_size(inode, lower_inode);
+out:
+ return rc;
+}
+
+enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
+ ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
+ ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
+ ecryptfs_opt_passthrough, ecryptfs_opt_err };
+
+static match_table_t tokens = {
+ {ecryptfs_opt_sig, "sig=%s"},
+ {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
+ {ecryptfs_opt_debug, "debug=%u"},
+ {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
+ {ecryptfs_opt_cipher, "cipher=%s"},
+ {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
+ {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
+ {ecryptfs_opt_passthrough, "ecryptfs_passthrough"},
+ {ecryptfs_opt_err, NULL}
+};
+
+/**
+ * ecryptfs_verify_version
+ * @version: The version number to confirm
+ *
+ * Returns zero on good version; non-zero otherwise
+ */
+static int ecryptfs_verify_version(u16 version)
+{
+ int rc = 0;
+ unsigned char major;
+ unsigned char minor;
+
+ major = ((version >> 8) & 0xFF);
+ minor = (version & 0xFF);
+ if (major != ECRYPTFS_VERSION_MAJOR) {
+ ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
+ "Expected [%d]; got [%d]\n",
+ ECRYPTFS_VERSION_MAJOR, major);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (minor != ECRYPTFS_VERSION_MINOR) {
+ ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
+ "Expected [%d]; got [%d]\n",
+ ECRYPTFS_VERSION_MINOR, minor);
+ rc = -EINVAL;
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_parse_options
+ * @sb: The ecryptfs super block
+ * @options: The options pased to the kernel
+ *
+ * Parse mount options:
+ * debug=N - ecryptfs_verbosity level for debug output
+ * sig=XXX - description(signature) of the key to use
+ *
+ * Returns the dentry object of the lower-level (lower/interposed)
+ * directory; We want to mount our stackable file system on top of
+ * that lower directory.
+ *
+ * The signature of the key to use must be the description of a key
+ * already in the keyring. Mounting will fail if the key can not be
+ * found.
+ *
+ * Returns zero on success; non-zero on error
+ */
+static int ecryptfs_parse_options(struct super_block *sb, char *options)
+{
+ char *p;
+ int rc = 0;
+ int sig_set = 0;
+ int cipher_name_set = 0;
+ int cipher_key_bytes;
+ int cipher_key_bytes_set = 0;
+ struct key *auth_tok_key = NULL;
+ struct ecryptfs_auth_tok *auth_tok = NULL;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
+ substring_t args[MAX_OPT_ARGS];
+ int token;
+ char *sig_src;
+ char *sig_dst;
+ char *debug_src;
+ char *cipher_name_dst;
+ char *cipher_name_src;
+ char *cipher_key_bytes_src;
+ struct crypto_tfm *tmp_tfm;
+ int cipher_name_len;
+
+ if (!options) {
+ rc = -EINVAL;
+ goto out;
+ }
+ while ((p = strsep(&options, ",")) != NULL) {
+ if (!*p)
+ continue;
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case ecryptfs_opt_sig:
+ case ecryptfs_opt_ecryptfs_sig:
+ sig_src = args[0].from;
+ sig_dst =
+ mount_crypt_stat->global_auth_tok_sig;
+ memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX);
+ sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+ ecryptfs_printk(KERN_DEBUG,
+ "The mount_crypt_stat "
+ "global_auth_tok_sig set to: "
+ "[%s]\n", sig_dst);
+ sig_set = 1;
+ break;
+ case ecryptfs_opt_debug:
+ case ecryptfs_opt_ecryptfs_debug:
+ debug_src = args[0].from;
+ ecryptfs_verbosity =
+ (int)simple_strtol(debug_src, &debug_src,
+ 0);
+ ecryptfs_printk(KERN_DEBUG,
+ "Verbosity set to [%d]" "\n",
+ ecryptfs_verbosity);
+ break;
+ case ecryptfs_opt_cipher:
+ case ecryptfs_opt_ecryptfs_cipher:
+ cipher_name_src = args[0].from;
+ cipher_name_dst =
+ mount_crypt_stat->
+ global_default_cipher_name;
+ strncpy(cipher_name_dst, cipher_name_src,
+ ECRYPTFS_MAX_CIPHER_NAME_SIZE);
+ ecryptfs_printk(KERN_DEBUG,
+ "The mount_crypt_stat "
+ "global_default_cipher_name set to: "
+ "[%s]\n", cipher_name_dst);
+ cipher_name_set = 1;
+ break;
+ case ecryptfs_opt_ecryptfs_key_bytes:
+ cipher_key_bytes_src = args[0].from;
+ cipher_key_bytes =
+ (int)simple_strtol(cipher_key_bytes_src,
+ &cipher_key_bytes_src, 0);
+ mount_crypt_stat->global_default_cipher_key_size =
+ cipher_key_bytes;
+ ecryptfs_printk(KERN_DEBUG,
+ "The mount_crypt_stat "
+ "global_default_cipher_key_size "
+ "set to: [%d]\n", mount_crypt_stat->
+ global_default_cipher_key_size);
+ cipher_key_bytes_set = 1;
+ break;
+ case ecryptfs_opt_passthrough:
+ mount_crypt_stat->flags |=
+ ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED;
+ break;
+ case ecryptfs_opt_err:
+ default:
+ ecryptfs_printk(KERN_WARNING,
+ "eCryptfs: unrecognized option '%s'\n",
+ p);
+ }
+ }
+ /* Do not support lack of mount-wide signature in 0.1
+ * release */
+ if (!sig_set) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "You must supply a valid "
+ "passphrase auth tok signature as a mount "
+ "parameter; see the eCryptfs README\n");
+ goto out;
+ }
+ if (!cipher_name_set) {
+ cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
+ if (unlikely(cipher_name_len
+ >= ECRYPTFS_MAX_CIPHER_NAME_SIZE)) {
+ rc = -EINVAL;
+ BUG();
+ goto out;
+ }
+ memcpy(mount_crypt_stat->global_default_cipher_name,
+ ECRYPTFS_DEFAULT_CIPHER, cipher_name_len);
+ mount_crypt_stat->global_default_cipher_name[cipher_name_len]
+ = '\0';
+ }
+ if (!cipher_key_bytes_set) {
+ mount_crypt_stat->global_default_cipher_key_size =
+ ECRYPTFS_DEFAULT_KEY_BYTES;
+ ecryptfs_printk(KERN_DEBUG, "Cipher key size was not "
+ "specified. Defaulting to [%d]\n",
+ mount_crypt_stat->
+ global_default_cipher_key_size);
+ }
+ rc = ecryptfs_process_cipher(
+ &tmp_tfm,
+ &mount_crypt_stat->global_key_tfm,
+ mount_crypt_stat->global_default_cipher_name,
+ mount_crypt_stat->global_default_cipher_key_size);
+ if (tmp_tfm)
+ crypto_free_tfm(tmp_tfm);
+ if (rc) {
+ printk(KERN_ERR "Error attempting to initialize cipher [%s] "
+ "with key size [%Zd] bytes; rc = [%d]\n",
+ mount_crypt_stat->global_default_cipher_name,
+ mount_crypt_stat->global_default_cipher_key_size, rc);
+ rc = -EINVAL;
+ goto out;
+ }
+ mutex_init(&mount_crypt_stat->global_key_tfm_mutex);
+ ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: "
+ "[%s]\n", mount_crypt_stat->global_auth_tok_sig);
+ /* The reference to this key is held until umount is done The
+ * call to key_put is done in ecryptfs_put_super() */
+ auth_tok_key = request_key(&key_type_user,
+ mount_crypt_stat->global_auth_tok_sig,
+ NULL);
+ if (!auth_tok_key || IS_ERR(auth_tok_key)) {
+ ecryptfs_printk(KERN_ERR, "Could not find key with "
+ "description: [%s]\n",
+ mount_crypt_stat->global_auth_tok_sig);
+ process_request_key_err(PTR_ERR(auth_tok_key));
+ rc = -EINVAL;
+ goto out;
+ }
+ auth_tok = ecryptfs_get_key_payload_data(auth_tok_key);
+ if (ecryptfs_verify_version(auth_tok->version)) {
+ ecryptfs_printk(KERN_ERR, "Data structure version mismatch. "
+ "Userspace tools must match eCryptfs kernel "
+ "module with major version [%d] and minor "
+ "version [%d]\n", ECRYPTFS_VERSION_MAJOR,
+ ECRYPTFS_VERSION_MINOR);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (auth_tok->token_type != ECRYPTFS_PASSWORD) {
+ ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure "
+ "returned from key\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ mount_crypt_stat->global_auth_tok_key = auth_tok_key;
+ mount_crypt_stat->global_auth_tok = auth_tok;
+out:
+ return rc;
+}
+
+struct kmem_cache *ecryptfs_sb_info_cache;
+
+/**
+ * ecryptfs_fill_super
+ * @sb: The ecryptfs super block
+ * @raw_data: The options passed to mount
+ * @silent: Not used but required by function prototype
+ *
+ * Sets up what we can of the sb, rest is done in ecryptfs_read_super
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)
+{
+ int rc = 0;
+
+ /* Released in ecryptfs_put_super() */
+ ecryptfs_set_superblock_private(sb,
+ kmem_cache_alloc(ecryptfs_sb_info_cache,
+ SLAB_KERNEL));
+ if (!ecryptfs_superblock_to_private(sb)) {
+ ecryptfs_printk(KERN_WARNING, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(ecryptfs_superblock_to_private(sb), 0,
+ sizeof(struct ecryptfs_sb_info));
+ sb->s_op = &ecryptfs_sops;
+ /* Released through deactivate_super(sb) from get_sb_nodev */
+ sb->s_root = d_alloc(NULL, &(const struct qstr) {
+ .hash = 0,.name = "/",.len = 1});
+ if (!sb->s_root) {
+ ecryptfs_printk(KERN_ERR, "d_alloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ sb->s_root->d_op = &ecryptfs_dops;
+ sb->s_root->d_sb = sb;
+ sb->s_root->d_parent = sb->s_root;
+ /* Released in d_release when dput(sb->s_root) is called */
+ /* through deactivate_super(sb) from get_sb_nodev() */
+ ecryptfs_set_dentry_private(sb->s_root,
+ kmem_cache_alloc(ecryptfs_dentry_info_cache,
+ SLAB_KERNEL));
+ if (!ecryptfs_dentry_to_private(sb->s_root)) {
+ ecryptfs_printk(KERN_ERR,
+ "dentry_info_cache alloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(ecryptfs_dentry_to_private(sb->s_root), 0,
+ sizeof(struct ecryptfs_dentry_info));
+ rc = 0;
+out:
+ /* Should be able to rely on deactivate_super called from
+ * get_sb_nodev */
+ return rc;
+}
+
+/**
+ * ecryptfs_read_super
+ * @sb: The ecryptfs super block
+ * @dev_name: The path to mount over
+ *
+ * Read the super block of the lower filesystem, and use
+ * ecryptfs_interpose to create our initial inode and super block
+ * struct.
+ */
+static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
+{
+ int rc;
+ struct nameidata nd;
+ struct dentry *lower_root;
+ struct vfsmount *lower_mnt;
+
+ memset(&nd, 0, sizeof(struct nameidata));
+ rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
+ goto out_free;
+ }
+ lower_root = nd.dentry;
+ if (!lower_root->d_inode) {
+ ecryptfs_printk(KERN_WARNING,
+ "No directory to interpose on\n");
+ rc = -ENOENT;
+ goto out_free;
+ }
+ lower_mnt = nd.mnt;
+ ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
+ sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
+ ecryptfs_set_dentry_lower(sb->s_root, lower_root);
+ ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
+ if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
+ goto out_free;
+ rc = 0;
+ goto out;
+out_free:
+ path_release(&nd);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_get_sb
+ * @fs_type
+ * @flags
+ * @dev_name: The path to mount over
+ * @raw_data: The options passed into the kernel
+ *
+ * The whole ecryptfs_get_sb process is broken into 4 functions:
+ * ecryptfs_parse_options(): handle options passed to ecryptfs, if any
+ * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block
+ * with as much information as it can before needing
+ * the lower filesystem.
+ * ecryptfs_read_super(): this accesses the lower filesystem and uses
+ * ecryptfs_interpolate to perform most of the linking
+ * ecryptfs_interpolate(): links the lower filesystem into ecryptfs
+ */
+static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *raw_data,
+ struct vfsmount *mnt)
+{
+ int rc;
+ struct super_block *sb;
+
+ rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt);
+ if (rc < 0) {
+ printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc);
+ goto out;
+ }
+ sb = mnt->mnt_sb;
+ rc = ecryptfs_parse_options(sb, raw_data);
+ if (rc) {
+ printk(KERN_ERR "Error parsing options; rc = [%d]\n", rc);
+ goto out_abort;
+ }
+ rc = ecryptfs_read_super(sb, dev_name);
+ if (rc) {
+ printk(KERN_ERR "Reading sb failed; rc = [%d]\n", rc);
+ goto out_abort;
+ }
+ goto out;
+out_abort:
+ dput(sb->s_root);
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_kill_block_super
+ * @sb: The ecryptfs super block
+ *
+ * Used to bring the superblock down and free the private data.
+ * Private data is free'd in ecryptfs_put_super()
+ */
+static void ecryptfs_kill_block_super(struct super_block *sb)
+{
+ generic_shutdown_super(sb);
+}
+
+static struct file_system_type ecryptfs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "ecryptfs",
+ .get_sb = ecryptfs_get_sb,
+ .kill_sb = ecryptfs_kill_block_super,
+ .fs_flags = 0
+};
+
+/**
+ * inode_info_init_once
+ *
+ * Initializes the ecryptfs_inode_info_cache when it is created
+ */
+static void
+inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags)
+{
+ struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
+
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static struct ecryptfs_cache_info {
+ kmem_cache_t **cache;
+ const char *name;
+ size_t size;
+ void (*ctor)(void*, struct kmem_cache *, unsigned long);
+} ecryptfs_cache_infos[] = {
+ {
+ .cache = &ecryptfs_auth_tok_list_item_cache,
+ .name = "ecryptfs_auth_tok_list_item",
+ .size = sizeof(struct ecryptfs_auth_tok_list_item),
+ },
+ {
+ .cache = &ecryptfs_file_info_cache,
+ .name = "ecryptfs_file_cache",
+ .size = sizeof(struct ecryptfs_file_info),
+ },
+ {
+ .cache = &ecryptfs_dentry_info_cache,
+ .name = "ecryptfs_dentry_info_cache",
+ .size = sizeof(struct ecryptfs_dentry_info),
+ },
+ {
+ .cache = &ecryptfs_inode_info_cache,
+ .name = "ecryptfs_inode_cache",
+ .size = sizeof(struct ecryptfs_inode_info),
+ .ctor = inode_info_init_once,
+ },
+ {
+ .cache = &ecryptfs_sb_info_cache,
+ .name = "ecryptfs_sb_cache",
+ .size = sizeof(struct ecryptfs_sb_info),
+ },
+ {
+ .cache = &ecryptfs_header_cache_0,
+ .name = "ecryptfs_headers_0",
+ .size = PAGE_CACHE_SIZE,
+ },
+ {
+ .cache = &ecryptfs_header_cache_1,
+ .name = "ecryptfs_headers_1",
+ .size = PAGE_CACHE_SIZE,
+ },
+ {
+ .cache = &ecryptfs_header_cache_2,
+ .name = "ecryptfs_headers_2",
+ .size = PAGE_CACHE_SIZE,
+ },
+ {
+ .cache = &ecryptfs_lower_page_cache,
+ .name = "ecryptfs_lower_page_cache",
+ .size = PAGE_CACHE_SIZE,
+ },
+};
+
+static void ecryptfs_free_kmem_caches(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
+ struct ecryptfs_cache_info *info;
+
+ info = &ecryptfs_cache_infos[i];
+ if (*(info->cache))
+ kmem_cache_destroy(*(info->cache));
+ }
+}
+
+/**
+ * ecryptfs_init_kmem_caches
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_init_kmem_caches(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
+ struct ecryptfs_cache_info *info;
+
+ info = &ecryptfs_cache_infos[i];
+ *(info->cache) = kmem_cache_create(info->name, info->size,
+ 0, SLAB_HWCACHE_ALIGN, info->ctor, NULL);
+ if (!*(info->cache)) {
+ ecryptfs_free_kmem_caches();
+ ecryptfs_printk(KERN_WARNING, "%s: "
+ "kmem_cache_create failed\n",
+ info->name);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+struct ecryptfs_obj {
+ char *name;
+ struct list_head slot_list;
+ struct kobject kobj;
+};
+
+struct ecryptfs_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct ecryptfs_obj *, char *);
+ ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
+};
+
+static ssize_t
+ecryptfs_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+ kobj);
+ struct ecryptfs_attribute *attribute =
+ container_of(attr, struct ecryptfs_attribute, attr);
+
+ return (attribute->store ? attribute->store(obj, buf, len) : 0);
+}
+
+static ssize_t
+ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+ kobj);
+ struct ecryptfs_attribute *attribute =
+ container_of(attr, struct ecryptfs_attribute, attr);
+
+ return (attribute->show ? attribute->show(obj, buf) : 0);
+}
+
+static struct sysfs_ops ecryptfs_sysfs_ops = {
+ .show = ecryptfs_attr_show,
+ .store = ecryptfs_attr_store
+};
+
+static struct kobj_type ecryptfs_ktype = {
+ .sysfs_ops = &ecryptfs_sysfs_ops
+};
+
+static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
+
+static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
+{
+ return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
+}
+
+static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
+
+struct ecryptfs_version_str_map_elem {
+ u32 flag;
+ char *str;
+} ecryptfs_version_str_map[] = {
+ {ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
+ {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
+ {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
+ {ECRYPTFS_VERSIONING_POLICY, "policy"}
+};
+
+static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
+{
+ int i;
+ int remaining = PAGE_SIZE;
+ int total_written = 0;
+
+ buff[0] = '\0';
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
+ int entry_size;
+
+ if (!(ECRYPTFS_VERSIONING_MASK
+ & ecryptfs_version_str_map[i].flag))
+ continue;
+ entry_size = strlen(ecryptfs_version_str_map[i].str);
+ if ((entry_size + 2) > remaining)
+ goto out;
+ memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
+ buff[entry_size++] = '\n';
+ buff[entry_size] = '\0';
+ buff += entry_size;
+ total_written += entry_size;
+ remaining -= entry_size;
+ }
+out:
+ return total_written;
+}
+
+static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
+
+static int do_sysfs_registration(void)
+{
+ int rc;
+
+ if ((rc = subsystem_register(&ecryptfs_subsys))) {
+ printk(KERN_ERR
+ "Unable to register ecryptfs sysfs subsystem\n");
+ goto out;
+ }
+ rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version.attr);
+ if (rc) {
+ printk(KERN_ERR
+ "Unable to create ecryptfs version attribute\n");
+ subsystem_unregister(&ecryptfs_subsys);
+ goto out;
+ }
+ rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version_str.attr);
+ if (rc) {
+ printk(KERN_ERR
+ "Unable to create ecryptfs version_str attribute\n");
+ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version.attr);
+ subsystem_unregister(&ecryptfs_subsys);
+ goto out;
+ }
+out:
+ return rc;
+}
+
+static int __init ecryptfs_init(void)
+{
+ int rc;
+
+ if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_CACHE_SIZE) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is "
+ "larger than the host's page size, and so "
+ "eCryptfs cannot run on this system. The "
+ "default eCryptfs extent size is [%d] bytes; "
+ "the page size is [%d] bytes.\n",
+ ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE);
+ goto out;
+ }
+ rc = ecryptfs_init_kmem_caches();
+ if (rc) {
+ printk(KERN_ERR
+ "Failed to allocate one or more kmem_cache objects\n");
+ goto out;
+ }
+ rc = register_filesystem(&ecryptfs_fs_type);
+ if (rc) {
+ printk(KERN_ERR "Failed to register filesystem\n");
+ ecryptfs_free_kmem_caches();
+ goto out;
+ }
+ kset_set_kset_s(&ecryptfs_subsys, fs_subsys);
+ sysfs_attr_version.attr.owner = THIS_MODULE;
+ sysfs_attr_version_str.attr.owner = THIS_MODULE;
+ rc = do_sysfs_registration();
+ if (rc) {
+ printk(KERN_ERR "sysfs registration failed\n");
+ unregister_filesystem(&ecryptfs_fs_type);
+ ecryptfs_free_kmem_caches();
+ goto out;
+ }
+out:
+ return rc;
+}
+
+static void __exit ecryptfs_exit(void)
+{
+ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version.attr);
+ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version_str.attr);
+ subsystem_unregister(&ecryptfs_subsys);
+ unregister_filesystem(&ecryptfs_fs_type);
+ ecryptfs_free_kmem_caches();
+}
+
+MODULE_AUTHOR("Michael A. Halcrow <mhalcrow@us.ibm.com>");
+MODULE_DESCRIPTION("eCryptfs");
+
+MODULE_LICENSE("GPL");
+
+module_init(ecryptfs_init)
+module_exit(ecryptfs_exit)
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
new file mode 100644
index 0000000..924dd90
--- /dev/null
+++ b/fs/ecryptfs/mmap.c
@@ -0,0 +1,788 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * This is where eCryptfs coordinates the symmetric encryption and
+ * decryption of the file data as it passes between the lower
+ * encrypted file and the upper decrypted file.
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/page-flags.h>
+#include <linux/mount.h>
+#include <linux/file.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+struct kmem_cache *ecryptfs_lower_page_cache;
+
+/**
+ * ecryptfs_get1page
+ *
+ * Get one page from cache or lower f/s, return error otherwise.
+ *
+ * Returns unlocked and up-to-date page (if ok), with increased
+ * refcnt.
+ */
+static struct page *ecryptfs_get1page(struct file *file, int index)
+{
+ struct page *page;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct address_space *mapping;
+
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
+ mapping = inode->i_mapping;
+ page = read_cache_page(mapping, index,
+ (filler_t *)mapping->a_ops->readpage,
+ (void *)file);
+ if (IS_ERR(page))
+ goto out;
+ wait_on_page_locked(page);
+out:
+ return page;
+}
+
+static
+int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
+
+/**
+ * ecryptfs_fill_zeros
+ * @file: The ecryptfs file
+ * @new_length: The new length of the data in the underlying file;
+ * everything between the prior end of the file and the
+ * new end of the file will be filled with zero's.
+ * new_length must be greater than current length
+ *
+ * Function for handling lseek-ing past the end of the file.
+ *
+ * This function does not support shrinking, only growing a file.
+ *
+ * Returns zero on success; non-zero otherwise.
+ */
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
+{
+ int rc = 0;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ pgoff_t old_end_page_index = 0;
+ pgoff_t index = old_end_page_index;
+ int old_end_pos_in_page = -1;
+ pgoff_t new_end_page_index;
+ int new_end_pos_in_page;
+ loff_t cur_length = i_size_read(inode);
+
+ if (cur_length != 0) {
+ index = old_end_page_index =
+ ((cur_length - 1) >> PAGE_CACHE_SHIFT);
+ old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK);
+ }
+ new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
+ new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
+ ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; "
+ "old_end_pos_in_page = [%d]; "
+ "new_end_page_index = [0x%.16x]; "
+ "new_end_pos_in_page = [%d]\n",
+ old_end_page_index, old_end_pos_in_page,
+ new_end_page_index, new_end_pos_in_page);
+ if (old_end_page_index == new_end_page_index) {
+ /* Start and end are in the same page; we just need to
+ * set a portion of the existing page to zero's */
+ rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+ (new_end_pos_in_page - old_end_pos_in_page));
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+ "index=[0x%.16x], "
+ "old_end_pos_in_page=[d], "
+ "(PAGE_CACHE_SIZE - new_end_pos_in_page"
+ "=[%d]"
+ ")=[d]) returned [%d]\n", file, index,
+ old_end_pos_in_page,
+ new_end_pos_in_page,
+ (PAGE_CACHE_SIZE - new_end_pos_in_page),
+ rc);
+ goto out;
+ }
+ /* Fill the remainder of the previous last page with zeros */
+ rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+ ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+ "index=[0x%.16x], old_end_pos_in_page=[d], "
+ "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
+ "returned [%d]\n", file, index,
+ old_end_pos_in_page,
+ (PAGE_CACHE_SIZE - old_end_pos_in_page), rc);
+ goto out;
+ }
+ index++;
+ while (index < new_end_page_index) {
+ /* Fill all intermediate pages with zeros */
+ rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+ "index=[0x%.16x], "
+ "old_end_pos_in_page=[d], "
+ "(PAGE_CACHE_SIZE - new_end_pos_in_page"
+ "=[%d]"
+ ")=[d]) returned [%d]\n", file, index,
+ old_end_pos_in_page,
+ new_end_pos_in_page,
+ (PAGE_CACHE_SIZE - new_end_pos_in_page),
+ rc);
+ goto out;
+ }
+ index++;
+ }
+ /* Fill the portion at the beginning of the last new page with
+ * zero's */
+ rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "write_zeros(file="
+ "[%p], index=[0x%.16x], 0, "
+ "new_end_pos_in_page=[%d]"
+ "returned [%d]\n", file, index,
+ new_end_pos_in_page, rc);
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_writepage
+ * @page: Page that is locked before this call is made
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct ecryptfs_page_crypt_context ctx;
+ int rc;
+
+ ctx.page = page;
+ ctx.mode = ECRYPTFS_WRITEPAGE_MODE;
+ ctx.param.wbc = wbc;
+ rc = ecryptfs_encrypt_page(&ctx);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error encrypting "
+ "page (upper index [0x%.16x])\n", page->index);
+ ClearPageUptodate(page);
+ goto out;
+ }
+ SetPageUptodate(page);
+ unlock_page(page);
+out:
+ return rc;
+}
+
+/**
+ * Reads the data from the lower file file at index lower_page_index
+ * and copies that data into page.
+ *
+ * @param page Page to fill
+ * @param lower_page_index Index of the page in the lower file to get
+ */
+int ecryptfs_do_readpage(struct file *file, struct page *page,
+ pgoff_t lower_page_index)
+{
+ int rc;
+ struct dentry *dentry;
+ struct file *lower_file;
+ struct dentry *lower_dentry;
+ struct inode *inode;
+ struct inode *lower_inode;
+ char *page_data;
+ struct page *lower_page = NULL;
+ char *lower_page_data;
+ const struct address_space_operations *lower_a_ops;
+
+ dentry = file->f_dentry;
+ lower_file = ecryptfs_file_to_lower(file);
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ inode = dentry->d_inode;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ lower_a_ops = lower_inode->i_mapping->a_ops;
+ lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index,
+ (filler_t *)lower_a_ops->readpage,
+ (void *)lower_file);
+ if (IS_ERR(lower_page)) {
+ rc = PTR_ERR(lower_page);
+ lower_page = NULL;
+ ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
+ goto out;
+ }
+ wait_on_page_locked(lower_page);
+ page_data = (char *)kmap(page);
+ if (!page_data) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error mapping page\n");
+ goto out;
+ }
+ lower_page_data = (char *)kmap(lower_page);
+ if (!lower_page_data) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error mapping page\n");
+ kunmap(page);
+ goto out;
+ }
+ memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
+ kunmap(lower_page);
+ kunmap(page);
+ rc = 0;
+out:
+ if (likely(lower_page))
+ page_cache_release(lower_page);
+ if (rc == 0)
+ SetPageUptodate(page);
+ else
+ ClearPageUptodate(page);
+ return rc;
+}
+
+/**
+ * ecryptfs_readpage
+ * @file: This is an ecryptfs file
+ * @page: ecryptfs associated page to stick the read data into
+ *
+ * Read in a page, decrypting if necessary.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int ecryptfs_readpage(struct file *file, struct page *page)
+{
+ int rc = 0;
+ struct ecryptfs_crypt_stat *crypt_stat;
+
+ BUG_ON(!(file && file->f_dentry && file->f_dentry->d_inode));
+ crypt_stat =
+ &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+ if (!crypt_stat
+ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)
+ || ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
+ ecryptfs_printk(KERN_DEBUG,
+ "Passing through unencrypted page\n");
+ rc = ecryptfs_do_readpage(file, page, page->index);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error reading page; rc = "
+ "[%d]\n", rc);
+ goto out;
+ }
+ } else {
+ rc = ecryptfs_decrypt_page(file, page);
+ if (rc) {
+
+ ecryptfs_printk(KERN_ERR, "Error decrypting page; "
+ "rc = [%d]\n", rc);
+ goto out;
+ }
+ }
+ SetPageUptodate(page);
+out:
+ if (rc)
+ ClearPageUptodate(page);
+ ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
+ page->index);
+ unlock_page(page);
+ return rc;
+}
+
+static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
+{
+ struct inode *inode = page->mapping->host;
+ int end_byte_in_page;
+ int rc = 0;
+ char *page_virt;
+
+ if ((i_size_read(inode) / PAGE_CACHE_SIZE) == page->index) {
+ end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
+ if (to > end_byte_in_page)
+ end_byte_in_page = to;
+ page_virt = kmap(page);
+ if (!page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_WARNING,
+ "Could not map page\n");
+ goto out;
+ }
+ memset((page_virt + end_byte_in_page), 0,
+ (PAGE_CACHE_SIZE - end_byte_in_page));
+ kunmap(page);
+ }
+out:
+ return rc;
+}
+
+static int ecryptfs_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ int rc = 0;
+
+ kmap(page);
+ if (from == 0 && to == PAGE_CACHE_SIZE)
+ goto out; /* If we are writing a full page, it will be
+ up to date. */
+ if (!PageUptodate(page))
+ rc = ecryptfs_do_readpage(file, page, page->index);
+out:
+ return rc;
+}
+
+int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
+ char **lower_virt,
+ struct inode *lower_inode,
+ unsigned long lower_page_index)
+{
+ int rc = 0;
+
+ (*lower_page) = grab_cache_page(lower_inode->i_mapping,
+ lower_page_index);
+ if (!(*lower_page)) {
+ ecryptfs_printk(KERN_ERR, "grab_cache_page for "
+ "lower_page_index = [0x%.16x] failed\n",
+ lower_page_index);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (lower_virt)
+ (*lower_virt) = kmap((*lower_page));
+ else
+ kmap((*lower_page));
+out:
+ return rc;
+}
+
+int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
+ struct inode *lower_inode,
+ struct writeback_control *wbc)
+{
+ int rc = 0;
+
+ rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); "
+ "rc = [%d]\n", rc);
+ goto out;
+ }
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ page_cache_release(lower_page);
+out:
+ return rc;
+}
+
+static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page)
+{
+ kunmap(lower_page);
+ ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = "
+ "[0x%.16x]\n", lower_page->index);
+ unlock_page(lower_page);
+ page_cache_release(lower_page);
+}
+
+/**
+ * ecryptfs_write_inode_size_to_header
+ *
+ * Writes the lower file size to the first 8 bytes of the header.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+int
+ecryptfs_write_inode_size_to_header(struct file *lower_file,
+ struct inode *lower_inode,
+ struct inode *inode)
+{
+ int rc = 0;
+ struct page *header_page;
+ char *header_virt;
+ const struct address_space_operations *lower_a_ops;
+ u64 file_size;
+
+ rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt,
+ lower_inode, 0);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "grab_cache_page for header page "
+ "failed\n");
+ goto out;
+ }
+ lower_a_ops = lower_inode->i_mapping->a_ops;
+ rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
+ file_size = (u64)i_size_read(inode);
+ ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
+ file_size = cpu_to_be64(file_size);
+ memcpy(header_virt, &file_size, sizeof(u64));
+ rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
+ if (rc < 0)
+ ecryptfs_printk(KERN_ERR, "Error commiting header page "
+ "write\n");
+ ecryptfs_unmap_and_release_lower_page(header_page);
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+out:
+ return rc;
+}
+
+int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
+ struct file *lower_file,
+ unsigned long lower_page_index, int byte_offset,
+ int region_bytes)
+{
+ int rc = 0;
+
+ rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, lower_inode,
+ lower_page_index);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to grab and map "
+ "lower page with index [0x%.16x]\n",
+ lower_page_index);
+ goto out;
+ }
+ rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file,
+ (*lower_page),
+ byte_offset,
+ region_bytes);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "prepare_write for "
+ "lower_page_index = [0x%.16x] failed; rc = "
+ "[%d]\n", lower_page_index, rc);
+ }
+out:
+ if (rc && (*lower_page)) {
+ ecryptfs_unmap_and_release_lower_page(*lower_page);
+ (*lower_page) = NULL;
+ }
+ return rc;
+}
+
+/**
+ * ecryptfs_commit_lower_page
+ *
+ * Returns zero on success; non-zero on error
+ */
+int
+ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
+ struct file *lower_file, int byte_offset,
+ int region_size)
+{
+ int rc = 0;
+
+ rc = lower_inode->i_mapping->a_ops->commit_write(
+ lower_file, lower_page, byte_offset, region_size);
+ if (rc < 0) {
+ ecryptfs_printk(KERN_ERR,
+ "Error committing write; rc = [%d]\n", rc);
+ } else
+ rc = 0;
+ ecryptfs_unmap_and_release_lower_page(lower_page);
+ return rc;
+}
+
+/**
+ * ecryptfs_copy_page_to_lower
+ *
+ * Used for plaintext pass-through; no page index interpolation
+ * required.
+ */
+int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
+ struct file *lower_file)
+{
+ int rc = 0;
+ struct page *lower_page;
+
+ rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file,
+ page->index, 0, PAGE_CACHE_SIZE);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to get page "
+ "at index [0x%.16x]\n", page->index);
+ goto out;
+ }
+ /* TODO: aops */
+ memcpy((char *)page_address(lower_page), page_address(page),
+ PAGE_CACHE_SIZE);
+ rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file,
+ 0, PAGE_CACHE_SIZE);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error attempting to commit page "
+ "at index [0x%.16x]\n", page->index);
+out:
+ return rc;
+}
+
+static int
+process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
+ struct file *file, struct inode *inode)
+{
+ struct page *header_page;
+ const struct address_space_operations *lower_a_ops;
+ struct inode *lower_inode;
+ struct file *lower_file;
+ char *header_virt;
+ int rc = 0;
+ int current_header_page = 0;
+ int header_pages;
+ int more_header_data_to_be_written = 1;
+
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ lower_file = ecryptfs_file_to_lower(file);
+ lower_a_ops = lower_inode->i_mapping->a_ops;
+ header_pages = ((crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front)
+ / PAGE_CACHE_SIZE);
+ BUG_ON(header_pages < 1);
+ while (current_header_page < header_pages) {
+ rc = ecryptfs_grab_and_map_lower_page(&header_page,
+ &header_virt,
+ lower_inode,
+ current_header_page);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "grab_cache_page for "
+ "header page [%d] failed; rc = [%d]\n",
+ current_header_page, rc);
+ goto out;
+ }
+ rc = lower_a_ops->prepare_write(lower_file, header_page, 0,
+ PAGE_CACHE_SIZE);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error preparing to write "
+ "header page out; rc = [%d]\n", rc);
+ goto out;
+ }
+ memset(header_virt, 0, PAGE_CACHE_SIZE);
+ if (more_header_data_to_be_written) {
+ rc = ecryptfs_write_headers_virt(header_virt,
+ crypt_stat,
+ file->f_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error "
+ "generating header; rc = "
+ "[%d]\n", rc);
+ rc = -EIO;
+ memset(header_virt, 0, PAGE_CACHE_SIZE);
+ ecryptfs_unmap_and_release_lower_page(
+ header_page);
+ goto out;
+ }
+ if (current_header_page == 0)
+ memset(header_virt, 0, 8);
+ more_header_data_to_be_written = 0;
+ }
+ rc = lower_a_ops->commit_write(lower_file, header_page, 0,
+ PAGE_CACHE_SIZE);
+ ecryptfs_unmap_and_release_lower_page(header_page);
+ if (rc < 0) {
+ ecryptfs_printk(KERN_ERR,
+ "Error commiting header page write; "
+ "rc = [%d]\n", rc);
+ break;
+ }
+ current_header_page++;
+ }
+ if (rc >= 0) {
+ rc = 0;
+ ecryptfs_printk(KERN_DEBUG, "lower_inode->i_blocks = "
+ "[0x%.16x]\n", lower_inode->i_blocks);
+ i_size_write(inode, 0);
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+ }
+ ecryptfs_printk(KERN_DEBUG, "Clearing ECRYPTFS_NEW_FILE flag in "
+ "crypt_stat at memory location [%p]\n", crypt_stat);
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_commit_write
+ * @file: The eCryptfs file object
+ * @page: The eCryptfs page
+ * @from: Ignored (we rotate the page IV on each write)
+ * @to: Ignored
+ *
+ * This is where we encrypt the data and pass the encrypted data to
+ * the lower filesystem. In OpenPGP-compatible mode, we operate on
+ * entire underlying packets.
+ */
+static int ecryptfs_commit_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ struct ecryptfs_page_crypt_context ctx;
+ loff_t pos;
+ struct inode *inode;
+ struct inode *lower_inode;
+ struct file *lower_file;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ int rc;
+
+ inode = page->mapping->host;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ lower_file = ecryptfs_file_to_lower(file);
+ mutex_lock(&lower_inode->i_mutex);
+ crypt_stat =
+ &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+ if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
+ ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
+ "crypt_stat at memory location [%p]\n", crypt_stat);
+ rc = process_new_file(crypt_stat, file, inode);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error processing new "
+ "file; rc = [%d]\n", rc);
+ goto out;
+ }
+ } else
+ ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
+ ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
+ "(page w/ index = [0x%.16x], to = [%d])\n", page->index,
+ to);
+ rc = fill_zeros_to_end_of_page(page, to);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
+ "zeros in page with index = [0x%.16x]\n",
+ page->index);
+ goto out;
+ }
+ ctx.page = page;
+ ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE;
+ ctx.param.lower_file = lower_file;
+ rc = ecryptfs_encrypt_page(&ctx);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
+ "index [0x%.16x])\n", page->index);
+ goto out;
+ }
+ rc = 0;
+ inode->i_blocks = lower_inode->i_blocks;
+ pos = (page->index << PAGE_CACHE_SHIFT) + to;
+ if (pos > i_size_read(inode)) {
+ i_size_write(inode, pos);
+ ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
+ "[0x%.16x]\n", i_size_read(inode));
+ }
+ ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+out:
+ kunmap(page); /* mapped in prior call (prepare_write) */
+ if (rc < 0)
+ ClearPageUptodate(page);
+ else
+ SetPageUptodate(page);
+ mutex_unlock(&lower_inode->i_mutex);
+ return rc;
+}
+
+/**
+ * write_zeros
+ * @file: The ecryptfs file
+ * @index: The index in which we are writing
+ * @start: The position after the last block of data
+ * @num_zeros: The number of zeros to write
+ *
+ * Write a specified number of zero's to a page.
+ *
+ * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE
+ */
+static
+int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
+{
+ int rc = 0;
+ struct page *tmp_page;
+
+ tmp_page = ecryptfs_get1page(file, index);
+ if (IS_ERR(tmp_page)) {
+ ecryptfs_printk(KERN_ERR, "Error getting page at index "
+ "[0x%.16x]\n", index);
+ rc = PTR_ERR(tmp_page);
+ goto out;
+ }
+ kmap(tmp_page);
+ rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
+ "to remainder of page at index [0x%.16x]\n",
+ index);
+ kunmap(tmp_page);
+ page_cache_release(tmp_page);
+ goto out;
+ }
+ memset(((char *)page_address(tmp_page) + start), 0, num_zeros);
+ rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
+ if (rc < 0) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to write zero's "
+ "to remainder of page at index [0x%.16x]\n",
+ index);
+ kunmap(tmp_page);
+ page_cache_release(tmp_page);
+ goto out;
+ }
+ rc = 0;
+ kunmap(tmp_page);
+ page_cache_release(tmp_page);
+out:
+ return rc;
+}
+
+static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
+{
+ int rc = 0;
+ struct inode *inode;
+ struct inode *lower_inode;
+
+ inode = (struct inode *)mapping->host;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ if (lower_inode->i_mapping->a_ops->bmap)
+ rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,
+ block);
+ return rc;
+}
+
+static void ecryptfs_sync_page(struct page *page)
+{
+ struct inode *inode;
+ struct inode *lower_inode;
+ struct page *lower_page;
+
+ inode = page->mapping->host;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ /* NOTE: Recently swapped with grab_cache_page(), since
+ * sync_page() just makes sure that pending I/O gets done. */
+ lower_page = find_lock_page(lower_inode->i_mapping, page->index);
+ if (!lower_page) {
+ ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n");
+ return;
+ }
+ lower_page->mapping->a_ops->sync_page(lower_page);
+ ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
+ lower_page->index);
+ unlock_page(lower_page);
+ page_cache_release(lower_page);
+}
+
+struct address_space_operations ecryptfs_aops = {
+ .writepage = ecryptfs_writepage,
+ .readpage = ecryptfs_readpage,
+ .prepare_write = ecryptfs_prepare_write,
+ .commit_write = ecryptfs_commit_write,
+ .bmap = ecryptfs_bmap,
+ .sync_page = ecryptfs_sync_page,
+};
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
new file mode 100644
index 0000000..c337c04
--- /dev/null
+++ b/fs/ecryptfs/super.c
@@ -0,0 +1,198 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.com>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/key.h>
+#include <linux/seq_file.h>
+#include <linux/crypto.h>
+#include "ecryptfs_kernel.h"
+
+struct kmem_cache *ecryptfs_inode_info_cache;
+
+/**
+ * ecryptfs_alloc_inode - allocate an ecryptfs inode
+ * @sb: Pointer to the ecryptfs super block
+ *
+ * Called to bring an inode into existence.
+ *
+ * Only handle allocation, setting up structures should be done in
+ * ecryptfs_read_inode. This is because the kernel, between now and
+ * then, will 0 out the private data pointer.
+ *
+ * Returns a pointer to a newly allocated inode, NULL otherwise
+ */
+static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
+{
+ struct ecryptfs_inode_info *ecryptfs_inode;
+ struct inode *inode = NULL;
+
+ ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache,
+ SLAB_KERNEL);
+ if (unlikely(!ecryptfs_inode))
+ goto out;
+ ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat);
+ inode = &ecryptfs_inode->vfs_inode;
+out:
+ return inode;
+}
+
+/**
+ * ecryptfs_destroy_inode
+ * @inode: The ecryptfs inode
+ *
+ * This is used during the final destruction of the inode.
+ * All allocation of memory related to the inode, including allocated
+ * memory in the crypt_stat struct, will be released here.
+ * There should be no chance that this deallocation will be missed.
+ */
+static void ecryptfs_destroy_inode(struct inode *inode)
+{
+ struct ecryptfs_inode_info *inode_info;
+
+ inode_info = ecryptfs_inode_to_private(inode);
+ ecryptfs_destruct_crypt_stat(&inode_info->crypt_stat);
+ kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
+}
+
+/**
+ * ecryptfs_init_inode
+ * @inode: The ecryptfs inode
+ *
+ * Set up the ecryptfs inode.
+ */
+void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
+{
+ ecryptfs_set_inode_lower(inode, lower_inode);
+ inode->i_ino = lower_inode->i_ino;
+ inode->i_version++;
+ inode->i_op = &ecryptfs_main_iops;
+ inode->i_fop = &ecryptfs_main_fops;
+ inode->i_mapping->a_ops = &ecryptfs_aops;
+}
+
+/**
+ * ecryptfs_put_super
+ * @sb: Pointer to the ecryptfs super block
+ *
+ * Final actions when unmounting a file system.
+ * This will handle deallocation and release of our private data.
+ */
+static void ecryptfs_put_super(struct super_block *sb)
+{
+ struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
+
+ ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat);
+ kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
+ ecryptfs_set_superblock_private(sb, NULL);
+}
+
+/**
+ * ecryptfs_statfs
+ * @sb: The ecryptfs super block
+ * @buf: The struct kstatfs to fill in with stats
+ *
+ * Get the filesystem statistics. Currently, we let this pass right through
+ * to the lower filesystem and take no action ourselves.
+ */
+static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
+}
+
+/**
+ * ecryptfs_clear_inode
+ * @inode - The ecryptfs inode
+ *
+ * Called by iput() when the inode reference count reached zero
+ * and the inode is not hashed anywhere. Used to clear anything
+ * that needs to be, before the inode is completely destroyed and put
+ * on the inode free list. We use this to drop out reference to the
+ * lower inode.
+ */
+static void ecryptfs_clear_inode(struct inode *inode)
+{
+ iput(ecryptfs_inode_to_lower(inode));
+}
+
+/**
+ * ecryptfs_umount_begin
+ *
+ * Called in do_umount().
+ */
+static void ecryptfs_umount_begin(struct vfsmount *vfsmnt, int flags)
+{
+ struct vfsmount *lower_mnt =
+ ecryptfs_dentry_to_lower_mnt(vfsmnt->mnt_sb->s_root);
+ struct super_block *lower_sb;
+
+ mntput(lower_mnt);
+ lower_sb = lower_mnt->mnt_sb;
+ if (lower_sb->s_op->umount_begin)
+ lower_sb->s_op->umount_begin(lower_mnt, flags);
+}
+
+/**
+ * ecryptfs_show_options
+ *
+ * Prints the directory we are currently mounted over.
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+ struct super_block *sb = mnt->mnt_sb;
+ struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
+ char *tmp_page;
+ char *path;
+ int rc = 0;
+
+ tmp_page = (char *)__get_free_page(GFP_KERNEL);
+ if (!tmp_page) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
+ if (IS_ERR(path)) {
+ rc = PTR_ERR(path);
+ goto out;
+ }
+ seq_printf(m, ",dir=%s", path);
+ free_page((unsigned long)tmp_page);
+out:
+ return rc;
+}
+
+struct super_operations ecryptfs_sops = {
+ .alloc_inode = ecryptfs_alloc_inode,
+ .destroy_inode = ecryptfs_destroy_inode,
+ .drop_inode = generic_delete_inode,
+ .put_super = ecryptfs_put_super,
+ .statfs = ecryptfs_statfs,
+ .remount_fs = NULL,
+ .clear_inode = ecryptfs_clear_inode,
+ .umount_begin = ecryptfs_umount_begin,
+ .show_options = ecryptfs_show_options
+};
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 87e1d03..e8c7765 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -144,42 +144,12 @@
*/
/*
- * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
- * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
- */
-static void nlmclnt_prepare_reclaim(struct nlm_host *host)
-{
- down_write(&host->h_rwsem);
- host->h_monitored = 0;
- host->h_state++;
- host->h_nextrebind = 0;
- nlm_rebind_host(host);
-
- /*
- * Mark the locks for reclaiming.
- */
- list_splice_init(&host->h_granted, &host->h_reclaim);
-
- dprintk("NLM: reclaiming locks for host %s\n", host->h_name);
-}
-
-static void nlmclnt_finish_reclaim(struct nlm_host *host)
-{
- host->h_reclaiming = 0;
- up_write(&host->h_rwsem);
- dprintk("NLM: done reclaiming locks for host %s", host->h_name);
-}
-
-/*
* Reclaim all locks on server host. We do this by spawning a separate
* reclaimer thread.
*/
void
-nlmclnt_recovery(struct nlm_host *host, u32 newstate)
+nlmclnt_recovery(struct nlm_host *host)
{
- if (host->h_nsmstate == newstate)
- return;
- host->h_nsmstate = newstate;
if (!host->h_reclaiming++) {
nlm_get_host(host);
__module_get(THIS_MODULE);
@@ -199,18 +169,30 @@
daemonize("%s-reclaim", host->h_name);
allow_signal(SIGKILL);
+ down_write(&host->h_rwsem);
+
/* This one ensures that our parent doesn't terminate while the
* reclaim is in progress */
lock_kernel();
lockd_up(0); /* note: this cannot fail as lockd is already running */
- nlmclnt_prepare_reclaim(host);
- /* First, reclaim all locks that have been marked. */
+ dprintk("lockd: reclaiming locks for host %s", host->h_name);
+
restart:
nsmstate = host->h_nsmstate;
+
+ /* Force a portmap getport - the peer's lockd will
+ * most likely end up on a different port.
+ */
+ host->h_nextrebind = jiffies;
+ nlm_rebind_host(host);
+
+ /* First, reclaim all locks that have been granted. */
+ list_splice_init(&host->h_granted, &host->h_reclaim);
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
list_del_init(&fl->fl_u.nfs_fl.list);
+ /* Why are we leaking memory here? --okir */
if (signalled())
continue;
if (nlmclnt_reclaim(host, fl) != 0)
@@ -218,11 +200,13 @@
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
if (host->h_nsmstate != nsmstate) {
/* Argh! The server rebooted again! */
- list_splice_init(&host->h_granted, &host->h_reclaim);
goto restart;
}
}
- nlmclnt_finish_reclaim(host);
+
+ host->h_reclaiming = 0;
+ up_write(&host->h_rwsem);
+ dprintk("NLM: done reclaiming locks for host %s", host->h_name);
/* Now, wake up all processes that sleep on a blocked lock */
list_for_each_entry(block, &nlm_blocked, b_list) {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 0116729..3d84f60 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -36,14 +36,14 @@
/*
* Cookie counter for NLM requests
*/
-static u32 nlm_cookie = 0x1234;
+static atomic_t nlm_cookie = ATOMIC_INIT(0x1234);
-static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
+void nlmclnt_next_cookie(struct nlm_cookie *c)
{
- memcpy(c->data, &nlm_cookie, 4);
- memset(c->data+4, 0, 4);
+ u32 cookie = atomic_inc_return(&nlm_cookie);
+
+ memcpy(c->data, &cookie, 4);
c->len=4;
- nlm_cookie++;
}
static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
@@ -153,6 +153,7 @@
{
struct rpc_clnt *client = NFS_CLIENT(inode);
struct sockaddr_in addr;
+ struct nfs_server *nfssrv = NFS_SERVER(inode);
struct nlm_host *host;
struct nlm_rqst *call;
sigset_t oldset;
@@ -166,7 +167,9 @@
}
rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr));
- host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers);
+ host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers,
+ nfssrv->nfs_client->cl_hostname,
+ strlen(nfssrv->nfs_client->cl_hostname));
if (host == NULL)
return -ENOLCK;
@@ -499,7 +502,7 @@
unsigned char fl_flags = fl->fl_flags;
int status = -ENOLCK;
- if (!host->h_monitored && nsm_monitor(host) < 0) {
+ if (nsm_monitor(host) < 0) {
printk(KERN_NOTICE "lockd: failed to monitor %s\n",
host->h_name);
goto out;
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index a0d0b58..fb24a97 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -27,46 +27,60 @@
#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ)
-static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH];
+static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
static unsigned long next_gc;
static int nrhosts;
static DEFINE_MUTEX(nlm_host_mutex);
static void nlm_gc_hosts(void);
+static struct nsm_handle * __nsm_find(const struct sockaddr_in *,
+ const char *, int, int);
/*
* Find an NLM server handle in the cache. If there is none, create it.
*/
struct nlm_host *
-nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
+nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
+ const char *hostname, int hostname_len)
{
- return nlm_lookup_host(0, sin, proto, version);
+ return nlm_lookup_host(0, sin, proto, version,
+ hostname, hostname_len);
}
/*
* Find an NLM client handle in the cache. If there is none, create it.
*/
struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp)
+nlmsvc_lookup_host(struct svc_rqst *rqstp,
+ const char *hostname, int hostname_len)
{
return nlm_lookup_host(1, &rqstp->rq_addr,
- rqstp->rq_prot, rqstp->rq_vers);
+ rqstp->rq_prot, rqstp->rq_vers,
+ hostname, hostname_len);
}
/*
* Common host lookup routine for server & client
*/
struct nlm_host *
-nlm_lookup_host(int server, struct sockaddr_in *sin,
- int proto, int version)
+nlm_lookup_host(int server, const struct sockaddr_in *sin,
+ int proto, int version,
+ const char *hostname,
+ int hostname_len)
{
- struct nlm_host *host, **hp;
- u32 addr;
+ struct hlist_head *chain;
+ struct hlist_node *pos;
+ struct nlm_host *host;
+ struct nsm_handle *nsm = NULL;
int hash;
- dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
- (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
+ dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n",
+ NIPQUAD(sin->sin_addr.s_addr), proto, version,
+ server? "server" : "client",
+ hostname_len,
+ hostname? hostname : "<none>");
+
hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
@@ -76,7 +90,22 @@
if (time_after_eq(jiffies, next_gc))
nlm_gc_hosts();
- for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
+ /* We may keep several nlm_host objects for a peer, because each
+ * nlm_host is identified by
+ * (address, protocol, version, server/client)
+ * We could probably simplify this a little by putting all those
+ * different NLM rpc_clients into one single nlm_host object.
+ * This would allow us to have one nlm_host per address.
+ */
+ chain = &nlm_hosts[hash];
+ hlist_for_each_entry(host, pos, chain, h_hash) {
+ if (!nlm_cmp_addr(&host->h_addr, sin))
+ continue;
+
+ /* See if we have an NSM handle for this client */
+ if (!nsm)
+ nsm = host->h_nsmhandle;
+
if (host->h_proto != proto)
continue;
if (host->h_version != version)
@@ -84,28 +113,30 @@
if (host->h_server != server)
continue;
- if (nlm_cmp_addr(&host->h_addr, sin)) {
- if (hp != nlm_hosts + hash) {
- *hp = host->h_next;
- host->h_next = nlm_hosts[hash];
- nlm_hosts[hash] = host;
- }
- nlm_get_host(host);
- mutex_unlock(&nlm_host_mutex);
- return host;
- }
- }
+ /* Move to head of hash chain. */
+ hlist_del(&host->h_hash);
+ hlist_add_head(&host->h_hash, chain);
- /* Ooops, no host found, create it */
- dprintk("lockd: creating host entry\n");
+ nlm_get_host(host);
+ goto out;
+ }
+ if (nsm)
+ atomic_inc(&nsm->sm_count);
+
+ host = NULL;
+
+ /* Sadly, the host isn't in our hash table yet. See if
+ * we have an NSM handle for it. If not, create one.
+ */
+ if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len)))
+ goto out;
host = kzalloc(sizeof(*host), GFP_KERNEL);
- if (!host)
- goto nohost;
-
- addr = sin->sin_addr.s_addr;
- sprintf(host->h_name, "%u.%u.%u.%u", NIPQUAD(addr));
-
+ if (!host) {
+ nsm_release(nsm);
+ goto out;
+ }
+ host->h_name = nsm->sm_name;
host->h_addr = *sin;
host->h_addr.sin_port = 0; /* ouch! */
host->h_version = version;
@@ -119,9 +150,9 @@
init_rwsem(&host->h_rwsem);
host->h_state = 0; /* pseudo NSM state */
host->h_nsmstate = 0; /* real NSM state */
+ host->h_nsmhandle = nsm;
host->h_server = server;
- host->h_next = nlm_hosts[hash];
- nlm_hosts[hash] = host;
+ hlist_add_head(&host->h_hash, chain);
INIT_LIST_HEAD(&host->h_lockowners);
spin_lock_init(&host->h_lock);
INIT_LIST_HEAD(&host->h_granted);
@@ -130,35 +161,39 @@
if (++nrhosts > NLM_HOST_MAX)
next_gc = 0;
-nohost:
+out:
mutex_unlock(&nlm_host_mutex);
return host;
}
-struct nlm_host *
-nlm_find_client(void)
+/*
+ * Destroy a host
+ */
+static void
+nlm_destroy_host(struct nlm_host *host)
{
- /* find a nlm_host for a client for which h_killed == 0.
- * and return it
+ struct rpc_clnt *clnt;
+
+ BUG_ON(!list_empty(&host->h_lockowners));
+ BUG_ON(atomic_read(&host->h_count));
+
+ /*
+ * Release NSM handle and unmonitor host.
*/
- int hash;
- mutex_lock(&nlm_host_mutex);
- for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
- struct nlm_host *host, **hp;
- for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
- if (host->h_server &&
- host->h_killed == 0) {
- nlm_get_host(host);
- mutex_unlock(&nlm_host_mutex);
- return host;
- }
+ nsm_unmonitor(host);
+
+ if ((clnt = host->h_rpcclnt) != NULL) {
+ if (atomic_read(&clnt->cl_users)) {
+ printk(KERN_WARNING
+ "lockd: active RPC handle\n");
+ clnt->cl_dead = 1;
+ } else {
+ rpc_destroy_client(host->h_rpcclnt);
}
}
- mutex_unlock(&nlm_host_mutex);
- return NULL;
+ kfree(host);
}
-
/*
* Create the NLM RPC client for an NLM peer
*/
@@ -260,22 +295,82 @@
}
/*
+ * We were notified that the host indicated by address &sin
+ * has rebooted.
+ * Release all resources held by that peer.
+ */
+void nlm_host_rebooted(const struct sockaddr_in *sin,
+ const char *hostname, int hostname_len,
+ u32 new_state)
+{
+ struct hlist_head *chain;
+ struct hlist_node *pos;
+ struct nsm_handle *nsm;
+ struct nlm_host *host;
+
+ dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
+ hostname, NIPQUAD(sin->sin_addr));
+
+ /* Find the NSM handle for this peer */
+ if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
+ return;
+
+ /* When reclaiming locks on this peer, make sure that
+ * we set up a new notification */
+ nsm->sm_monitored = 0;
+
+ /* Mark all hosts tied to this NSM state as having rebooted.
+ * We run the loop repeatedly, because we drop the host table
+ * lock for this.
+ * To avoid processing a host several times, we match the nsmstate.
+ */
+again: mutex_lock(&nlm_host_mutex);
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash) {
+ if (host->h_nsmhandle == nsm
+ && host->h_nsmstate != new_state) {
+ host->h_nsmstate = new_state;
+ host->h_state++;
+
+ nlm_get_host(host);
+ mutex_unlock(&nlm_host_mutex);
+
+ if (host->h_server) {
+ /* We're server for this guy, just ditch
+ * all the locks he held. */
+ nlmsvc_free_host_resources(host);
+ } else {
+ /* He's the server, initiate lock recovery. */
+ nlmclnt_recovery(host);
+ }
+
+ nlm_release_host(host);
+ goto again;
+ }
+ }
+ }
+
+ mutex_unlock(&nlm_host_mutex);
+}
+
+/*
* Shut down the hosts module.
* Note that this routine is called only at server shutdown time.
*/
void
nlm_shutdown_hosts(void)
{
+ struct hlist_head *chain;
+ struct hlist_node *pos;
struct nlm_host *host;
- int i;
dprintk("lockd: shutting down host module\n");
mutex_lock(&nlm_host_mutex);
/* First, make all hosts eligible for gc */
dprintk("lockd: nuking all hosts...\n");
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- for (host = nlm_hosts[i]; host; host = host->h_next)
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash)
host->h_expires = jiffies - 1;
}
@@ -287,8 +382,8 @@
if (nrhosts) {
printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
dprintk("lockd: %d hosts left:\n", nrhosts);
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- for (host = nlm_hosts[i]; host; host = host->h_next) {
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash) {
dprintk(" %s (cnt %d use %d exp %ld)\n",
host->h_name, atomic_read(&host->h_count),
host->h_inuse, host->h_expires);
@@ -305,45 +400,32 @@
static void
nlm_gc_hosts(void)
{
- struct nlm_host **q, *host;
- struct rpc_clnt *clnt;
- int i;
+ struct hlist_head *chain;
+ struct hlist_node *pos, *next;
+ struct nlm_host *host;
dprintk("lockd: host garbage collection\n");
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- for (host = nlm_hosts[i]; host; host = host->h_next)
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash)
host->h_inuse = 0;
}
/* Mark all hosts that hold locks, blocks or shares */
nlmsvc_mark_resources();
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- q = &nlm_hosts[i];
- while ((host = *q) != NULL) {
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry_safe(host, pos, next, chain, h_hash) {
if (atomic_read(&host->h_count) || host->h_inuse
|| time_before(jiffies, host->h_expires)) {
dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n",
host->h_name, atomic_read(&host->h_count),
host->h_inuse, host->h_expires);
- q = &host->h_next;
continue;
}
dprintk("lockd: delete host %s\n", host->h_name);
- *q = host->h_next;
- /* Don't unmonitor hosts that have been invalidated */
- if (host->h_monitored && !host->h_killed)
- nsm_unmonitor(host);
- if ((clnt = host->h_rpcclnt) != NULL) {
- if (atomic_read(&clnt->cl_users)) {
- printk(KERN_WARNING
- "lockd: active RPC handle\n");
- clnt->cl_dead = 1;
- } else {
- rpc_destroy_client(host->h_rpcclnt);
- }
- }
- kfree(host);
+ hlist_del_init(&host->h_hash);
+
+ nlm_destroy_host(host);
nrhosts--;
}
}
@@ -351,3 +433,88 @@
next_gc = jiffies + NLM_HOST_COLLECT;
}
+
+/*
+ * Manage NSM handles
+ */
+static LIST_HEAD(nsm_handles);
+static DEFINE_MUTEX(nsm_mutex);
+
+static struct nsm_handle *
+__nsm_find(const struct sockaddr_in *sin,
+ const char *hostname, int hostname_len,
+ int create)
+{
+ struct nsm_handle *nsm = NULL;
+ struct list_head *pos;
+
+ if (!sin)
+ return NULL;
+
+ if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
+ if (printk_ratelimit()) {
+ printk(KERN_WARNING "Invalid hostname \"%.*s\" "
+ "in NFS lock request\n",
+ hostname_len, hostname);
+ }
+ return NULL;
+ }
+
+ mutex_lock(&nsm_mutex);
+ list_for_each(pos, &nsm_handles) {
+ nsm = list_entry(pos, struct nsm_handle, sm_link);
+
+ if (hostname && nsm_use_hostnames) {
+ if (strlen(nsm->sm_name) != hostname_len
+ || memcmp(nsm->sm_name, hostname, hostname_len))
+ continue;
+ } else if (!nlm_cmp_addr(&nsm->sm_addr, sin))
+ continue;
+ atomic_inc(&nsm->sm_count);
+ goto out;
+ }
+
+ if (!create) {
+ nsm = NULL;
+ goto out;
+ }
+
+ nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
+ if (nsm != NULL) {
+ nsm->sm_addr = *sin;
+ nsm->sm_name = (char *) (nsm + 1);
+ memcpy(nsm->sm_name, hostname, hostname_len);
+ nsm->sm_name[hostname_len] = '\0';
+ atomic_set(&nsm->sm_count, 1);
+
+ list_add(&nsm->sm_link, &nsm_handles);
+ }
+
+out:
+ mutex_unlock(&nsm_mutex);
+ return nsm;
+}
+
+struct nsm_handle *
+nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len)
+{
+ return __nsm_find(sin, hostname, hostname_len, 1);
+}
+
+/*
+ * Release an NSM handle
+ */
+void
+nsm_release(struct nsm_handle *nsm)
+{
+ if (!nsm)
+ return;
+ if (atomic_dec_and_test(&nsm->sm_count)) {
+ mutex_lock(&nsm_mutex);
+ if (atomic_read(&nsm->sm_count) == 0) {
+ list_del(&nsm->sm_link);
+ kfree(nsm);
+ }
+ mutex_unlock(&nsm_mutex);
+ }
+}
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index a816b92..e0179f8 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -24,13 +24,13 @@
/*
* Local NSM state
*/
-u32 nsm_local_state;
+int nsm_local_state;
/*
* Common procedure for SM_MON/SM_UNMON calls
*/
static int
-nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
+nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
{
struct rpc_clnt *clnt;
int status;
@@ -46,10 +46,11 @@
goto out;
}
- args.addr = host->h_addr.sin_addr.s_addr;
- args.proto= (host->h_proto<<1) | host->h_server;
+ memset(&args, 0, sizeof(args));
+ args.mon_name = nsm->sm_name;
+ args.addr = nsm->sm_addr.sin_addr.s_addr;
args.prog = NLM_PROGRAM;
- args.vers = host->h_version;
+ args.vers = 3;
args.proc = NLMPROC_NSM_NOTIFY;
memset(res, 0, sizeof(*res));
@@ -70,17 +71,22 @@
int
nsm_monitor(struct nlm_host *host)
{
+ struct nsm_handle *nsm = host->h_nsmhandle;
struct nsm_res res;
int status;
dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
+ BUG_ON(nsm == NULL);
- status = nsm_mon_unmon(host, SM_MON, &res);
+ if (nsm->sm_monitored)
+ return 0;
+
+ status = nsm_mon_unmon(nsm, SM_MON, &res);
if (status < 0 || res.status != 0)
printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
else
- host->h_monitored = 1;
+ nsm->sm_monitored = 1;
return status;
}
@@ -90,16 +96,26 @@
int
nsm_unmonitor(struct nlm_host *host)
{
+ struct nsm_handle *nsm = host->h_nsmhandle;
struct nsm_res res;
- int status;
+ int status = 0;
- dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+ if (nsm == NULL)
+ return 0;
+ host->h_nsmhandle = NULL;
- status = nsm_mon_unmon(host, SM_UNMON, &res);
- if (status < 0)
- printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
- else
- host->h_monitored = 0;
+ if (atomic_read(&nsm->sm_count) == 1
+ && nsm->sm_monitored && !nsm->sm_sticky) {
+ dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+
+ status = nsm_mon_unmon(nsm, SM_UNMON, &res);
+ if (status < 0)
+ printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
+ host->h_name);
+ else
+ nsm->sm_monitored = 0;
+ }
+ nsm_release(nsm);
return status;
}
@@ -135,7 +151,7 @@
static u32 *
xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
{
- char buffer[20];
+ char buffer[20], *name;
/*
* Use the dotted-quad IP address of the remote host as
@@ -143,8 +159,13 @@
* hostname first for whatever remote hostname it receives,
* so this works alright.
*/
- sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
- if (!(p = xdr_encode_string(p, buffer))
+ if (nsm_use_hostnames) {
+ name = argp->mon_name;
+ } else {
+ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
+ name = buffer;
+ }
+ if (!(p = xdr_encode_string(p, name))
|| !(p = xdr_encode_string(p, utsname()->nodename)))
return ERR_PTR(-EIO);
*p++ = htonl(argp->prog);
@@ -160,9 +181,11 @@
p = xdr_encode_common(rqstp, p, argp);
if (IS_ERR(p))
return PTR_ERR(p);
+
+ /* Surprise - there may even be room for an IPv6 address now */
*p++ = argp->addr;
- *p++ = argp->vers;
- *p++ = argp->proto;
+ *p++ = 0;
+ *p++ = 0;
*p++ = 0;
rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
return 0;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 3cc369e..6341392 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -33,6 +33,7 @@
#include <linux/sunrpc/svcsock.h>
#include <net/ip.h>
#include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
#include <linux/nfs.h>
#define NLMDBG_FACILITY NLMDBG_SVC
@@ -61,6 +62,7 @@
static unsigned long nlm_grace_period;
static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
static int nlm_udpport, nlm_tcpport;
+int nsm_use_hostnames = 0;
/*
* Constants needed for the sysctl interface.
@@ -395,6 +397,22 @@
.extra1 = (int *) &nlm_port_min,
.extra2 = (int *) &nlm_port_max,
},
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nsm_use_hostnames",
+ .data = &nsm_use_hostnames,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nsm_local_state",
+ .data = &nsm_local_state,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
{ .ctl_name = 0 }
};
@@ -483,6 +501,7 @@
&nlm_udpport, 0644);
module_param_call(nlm_tcpport, param_set_port, param_get_int,
&nlm_tcpport, 0644);
+module_param(nsm_use_hostnames, bool, 0644);
/*
* Initialising and terminating the module.
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index a2dd9cc..fa370f6 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -38,8 +38,8 @@
return nlm_lck_denied_nolocks;
/* Obtain host handle */
- if (!(host = nlmsvc_lookup_host(rqstp))
- || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+ if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
+ || (argp->monitor && nsm_monitor(host) < 0))
goto no_locks;
*hostp = host;
@@ -260,7 +260,9 @@
struct nlm_rqst *call;
int stat;
- host = nlmsvc_lookup_host(rqstp);
+ host = nlmsvc_lookup_host(rqstp,
+ argp->lock.caller,
+ argp->lock.len);
if (host == NULL)
return rpc_system_err;
@@ -420,10 +422,6 @@
void *resp)
{
struct sockaddr_in saddr = rqstp->rq_addr;
- int vers = argp->vers;
- int prot = argp->proto >> 1;
-
- struct nlm_host *host;
dprintk("lockd: SM_NOTIFY called\n");
if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
@@ -438,21 +436,10 @@
/* Obtain the host pointer for this NFS server and try to
* reclaim all locks we hold on this server.
*/
+ memset(&saddr, 0, sizeof(saddr));
saddr.sin_addr.s_addr = argp->addr;
+ nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
- if ((argp->proto & 1)==0) {
- if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
- nlmclnt_recovery(host, argp->state);
- nlm_release_host(host);
- }
- } else {
- /* If we run on an NFS server, delete all locks held by the client */
-
- if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
- nlmsvc_free_host_resources(host);
- nlm_release_host(host);
- }
- }
return rpc_success;
}
@@ -468,7 +455,7 @@
dprintk("lockd: GRANTED_RES called\n");
- nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+ nlmsvc_grant_reply(&argp->cookie, argp->status);
return rpc_success;
}
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 93c00ee..814c606 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -40,7 +40,7 @@
static void nlmsvc_release_block(struct nlm_block *block);
static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
-static int nlmsvc_remove_block(struct nlm_block *block);
+static void nlmsvc_remove_block(struct nlm_block *block);
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
static void nlmsvc_freegrantargs(struct nlm_rqst *call);
@@ -49,7 +49,7 @@
/*
* The list of blocked locks to retry
*/
-static struct nlm_block * nlm_blocked;
+static LIST_HEAD(nlm_blocked);
/*
* Insert a blocked lock into the global list
@@ -57,48 +57,44 @@
static void
nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
{
- struct nlm_block **bp, *b;
+ struct nlm_block *b;
+ struct list_head *pos;
dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
- kref_get(&block->b_count);
- if (block->b_queued)
- nlmsvc_remove_block(block);
- bp = &nlm_blocked;
+ if (list_empty(&block->b_list)) {
+ kref_get(&block->b_count);
+ } else {
+ list_del_init(&block->b_list);
+ }
+
+ pos = &nlm_blocked;
if (when != NLM_NEVER) {
if ((when += jiffies) == NLM_NEVER)
when ++;
- while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER)
- bp = &b->b_next;
- } else
- while ((b = *bp) != 0)
- bp = &b->b_next;
+ list_for_each(pos, &nlm_blocked) {
+ b = list_entry(pos, struct nlm_block, b_list);
+ if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
+ break;
+ }
+ /* On normal exit from the loop, pos == &nlm_blocked,
+ * so we will be adding to the end of the list - good
+ */
+ }
- block->b_queued = 1;
+ list_add_tail(&block->b_list, pos);
block->b_when = when;
- block->b_next = b;
- *bp = block;
}
/*
* Remove a block from the global list
*/
-static int
+static inline void
nlmsvc_remove_block(struct nlm_block *block)
{
- struct nlm_block **bp, *b;
-
- if (!block->b_queued)
- return 1;
- for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) {
- if (b == block) {
- *bp = block->b_next;
- block->b_queued = 0;
- nlmsvc_release_block(block);
- return 1;
- }
+ if (!list_empty(&block->b_list)) {
+ list_del_init(&block->b_list);
+ nlmsvc_release_block(block);
}
-
- return 0;
}
/*
@@ -107,14 +103,14 @@
static struct nlm_block *
nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
{
- struct nlm_block **head, *block;
+ struct nlm_block *block;
struct file_lock *fl;
dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
file, lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end, lock->fl.fl_type);
- for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
+ list_for_each_entry(block, &nlm_blocked, b_list) {
fl = &block->b_call->a_args.lock.fl;
dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
block->b_file, fl->fl_pid,
@@ -143,20 +139,20 @@
* Find a block with a given NLM cookie.
*/
static inline struct nlm_block *
-nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
+nlmsvc_find_block(struct nlm_cookie *cookie)
{
struct nlm_block *block;
- for (block = nlm_blocked; block; block = block->b_next) {
- dprintk("cookie: head of blocked queue %p, block %p\n",
- nlm_blocked, block);
- if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)
- && nlm_cmp_addr(sin, &block->b_host->h_addr))
- break;
+ list_for_each_entry(block, &nlm_blocked, b_list) {
+ if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
+ goto found;
}
- if (block != NULL)
- kref_get(&block->b_count);
+ return NULL;
+
+found:
+ dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
+ kref_get(&block->b_count);
return block;
}
@@ -169,6 +165,11 @@
* request, but (as I found out later) that's because some implementations
* do just this. Never mind the standards comittees, they support our
* logging industries.
+ *
+ * 10 years later: I hope we can safely ignore these old and broken
+ * clients by now. Let's fix this so we can uniquely identify an incoming
+ * GRANTED_RES message by cookie, without having to rely on the client's IP
+ * address. --okir
*/
static inline struct nlm_block *
nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
@@ -179,7 +180,7 @@
struct nlm_rqst *call = NULL;
/* Create host handle for callback */
- host = nlmsvc_lookup_host(rqstp);
+ host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len);
if (host == NULL)
return NULL;
@@ -192,6 +193,8 @@
if (block == NULL)
goto failed;
kref_init(&block->b_count);
+ INIT_LIST_HEAD(&block->b_list);
+ INIT_LIST_HEAD(&block->b_flist);
if (!nlmsvc_setgrantargs(call, lock))
goto failed_free;
@@ -199,7 +202,7 @@
/* Set notifier function for VFS, and init args */
call->a_args.lock.fl.fl_flags |= FL_SLEEP;
call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
- call->a_args.cookie = *cookie; /* see above */
+ nlmclnt_next_cookie(&call->a_args.cookie);
dprintk("lockd: created block %p...\n", block);
@@ -210,8 +213,7 @@
file->f_count++;
/* Add to file's list of blocks */
- block->b_fnext = file->f_blocks;
- file->f_blocks = block;
+ list_add(&block->b_flist, &file->f_blocks);
/* Set up RPC arguments for callback */
block->b_call = call;
@@ -248,19 +250,13 @@
{
struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
struct nlm_file *file = block->b_file;
- struct nlm_block **bp;
dprintk("lockd: freeing block %p...\n", block);
- down(&file->f_sema);
/* Remove block from file's list of blocks */
- for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
- if (*bp == block) {
- *bp = block->b_fnext;
- break;
- }
- }
- up(&file->f_sema);
+ mutex_lock(&file->f_mutex);
+ list_del_init(&block->b_flist);
+ mutex_unlock(&file->f_mutex);
nlmsvc_freegrantargs(block->b_call);
nlm_release_call(block->b_call);
@@ -274,47 +270,32 @@
kref_put(&block->b_count, nlmsvc_free_block);
}
-static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file)
+/*
+ * Loop over all blocks and delete blocks held by
+ * a matching host.
+ */
+void nlmsvc_traverse_blocks(struct nlm_host *host,
+ struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
- struct nlm_block *block;
-
- down(&file->f_sema);
- for (block = file->f_blocks; block != NULL; block = block->b_fnext)
- block->b_host->h_inuse = 1;
- up(&file->f_sema);
-}
-
-static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
-{
- struct nlm_block *block;
+ struct nlm_block *block, *next;
restart:
- down(&file->f_sema);
- for (block = file->f_blocks; block != NULL; block = block->b_fnext) {
- if (host != NULL && host != block->b_host)
+ mutex_lock(&file->f_mutex);
+ list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
+ if (!match(block->b_host, host))
continue;
- if (!block->b_queued)
+ /* Do not destroy blocks that are not on
+ * the global retry list - why? */
+ if (list_empty(&block->b_list))
continue;
kref_get(&block->b_count);
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
goto restart;
}
- up(&file->f_sema);
-}
-
-/*
- * Loop over all blocks and perform the action specified.
- * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
- */
-void
-nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
-{
- if (action == NLM_ACT_MARK)
- nlmsvc_act_mark(host, file);
- else
- nlmsvc_act_unlock(host, file);
+ mutex_unlock(&file->f_mutex);
}
/*
@@ -373,7 +354,7 @@
lock->fl.fl_flags &= ~FL_SLEEP;
again:
/* Lock file against concurrent access */
- down(&file->f_sema);
+ mutex_lock(&file->f_mutex);
/* Get existing block (in case client is busy-waiting) */
block = nlmsvc_lookup_block(file, lock);
if (block == NULL) {
@@ -411,10 +392,10 @@
/* If we don't have a block, create and initialize it. Then
* retry because we may have slept in kmalloc. */
- /* We have to release f_sema as nlmsvc_create_block may try to
+ /* We have to release f_mutex as nlmsvc_create_block may try to
* to claim it while doing host garbage collection */
if (newblock == NULL) {
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
dprintk("lockd: blocking on this lock (allocating).\n");
if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
return nlm_lck_denied_nolocks;
@@ -424,7 +405,7 @@
/* Append to list of blocked */
nlmsvc_insert_block(newblock, NLM_NEVER);
out:
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
nlmsvc_release_block(newblock);
nlmsvc_release_block(block);
dprintk("lockd: nlmsvc_lock returned %u\n", ret);
@@ -451,6 +432,7 @@
(long long)conflock->fl.fl_start,
(long long)conflock->fl.fl_end);
conflock->caller = "somehost"; /* FIXME */
+ conflock->len = strlen(conflock->caller);
conflock->oh.len = 0; /* don't return OH info */
conflock->svid = conflock->fl.fl_pid;
return nlm_lck_denied;
@@ -507,9 +489,9 @@
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
- down(&file->f_sema);
+ mutex_lock(&file->f_mutex);
block = nlmsvc_lookup_block(file, lock);
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
if (block != NULL) {
status = nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
@@ -527,10 +509,10 @@
static void
nlmsvc_notify_blocked(struct file_lock *fl)
{
- struct nlm_block **bp, *block;
+ struct nlm_block *block;
dprintk("lockd: VFS unblock notification for block %p\n", fl);
- for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
+ list_for_each_entry(block, &nlm_blocked, b_list) {
if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
nlmsvc_insert_block(block, 0);
svc_wake_up(block->b_daemon);
@@ -663,17 +645,14 @@
* block.
*/
void
-nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status)
+nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
{
struct nlm_block *block;
- struct nlm_file *file;
- dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n",
- *(unsigned int *)(cookie->data),
- ntohl(rqstp->rq_addr.sin_addr.s_addr), status);
- if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr)))
+ dprintk("grant_reply: looking for cookie %x, s=%d \n",
+ *(unsigned int *)(cookie->data), status);
+ if (!(block = nlmsvc_find_block(cookie)))
return;
- file = block->b_file;
if (block) {
if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
@@ -696,16 +675,19 @@
unsigned long
nlmsvc_retry_blocked(void)
{
- struct nlm_block *block;
+ unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+ struct nlm_block *block;
- dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
- nlm_blocked,
- nlm_blocked? nlm_blocked->b_when : 0);
- while ((block = nlm_blocked) != 0) {
+ while (!list_empty(&nlm_blocked)) {
+ block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
+
if (block->b_when == NLM_NEVER)
break;
- if (time_after(block->b_when,jiffies))
+ if (time_after(block->b_when,jiffies)) {
+ timeout = block->b_when - jiffies;
break;
+ }
+
dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
block, block->b_when);
kref_get(&block->b_count);
@@ -713,8 +695,5 @@
nlmsvc_release_block(block);
}
- if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
- return (block->b_when - jiffies);
-
- return MAX_SCHEDULE_TIMEOUT;
+ return timeout;
}
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index dbb66a3..75b2c81 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -66,8 +66,8 @@
return nlm_lck_denied_nolocks;
/* Obtain host handle */
- if (!(host = nlmsvc_lookup_host(rqstp))
- || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+ if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
+ || (argp->monitor && nsm_monitor(host) < 0))
goto no_locks;
*hostp = host;
@@ -287,7 +287,9 @@
struct nlm_rqst *call;
int stat;
- host = nlmsvc_lookup_host(rqstp);
+ host = nlmsvc_lookup_host(rqstp,
+ argp->lock.caller,
+ argp->lock.len);
if (host == NULL)
return rpc_system_err;
@@ -449,9 +451,6 @@
void *resp)
{
struct sockaddr_in saddr = rqstp->rq_addr;
- int vers = argp->vers;
- int prot = argp->proto >> 1;
- struct nlm_host *host;
dprintk("lockd: SM_NOTIFY called\n");
if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
@@ -466,19 +465,9 @@
/* Obtain the host pointer for this NFS server and try to
* reclaim all locks we hold on this server.
*/
+ memset(&saddr, 0, sizeof(saddr));
saddr.sin_addr.s_addr = argp->addr;
- if ((argp->proto & 1)==0) {
- if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
- nlmclnt_recovery(host, argp->state);
- nlm_release_host(host);
- }
- } else {
- /* If we run on an NFS server, delete all locks held by the client */
- if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
- nlmsvc_free_host_resources(host);
- nlm_release_host(host);
- }
- }
+ nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
return rpc_success;
}
@@ -495,7 +484,7 @@
dprintk("lockd: GRANTED_RES called\n");
- nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+ nlmsvc_grant_reply(&argp->cookie, argp->status);
return rpc_success;
}
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 27288c8..b9926ce 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -85,24 +85,20 @@
}
/*
- * Traverse all shares for a given file (and host).
- * NLM_ACT_CHECK is handled by nlmsvc_inspect_file.
+ * Traverse all shares for a given file, and delete
+ * those owned by the given (type of) host
*/
-void
-nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
+void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
struct nlm_share *share, **shpp;
shpp = &file->f_shares;
while ((share = *shpp) != NULL) {
- if (action == NLM_ACT_MARK)
- share->s_host->h_inuse = 1;
- else if (action == NLM_ACT_UNLOCK) {
- if (host == NULL || host == share->s_host) {
- *shpp = share->s_next;
- kfree(share);
- continue;
- }
+ if (match(share->s_host, host)) {
+ *shpp = share->s_next;
+ kfree(share);
+ continue;
}
shpp = &share->s_next;
}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index a92dd98f..514f5f2 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -25,9 +25,9 @@
/*
* Global file hash table
*/
-#define FILE_HASH_BITS 5
+#define FILE_HASH_BITS 7
#define FILE_NRHASH (1<<FILE_HASH_BITS)
-static struct nlm_file * nlm_files[FILE_NRHASH];
+static struct hlist_head nlm_files[FILE_NRHASH];
static DEFINE_MUTEX(nlm_file_mutex);
#ifdef NFSD_DEBUG
@@ -82,6 +82,7 @@
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
struct nfs_fh *f)
{
+ struct hlist_node *pos;
struct nlm_file *file;
unsigned int hash;
u32 nfserr;
@@ -93,7 +94,7 @@
/* Lock file table */
mutex_lock(&nlm_file_mutex);
- for (file = nlm_files[hash]; file; file = file->f_next)
+ hlist_for_each_entry(file, pos, &nlm_files[hash], f_list)
if (!nfs_compare_fh(&file->f_handle, f))
goto found;
@@ -105,8 +106,9 @@
goto out_unlock;
memcpy(&file->f_handle, f, sizeof(struct nfs_fh));
- file->f_hash = hash;
- init_MUTEX(&file->f_sema);
+ mutex_init(&file->f_mutex);
+ INIT_HLIST_NODE(&file->f_list);
+ INIT_LIST_HEAD(&file->f_blocks);
/* Open the file. Note that this must not sleep for too long, else
* we would lock up lockd:-) So no NFS re-exports, folks.
@@ -115,12 +117,11 @@
* the file.
*/
if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) {
- dprintk("lockd: open failed (nfserr %d)\n", ntohl(nfserr));
+ dprintk("lockd: open failed (error %d)\n", nfserr);
goto out_free;
}
- file->f_next = nlm_files[hash];
- nlm_files[hash] = file;
+ hlist_add_head(&file->f_list, &nlm_files[hash]);
found:
dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
@@ -149,22 +150,14 @@
static inline void
nlm_delete_file(struct nlm_file *file)
{
- struct nlm_file **fp, *f;
-
nlm_debug_print_file("closing file", file);
-
- fp = nlm_files + file->f_hash;
- while ((f = *fp) != NULL) {
- if (f == file) {
- *fp = file->f_next;
- nlmsvc_ops->fclose(file->f_file);
- kfree(file);
- return;
- }
- fp = &f->f_next;
+ if (!hlist_unhashed(&file->f_list)) {
+ hlist_del(&file->f_list);
+ nlmsvc_ops->fclose(file->f_file);
+ kfree(file);
+ } else {
+ printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
}
-
- printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
}
/*
@@ -172,7 +165,8 @@
* action.
*/
static int
-nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
struct inode *inode = nlmsvc_file_inode(file);
struct file_lock *fl;
@@ -186,16 +180,10 @@
/* update current lock count */
file->f_locks++;
- lockhost = (struct nlm_host *) fl->fl_owner;
- if (action == NLM_ACT_MARK)
- lockhost->h_inuse = 1;
- else if (action == NLM_ACT_CHECK)
- return 1;
- else if (action == NLM_ACT_UNLOCK) {
- struct file_lock lock = *fl;
- if (host && lockhost != host)
- continue;
+ lockhost = (struct nlm_host *) fl->fl_owner;
+ if (match(lockhost, host)) {
+ struct file_lock lock = *fl;
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
@@ -213,53 +201,66 @@
}
/*
- * Operate on a single file
+ * Inspect a single file
*/
static inline int
-nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match)
{
- if (action == NLM_ACT_CHECK) {
- /* Fast path for mark and sweep garbage collection */
- if (file->f_count || file->f_blocks || file->f_shares)
+ nlmsvc_traverse_blocks(host, file, match);
+ nlmsvc_traverse_shares(host, file, match);
+ return nlm_traverse_locks(host, file, match);
+}
+
+/*
+ * Quick check whether there are still any locks, blocks or
+ * shares on a given file.
+ */
+static inline int
+nlm_file_inuse(struct nlm_file *file)
+{
+ struct inode *inode = nlmsvc_file_inode(file);
+ struct file_lock *fl;
+
+ if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
+ return 1;
+
+ for (fl = inode->i_flock; fl; fl = fl->fl_next) {
+ if (fl->fl_lmops == &nlmsvc_lock_operations)
return 1;
- } else {
- nlmsvc_traverse_blocks(host, file, action);
- nlmsvc_traverse_shares(host, file, action);
}
- return nlm_traverse_locks(host, file, action);
+ file->f_locks = 0;
+ return 0;
}
/*
* Loop over all files in the file table.
*/
static int
-nlm_traverse_files(struct nlm_host *host, int action)
+nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
{
- struct nlm_file *file, **fp;
+ struct hlist_node *pos, *next;
+ struct nlm_file *file;
int i, ret = 0;
mutex_lock(&nlm_file_mutex);
for (i = 0; i < FILE_NRHASH; i++) {
- fp = nlm_files + i;
- while ((file = *fp) != NULL) {
+ hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
file->f_count++;
mutex_unlock(&nlm_file_mutex);
/* Traverse locks, blocks and shares of this file
* and update file->f_locks count */
- if (nlm_inspect_file(host, file, action))
+ if (nlm_inspect_file(host, file, match))
ret = 1;
mutex_lock(&nlm_file_mutex);
file->f_count--;
/* No more references to this file. Let go of it. */
- if (!file->f_blocks && !file->f_locks
+ if (list_empty(&file->f_blocks) && !file->f_locks
&& !file->f_shares && !file->f_count) {
- *fp = file->f_next;
+ hlist_del(&file->f_list);
nlmsvc_ops->fclose(file->f_file);
kfree(file);
- } else {
- fp = &file->f_next;
}
}
}
@@ -286,23 +287,54 @@
mutex_lock(&nlm_file_mutex);
/* If there are no more locks etc, delete the file */
- if(--file->f_count == 0) {
- if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
- nlm_delete_file(file);
- }
+ if (--file->f_count == 0 && !nlm_file_inuse(file))
+ nlm_delete_file(file);
mutex_unlock(&nlm_file_mutex);
}
/*
+ * Helpers function for resource traversal
+ *
+ * nlmsvc_mark_host:
+ * used by the garbage collector; simply sets h_inuse.
+ * Always returns 0.
+ *
+ * nlmsvc_same_host:
+ * returns 1 iff the two hosts match. Used to release
+ * all resources bound to a specific host.
+ *
+ * nlmsvc_is_client:
+ * returns 1 iff the host is a client.
+ * Used by nlmsvc_invalidate_all
+ */
+static int
+nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy)
+{
+ host->h_inuse = 1;
+ return 0;
+}
+
+static int
+nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other)
+{
+ return host == other;
+}
+
+static int
+nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy)
+{
+ return host->h_server;
+}
+
+/*
* Mark all hosts that still hold resources
*/
void
nlmsvc_mark_resources(void)
{
dprintk("lockd: nlmsvc_mark_resources\n");
-
- nlm_traverse_files(NULL, NLM_ACT_MARK);
+ nlm_traverse_files(NULL, nlmsvc_mark_host);
}
/*
@@ -313,23 +345,25 @@
{
dprintk("lockd: nlmsvc_free_host_resources\n");
- if (nlm_traverse_files(host, NLM_ACT_UNLOCK))
+ if (nlm_traverse_files(host, nlmsvc_same_host)) {
printk(KERN_WARNING
- "lockd: couldn't remove all locks held by %s",
+ "lockd: couldn't remove all locks held by %s\n",
host->h_name);
+ BUG();
+ }
}
/*
- * delete all hosts structs for clients
+ * Remove all locks held for clients
*/
void
nlmsvc_invalidate_all(void)
{
- struct nlm_host *host;
- while ((host = nlm_find_client()) != NULL) {
- nlmsvc_free_host_resources(host);
- host->h_expires = 0;
- host->h_killed = 1;
- nlm_release_host(host);
- }
+ /* Release all locks held by NFS clients.
+ * Previously, the code would call
+ * nlmsvc_free_host_resources for each client in
+ * turn, which is about as inefficient as it gets.
+ * Now we just do it once in nlm_traverse_files.
+ */
+ nlm_traverse_files(NULL, nlmsvc_is_client);
}
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index cfe141e..e13fa23 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -319,12 +319,25 @@
static struct cache_head *export_table[EXPORT_HASHMAX];
+static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
+{
+ int i;
+
+ for (i = 0; i < fsloc->locations_count; i++) {
+ kfree(fsloc->locations[i].path);
+ kfree(fsloc->locations[i].hosts);
+ }
+ kfree(fsloc->locations);
+}
+
static void svc_export_put(struct kref *ref)
{
struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
dput(exp->ex_dentry);
mntput(exp->ex_mnt);
auth_domain_put(exp->ex_client);
+ kfree(exp->ex_path);
+ nfsd4_fslocs_free(&exp->ex_fslocs);
kfree(exp);
}
@@ -386,6 +399,69 @@
}
+#ifdef CONFIG_NFSD_V4
+
+static int
+fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
+{
+ int len;
+ int migrated, i, err;
+
+ len = qword_get(mesg, buf, PAGE_SIZE);
+ if (len != 5 || memcmp(buf, "fsloc", 5))
+ return 0;
+
+ /* listsize */
+ err = get_int(mesg, &fsloc->locations_count);
+ if (err)
+ return err;
+ if (fsloc->locations_count > MAX_FS_LOCATIONS)
+ return -EINVAL;
+ if (fsloc->locations_count == 0)
+ return 0;
+
+ fsloc->locations = kzalloc(fsloc->locations_count
+ * sizeof(struct nfsd4_fs_location), GFP_KERNEL);
+ if (!fsloc->locations)
+ return -ENOMEM;
+ for (i=0; i < fsloc->locations_count; i++) {
+ /* colon separated host list */
+ err = -EINVAL;
+ len = qword_get(mesg, buf, PAGE_SIZE);
+ if (len <= 0)
+ goto out_free_all;
+ err = -ENOMEM;
+ fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
+ if (!fsloc->locations[i].hosts)
+ goto out_free_all;
+ err = -EINVAL;
+ /* slash separated path component list */
+ len = qword_get(mesg, buf, PAGE_SIZE);
+ if (len <= 0)
+ goto out_free_all;
+ err = -ENOMEM;
+ fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
+ if (!fsloc->locations[i].path)
+ goto out_free_all;
+ }
+ /* migrated */
+ err = get_int(mesg, &migrated);
+ if (err)
+ goto out_free_all;
+ err = -EINVAL;
+ if (migrated < 0 || migrated > 1)
+ goto out_free_all;
+ fsloc->migrated = migrated;
+ return 0;
+out_free_all:
+ nfsd4_fslocs_free(fsloc);
+ return err;
+}
+
+#else /* CONFIG_NFSD_V4 */
+static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; }
+#endif
+
static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
{
/* client path expiry [flags anonuid anongid fsid] */
@@ -398,6 +474,7 @@
int an_int;
nd.dentry = NULL;
+ exp.ex_path = NULL;
if (mesg[mlen-1] != '\n')
return -EINVAL;
@@ -428,6 +505,10 @@
exp.ex_client = dom;
exp.ex_mnt = nd.mnt;
exp.ex_dentry = nd.dentry;
+ exp.ex_path = kstrdup(buf, GFP_KERNEL);
+ err = -ENOMEM;
+ if (!exp.ex_path)
+ goto out;
/* expiry */
err = -EINVAL;
@@ -435,6 +516,11 @@
if (exp.h.expiry_time == 0)
goto out;
+ /* fs locations */
+ exp.ex_fslocs.locations = NULL;
+ exp.ex_fslocs.locations_count = 0;
+ exp.ex_fslocs.migrated = 0;
+
/* flags */
err = get_int(&mesg, &an_int);
if (err == -ENOENT)
@@ -460,6 +546,10 @@
err = check_export(nd.dentry->d_inode, exp.ex_flags);
if (err) goto out;
+
+ err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
+ if (err)
+ goto out;
}
expp = svc_export_lookup(&exp);
@@ -473,6 +563,7 @@
else
exp_put(expp);
out:
+ kfree(exp.ex_path);
if (nd.dentry)
path_release(&nd);
out_no_path:
@@ -482,7 +573,8 @@
return err;
}
-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong);
+static void exp_flags(struct seq_file *m, int flag, int fsid,
+ uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
static int svc_export_show(struct seq_file *m,
struct cache_detail *cd,
@@ -501,8 +593,8 @@
seq_putc(m, '(');
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
- exp_flags(m, exp->ex_flags, exp->ex_fsid,
- exp->ex_anon_uid, exp->ex_anon_gid);
+ exp_flags(m, exp->ex_flags, exp->ex_fsid,
+ exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
seq_puts(m, ")\n");
return 0;
}
@@ -524,6 +616,10 @@
new->ex_client = item->ex_client;
new->ex_dentry = dget(item->ex_dentry);
new->ex_mnt = mntget(item->ex_mnt);
+ new->ex_path = NULL;
+ new->ex_fslocs.locations = NULL;
+ new->ex_fslocs.locations_count = 0;
+ new->ex_fslocs.migrated = 0;
}
static void export_update(struct cache_head *cnew, struct cache_head *citem)
@@ -535,6 +631,14 @@
new->ex_anon_uid = item->ex_anon_uid;
new->ex_anon_gid = item->ex_anon_gid;
new->ex_fsid = item->ex_fsid;
+ new->ex_path = item->ex_path;
+ item->ex_path = NULL;
+ new->ex_fslocs.locations = item->ex_fslocs.locations;
+ item->ex_fslocs.locations = NULL;
+ new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
+ item->ex_fslocs.locations_count = 0;
+ new->ex_fslocs.migrated = item->ex_fslocs.migrated;
+ item->ex_fslocs.migrated = 0;
}
static struct cache_head *svc_export_alloc(void)
@@ -1048,30 +1152,21 @@
exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
struct cache_req *creq)
{
- struct svc_expkey *fsid_key;
struct svc_export *exp;
int rv;
u32 fsidv[2];
mk_fsid_v1(fsidv, 0);
- fsid_key = exp_find_key(clp, 1, fsidv, creq);
- if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN)
+ exp = exp_find(clp, 1, fsidv, creq);
+ if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
return nfserr_dropit;
- if (!fsid_key || IS_ERR(fsid_key))
- return nfserr_perm;
-
- exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq);
if (exp == NULL)
- rv = nfserr_perm;
+ return nfserr_perm;
else if (IS_ERR(exp))
- rv = nfserrno(PTR_ERR(exp));
- else {
- rv = fh_compose(fhp, exp,
- fsid_key->ek_dentry, NULL);
- exp_put(exp);
- }
- cache_put(&fsid_key->h, &svc_expkey_cache);
+ return nfserrno(PTR_ERR(exp));
+ rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
+ exp_put(exp);
return rv;
}
@@ -1158,7 +1253,8 @@
{ 0, {"", ""}}
};
-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong)
+static void exp_flags(struct seq_file *m, int flag, int fsid,
+ uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
{
int first = 0;
struct flags *flg;
@@ -1174,6 +1270,21 @@
seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
if (anong != (gid_t)-2 && anong != (0x10000-2))
seq_printf(m, "%sanongid=%d", first++?",":"", anong);
+ if (fsloc && fsloc->locations_count > 0) {
+ char *loctype = (fsloc->migrated) ? "refer" : "replicas";
+ int i;
+
+ seq_printf(m, "%s%s=", first++?",":"", loctype);
+ seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
+ seq_putc(m, '@');
+ seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
+ for (i = 1; i < fsloc->locations_count; i++) {
+ seq_putc(m, ';');
+ seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
+ seq_putc(m, '@');
+ seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
+ }
+ }
}
static int e_show(struct seq_file *m, void *p)
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index fe56b38..9187755 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -241,7 +241,7 @@
rqstp->rq_res.page_len = w;
while (w > 0) {
- if (!svc_take_res_page(rqstp))
+ if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
w -= PAGE_SIZE;
}
@@ -333,4 +333,5 @@
.vs_proc = nfsd_acl_procedures2,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
+ .vs_hidden = 1,
};
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 16e10c1..d4bdc00 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -185,7 +185,7 @@
rqstp->rq_res.page_len = w;
while (w > 0) {
- if (!svc_take_res_page(rqstp))
+ if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
w -= PAGE_SIZE;
}
@@ -263,5 +263,6 @@
.vs_proc = nfsd_acl_procedures3,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
+ .vs_hidden = 1,
};
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index f61142a..a5ebc7d 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -160,6 +160,7 @@
struct nfsd3_readres *resp)
{
int nfserr;
+ u32 max_blocksize = svc_max_payload(rqstp);
dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
SVCFH_fmt(&argp->fh),
@@ -172,15 +173,15 @@
*/
resp->count = argp->count;
- if (NFSSVC_MAXBLKSIZE < resp->count)
- resp->count = NFSSVC_MAXBLKSIZE;
+ if (max_blocksize < resp->count)
+ resp->count = max_blocksize;
svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_read(rqstp, &resp->fh, NULL,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
&resp->count);
if (nfserr == 0) {
struct inode *inode = resp->fh.fh_dentry->d_inode;
@@ -210,7 +211,7 @@
resp->committed = argp->stable;
nfserr = nfsd_write(rqstp, &resp->fh, NULL,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
argp->len,
&resp->committed);
resp->count = argp->count;
@@ -538,15 +539,16 @@
struct nfsd3_fsinfores *resp)
{
int nfserr;
+ u32 max_blocksize = svc_max_payload(rqstp);
dprintk("nfsd: FSINFO(3) %s\n",
SVCFH_fmt(&argp->fh));
- resp->f_rtmax = NFSSVC_MAXBLKSIZE;
- resp->f_rtpref = NFSSVC_MAXBLKSIZE;
+ resp->f_rtmax = max_blocksize;
+ resp->f_rtpref = max_blocksize;
resp->f_rtmult = PAGE_SIZE;
- resp->f_wtmax = NFSSVC_MAXBLKSIZE;
- resp->f_wtpref = NFSSVC_MAXBLKSIZE;
+ resp->f_wtmax = max_blocksize;
+ resp->f_wtpref = max_blocksize;
resp->f_wtmult = PAGE_SIZE;
resp->f_dtpref = PAGE_SIZE;
resp->f_maxfilesize = ~(u32) 0;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 243d94b..247d518 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -330,6 +330,7 @@
{
unsigned int len;
int v,pn;
+ u32 max_blocksize = svc_max_payload(rqstp);
if (!(p = decode_fh(p, &args->fh))
|| !(p = xdr_decode_hyper(p, &args->offset)))
@@ -337,17 +338,16 @@
len = args->count = ntohl(*p++);
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > max_blocksize)
+ len = max_blocksize;
/* set up the kvec */
v=0;
while (len > 0) {
- pn = rqstp->rq_resused;
- svc_take_page(rqstp);
- args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
- args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
- len -= args->vec[v].iov_len;
+ pn = rqstp->rq_resused++;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+ rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
+ len -= rqstp->rq_vec[v].iov_len;
v++;
}
args->vlen = v;
@@ -359,6 +359,7 @@
struct nfsd3_writeargs *args)
{
unsigned int len, v, hdr;
+ u32 max_blocksize = svc_max_payload(rqstp);
if (!(p = decode_fh(p, &args->fh))
|| !(p = xdr_decode_hyper(p, &args->offset)))
@@ -373,22 +374,22 @@
rqstp->rq_arg.len - hdr < len)
return 0;
- args->vec[0].iov_base = (void*)p;
- args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
+ rqstp->rq_vec[0].iov_base = (void*)p;
+ rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > max_blocksize)
+ len = max_blocksize;
v= 0;
- while (len > args->vec[v].iov_len) {
- len -= args->vec[v].iov_len;
+ while (len > rqstp->rq_vec[v].iov_len) {
+ len -= rqstp->rq_vec[v].iov_len;
v++;
- args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
- args->vec[v].iov_len = PAGE_SIZE;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
+ rqstp->rq_vec[v].iov_len = PAGE_SIZE;
}
- args->vec[v].iov_len = len;
+ rqstp->rq_vec[v].iov_len = len;
args->vlen = v+1;
- return args->count == args->len && args->vec[0].iov_len > 0;
+ return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
}
int
@@ -446,11 +447,11 @@
* This page appears in the rq_res.pages list, but as pages_len is always
* 0, it won't get in the way
*/
- svc_take_page(rqstp);
len = ntohl(*p++);
if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
return 0;
- args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->tname = new =
+ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
args->tlen = len;
/* first copy and check from the first page */
old = (char*)p;
@@ -522,8 +523,8 @@
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer =
+ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
@@ -554,8 +555,8 @@
if (args->count > PAGE_SIZE)
args->count = PAGE_SIZE;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer =
+ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
@@ -565,6 +566,7 @@
struct nfsd3_readdirargs *args)
{
int len, pn;
+ u32 max_blocksize = svc_max_payload(rqstp);
if (!(p = decode_fh(p, &args->fh)))
return 0;
@@ -573,13 +575,12 @@
args->dircount = ntohl(*p++);
args->count = ntohl(*p++);
- len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE :
+ len = (args->count > max_blocksize) ? max_blocksize :
args->count;
args->count = len;
while (len > 0) {
- pn = rqstp->rq_resused;
- svc_take_page(rqstp);
+ pn = rqstp->rq_resused++;
if (!args->buffer)
args->buffer = page_address(rqstp->rq_respages[pn]);
len -= PAGE_SIZE;
@@ -668,7 +669,6 @@
rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -693,7 +693,6 @@
rqstp->rq_res.page_len = resp->count;
if (resp->count & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
@@ -768,7 +767,6 @@
rqstp->rq_res.page_len = (resp->count) << 2;
/* add the 'tail' to the end of the 'head' page - page 0. */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p++ = 0; /* no more entries */
*p++ = htonl(resp->common.err == nfserr_eof);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index edb107e..5d94555 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -63,6 +63,8 @@
#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
| NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)
+#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP)
+
#define MASK_EQUAL(mask1, mask2) \
( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
@@ -96,24 +98,26 @@
/* XXX: modify functions to return NFS errors; they're only ever
* used by nfs code, after all.... */
-static int
-mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
-{
- u32 ignore = 0;
+/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
+ * side of being more restrictive, so the mode bit mapping below is
+ * pessimistic. An optimistic version would be needed to handle DENY's,
+ * but we espect to coalesce all ALLOWs and DENYs before mapping to mode
+ * bits. */
- if (!(flags & NFS4_ACL_DIR))
- ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */
- perm |= ignore;
+static void
+low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
+{
+ u32 write_mode = NFS4_WRITE_MODE;
+
+ if (flags & NFS4_ACL_DIR)
+ write_mode |= NFS4_ACE_DELETE_CHILD;
*mode = 0;
if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
*mode |= ACL_READ;
- if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE)
+ if ((perm & write_mode) == write_mode)
*mode |= ACL_WRITE;
if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
*mode |= ACL_EXECUTE;
- if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags)))
- return -EINVAL;
- return 0;
}
struct ace_container {
@@ -338,38 +342,6 @@
return;
}
-static int
-write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
- struct posix_acl_entry **pace, short tag, unsigned int flags)
-{
- struct posix_acl_entry *this = *pace;
-
- if (*pace == pacl->a_entries + pacl->a_count)
- return -EINVAL; /* fell off the end */
- (*pace)++;
- this->e_tag = tag;
- if (tag == ACL_USER_OBJ)
- flags |= NFS4_ACL_OWNER;
- if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags))
- return -EINVAL;
- this->e_id = (tag == ACL_USER || tag == ACL_GROUP ?
- ace->who : ACL_UNDEFINED_ID);
- return 0;
-}
-
-static struct nfs4_ace *
-get_next_v4_ace(struct list_head **p, struct list_head *head)
-{
- struct nfs4_ace *ace;
-
- *p = (*p)->next;
- if (*p == head)
- return NULL;
- ace = list_entry(*p, struct nfs4_ace, l_ace);
-
- return ace;
-}
-
int
nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
struct posix_acl **dpacl, unsigned int flags)
@@ -385,42 +357,23 @@
goto out;
error = nfs4_acl_split(acl, dacl);
- if (error < 0)
+ if (error)
goto out_acl;
- if (pacl != NULL) {
- if (acl->naces == 0) {
- error = -ENODATA;
- goto try_dpacl;
- }
-
- *pacl = _nfsv4_to_posix_one(acl, flags);
- if (IS_ERR(*pacl)) {
- error = PTR_ERR(*pacl);
- *pacl = NULL;
- goto out_acl;
- }
+ *pacl = _nfsv4_to_posix_one(acl, flags);
+ if (IS_ERR(*pacl)) {
+ error = PTR_ERR(*pacl);
+ *pacl = NULL;
+ goto out_acl;
}
-try_dpacl:
- if (dpacl != NULL) {
- if (dacl->naces == 0) {
- if (pacl == NULL || *pacl == NULL)
- error = -ENODATA;
- goto out_acl;
- }
-
- error = 0;
- *dpacl = _nfsv4_to_posix_one(dacl, flags);
- if (IS_ERR(*dpacl)) {
- error = PTR_ERR(*dpacl);
- *dpacl = NULL;
- goto out_acl;
- }
+ *dpacl = _nfsv4_to_posix_one(dacl, flags);
+ if (IS_ERR(*dpacl)) {
+ error = PTR_ERR(*dpacl);
+ *dpacl = NULL;
}
-
out_acl:
- if (error && pacl) {
+ if (error) {
posix_acl_release(*pacl);
*pacl = NULL;
}
@@ -429,349 +382,311 @@
return error;
}
-static int
-same_who(struct nfs4_ace *a, struct nfs4_ace *b)
-{
- return a->whotype == b->whotype &&
- (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who);
-}
+/*
+ * While processing the NFSv4 ACE, this maintains bitmasks representing
+ * which permission bits have been allowed and which denied to a given
+ * entity: */
+struct posix_ace_state {
+ u32 allow;
+ u32 deny;
+};
+
+struct posix_user_ace_state {
+ uid_t uid;
+ struct posix_ace_state perms;
+};
+
+struct posix_ace_state_array {
+ int n;
+ struct posix_user_ace_state aces[];
+};
+
+/*
+ * While processing the NFSv4 ACE, this maintains the partial permissions
+ * calculated so far: */
+
+struct posix_acl_state {
+ struct posix_ace_state owner;
+ struct posix_ace_state group;
+ struct posix_ace_state other;
+ struct posix_ace_state everyone;
+ struct posix_ace_state mask; /* Deny unused in this case */
+ struct posix_ace_state_array *users;
+ struct posix_ace_state_array *groups;
+};
static int
-complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny,
- unsigned int flags)
+init_state(struct posix_acl_state *state, int cnt)
{
- int ignore = 0;
- if (!(flags & NFS4_ACL_DIR))
- ignore |= NFS4_ACE_DELETE_CHILD;
- return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags),
- ignore|deny->access_mask) &&
- allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
- deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
- allow->flag == deny->flag &&
- same_who(allow, deny);
+ int alloc;
+
+ memset(state, 0, sizeof(struct posix_acl_state));
+ /*
+ * In the worst case, each individual acl could be for a distinct
+ * named user or group, but we don't no which, so we allocate
+ * enough space for either:
+ */
+ alloc = sizeof(struct posix_ace_state_array)
+ + cnt*sizeof(struct posix_ace_state);
+ state->users = kzalloc(alloc, GFP_KERNEL);
+ if (!state->users)
+ return -ENOMEM;
+ state->groups = kzalloc(alloc, GFP_KERNEL);
+ if (!state->groups) {
+ kfree(state->users);
+ return -ENOMEM;
+ }
+ return 0;
}
-static inline int
-user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
-{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
-
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace2type(ace) != ACL_USER_OBJ)
- goto out;
- error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace2 == NULL)
- goto out;
- if (!complementary_ace_pair(ace, ace2, flags))
- goto out;
- error = 0;
-out:
- return error;
+static void
+free_state(struct posix_acl_state *state) {
+ kfree(state->users);
+ kfree(state->groups);
}
-static inline int
-users_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct nfs4_ace **mask_ace,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
-
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- while (ace2type(ace) == ACL_USER) {
- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
- goto out;
- if (*mask_ace &&
- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
- goto out;
- *mask_ace = ace;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
- goto out;
- error = write_pace(ace, pacl, pace, ACL_USER, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace2 == NULL)
- goto out;
- if (!complementary_ace_pair(ace, ace2, flags))
- goto out;
- if ((*mask_ace)->flag != ace2->flag ||
- !same_who(*mask_ace, ace2))
- goto out;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- }
- error = 0;
-out:
- return error;
+ state->mask.allow |= astate->allow;
}
-static inline int
-group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct nfs4_ace **mask_ace,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+/*
+ * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS,
+ * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate
+ * to traditional read/write/execute permissions.
+ *
+ * It's problematic to reject acls that use certain mode bits, because it
+ * places the burden on users to learn the rules about which bits one
+ * particular server sets, without giving the user a lot of help--we return an
+ * error that could mean any number of different things. To make matters
+ * worse, the problematic bits might be introduced by some application that's
+ * automatically mapping from some other acl model.
+ *
+ * So wherever possible we accept anything, possibly erring on the side of
+ * denying more permissions than necessary.
+ *
+ * However we do reject *explicit* DENY's of a few bits representing
+ * permissions we could never deny:
+ */
+
+static inline int check_deny(u32 mask, int isowner)
{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
- struct ace_container *ac;
- struct list_head group_l;
-
- INIT_LIST_HEAD(&group_l);
- ace = list_entry(*p, struct nfs4_ace, l_ace);
-
- /* group owner (mask and allow aces) */
-
- if (pacl->a_count != 3) {
- /* then the group owner should be preceded by mask */
- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
- goto out;
- if (*mask_ace &&
- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
- goto out;
- *mask_ace = ace;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
-
- if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace))
- goto out;
- }
-
- if (ace2type(ace) != ACL_GROUP_OBJ)
- goto out;
-
- ac = kmalloc(sizeof(*ac), GFP_KERNEL);
- error = -ENOMEM;
- if (ac == NULL)
- goto out;
- ac->ace = ace;
- list_add_tail(&ac->ace_l, &group_l);
-
- error = -EINVAL;
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
- goto out;
-
- error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags);
- if (error < 0)
- goto out;
-
- error = -EINVAL;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
-
- /* groups (mask and allow aces) */
-
- while (ace2type(ace) == ACL_GROUP) {
- if (*mask_ace == NULL)
- goto out;
-
- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
- goto out;
- *mask_ace = ace;
-
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- ac = kmalloc(sizeof(*ac), GFP_KERNEL);
- error = -ENOMEM;
- if (ac == NULL)
- goto out;
- error = -EINVAL;
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
- !same_who(ace, *mask_ace))
- goto out;
-
- ac->ace = ace;
- list_add_tail(&ac->ace_l, &group_l);
-
- error = write_pace(ace, pacl, pace, ACL_GROUP, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- }
-
- /* group owner (deny ace) */
-
- if (ace2type(ace) != ACL_GROUP_OBJ)
- goto out;
- ac = list_entry(group_l.next, struct ace_container, ace_l);
- ace2 = ac->ace;
- if (!complementary_ace_pair(ace2, ace, flags))
- goto out;
- list_del(group_l.next);
- kfree(ac);
-
- /* groups (deny aces) */
-
- while (!list_empty(&group_l)) {
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace2type(ace) != ACL_GROUP)
- goto out;
- ac = list_entry(group_l.next, struct ace_container, ace_l);
- ace2 = ac->ace;
- if (!complementary_ace_pair(ace2, ace, flags))
- goto out;
- list_del(group_l.next);
- kfree(ac);
- }
-
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace2type(ace) != ACL_OTHER)
- goto out;
- error = 0;
-out:
- while (!list_empty(&group_l)) {
- ac = list_entry(group_l.next, struct ace_container, ace_l);
- list_del(group_l.next);
- kfree(ac);
- }
- return error;
+ if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL))
+ return -EINVAL;
+ if (!isowner)
+ return 0;
+ if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL))
+ return -EINVAL;
+ return 0;
}
-static inline int
-mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct nfs4_ace **mask_ace,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+static struct posix_acl *
+posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
{
- int error = -EINVAL;
- struct nfs4_ace *ace;
+ struct posix_acl_entry *pace;
+ struct posix_acl *pacl;
+ int nace;
+ int i, error = 0;
- ace = list_entry(*p, struct nfs4_ace, l_ace);
- if (pacl->a_count != 3) {
- if (*mask_ace == NULL)
- goto out;
- (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags);
- write_pace(*mask_ace, pacl, pace, ACL_MASK, flags);
+ nace = 4 + state->users->n + state->groups->n;
+ pacl = posix_acl_alloc(nace, GFP_KERNEL);
+ if (!pacl)
+ return ERR_PTR(-ENOMEM);
+
+ pace = pacl->a_entries;
+ pace->e_tag = ACL_USER_OBJ;
+ error = check_deny(state->owner.deny, 1);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
+
+ for (i=0; i < state->users->n; i++) {
+ pace++;
+ pace->e_tag = ACL_USER;
+ error = check_deny(state->users->aces[i].perms.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->users->aces[i].perms.allow,
+ &pace->e_perm, flags);
+ pace->e_id = state->users->aces[i].uid;
+ add_to_mask(state, &state->users->aces[i].perms);
}
- error = 0;
-out:
- return error;
+
+ pace++;
+ pace->e_tag = ACL_GROUP_OBJ;
+ error = check_deny(state->group.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
+ add_to_mask(state, &state->group);
+
+ for (i=0; i < state->groups->n; i++) {
+ pace++;
+ pace->e_tag = ACL_GROUP;
+ error = check_deny(state->groups->aces[i].perms.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->groups->aces[i].perms.allow,
+ &pace->e_perm, flags);
+ pace->e_id = state->groups->aces[i].uid;
+ add_to_mask(state, &state->groups->aces[i].perms);
+ }
+
+ pace++;
+ pace->e_tag = ACL_MASK;
+ low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
+
+ pace++;
+ pace->e_tag = ACL_OTHER;
+ error = check_deny(state->other.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
+
+ return pacl;
+out_err:
+ posix_acl_release(pacl);
+ return ERR_PTR(error);
}
-static inline int
-other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
-
- ace = list_entry(*p, struct nfs4_ace, l_ace);
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
- goto out;
- error = write_pace(ace, pacl, pace, ACL_OTHER, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace2 == NULL)
- goto out;
- if (!complementary_ace_pair(ace, ace2, flags))
- goto out;
- error = 0;
-out:
- return error;
+ /* Allow all bits in the mask not already denied: */
+ astate->allow |= mask & ~astate->deny;
}
-static int
-calculate_posix_ace_count(struct nfs4_acl *n4acl)
+static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
{
- if (n4acl->naces == 6) /* owner, owner group, and other only */
- return 3;
- else { /* Otherwise there must be a mask entry. */
- /* Also, the remaining entries are for named users and
- * groups, and come in threes (mask, allow, deny): */
- if (n4acl->naces < 7)
- return -EINVAL;
- if ((n4acl->naces - 7) % 3)
- return -EINVAL;
- return 4 + (n4acl->naces - 7)/3;
+ /* Deny all bits in the mask not already allowed: */
+ astate->deny |= mask & ~astate->allow;
+}
+
+static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid)
+{
+ int i;
+
+ for (i = 0; i < a->n; i++)
+ if (a->aces[i].uid == uid)
+ return i;
+ /* Not found: */
+ a->n++;
+ a->aces[i].uid = uid;
+ a->aces[i].perms.allow = state->everyone.allow;
+ a->aces[i].perms.deny = state->everyone.deny;
+
+ return i;
+}
+
+static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
+{
+ int i;
+
+ for (i=0; i < a->n; i++)
+ deny_bits(&a->aces[i].perms, mask);
+}
+
+static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
+{
+ int i;
+
+ for (i=0; i < a->n; i++)
+ allow_bits(&a->aces[i].perms, mask);
+}
+
+static void process_one_v4_ace(struct posix_acl_state *state,
+ struct nfs4_ace *ace)
+{
+ u32 mask = ace->access_mask;
+ int i;
+
+ switch (ace2type(ace)) {
+ case ACL_USER_OBJ:
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->owner, mask);
+ } else {
+ deny_bits(&state->owner, mask);
+ }
+ break;
+ case ACL_USER:
+ i = find_uid(state, state->users, ace->who);
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->users->aces[i].perms, mask);
+ } else {
+ deny_bits(&state->users->aces[i].perms, mask);
+ mask = state->users->aces[i].perms.deny;
+ deny_bits(&state->owner, mask);
+ }
+ break;
+ case ACL_GROUP_OBJ:
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->group, mask);
+ } else {
+ deny_bits(&state->group, mask);
+ mask = state->group.deny;
+ deny_bits(&state->owner, mask);
+ deny_bits(&state->everyone, mask);
+ deny_bits_array(state->users, mask);
+ deny_bits_array(state->groups, mask);
+ }
+ break;
+ case ACL_GROUP:
+ i = find_uid(state, state->groups, ace->who);
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->groups->aces[i].perms, mask);
+ } else {
+ deny_bits(&state->groups->aces[i].perms, mask);
+ mask = state->groups->aces[i].perms.deny;
+ deny_bits(&state->owner, mask);
+ deny_bits(&state->group, mask);
+ deny_bits(&state->everyone, mask);
+ deny_bits_array(state->users, mask);
+ deny_bits_array(state->groups, mask);
+ }
+ break;
+ case ACL_OTHER:
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->owner, mask);
+ allow_bits(&state->group, mask);
+ allow_bits(&state->other, mask);
+ allow_bits(&state->everyone, mask);
+ allow_bits_array(state->users, mask);
+ allow_bits_array(state->groups, mask);
+ } else {
+ deny_bits(&state->owner, mask);
+ deny_bits(&state->group, mask);
+ deny_bits(&state->other, mask);
+ deny_bits(&state->everyone, mask);
+ deny_bits_array(state->users, mask);
+ deny_bits_array(state->groups, mask);
+ }
}
}
-
static struct posix_acl *
_nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags)
{
+ struct posix_acl_state state;
struct posix_acl *pacl;
- int error = -EINVAL, nace = 0;
- struct list_head *p;
- struct nfs4_ace *mask_ace = NULL;
- struct posix_acl_entry *pace;
+ struct nfs4_ace *ace;
+ int ret;
- nace = calculate_posix_ace_count(n4acl);
- if (nace < 0)
- goto out_err;
+ ret = init_state(&state, n4acl->naces);
+ if (ret)
+ return ERR_PTR(ret);
- pacl = posix_acl_alloc(nace, GFP_KERNEL);
- error = -ENOMEM;
- if (pacl == NULL)
- goto out_err;
+ list_for_each_entry(ace, &n4acl->ace_head, l_ace)
+ process_one_v4_ace(&state, ace);
- pace = &pacl->a_entries[0];
- p = &n4acl->ace_head;
+ pacl = posix_state_to_acl(&state, flags);
- error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags);
- if (error)
- goto out_acl;
+ free_state(&state);
- error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
- if (error)
- goto out_acl;
-
- error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
- flags);
- if (error)
- goto out_acl;
-
- error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
- if (error)
- goto out_acl;
- error = other_from_v4(n4acl, &p, pacl, &pace, flags);
- if (error)
- goto out_acl;
-
- error = -EINVAL;
- if (p->next != &n4acl->ace_head)
- goto out_acl;
- if (pace != pacl->a_entries + pacl->a_count)
- goto out_acl;
-
- sort_pacl(pacl);
-
- return pacl;
-out_acl:
- posix_acl_release(pacl);
-out_err:
- pacl = ERR_PTR(error);
+ if (!IS_ERR(pacl))
+ sort_pacl(pacl);
return pacl;
}
@@ -785,22 +700,41 @@
list_for_each_safe(h, n, &acl->ace_head) {
ace = list_entry(h, struct nfs4_ace, l_ace);
- if ((ace->flag & NFS4_INHERITANCE_FLAGS)
- != NFS4_INHERITANCE_FLAGS)
+ if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
+ ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+ return -EINVAL;
+
+ if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
+ return -EINVAL;
+
+ switch (ace->flag & NFS4_INHERITANCE_FLAGS) {
+ case 0:
+ /* Leave this ace in the effective acl: */
continue;
-
- error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+ case NFS4_INHERITANCE_FLAGS:
+ /* Add this ace to the default acl and remove it
+ * from the effective acl: */
+ error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
ace->access_mask, ace->whotype, ace->who);
- if (error < 0)
- goto out;
-
- list_del(h);
- kfree(ace);
- acl->naces--;
+ if (error)
+ return error;
+ list_del(h);
+ kfree(ace);
+ acl->naces--;
+ break;
+ case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE:
+ /* Add this ace to the default, but leave it in
+ * the effective acl as well: */
+ error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+ ace->access_mask, ace->whotype, ace->who);
+ if (error)
+ return error;
+ break;
+ default:
+ return -EINVAL;
+ }
}
-
-out:
- return error;
+ return 0;
}
static short
@@ -930,23 +864,6 @@
return -1;
}
-static inline int
-match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
-{
- switch (ace->whotype) {
- case NFS4_ACL_WHO_NAMED:
- return who == ace->who;
- case NFS4_ACL_WHO_OWNER:
- return who == owner;
- case NFS4_ACL_WHO_GROUP:
- return who == group;
- case NFS4_ACL_WHO_EVERYONE:
- return 1;
- default:
- return 0;
- }
-}
-
EXPORT_SYMBOL(nfs4_acl_new);
EXPORT_SYMBOL(nfs4_acl_free);
EXPORT_SYMBOL(nfs4_acl_add_ace);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 15ded7a..8333db1 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -646,7 +646,7 @@
*p++ = nfssvc_boot.tv_usec;
status = nfsd_write(rqstp, current_fh, filp, write->wr_offset,
- write->wr_vec, write->wr_vlen, write->wr_buflen,
+ rqstp->rq_vec, write->wr_vlen, write->wr_buflen,
&write->wr_how_written);
if (filp)
fput(filp);
@@ -802,13 +802,29 @@
* SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
* require a valid current filehandle
*/
- if ((!current_fh->fh_dentry) &&
- !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
- (op->opnum == OP_SETCLIENTID) ||
- (op->opnum == OP_SETCLIENTID_CONFIRM) ||
- (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) ||
- (op->opnum == OP_RELEASE_LOCKOWNER))) {
- op->status = nfserr_nofilehandle;
+ if (!current_fh->fh_dentry) {
+ if (!((op->opnum == OP_PUTFH) ||
+ (op->opnum == OP_PUTROOTFH) ||
+ (op->opnum == OP_SETCLIENTID) ||
+ (op->opnum == OP_SETCLIENTID_CONFIRM) ||
+ (op->opnum == OP_RENEW) ||
+ (op->opnum == OP_RESTOREFH) ||
+ (op->opnum == OP_RELEASE_LOCKOWNER))) {
+ op->status = nfserr_nofilehandle;
+ goto encode_op;
+ }
+ }
+ /* Check must be done at start of each operation, except
+ * for GETATTR and ops not listed as returning NFS4ERR_MOVED
+ */
+ else if (current_fh->fh_export->ex_fslocs.migrated &&
+ !((op->opnum == OP_GETATTR) ||
+ (op->opnum == OP_PUTROOTFH) ||
+ (op->opnum == OP_PUTPUBFH) ||
+ (op->opnum == OP_RENEW) ||
+ (op->opnum == OP_SETCLIENTID) ||
+ (op->opnum == OP_RELEASE_LOCKOWNER))) {
+ op->status = nfserr_moved;
goto encode_op;
}
switch (op->opnum) {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5be0043..41fc241 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -60,6 +60,14 @@
#define NFSDDBG_FACILITY NFSDDBG_XDR
+/*
+ * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
+ * directory in order to indicate to the client that a filesystem boundary is present
+ * We use a fixed fsid for a referral
+ */
+#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL
+#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL
+
static int
check_filename(char *str, int len, int err)
{
@@ -926,26 +934,26 @@
printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__);
goto xdr_error;
}
- write->wr_vec[0].iov_base = p;
- write->wr_vec[0].iov_len = avail;
+ argp->rqstp->rq_vec[0].iov_base = p;
+ argp->rqstp->rq_vec[0].iov_len = avail;
v = 0;
len = write->wr_buflen;
- while (len > write->wr_vec[v].iov_len) {
- len -= write->wr_vec[v].iov_len;
+ while (len > argp->rqstp->rq_vec[v].iov_len) {
+ len -= argp->rqstp->rq_vec[v].iov_len;
v++;
- write->wr_vec[v].iov_base = page_address(argp->pagelist[0]);
+ argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]);
argp->pagelist++;
if (argp->pagelen >= PAGE_SIZE) {
- write->wr_vec[v].iov_len = PAGE_SIZE;
+ argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE;
argp->pagelen -= PAGE_SIZE;
} else {
- write->wr_vec[v].iov_len = argp->pagelen;
+ argp->rqstp->rq_vec[v].iov_len = argp->pagelen;
argp->pagelen -= len;
}
}
- argp->end = (u32*) (write->wr_vec[v].iov_base + write->wr_vec[v].iov_len);
- argp->p = (u32*) (write->wr_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
- write->wr_vec[v].iov_len = len;
+ argp->end = (u32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len);
+ argp->p = (u32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
+ argp->rqstp->rq_vec[v].iov_len = len;
write->wr_vlen = v+1;
DECODE_TAIL;
@@ -1223,6 +1231,119 @@
stateowner->so_replay.rp_buflen); \
} } while (0);
+/* Encode as an array of strings the string given with components
+ * seperated @sep.
+ */
+static int nfsd4_encode_components(char sep, char *components,
+ u32 **pp, int *buflen)
+{
+ u32 *p = *pp;
+ u32 *countp = p;
+ int strlen, count=0;
+ char *str, *end;
+
+ dprintk("nfsd4_encode_components(%s)\n", components);
+ if ((*buflen -= 4) < 0)
+ return nfserr_resource;
+ WRITE32(0); /* We will fill this in with @count later */
+ end = str = components;
+ while (*end) {
+ for (; *end && (*end != sep); end++)
+ ; /* Point to end of component */
+ strlen = end - str;
+ if (strlen) {
+ if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)
+ return nfserr_resource;
+ WRITE32(strlen);
+ WRITEMEM(str, strlen);
+ count++;
+ }
+ else
+ end++;
+ str = end;
+ }
+ *pp = p;
+ p = countp;
+ WRITE32(count);
+ return 0;
+}
+
+/*
+ * encode a location element of a fs_locations structure
+ */
+static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
+ u32 **pp, int *buflen)
+{
+ int status;
+ u32 *p = *pp;
+
+ status = nfsd4_encode_components(':', location->hosts, &p, buflen);
+ if (status)
+ return status;
+ status = nfsd4_encode_components('/', location->path, &p, buflen);
+ if (status)
+ return status;
+ *pp = p;
+ return 0;
+}
+
+/*
+ * Return the path to an export point in the pseudo filesystem namespace
+ * Returned string is safe to use as long as the caller holds a reference
+ * to @exp.
+ */
+static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp)
+{
+ struct svc_fh tmp_fh;
+ char *path, *rootpath;
+ int stat;
+
+ fh_init(&tmp_fh, NFS4_FHSIZE);
+ stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle);
+ if (stat)
+ return ERR_PTR(stat);
+ rootpath = tmp_fh.fh_export->ex_path;
+
+ path = exp->ex_path;
+
+ if (strncmp(path, rootpath, strlen(rootpath))) {
+ printk("nfsd: fs_locations failed;"
+ "%s is not contained in %s\n", path, rootpath);
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ return path + strlen(rootpath);
+}
+
+/*
+ * encode a fs_locations structure
+ */
+static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
+ struct svc_export *exp,
+ u32 **pp, int *buflen)
+{
+ int status, i;
+ u32 *p = *pp;
+ struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
+ char *root = nfsd4_path(rqstp, exp);
+
+ if (IS_ERR(root))
+ return PTR_ERR(root);
+ status = nfsd4_encode_components('/', root, &p, buflen);
+ if (status)
+ return status;
+ if ((*buflen -= 4) < 0)
+ return nfserr_resource;
+ WRITE32(fslocs->locations_count);
+ for (i=0; i<fslocs->locations_count; i++) {
+ status = nfsd4_encode_fs_location4(&fslocs->locations[i],
+ &p, buflen);
+ if (status)
+ return status;
+ }
+ *pp = p;
+ return 0;
+}
static u32 nfs4_ftypes[16] = {
NF4BAD, NF4FIFO, NF4CHR, NF4BAD,
@@ -1272,6 +1393,25 @@
return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
}
+#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
+ FATTR4_WORD0_RDATTR_ERROR)
+#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+
+static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+{
+ /* As per referral draft: */
+ if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
+ *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
+ if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
+ *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
+ *rdattr_err = NFSERR_MOVED;
+ else
+ return nfserr_moved;
+ }
+ *bmval0 &= WORD0_ABSENT_FS_ATTRS;
+ *bmval1 &= WORD1_ABSENT_FS_ATTRS;
+ return 0;
+}
/*
* Note: @fhp can be NULL; in this case, we might have to compose the filehandle
@@ -1294,6 +1434,7 @@
u32 *attrlenp;
u32 dummy;
u64 dummy64;
+ u32 rdattr_err = 0;
u32 *p = buffer;
int status;
int aclsupport = 0;
@@ -1303,6 +1444,12 @@
BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
+ if (exp->ex_fslocs.migrated) {
+ status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+ if (status)
+ goto out;
+ }
+
status = vfs_getattr(exp->ex_mnt, dentry, &stat);
if (status)
goto out_nfserr;
@@ -1334,6 +1481,11 @@
goto out_nfserr;
}
}
+ if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
+ if (exp->ex_fslocs.locations == NULL) {
+ bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
+ }
+ }
if ((buflen -= 16) < 0)
goto out_resource;
@@ -1343,12 +1495,15 @@
attrlenp = p++; /* to be backfilled later */
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
+ u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
if ((buflen -= 12) < 0)
goto out_resource;
+ if (!aclsupport)
+ word0 &= ~FATTR4_WORD0_ACL;
+ if (!exp->ex_fslocs.locations)
+ word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
WRITE32(2);
- WRITE32(aclsupport ?
- NFSD_SUPPORTED_ATTRS_WORD0 :
- NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL);
+ WRITE32(word0);
WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
}
if (bmval0 & FATTR4_WORD0_TYPE) {
@@ -1402,7 +1557,10 @@
if (bmval0 & FATTR4_WORD0_FSID) {
if ((buflen -= 16) < 0)
goto out_resource;
- if (is_fsid(fhp, rqstp->rq_reffh)) {
+ if (exp->ex_fslocs.migrated) {
+ WRITE64(NFS4_REFERRAL_FSID_MAJOR);
+ WRITE64(NFS4_REFERRAL_FSID_MINOR);
+ } else if (is_fsid(fhp, rqstp->rq_reffh)) {
WRITE64((u64)exp->ex_fsid);
WRITE64((u64)0);
} else {
@@ -1425,7 +1583,7 @@
if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
if ((buflen -= 4) < 0)
goto out_resource;
- WRITE32(0);
+ WRITE32(rdattr_err);
}
if (bmval0 & FATTR4_WORD0_ACL) {
struct nfs4_ace *ace;
@@ -1513,6 +1671,13 @@
goto out_resource;
WRITE64((u64) statfs.f_files);
}
+ if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
+ status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
+ if (status == nfserr_resource)
+ goto out_resource;
+ if (status)
+ goto out;
+ }
if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
if ((buflen -= 4) < 0)
goto out_resource;
@@ -1536,12 +1701,12 @@
if (bmval0 & FATTR4_WORD0_MAXREAD) {
if ((buflen -= 8) < 0)
goto out_resource;
- WRITE64((u64) NFSSVC_MAXBLKSIZE);
+ WRITE64((u64) svc_max_payload(rqstp));
}
if (bmval0 & FATTR4_WORD0_MAXWRITE) {
if ((buflen -= 8) < 0)
goto out_resource;
- WRITE64((u64) NFSSVC_MAXBLKSIZE);
+ WRITE64((u64) svc_max_payload(rqstp));
}
if (bmval1 & FATTR4_WORD1_MODE) {
if ((buflen -= 4) < 0)
@@ -1845,7 +2010,6 @@
nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
resp->p, &buflen, getattr->ga_bmval,
resp->rqstp);
-
if (!nfserr)
resp->p += buflen;
return nfserr;
@@ -2039,7 +2203,8 @@
}
static int
-nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
+nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr,
+ struct nfsd4_read *read)
{
u32 eof;
int v, pn;
@@ -2054,31 +2219,33 @@
RESERVE_SPACE(8); /* eof flag and byte count */
- maxcount = NFSSVC_MAXBLKSIZE;
+ maxcount = svc_max_payload(resp->rqstp);
if (maxcount > read->rd_length)
maxcount = read->rd_length;
len = maxcount;
v = 0;
while (len > 0) {
- pn = resp->rqstp->rq_resused;
- svc_take_page(resp->rqstp);
- read->rd_iov[v].iov_base = page_address(resp->rqstp->rq_respages[pn]);
- read->rd_iov[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE;
+ pn = resp->rqstp->rq_resused++;
+ resp->rqstp->rq_vec[v].iov_base =
+ page_address(resp->rqstp->rq_respages[pn]);
+ resp->rqstp->rq_vec[v].iov_len =
+ len < PAGE_SIZE ? len : PAGE_SIZE;
v++;
len -= PAGE_SIZE;
}
read->rd_vlen = v;
nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
- read->rd_offset, read->rd_iov, read->rd_vlen,
+ read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
&maxcount);
if (nfserr == nfserr_symlink)
nfserr = nfserr_inval;
if (nfserr)
return nfserr;
- eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);
+ eof = (read->rd_offset + maxcount >=
+ read->rd_fhp->fh_dentry->d_inode->i_size);
WRITE32(eof);
WRITE32(maxcount);
@@ -2088,7 +2255,6 @@
resp->xbuf->page_len = maxcount;
/* Use rest of head for padding and remaining ops: */
- resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
if (maxcount&3) {
@@ -2113,8 +2279,7 @@
if (resp->xbuf->page_len)
return nfserr_resource;
- svc_take_page(resp->rqstp);
- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+ page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
maxcount = PAGE_SIZE;
RESERVE_SPACE(4);
@@ -2138,7 +2303,6 @@
resp->xbuf->page_len = maxcount;
/* Use rest of head for padding and remaining ops: */
- resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
if (maxcount&3) {
@@ -2189,8 +2353,7 @@
goto err_no_verf;
}
- svc_take_page(resp->rqstp);
- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+ page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
readdir->common.err = 0;
readdir->buflen = maxcount;
readdir->buffer = page;
@@ -2215,10 +2378,10 @@
p = readdir->buffer;
*p++ = 0; /* no more entries */
*p++ = htonl(readdir->common.err == nfserr_eof);
- resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+ resp->xbuf->page_len = ((char*)p) - (char*)page_address(
+ resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
/* Use rest of head for padding and remaining ops: */
- resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = tailbase;
resp->xbuf->tail[0].iov_len = 0;
resp->p = resp->xbuf->tail[0].iov_base;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 5c6a477..39aed90 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -57,6 +57,7 @@
NFSD_Pool_Threads,
NFSD_Versions,
NFSD_Ports,
+ NFSD_MaxBlkSize,
/*
* The below MUST come last. Otherwise we leave a hole in nfsd_files[]
* with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
@@ -82,6 +83,7 @@
static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
static ssize_t write_versions(struct file *file, char *buf, size_t size);
static ssize_t write_ports(struct file *file, char *buf, size_t size);
+static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
#ifdef CONFIG_NFSD_V4
static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
@@ -100,6 +102,7 @@
[NFSD_Pool_Threads] = write_pool_threads,
[NFSD_Versions] = write_versions,
[NFSD_Ports] = write_ports,
+ [NFSD_MaxBlkSize] = write_maxblksize,
#ifdef CONFIG_NFSD_V4
[NFSD_Leasetime] = write_leasetime,
[NFSD_RecoveryDir] = write_recoverydir,
@@ -523,18 +526,20 @@
err = nfsd_create_serv();
if (!err) {
int proto = 0;
- err = lockd_up(proto);
- if (!err) {
- err = svc_addsock(nfsd_serv, fd, buf, &proto);
- if (err)
- lockd_down();
+ err = svc_addsock(nfsd_serv, fd, buf, &proto);
+ if (err >= 0) {
+ err = lockd_up(proto);
+ if (err < 0)
+ svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
}
/* Decrease the count, but don't shutdown the
* the service
*/
+ lock_kernel();
nfsd_serv->sv_nrthreads--;
+ unlock_kernel();
}
- return err;
+ return err < 0 ? err : 0;
}
if (buf[0] == '-') {
char *toclose = kstrdup(buf+1, GFP_KERNEL);
@@ -545,12 +550,43 @@
if (nfsd_serv)
len = svc_sock_names(buf, nfsd_serv, toclose);
unlock_kernel();
+ if (len >= 0)
+ lockd_down();
kfree(toclose);
return len;
}
return -EINVAL;
}
+int nfsd_max_blksize;
+
+static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
+{
+ char *mesg = buf;
+ if (size > 0) {
+ int bsize;
+ int rv = get_int(&mesg, &bsize);
+ if (rv)
+ return rv;
+ /* force bsize into allowed range and
+ * required alignment.
+ */
+ if (bsize < 1024)
+ bsize = 1024;
+ if (bsize > NFSSVC_MAXBLKSIZE)
+ bsize = NFSSVC_MAXBLKSIZE;
+ bsize &= ~(1024-1);
+ lock_kernel();
+ if (nfsd_serv && nfsd_serv->sv_nrthreads) {
+ unlock_kernel();
+ return -EBUSY;
+ }
+ nfsd_max_blksize = bsize;
+ unlock_kernel();
+ }
+ return sprintf(buf, "%d\n", nfsd_max_blksize);
+}
+
#ifdef CONFIG_NFSD_V4
extern time_t nfs4_leasetime(void);
@@ -616,6 +652,7 @@
[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
+ [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
#ifdef CONFIG_NFSD_V4
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 06cd0db..9ee1dab 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -146,20 +146,20 @@
* status, 17 words for fattr, and 1 word for the byte count.
*/
- if (NFSSVC_MAXBLKSIZE < argp->count) {
+ if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
printk(KERN_NOTICE
"oversized read request from %u.%u.%u.%u:%d (%d bytes)\n",
NIPQUAD(rqstp->rq_addr.sin_addr.s_addr),
ntohs(rqstp->rq_addr.sin_port),
argp->count);
- argp->count = NFSSVC_MAXBLKSIZE;
+ argp->count = NFSSVC_MAXBLKSIZE_V2;
}
svc_reserve(rqstp, (19<<2) + argp->count + 4);
resp->count = argp->count;
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
&resp->count);
if (nfserr) return nfserr;
@@ -185,7 +185,7 @@
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
argp->len,
&stable);
return nfsd_return_attrs(nfserr, resp);
@@ -225,7 +225,7 @@
nfserr = nfserr_exist;
if (isdotent(argp->name, argp->len))
goto done;
- fh_lock(dirfhp);
+ fh_lock_nested(dirfhp, I_MUTEX_PARENT);
dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
if (IS_ERR(dchild)) {
nfserr = nfserrno(PTR_ERR(dchild));
@@ -553,7 +553,7 @@
PROC(none, void, void, none, RC_NOCACHE, ST),
PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT),
PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
- PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE/4),
+ PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4),
PROC(none, void, void, none, RC_NOCACHE, ST),
PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT),
PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT),
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 1944305..6fa6340 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -198,9 +198,26 @@
unlock_kernel();
return 0;
}
+ if (nfsd_max_blksize == 0) {
+ /* choose a suitable default */
+ struct sysinfo i;
+ si_meminfo(&i);
+ /* Aim for 1/4096 of memory per thread
+ * This gives 1MB on 4Gig machines
+ * But only uses 32K on 128M machines.
+ * Bottom out at 8K on 32M and smaller.
+ * Of course, this is only a default.
+ */
+ nfsd_max_blksize = NFSSVC_MAXBLKSIZE;
+ i.totalram <<= PAGE_SHIFT - 12;
+ while (nfsd_max_blksize > i.totalram &&
+ nfsd_max_blksize >= 8*1024*2)
+ nfsd_max_blksize /= 2;
+ }
atomic_set(&nfsd_busy, 0);
- nfsd_serv = svc_create_pooled(&nfsd_program, NFSD_BUFSIZE,
+ nfsd_serv = svc_create_pooled(&nfsd_program,
+ NFSD_BUFSIZE - NFSSVC_MAXBLKSIZE + nfsd_max_blksize,
nfsd_last_thread,
nfsd, SIG_NOCLEAN, THIS_MODULE);
if (nfsd_serv == NULL)
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 3f14a17..1135c0d 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -254,19 +254,18 @@
len = args->count = ntohl(*p++);
p++; /* totalcount - unused */
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > NFSSVC_MAXBLKSIZE_V2)
+ len = NFSSVC_MAXBLKSIZE_V2;
/* set up somewhere to store response.
* We take pages, put them on reslist and include in iovec
*/
v=0;
while (len > 0) {
- pn=rqstp->rq_resused;
- svc_take_page(rqstp);
- args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
- args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
- len -= args->vec[v].iov_len;
+ pn = rqstp->rq_resused++;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+ rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
+ len -= rqstp->rq_vec[v].iov_len;
v++;
}
args->vlen = v;
@@ -286,21 +285,21 @@
args->offset = ntohl(*p++); /* offset */
p++; /* totalcount */
len = args->len = ntohl(*p++);
- args->vec[0].iov_base = (void*)p;
- args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
+ rqstp->rq_vec[0].iov_base = (void*)p;
+ rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
(((void*)p) - rqstp->rq_arg.head[0].iov_base);
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > NFSSVC_MAXBLKSIZE_V2)
+ len = NFSSVC_MAXBLKSIZE_V2;
v = 0;
- while (len > args->vec[v].iov_len) {
- len -= args->vec[v].iov_len;
+ while (len > rqstp->rq_vec[v].iov_len) {
+ len -= rqstp->rq_vec[v].iov_len;
v++;
- args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
- args->vec[v].iov_len = PAGE_SIZE;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
+ rqstp->rq_vec[v].iov_len = PAGE_SIZE;
}
- args->vec[v].iov_len = len;
+ rqstp->rq_vec[v].iov_len = len;
args->vlen = v+1;
- return args->vec[0].iov_len > 0;
+ return rqstp->rq_vec[0].iov_len > 0;
}
int
@@ -333,8 +332,7 @@
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
@@ -375,8 +373,7 @@
if (args->count > PAGE_SIZE)
args->count = PAGE_SIZE;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
@@ -416,7 +413,6 @@
rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -436,7 +432,6 @@
rqstp->rq_res.page_len = resp->count;
if (resp->count & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
@@ -463,7 +458,7 @@
{
struct kstatfs *stat = &resp->stats;
- *p++ = htonl(NFSSVC_MAXBLKSIZE); /* max transfer size */
+ *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */
*p++ = htonl(stat->f_bsize);
*p++ = htonl(stat->f_blocks);
*p++ = htonl(stat->f_bfree);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 443ebc5..1141bd2 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -54,6 +54,7 @@
#include <linux/nfsd_idmap.h>
#include <linux/security.h>
#endif /* CONFIG_NFSD_V4 */
+#include <linux/jhash.h>
#include <asm/uaccess.h>
@@ -81,10 +82,19 @@
dev_t p_dev;
int p_set;
struct file_ra_state p_ra;
+ unsigned int p_hindex;
};
+struct raparm_hbucket {
+ struct raparms *pb_head;
+ spinlock_t pb_lock;
+} ____cacheline_aligned_in_smp;
+
static struct raparms * raparml;
-static struct raparms * raparm_cache;
+#define RAPARM_HASH_BITS 4
+#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
+#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
+static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
/*
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
@@ -437,13 +447,11 @@
} else if (error < 0)
goto out_nfserr;
- if (pacl) {
- error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
- if (error < 0)
- goto out_nfserr;
- }
+ error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+ if (error < 0)
+ goto out_nfserr;
- if (dpacl) {
+ if (S_ISDIR(inode->i_mode)) {
error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
if (error < 0)
goto out_nfserr;
@@ -743,16 +751,20 @@
* Obtain the readahead parameters for the file
* specified by (dev, ino).
*/
-static DEFINE_SPINLOCK(ra_lock);
static inline struct raparms *
nfsd_get_raparms(dev_t dev, ino_t ino)
{
struct raparms *ra, **rap, **frap = NULL;
int depth = 0;
+ unsigned int hash;
+ struct raparm_hbucket *rab;
- spin_lock(&ra_lock);
- for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
+ hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;
+ rab = &raparm_hash[hash];
+
+ spin_lock(&rab->pb_lock);
+ for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {
if (ra->p_ino == ino && ra->p_dev == dev)
goto found;
depth++;
@@ -761,7 +773,7 @@
}
depth = nfsdstats.ra_size*11/10;
if (!frap) {
- spin_unlock(&ra_lock);
+ spin_unlock(&rab->pb_lock);
return NULL;
}
rap = frap;
@@ -769,15 +781,16 @@
ra->p_dev = dev;
ra->p_ino = ino;
ra->p_set = 0;
+ ra->p_hindex = hash;
found:
- if (rap != &raparm_cache) {
+ if (rap != &rab->pb_head) {
*rap = ra->p_next;
- ra->p_next = raparm_cache;
- raparm_cache = ra;
+ ra->p_next = rab->pb_head;
+ rab->pb_head = ra;
}
ra->p_count++;
nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
- spin_unlock(&ra_lock);
+ spin_unlock(&rab->pb_lock);
return ra;
}
@@ -791,22 +804,26 @@
{
unsigned long count = desc->count;
struct svc_rqst *rqstp = desc->arg.data;
+ struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
if (size > count)
size = count;
if (rqstp->rq_res.page_len == 0) {
get_page(page);
- rqstp->rq_respages[rqstp->rq_resused++] = page;
+ put_page(*pp);
+ *pp = page;
+ rqstp->rq_resused++;
rqstp->rq_res.page_base = offset;
rqstp->rq_res.page_len = size;
- } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) {
+ } else if (page != pp[-1]) {
get_page(page);
- rqstp->rq_respages[rqstp->rq_resused++] = page;
+ put_page(*pp);
+ *pp = page;
+ rqstp->rq_resused++;
rqstp->rq_res.page_len += size;
- } else {
+ } else
rqstp->rq_res.page_len += size;
- }
desc->count = count - size;
desc->written += size;
@@ -837,7 +854,7 @@
file->f_ra = ra->p_ra;
if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
- svc_pushback_unused_pages(rqstp);
+ rqstp->rq_resused = 1;
err = file->f_op->sendfile(file, &offset, *count,
nfsd_read_actor, rqstp);
} else {
@@ -849,11 +866,12 @@
/* Write back readahead params */
if (ra) {
- spin_lock(&ra_lock);
+ struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
+ spin_lock(&rab->pb_lock);
ra->p_ra = file->f_ra;
ra->p_set = 1;
ra->p_count--;
- spin_unlock(&ra_lock);
+ spin_unlock(&rab->pb_lock);
}
if (err >= 0) {
@@ -1829,11 +1847,11 @@
void
nfsd_racache_shutdown(void)
{
- if (!raparm_cache)
+ if (!raparml)
return;
dprintk("nfsd: freeing readahead buffers.\n");
kfree(raparml);
- raparm_cache = raparml = NULL;
+ raparml = NULL;
}
/*
* Initialize readahead param cache
@@ -1842,19 +1860,31 @@
nfsd_racache_init(int cache_size)
{
int i;
+ int j = 0;
+ int nperbucket;
- if (raparm_cache)
+
+ if (raparml)
return 0;
+ if (cache_size < 2*RAPARM_HASH_SIZE)
+ cache_size = 2*RAPARM_HASH_SIZE;
raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL);
if (raparml != NULL) {
dprintk("nfsd: allocating %d readahead buffers.\n",
cache_size);
+ for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
+ raparm_hash[i].pb_head = NULL;
+ spin_lock_init(&raparm_hash[i].pb_lock);
+ }
+ nperbucket = cache_size >> RAPARM_HASH_BITS;
memset(raparml, 0, sizeof(struct raparms) * cache_size);
for (i = 0; i < cache_size - 1; i++) {
- raparml[i].p_next = raparml + i + 1;
+ if (i % nperbucket == 0)
+ raparm_hash[j++].pb_head = raparml + i;
+ if (i % nperbucket < nperbucket-1)
+ raparml[i].p_next = raparml + i + 1;
}
- raparm_cache = raparml;
} else {
printk(KERN_WARNING
"nfsd: Could not allocate memory read-ahead cache.\n");
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 7e5a2f5..9c69bca 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1780,7 +1780,7 @@
err = -EDQUOT;
goto out_end_trans;
}
- if (!dir || !dir->i_nlink) {
+ if (!dir->i_nlink) {
err = -EPERM;
goto out_bad_inode;
}
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index 87e5a35..88f02a0 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -17,8 +17,6 @@
#include <asm/irq.h>
#include <asm/sections.h>
-struct hw_interrupt_type;
-
#define NMI_VECTOR 0x02
/*
@@ -30,7 +28,6 @@
extern u8 irq_vector[NR_IRQ_VECTORS];
#define IO_APIC_VECTOR(irq) (irq_vector[irq])
-#define AUTO_ASSIGN -1
extern void (*interrupt[NR_IRQS])(void);
diff --git a/include/asm-i386/hypertransport.h b/include/asm-i386/hypertransport.h
new file mode 100644
index 0000000..c16c6ff
--- /dev/null
+++ b/include/asm-i386/hypertransport.h
@@ -0,0 +1,42 @@
+#ifndef ASM_HYPERTRANSPORT_H
+#define ASM_HYPERTRANSPORT_H
+
+/*
+ * Constants for x86 Hypertransport Interrupts.
+ */
+
+#define HT_IRQ_LOW_BASE 0xf8000000
+
+#define HT_IRQ_LOW_VECTOR_SHIFT 16
+#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000
+#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
+
+#define HT_IRQ_LOW_DEST_ID_SHIFT 8
+#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00
+#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
+
+#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000
+#define HT_IRQ_LOW_DM_LOGICAL 0x0000040
+
+#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000
+#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020
+
+
+#define HT_IRQ_LOW_MT_FIXED 0x0000000
+#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004
+#define HT_IRQ_LOW_MT_SMI 0x0000008
+#define HT_IRQ_LOW_MT_NMI 0x000000c
+#define HT_IRQ_LOW_MT_INIT 0x0000010
+#define HT_IRQ_LOW_MT_STARTUP 0x0000014
+#define HT_IRQ_LOW_MT_EXTINT 0x0000018
+#define HT_IRQ_LOW_MT_LINT1 0x000008c
+#define HT_IRQ_LOW_MT_LINT0 0x0000098
+
+#define HT_IRQ_LOW_IRQ_MASKED 0x0000001
+
+
+#define HT_IRQ_HIGH_DEST_ID_SHIFT 0
+#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff
+#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
+
+#endif /* ASM_HYPERTRANSPORT_H */
diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h
index 5d30927..276ea7e 100644
--- a/include/asm-i386/io_apic.h
+++ b/include/asm-i386/io_apic.h
@@ -12,46 +12,6 @@
#ifdef CONFIG_X86_IO_APIC
-#ifdef CONFIG_PCI_MSI
-static inline int use_pci_vector(void) {return 1;}
-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
-static inline void end_edge_ioapic_vector (unsigned int vector) { }
-#define startup_level_ioapic startup_level_ioapic_vector
-#define shutdown_level_ioapic mask_IO_APIC_vector
-#define enable_level_ioapic unmask_IO_APIC_vector
-#define disable_level_ioapic mask_IO_APIC_vector
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
-#define end_level_ioapic end_level_ioapic_vector
-#define set_ioapic_affinity set_ioapic_affinity_vector
-
-#define startup_edge_ioapic startup_edge_ioapic_vector
-#define shutdown_edge_ioapic disable_edge_ioapic_vector
-#define enable_edge_ioapic unmask_IO_APIC_vector
-#define disable_edge_ioapic disable_edge_ioapic_vector
-#define ack_edge_ioapic ack_edge_ioapic_vector
-#define end_edge_ioapic end_edge_ioapic_vector
-#else
-static inline int use_pci_vector(void) {return 0;}
-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
-static inline void end_edge_ioapic_irq (unsigned int irq) { }
-#define startup_level_ioapic startup_level_ioapic_irq
-#define shutdown_level_ioapic mask_IO_APIC_irq
-#define enable_level_ioapic unmask_IO_APIC_irq
-#define disable_level_ioapic mask_IO_APIC_irq
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
-#define end_level_ioapic end_level_ioapic_irq
-#define set_ioapic_affinity set_ioapic_affinity_irq
-
-#define startup_edge_ioapic startup_edge_ioapic_irq
-#define shutdown_edge_ioapic disable_edge_ioapic_irq
-#define enable_edge_ioapic unmask_IO_APIC_irq
-#define disable_edge_ioapic disable_edge_ioapic_irq
-#define ack_edge_ioapic ack_edge_ioapic_irq
-#define end_edge_ioapic end_edge_ioapic_irq
-#endif
-
#define IO_APIC_BASE(idx) \
((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \
+ (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK)))
@@ -219,6 +179,4 @@
static inline void disable_ioapic_setup(void) { }
#endif
-extern int assign_irq_vector(int irq);
-
#endif
diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h
index b330026..7f161e7 100644
--- a/include/asm-i386/mach-default/irq_vectors_limits.h
+++ b/include/asm-i386/mach-default/irq_vectors_limits.h
@@ -1,10 +1,6 @@
#ifndef _ASM_IRQ_VECTORS_LIMITS_H
#define _ASM_IRQ_VECTORS_LIMITS_H
-#ifdef CONFIG_PCI_MSI
-#define NR_IRQS FIRST_SYSTEM_VECTOR
-#define NR_IRQ_VECTORS NR_IRQS
-#else
#ifdef CONFIG_X86_IO_APIC
#define NR_IRQS 224
# if (224 >= 32 * NR_CPUS)
@@ -16,6 +12,5 @@
#define NR_IRQS 16
#define NR_IRQ_VECTORS NR_IRQS
#endif
-#endif
#endif /* _ASM_IRQ_VECTORS_LIMITS_H */
diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h
deleted file mode 100644
index b11c4b7..0000000
--- a/include/asm-i386/msi.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <mach_apic.h>
-
-#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
-#define MSI_TARGET_CPU_SHIFT 12
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
- msi_register(&msi_apic_ops);
- return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-i386/msidef.h b/include/asm-i386/msidef.h
new file mode 100644
index 0000000..5b8acdd
--- /dev/null
+++ b/include/asm-i386/msidef.h
@@ -0,0 +1,47 @@
+#ifndef ASM_MSIDEF_H
+#define ASM_MSIDEF_H
+
+/*
+ * Constants for Intel APIC based MSI messages.
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT 0
+#define MSI_DATA_VECTOR_MASK 0x000000ff
+#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT 8
+#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
+#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT 14
+#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT 15
+#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_BASE_HI 0
+#define MSI_ADDR_BASE_LO 0xfee00000
+
+#define MSI_ADDR_DEST_MODE_SHIFT 2
+#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
+#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT 3
+#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
+#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
+
+#define MSI_ADDR_DEST_ID_SHIFT 12
+#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
+#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
+
+#endif /* ASM_MSIDEF_H */
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index 15b545a..90cba96 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -20,6 +20,7 @@
struct mm_struct;
struct pci_bus;
struct task_struct;
+struct pci_dev;
typedef void ia64_mv_setup_t (char **);
typedef void ia64_mv_cpu_init_t (void);
@@ -75,7 +76,9 @@
typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
-typedef int ia64_mv_msi_init_t (void);
+
+typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
static inline void
machvec_noop (void)
@@ -154,7 +157,8 @@
# define platform_readl_relaxed ia64_mv.readl_relaxed
# define platform_readq_relaxed ia64_mv.readq_relaxed
# define platform_migrate ia64_mv.migrate
-# define platform_msi_init ia64_mv.msi_init
+# define platform_setup_msi_irq ia64_mv.setup_msi_irq
+# define platform_teardown_msi_irq ia64_mv.teardown_msi_irq
# endif
/* __attribute__((__aligned__(16))) is required to make size of the
@@ -204,7 +208,8 @@
ia64_mv_readl_relaxed_t *readl_relaxed;
ia64_mv_readq_relaxed_t *readq_relaxed;
ia64_mv_migrate_t *migrate;
- ia64_mv_msi_init_t *msi_init;
+ ia64_mv_setup_msi_irq_t *setup_msi_irq;
+ ia64_mv_teardown_msi_irq_t *teardown_msi_irq;
} __attribute__((__aligned__(16))); /* align attrib? see above comment */
#define MACHVEC_INIT(name) \
@@ -250,7 +255,8 @@
platform_readl_relaxed, \
platform_readq_relaxed, \
platform_migrate, \
- platform_msi_init, \
+ platform_setup_msi_irq, \
+ platform_teardown_msi_irq, \
}
extern struct ia64_machine_vector ia64_mv;
@@ -404,8 +410,11 @@
#ifndef platform_migrate
# define platform_migrate machvec_noop_task
#endif
-#ifndef platform_msi_init
-# define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
+#ifndef platform_setup_msi_irq
+# define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL)
+#endif
+#ifndef platform_teardown_msi_irq
+# define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL)
#endif
#endif /* _ASM_IA64_MACHVEC_H */
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
index cf724dc..c54b165 100644
--- a/include/asm-ia64/machvec_sn2.h
+++ b/include/asm-ia64/machvec_sn2.h
@@ -67,7 +67,8 @@
extern ia64_mv_dma_mapping_error sn_dma_mapping_error;
extern ia64_mv_dma_supported sn_dma_supported;
extern ia64_mv_migrate_t sn_migrate;
-extern ia64_mv_msi_init_t sn_msi_init;
+extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq;
+extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq;
/*
@@ -120,9 +121,11 @@
#define platform_dma_supported sn_dma_supported
#define platform_migrate sn_migrate
#ifdef CONFIG_PCI_MSI
-#define platform_msi_init sn_msi_init
+#define platform_setup_msi_irq sn_setup_msi_irq
+#define platform_teardown_msi_irq sn_teardown_msi_irq
#else
-#define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
+#define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL)
+#define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL)
#endif
#include <asm/sn/io.h>
diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h
deleted file mode 100644
index bb92b0d..0000000
--- a/include/asm-ia64/msi.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#define NR_VECTORS NR_IRQS
-#define FIRST_DEVICE_VECTOR IA64_FIRST_DEVICE_VECTOR
-#define LAST_DEVICE_VECTOR IA64_LAST_DEVICE_VECTOR
-static inline void set_intr_gate (int nr, void *func) {}
-#define IO_APIC_VECTOR(irq) (irq)
-#define ack_APIC_irq ia64_eoi
-#define MSI_TARGET_CPU_SHIFT 4
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
- if (platform_msi_init)
- return platform_msi_init();
-
- /* default ops for most ia64 platforms */
- msi_register(&msi_apic_ops);
- return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
index 64a65ce..95d5e09 100644
--- a/include/asm-x86_64/hardirq.h
+++ b/include/asm-x86_64/hardirq.h
@@ -6,6 +6,9 @@
#include <asm/pda.h>
#include <asm/apic.h>
+/* We can have at most NR_VECTORS irqs routed to a cpu at a time */
+#define MAX_HARDIRQS_PER_CPU NR_VECTORS
+
#define __ARCH_IRQ_STAT 1
#define local_softirq_pending() read_pda(__softirq_pending)
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index 48a4a53..53d0d9f 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -19,8 +19,7 @@
#include <asm/irq.h>
#include <linux/profile.h>
#include <linux/smp.h>
-
-struct hw_interrupt_type;
+#include <linux/percpu.h>
#endif
#define NMI_VECTOR 0x02
@@ -75,9 +74,10 @@
#ifndef __ASSEMBLY__
-extern u8 irq_vector[NR_IRQ_VECTORS];
+extern unsigned int irq_vector[NR_IRQ_VECTORS];
+typedef int vector_irq_t[NR_VECTORS];
+DECLARE_PER_CPU(vector_irq_t, vector_irq);
#define IO_APIC_VECTOR(irq) (irq_vector[irq])
-#define AUTO_ASSIGN -1
/*
* Various low-level irq details needed by irq.c, process.c,
diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h
new file mode 100644
index 0000000..c16c6ff
--- /dev/null
+++ b/include/asm-x86_64/hypertransport.h
@@ -0,0 +1,42 @@
+#ifndef ASM_HYPERTRANSPORT_H
+#define ASM_HYPERTRANSPORT_H
+
+/*
+ * Constants for x86 Hypertransport Interrupts.
+ */
+
+#define HT_IRQ_LOW_BASE 0xf8000000
+
+#define HT_IRQ_LOW_VECTOR_SHIFT 16
+#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000
+#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
+
+#define HT_IRQ_LOW_DEST_ID_SHIFT 8
+#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00
+#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
+
+#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000
+#define HT_IRQ_LOW_DM_LOGICAL 0x0000040
+
+#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000
+#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020
+
+
+#define HT_IRQ_LOW_MT_FIXED 0x0000000
+#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004
+#define HT_IRQ_LOW_MT_SMI 0x0000008
+#define HT_IRQ_LOW_MT_NMI 0x000000c
+#define HT_IRQ_LOW_MT_INIT 0x0000010
+#define HT_IRQ_LOW_MT_STARTUP 0x0000014
+#define HT_IRQ_LOW_MT_EXTINT 0x0000018
+#define HT_IRQ_LOW_MT_LINT1 0x000008c
+#define HT_IRQ_LOW_MT_LINT0 0x0000098
+
+#define HT_IRQ_LOW_IRQ_MASKED 0x0000001
+
+
+#define HT_IRQ_HIGH_DEST_ID_SHIFT 0
+#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff
+#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
+
+#endif /* ASM_HYPERTRANSPORT_H */
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
index 5d1b5c6..171ec2d 100644
--- a/include/asm-x86_64/io_apic.h
+++ b/include/asm-x86_64/io_apic.h
@@ -10,46 +10,6 @@
* Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
*/
-#ifdef CONFIG_PCI_MSI
-static inline int use_pci_vector(void) {return 1;}
-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
-static inline void end_edge_ioapic_vector (unsigned int vector) { }
-#define startup_level_ioapic startup_level_ioapic_vector
-#define shutdown_level_ioapic mask_IO_APIC_vector
-#define enable_level_ioapic unmask_IO_APIC_vector
-#define disable_level_ioapic mask_IO_APIC_vector
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
-#define end_level_ioapic end_level_ioapic_vector
-#define set_ioapic_affinity set_ioapic_affinity_vector
-
-#define startup_edge_ioapic startup_edge_ioapic_vector
-#define shutdown_edge_ioapic disable_edge_ioapic_vector
-#define enable_edge_ioapic unmask_IO_APIC_vector
-#define disable_edge_ioapic disable_edge_ioapic_vector
-#define ack_edge_ioapic ack_edge_ioapic_vector
-#define end_edge_ioapic end_edge_ioapic_vector
-#else
-static inline int use_pci_vector(void) {return 0;}
-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
-static inline void end_edge_ioapic_irq (unsigned int irq) { }
-#define startup_level_ioapic startup_level_ioapic_irq
-#define shutdown_level_ioapic mask_IO_APIC_irq
-#define enable_level_ioapic unmask_IO_APIC_irq
-#define disable_level_ioapic mask_IO_APIC_irq
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
-#define end_level_ioapic end_level_ioapic_irq
-#define set_ioapic_affinity set_ioapic_affinity_irq
-
-#define startup_edge_ioapic startup_edge_ioapic_irq
-#define shutdown_edge_ioapic disable_edge_ioapic_irq
-#define enable_edge_ioapic unmask_IO_APIC_irq
-#define disable_edge_ioapic disable_edge_ioapic_irq
-#define ack_edge_ioapic ack_edge_ioapic_irq
-#define end_edge_ioapic end_edge_ioapic_irq
-#endif
-
#define APIC_MISMATCH_DEBUG
#define IO_APIC_BASE(idx) \
@@ -202,13 +162,10 @@
extern int io_apic_get_version (int ioapic);
extern int io_apic_get_redir_entries (int ioapic);
extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int);
-extern int timer_uses_ioapic_pin_0;
#endif
extern int sis_apic_bug; /* dummy */
-extern int assign_irq_vector(int irq);
-
void enable_NMI_through_LVT0 (void * dummy);
extern spinlock_t i8259A_lock;
diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h
index 43469d8a..5006c6e 100644
--- a/include/asm-x86_64/irq.h
+++ b/include/asm-x86_64/irq.h
@@ -31,13 +31,8 @@
#define FIRST_SYSTEM_VECTOR 0xef /* duplicated in hw_irq.h */
-#ifdef CONFIG_PCI_MSI
-#define NR_IRQS FIRST_SYSTEM_VECTOR
+#define NR_IRQS (NR_VECTORS + (32 *NR_CPUS))
#define NR_IRQ_VECTORS NR_IRQS
-#else
-#define NR_IRQS 224
-#define NR_IRQ_VECTORS (32 * NR_CPUS)
-#endif
static __inline__ int irq_canonicalize(int irq)
{
diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h
deleted file mode 100644
index 3ad23466..0000000
--- a/include/asm-x86_64/msi.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <asm/mach_apic.h>
-#include <asm/smp.h>
-
-#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
-#define MSI_TARGET_CPU_SHIFT 12
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
- msi_register(&msi_apic_ops);
- return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h
new file mode 100644
index 0000000..5b8acdd
--- /dev/null
+++ b/include/asm-x86_64/msidef.h
@@ -0,0 +1,47 @@
+#ifndef ASM_MSIDEF_H
+#define ASM_MSIDEF_H
+
+/*
+ * Constants for Intel APIC based MSI messages.
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT 0
+#define MSI_DATA_VECTOR_MASK 0x000000ff
+#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT 8
+#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
+#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT 14
+#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT 15
+#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_BASE_HI 0
+#define MSI_ADDR_BASE_LO 0xfee00000
+
+#define MSI_ADDR_DEST_MODE_SHIFT 2
+#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
+#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT 3
+#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
+#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
+
+#define MSI_ADDR_DEST_ID_SHIFT 12
+#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
+#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
+
+#endif /* ASM_MSIDEF_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index f7a52e1..7d564b6 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -156,12 +156,10 @@
header-y += ultrasound.h
header-y += un.h
header-y += utime.h
-header-y += utsname.h
header-y += video_decoder.h
header-y += video_encoder.h
header-y += videotext.h
header-y += vt.h
-header-y += wavefront.h
header-y += wireless.h
header-y += xattr.h
header-y += x25.h
@@ -333,6 +331,7 @@
unifdef-y += usb_ch9.h
unifdef-y += usbdevice_fs.h
unifdef-y += user.h
+unifdef-y += utsname.h
unifdef-y += videodev2.h
unifdef-y += videodev.h
unifdef-y += wait.h
diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h
index 2ed2fd8..22eb936 100644
--- a/include/linux/ac97_codec.h
+++ b/include/linux/ac97_codec.h
@@ -331,8 +331,6 @@
extern int ac97_probe_codec(struct ac97_codec *);
extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
-extern int ac97_save_state(struct ac97_codec *codec);
-extern int ac97_restore_state(struct ac97_codec *codec);
extern struct ac97_codec *ac97_alloc_codec(void);
extern void ac97_release_codec(struct ac97_codec *codec);
@@ -346,9 +344,6 @@
void (*remove) (struct ac97_codec *codec, struct ac97_driver *driver);
};
-extern int ac97_register_driver(struct ac97_driver *driver);
-extern void ac97_unregister_driver(struct ac97_driver *driver);
-
/* quirk types */
enum {
AC97_TUNE_DEFAULT = -1, /* use default from quirk list (not valid in list) */
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 50d8b57..612472a 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -28,11 +28,16 @@
#ifndef HARDIRQ_BITS
#define HARDIRQ_BITS 12
+
+#ifndef MAX_HARDIRQS_PER_CPU
+#define MAX_HARDIRQS_PER_CPU NR_IRQS
+#endif
+
/*
* The hardirq mask has to be large enough to have space for potentially
* all IRQ sources in the system nesting on a single CPU.
*/
-#if (1 << HARDIRQ_BITS) < NR_IRQS
+#if (1 << HARDIRQ_BITS) < MAX_HARDIRQS_PER_CPU
# error HARDIRQ_BITS is too low!
#endif
#endif
diff --git a/include/linux/htirq.h b/include/linux/htirq.h
new file mode 100644
index 0000000..1f15ce2
--- /dev/null
+++ b/include/linux/htirq.h
@@ -0,0 +1,15 @@
+#ifndef LINUX_HTIRQ_H
+#define LINUX_HTIRQ_H
+
+/* Helper functions.. */
+void write_ht_irq_low(unsigned int irq, u32 data);
+void write_ht_irq_high(unsigned int irq, u32 data);
+u32 read_ht_irq_low(unsigned int irq);
+u32 read_ht_irq_high(unsigned int irq);
+void mask_ht_irq(unsigned int irq);
+void unmask_ht_irq(unsigned int irq);
+
+/* The arch hook for getting things started */
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
+
+#endif /* LINUX_HTIRQ_H */
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index d9e2b3f..636094c 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -2,7 +2,6 @@
#define _LINUX_IPC_H
#include <linux/types.h>
-#include <linux/kref.h>
#define IPC_PRIVATE ((__kernel_key_t) 0)
@@ -52,6 +51,8 @@
#ifdef __KERNEL__
+#include <linux/kref.h>
+
#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
/* used by in-kernel data structures */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 48d3cb3..6f46360 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -59,6 +59,7 @@
#define IRQ_NOAUTOEN 0x08000000 /* IRQ will not be enabled on request irq */
#define IRQ_DELAYED_DISABLE 0x10000000 /* IRQ disable (masking) happens delayed. */
#define IRQ_WAKEUP 0x20000000 /* IRQ triggers system wakeup */
+#define IRQ_MOVE_PENDING 0x40000000 /* need to re-target IRQ destination */
struct proc_dir_entry;
@@ -132,7 +133,6 @@
* @affinity: IRQ affinity on SMP
* @cpu: cpu index useful for balancing
* @pending_mask: pending rebalanced interrupts
- * @move_irq: need to re-target IRQ destination
* @dir: /proc/irq/ procfs entry
* @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP
*
@@ -159,7 +159,6 @@
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
- unsigned int move_irq; /* need to re-target IRQ dest */
#endif
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
@@ -206,36 +205,7 @@
void set_pending_irq(unsigned int irq, cpumask_t mask);
void move_native_irq(int irq);
-
-#ifdef CONFIG_PCI_MSI
-/*
- * Wonder why these are dummies?
- * For e.g the set_ioapic_affinity_vector() calls the set_ioapic_affinity_irq()
- * counter part after translating the vector to irq info. We need to perform
- * this operation on the real irq, when we dont use vector, i.e when
- * pci_use_vector() is false.
- */
-static inline void move_irq(int irq)
-{
-}
-
-static inline void set_irq_info(int irq, cpumask_t mask)
-{
-}
-
-#else /* CONFIG_PCI_MSI */
-
-static inline void move_irq(int irq)
-{
- move_native_irq(irq);
-}
-
-static inline void set_irq_info(int irq, cpumask_t mask)
-{
- set_native_irq_info(irq, mask);
-}
-
-#endif /* CONFIG_PCI_MSI */
+void move_masked_irq(int irq);
#else /* CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE */
@@ -247,21 +217,20 @@
{
}
-static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+static inline void move_masked_irq(int irq)
{
}
-static inline void set_irq_info(int irq, cpumask_t mask)
+static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
{
- set_native_irq_info(irq, mask);
}
#endif /* CONFIG_GENERIC_PENDING_IRQ */
#else /* CONFIG_SMP */
-#define move_irq(x)
#define move_native_irq(x)
+#define move_masked_irq(x)
#endif /* CONFIG_SMP */
@@ -399,8 +368,22 @@
__set_irq_handler(irq, handle, 1);
}
-/* Set/get chip/data for an IRQ: */
+/* Handle dynamic irq creation and destruction */
+extern int create_irq(void);
+extern void destroy_irq(unsigned int irq);
+/* Test to see if a driver has successfully requested an irq */
+static inline int irq_has_action(unsigned int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+ return desc->action != NULL;
+}
+
+/* Dynamic irq helper functions */
+extern void dynamic_irq_init(unsigned int irq);
+extern void dynamic_irq_cleanup(unsigned int irq);
+
+/* Set/get chip/data for an IRQ: */
extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
extern int set_irq_data(unsigned int irq, void *data);
extern int set_irq_chip_data(unsigned int irq, void *data);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d6a3d4b..d1af1dbe 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -109,6 +109,10 @@
#define ATA_TAG_POISON 0xfafbfcfdU
/* move to PCI layer? */
+#define PCI_VDEVICE(vendor, device) \
+ PCI_VENDOR_ID_##vendor, (device), \
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0
+
static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
{
return &pdev->dev;
@@ -138,8 +142,9 @@
ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
- ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
- ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */
+ ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
+ ATA_DFLAG_NCQ_OFF = (1 << 9), /* devied limited to non-NCQ mode */
+ ATA_DFLAG_SUSPENDED = (1 << 10), /* device suspended */
ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
ATA_DFLAG_DETACH = (1 << 16),
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 47b7dbd..2909619 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -37,17 +37,15 @@
* Lockd host handle (used both by the client and server personality).
*/
struct nlm_host {
- struct nlm_host * h_next; /* linked list (hash table) */
+ struct hlist_node h_hash; /* doubly linked list */
struct sockaddr_in h_addr; /* peer address */
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
- char h_name[20]; /* remote hostname */
+ char * h_name; /* remote hostname */
u32 h_version; /* interface version */
unsigned short h_proto; /* transport proto */
unsigned short h_reclaiming : 1,
h_server : 1, /* server side, not client side */
- h_inuse : 1,
- h_killed : 1,
- h_monitored : 1;
+ h_inuse : 1;
wait_queue_head_t h_gracewait; /* wait while reclaiming */
struct rw_semaphore h_rwsem; /* Reboot recovery lock */
u32 h_state; /* pseudo-state counter */
@@ -61,6 +59,16 @@
spinlock_t h_lock;
struct list_head h_granted; /* Locks in GRANTED state */
struct list_head h_reclaim; /* Locks in RECLAIM state */
+ struct nsm_handle * h_nsmhandle; /* NSM status handle */
+};
+
+struct nsm_handle {
+ struct list_head sm_link;
+ atomic_t sm_count;
+ char * sm_name;
+ struct sockaddr_in sm_addr;
+ unsigned int sm_monitored : 1,
+ sm_sticky : 1; /* don't unmonitor */
};
/*
@@ -96,15 +104,14 @@
* an NFS client.
*/
struct nlm_file {
- struct nlm_file * f_next; /* linked list */
+ struct hlist_node f_list; /* linked list */
struct nfs_fh f_handle; /* NFS file handle */
struct file * f_file; /* VFS file pointer */
struct nlm_share * f_shares; /* DOS shares */
- struct nlm_block * f_blocks; /* blocked locks */
+ struct list_head f_blocks; /* blocked locks */
unsigned int f_locks; /* guesstimate # of locks */
unsigned int f_count; /* reference count */
- struct semaphore f_sema; /* avoid concurrent access */
- int f_hash; /* hash of f_handle */
+ struct mutex f_mutex; /* avoid concurrent access */
};
/*
@@ -114,26 +121,18 @@
#define NLM_NEVER (~(unsigned long) 0)
struct nlm_block {
struct kref b_count; /* Reference count */
- struct nlm_block * b_next; /* linked list (all blocks) */
- struct nlm_block * b_fnext; /* linked list (per file) */
+ struct list_head b_list; /* linked list of all blocks */
+ struct list_head b_flist; /* linked list (per file) */
struct nlm_rqst * b_call; /* RPC args & callback info */
struct svc_serv * b_daemon; /* NLM service */
struct nlm_host * b_host; /* host handle for RPC clnt */
unsigned long b_when; /* next re-xmit */
unsigned int b_id; /* block id */
- unsigned char b_queued; /* re-queued */
unsigned char b_granted; /* VFS granted lock */
struct nlm_file * b_file; /* file in question */
};
/*
- * Valid actions for nlmsvc_traverse_files
- */
-#define NLM_ACT_CHECK 0 /* check for locks */
-#define NLM_ACT_MARK 1 /* mark & sweep */
-#define NLM_ACT_UNLOCK 2 /* release all locks */
-
-/*
* Global variables
*/
extern struct rpc_program nlm_program;
@@ -143,6 +142,7 @@
#endif
extern int nlmsvc_grace_period;
extern unsigned long nlmsvc_timeout;
+extern int nsm_use_hostnames;
/*
* Lockd client functions
@@ -155,24 +155,33 @@
void nlmclnt_finish_block(struct nlm_wait *block);
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
-void nlmclnt_recovery(struct nlm_host *, u32);
+void nlmclnt_recovery(struct nlm_host *);
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
+void nlmclnt_next_cookie(struct nlm_cookie *);
/*
* Host cache
*/
-struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int);
-struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *);
-struct nlm_host * nlm_lookup_host(int server, struct sockaddr_in *, int, int);
+struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int);
+struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int);
+struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int, const char *, int);
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *);
void nlm_release_host(struct nlm_host *);
void nlm_shutdown_hosts(void);
-extern struct nlm_host *nlm_find_client(void);
+extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32);
+struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int);
+void nsm_release(struct nsm_handle *);
/*
+ * This is used in garbage collection and resource reclaim
+ * A return value != 0 means destroy the lock/block/share
+ */
+typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref);
+
+/*
* Server-side lock handling
*/
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
@@ -183,8 +192,8 @@
u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
unsigned long nlmsvc_retry_blocked(void);
void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
- int action);
-void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32);
+ nlm_host_match_fn_t match);
+void nlmsvc_grant_reply(struct nlm_cookie *, u32);
/*
* File handling for the server personality
diff --git a/include/linux/lockd/share.h b/include/linux/lockd/share.h
index c75a424..cd7816e 100644
--- a/include/linux/lockd/share.h
+++ b/include/linux/lockd/share.h
@@ -25,6 +25,7 @@
struct nlm_args *);
u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
struct nlm_args *);
-void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int);
+void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
+ nlm_host_match_fn_t);
#endif /* LINUX_LOCKD_SHARE_H */
diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h
index 1080bb6..fc61d40 100644
--- a/include/linux/lockd/sm_inter.h
+++ b/include/linux/lockd/sm_inter.h
@@ -28,7 +28,8 @@
u32 prog; /* RPC callback info */
u32 vers;
u32 proc;
- u32 proto; /* protocol (udp/tcp) plus server/client flag */
+
+ char * mon_name;
};
/*
@@ -41,6 +42,6 @@
int nsm_monitor(struct nlm_host *);
int nsm_unmonitor(struct nlm_host *);
-extern u32 nsm_local_state;
+extern int nsm_local_state;
#endif /* LINUX_LOCKD_SM_INTER_H */
diff --git a/include/linux/msi.h b/include/linux/msi.h
new file mode 100644
index 0000000..c7ef943
--- /dev/null
+++ b/include/linux/msi.h
@@ -0,0 +1,49 @@
+#ifndef LINUX_MSI_H
+#define LINUX_MSI_H
+
+struct msi_msg {
+ u32 address_lo; /* low 32 bits of msi message address */
+ u32 address_hi; /* high 32 bits of msi message address */
+ u32 data; /* 16 bits of msi message data */
+};
+
+/* Heper functions */
+extern void mask_msi_irq(unsigned int irq);
+extern void unmask_msi_irq(unsigned int irq);
+extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+struct msi_desc {
+ struct {
+ __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
+ __u8 maskbit : 1; /* mask-pending bit supported ? */
+ __u8 unused : 1;
+ __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
+ __u8 pos; /* Location of the msi capability */
+ __u16 entry_nr; /* specific enabled entry */
+ unsigned default_irq; /* default pre-assigned irq */
+ }msi_attrib;
+
+ struct {
+ __u16 head;
+ __u16 tail;
+ }link;
+
+ void __iomem *mask_base;
+ struct pci_dev *dev;
+
+#ifdef CONFIG_PM
+ /* PM save area for MSIX address/data */
+ struct msi_msg msg_save;
+#endif
+};
+
+/*
+ * The arch hook for setup up msi irqs
+ */
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+void arch_teardown_msi_irq(unsigned int irq);
+
+
+#endif /* LINUX_MSI_H */
diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h
index b75bb1b3..f0cc777 100644
--- a/include/linux/nfsd/const.h
+++ b/include/linux/nfsd/const.h
@@ -20,17 +20,31 @@
#define NFSSVC_MAXVERS 3
/*
- * Maximum blocksize supported by daemon currently at 32K
+ * Maximum blocksizes supported by daemon under various circumstances.
*/
-#define NFSSVC_MAXBLKSIZE (32*1024)
+#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD
+/* NFSv2 is limited by the protocol specification, see RFC 1094 */
+#define NFSSVC_MAXBLKSIZE_V2 (8*1024)
#ifdef __KERNEL__
+#include <linux/sunrpc/msg_prot.h>
+
#ifndef NFS_SUPER_MAGIC
# define NFS_SUPER_MAGIC 0x6969
#endif
-#define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE)
+/*
+ * Largest number of bytes we need to allocate for an NFS
+ * call or reply. Used to control buffer sizes. We use
+ * the length of v3 WRITE, READDIR and READDIR replies
+ * which are an RPC header, up to 26 XDR units of reply
+ * data, and some page data.
+ *
+ * Note that accuracy here doesn't matter too much as the
+ * size is rounded up to a page size when allocating space.
+ */
+#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE)
#ifdef CONFIG_NFSD_V4
# define NFSSVC_XDRSIZE NFS4_SVC_XDRSIZE
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index d2a8abb..6e78ea9 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -45,15 +45,36 @@
#ifdef __KERNEL__
+/*
+ * FS Locations
+ */
+
+#define MAX_FS_LOCATIONS 128
+
+struct nfsd4_fs_location {
+ char *hosts; /* colon separated list of hosts */
+ char *path; /* slash separated list of path components */
+};
+
+struct nfsd4_fs_locations {
+ uint32_t locations_count;
+ struct nfsd4_fs_location *locations;
+/* If we're not actually serving this data ourselves (only providing a
+ * list of replicas that do serve it) then we set "migrated": */
+ int migrated;
+};
+
struct svc_export {
struct cache_head h;
struct auth_domain * ex_client;
int ex_flags;
struct vfsmount * ex_mnt;
struct dentry * ex_dentry;
+ char * ex_path;
uid_t ex_anon_uid;
gid_t ex_anon_gid;
int ex_fsid;
+ struct nfsd4_fs_locations ex_fslocs;
};
/* an "export key" (expkey) maps a filehandlefragement to an
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index e1dbc86..d0d4aae 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -145,6 +145,7 @@
void nfsd_reset_versions(void);
int nfsd_create_serv(void);
+extern int nfsd_max_blksize;
/*
* NFSv4 State
@@ -215,6 +216,7 @@
#define nfserr_clid_inuse __constant_htonl(NFSERR_CLID_INUSE)
#define nfserr_stale_clientid __constant_htonl(NFSERR_STALE_CLIENTID)
#define nfserr_resource __constant_htonl(NFSERR_RESOURCE)
+#define nfserr_moved __constant_htonl(NFSERR_MOVED)
#define nfserr_nofilehandle __constant_htonl(NFSERR_NOFILEHANDLE)
#define nfserr_minor_vers_mismatch __constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
#define nfserr_share_denied __constant_htonl(NFSERR_SHARE_DENIED)
@@ -291,7 +293,6 @@
/*
* The following attributes are currently not supported by the NFSv4 server:
* ARCHIVE (deprecated anyway)
- * FS_LOCATIONS (will be supported eventually)
* HIDDEN (unlikely to be supported any time soon)
* MIMETYPE (unlikely to be supported any time soon)
* QUOTA_* (will be supported in a forthcoming patch)
@@ -307,7 +308,7 @@
| FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \
| FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \
| FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \
- | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_HOMOGENEOUS \
+ | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \
| FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \
| FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL)
diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
index a38f9d7..0e53de8 100644
--- a/include/linux/nfsd/xdr.h
+++ b/include/linux/nfsd/xdr.h
@@ -30,7 +30,6 @@
struct svc_fh fh;
__u32 offset;
__u32 count;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
@@ -38,7 +37,6 @@
svc_fh fh;
__u32 offset;
int len;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
index a432274..474d882 100644
--- a/include/linux/nfsd/xdr3.h
+++ b/include/linux/nfsd/xdr3.h
@@ -33,7 +33,6 @@
struct svc_fh fh;
__u64 offset;
__u32 count;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
@@ -43,7 +42,6 @@
__u32 count;
int stable;
__u32 len;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 77adba7..66e6427 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -241,7 +241,6 @@
stateid_t rd_stateid; /* request */
u64 rd_offset; /* request */
u32 rd_length; /* request */
- struct kvec rd_iov[RPCSVC_MAXPAGES];
int rd_vlen;
struct file *rd_filp;
@@ -326,7 +325,6 @@
u64 wr_offset; /* request */
u32 wr_stable_how; /* request */
u32 wr_buflen; /* request */
- struct kvec wr_vec[RPCSVC_MAXPAGES]; /* request */
int wr_vlen;
u32 wr_bytes_written; /* response */
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 7ff386a..10a43ed 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -12,9 +12,10 @@
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
+#include <linux/srcu.h>
/*
- * Notifier chains are of three types:
+ * Notifier chains are of four types:
*
* Atomic notifier chains: Chain callbacks run in interrupt/atomic
* context. Callouts are not allowed to block.
@@ -23,13 +24,27 @@
* Raw notifier chains: There are no restrictions on callbacks,
* registration, or unregistration. All locking and protection
* must be provided by the caller.
+ * SRCU notifier chains: A variant of blocking notifier chains, with
+ * the same restrictions.
*
* atomic_notifier_chain_register() may be called from an atomic context,
- * but blocking_notifier_chain_register() must be called from a process
- * context. Ditto for the corresponding _unregister() routines.
+ * but blocking_notifier_chain_register() and srcu_notifier_chain_register()
+ * must be called from a process context. Ditto for the corresponding
+ * _unregister() routines.
*
- * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister()
- * _must not_ be called from within the call chain.
+ * atomic_notifier_chain_unregister(), blocking_notifier_chain_unregister(),
+ * and srcu_notifier_chain_unregister() _must not_ be called from within
+ * the call chain.
+ *
+ * SRCU notifier chains are an alternative form of blocking notifier chains.
+ * They use SRCU (Sleepable Read-Copy Update) instead of rw-semaphores for
+ * protection of the chain links. This means there is _very_ low overhead
+ * in srcu_notifier_call_chain(): no cache bounces and no memory barriers.
+ * As compensation, srcu_notifier_chain_unregister() is rather expensive.
+ * SRCU notifier chains should be used when the chain will be called very
+ * often but notifier_blocks will seldom be removed. Also, SRCU notifier
+ * chains are slightly more difficult to use because they require special
+ * runtime initialization.
*/
struct notifier_block {
@@ -52,6 +67,12 @@
struct notifier_block *head;
};
+struct srcu_notifier_head {
+ struct mutex mutex;
+ struct srcu_struct srcu;
+ struct notifier_block *head;
+};
+
#define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \
spin_lock_init(&(name)->lock); \
(name)->head = NULL; \
@@ -64,6 +85,11 @@
(name)->head = NULL; \
} while (0)
+/* srcu_notifier_heads must be initialized and cleaned up dynamically */
+extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
+#define srcu_cleanup_notifier_head(name) \
+ cleanup_srcu_struct(&(name)->srcu);
+
#define ATOMIC_NOTIFIER_INIT(name) { \
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
.head = NULL }
@@ -72,6 +98,7 @@
.head = NULL }
#define RAW_NOTIFIER_INIT(name) { \
.head = NULL }
+/* srcu_notifier_heads cannot be initialized statically */
#define ATOMIC_NOTIFIER_HEAD(name) \
struct atomic_notifier_head name = \
@@ -91,6 +118,8 @@
struct notifier_block *);
extern int raw_notifier_chain_register(struct raw_notifier_head *,
struct notifier_block *);
+extern int srcu_notifier_chain_register(struct srcu_notifier_head *,
+ struct notifier_block *);
extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
struct notifier_block *);
@@ -98,6 +127,8 @@
struct notifier_block *);
extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
struct notifier_block *);
+extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *,
+ struct notifier_block *);
extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
unsigned long val, void *v);
@@ -105,6 +136,8 @@
unsigned long val, void *v);
extern int raw_notifier_call_chain(struct raw_notifier_head *,
unsigned long val, void *v);
+extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
+ unsigned long val, void *v);
#define NOTIFY_DONE 0x0000 /* Don't care */
#define NOTIFY_OK 0x0001 /* Suits me */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4431ce4..5c604f5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -595,6 +595,7 @@
u16 entry; /* driver uses to specify entry, OS writes */
};
+
#ifndef CONFIG_PCI_MSI
static inline void pci_scan_msi_device(struct pci_dev *dev) {}
static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -613,6 +614,12 @@
extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
#endif
+#ifdef CONFIG_HT_IRQ
+/* The functions a driver should call */
+int ht_create_irq(struct pci_dev *dev, int idx);
+void ht_destroy_irq(unsigned int irq);
+#endif /* CONFIG_HT_IRQ */
+
extern void pci_block_user_cfg_access(struct pci_dev *dev);
extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 7d0e26c..c312a12 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -12,6 +12,11 @@
* PCI Local Bus Specification
* PCI to PCI Bridge Specification
* PCI System Design Guide
+ *
+ * For hypertransport information, please consult the following manuals
+ * from http://www.hypertransport.org
+ *
+ * The Hypertransport I/O Link Specification
*/
#ifndef LINUX_PCI_REGS_H
@@ -463,4 +468,20 @@
#define PCI_PWR_CAP 12 /* Capability */
#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
+/* Hypertransport sub capability types */
+#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */
+#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */
+#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */
+#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */
+#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */
+
+
#endif /* LINUX_PCI_REGS_H */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index b4ca73d..c6b7485 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -19,7 +19,7 @@
*
* Author: Dipankar Sarma <dipankar@in.ibm.com>
*
- * Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
+ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
* and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
* Papers:
* http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
@@ -66,6 +66,8 @@
long completed; /* Number of the last completed batch */
int next_pending; /* Is the next batch already waiting? */
+ int signaled;
+
spinlock_t lock ____cacheline_internodealigned_in_smp;
cpumask_t cpumask; /* CPUs that need to switch in order */
/* for current batch to proceed. */
@@ -106,9 +108,6 @@
long blimit; /* Upper limit on a processed batch */
int cpu;
struct rcu_head barrier;
-#ifdef CONFIG_SMP
- long last_rs_qlen; /* qlen during the last resched */
-#endif
};
DECLARE_PER_CPU(struct rcu_data, rcu_data);
diff --git a/include/linux/scx200.h b/include/linux/scx200.h
index 693c055..de466e1 100644
--- a/include/linux/scx200.h
+++ b/include/linux/scx200.h
@@ -32,7 +32,7 @@
/* High Resolution Timer */
#define SCx200_TIMER_OFFSET 0x08
-#define SCx200_TIMER_SIZE 0x05
+#define SCx200_TIMER_SIZE 0x06
/* Clock Generators */
#define SCx200_CLOCKGEN_OFFSET 0x10
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 70be57d..c4947b8 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -77,13 +77,6 @@
extern struct cache_sizes malloc_sizes[];
extern void *__kmalloc(size_t, gfp_t);
-#ifndef CONFIG_DEBUG_SLAB
-#define ____kmalloc(size, flags) __kmalloc(size, flags)
-#else
-extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
-#define ____kmalloc(size, flags) \
- __kmalloc_track_caller(size, flags, __builtin_return_address(0))
-#endif
/**
* kmalloc - allocate memory
@@ -153,6 +146,23 @@
return __kmalloc(size, flags);
}
+/*
+ * kmalloc_track_caller is a special version of kmalloc that records the
+ * calling function of the routine calling it for slab leak tracking instead
+ * of just the calling function (confusing, eh?).
+ * It's useful when the call to kmalloc comes from a widely-used standard
+ * allocator where we care about the real place the memory allocation
+ * request comes from.
+ */
+#ifndef CONFIG_DEBUG_SLAB
+#define kmalloc_track_caller(size, flags) \
+ __kmalloc(size, flags)
+#else
+extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
+#define kmalloc_track_caller(size, flags) \
+ __kmalloc_track_caller(size, flags, __builtin_return_address(0))
+#endif
+
extern void *__kzalloc(size_t, gfp_t);
/**
@@ -271,7 +281,7 @@
#define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f)
#define kmalloc_node(s, f, n) kmalloc(s, f)
#define kzalloc(s, f) __kzalloc(s, f)
-#define ____kmalloc kmalloc
+#define kmalloc_track_caller kmalloc
#endif /* CONFIG_SLOB */
diff --git a/include/linux/sound.h b/include/linux/sound.h
index f63d834..9e2a94f 100644
--- a/include/linux/sound.h
+++ b/include/linux/sound.h
@@ -35,10 +35,8 @@
extern int register_sound_mixer(const struct file_operations *fops, int dev);
extern int register_sound_midi(const struct file_operations *fops, int dev);
extern int register_sound_dsp(const struct file_operations *fops, int dev);
-extern int register_sound_synth(const struct file_operations *fops, int dev);
extern void unregister_sound_special(int unit);
extern void unregister_sound_mixer(int unit);
extern void unregister_sound_midi(int unit);
extern void unregister_sound_dsp(int unit);
-extern void unregister_sound_synth(int unit);
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
new file mode 100644
index 0000000..aca0eee
--- /dev/null
+++ b/include/linux/srcu.h
@@ -0,0 +1,53 @@
+/*
+ * Sleepable Read-Copy Update mechanism for mutual exclusion
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Paul McKenney <paulmck@us.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * Documentation/RCU/ *.txt
+ *
+ */
+
+#ifndef _LINUX_SRCU_H
+#define _LINUX_SRCU_H
+
+struct srcu_struct_array {
+ int c[2];
+};
+
+struct srcu_struct {
+ int completed;
+ struct srcu_struct_array *per_cpu_ref;
+ struct mutex mutex;
+};
+
+#ifndef CONFIG_PREEMPT
+#define srcu_barrier() barrier()
+#else /* #ifndef CONFIG_PREEMPT */
+#define srcu_barrier()
+#endif /* #else #ifndef CONFIG_PREEMPT */
+
+int init_srcu_struct(struct srcu_struct *sp);
+void cleanup_srcu_struct(struct srcu_struct *sp);
+int srcu_read_lock(struct srcu_struct *sp) __acquires(sp);
+void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp);
+void synchronize_srcu(struct srcu_struct *sp);
+long srcu_batches_completed(struct srcu_struct *sp);
+
+#endif
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 862c0d8c..534cdc7 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -20,9 +20,6 @@
/* size of the nodename buffer */
#define UNX_MAXNODENAME 32
-/* Maximum size (in bytes) of an rpc credential or verifier */
-#define RPC_MAX_AUTH_SIZE (400)
-
/* Work around the lack of a VFS credential */
struct auth_cred {
uid_t uid;
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index b5612c9..3699dff 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -163,6 +163,17 @@
kref_put(&h->ref, cd->cache_put);
}
+static inline int cache_valid(struct cache_head *h)
+{
+ /* If an item has been unhashed pending removal when
+ * the refcount drops to 0, the expiry_time will be
+ * set to 0. We don't want to consider such items
+ * valid in this context even though CACHE_VALID is
+ * set.
+ */
+ return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags));
+}
+
extern int cache_check(struct cache_detail *detail,
struct cache_head *h, struct cache_req *rqstp);
extern void cache_flush(void);
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index 8d10d14..1e65f2d 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -11,6 +11,9 @@
#define RPC_VERSION 2
+/* size of an XDR encoding unit in bytes, i.e. 32bit */
+#define XDR_UNIT (4)
+
/* spec defines authentication flavor as an unsigned 32 bit integer */
typedef u32 rpc_authflavor_t;
@@ -34,6 +37,9 @@
RPC_AUTH_GSS_SPKMP = 390011,
};
+/* Maximum size (in bytes) of an rpc credential or verifier */
+#define RPC_MAX_AUTH_SIZE (400)
+
enum rpc_msg_type {
RPC_CALL = 0,
RPC_REPLY = 1
@@ -101,5 +107,39 @@
#define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT)
#define RPC_MAX_FRAGMENT_SIZE ((1U << 31) - 1)
+/*
+ * RPC call and reply header size as number of 32bit words (verifier
+ * size computed separately, see below)
+ */
+#define RPC_CALLHDRSIZE (6)
+#define RPC_REPHDRSIZE (4)
+
+
+/*
+ * Maximum RPC header size, including authentication,
+ * as number of 32bit words (see RFCs 1831, 1832).
+ *
+ * xid 1 xdr unit = 4 bytes
+ * mtype 1
+ * rpc_version 1
+ * program 1
+ * prog_version 1
+ * procedure 1
+ * cred {
+ * flavor 1
+ * length 1
+ * body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
+ * }
+ * verf {
+ * flavor 1
+ * length 1
+ * body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
+ * }
+ * TOTAL 210 xdr units = 840 bytes
+ */
+#define RPC_MAX_HEADER_WITH_AUTH \
+ (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
+
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_MSGPROT_H_ */
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 4ebcdf9..d6288e8 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -13,6 +13,7 @@
#include <linux/in.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/auth.h>
#include <linux/sunrpc/svcauth.h>
#include <linux/wait.h>
#include <linux/mm.h>
@@ -95,8 +96,28 @@
* Maximum payload size supported by a kernel RPC server.
* This is use to determine the max number of pages nfsd is
* willing to return in a single READ operation.
+ *
+ * These happen to all be powers of 2, which is not strictly
+ * necessary but helps enforce the real limitation, which is
+ * that they should be multiples of PAGE_CACHE_SIZE.
+ *
+ * For UDP transports, a block plus NFS,RPC, and UDP headers
+ * has to fit into the IP datagram limit of 64K. The largest
+ * feasible number for all known page sizes is probably 48K,
+ * but we choose 32K here. This is the same as the historical
+ * Linux limit; someone who cares more about NFS/UDP performance
+ * can test a larger number.
+ *
+ * For TCP transports we have more freedom. A size of 1MB is
+ * chosen to match the client limit. Other OSes are known to
+ * have larger limits, but those numbers are probably beyond
+ * the point of diminishing returns.
*/
-#define RPCSVC_MAXPAYLOAD (64*1024u)
+#define RPCSVC_MAXPAYLOAD (1*1024*1024u)
+#define RPCSVC_MAXPAYLOAD_TCP RPCSVC_MAXPAYLOAD
+#define RPCSVC_MAXPAYLOAD_UDP (32*1024u)
+
+extern u32 svc_max_payload(const struct svc_rqst *rqstp);
/*
* RPC Requsts and replies are stored in one or more pages.
@@ -170,7 +191,6 @@
/*
* The context of a single thread, including the request currently being
* processed.
- * NOTE: First two items must be prev/next.
*/
struct svc_rqst {
struct list_head rq_list; /* idle list */
@@ -189,12 +209,11 @@
struct xdr_buf rq_arg;
struct xdr_buf rq_res;
- struct page * rq_argpages[RPCSVC_MAXPAGES];
- struct page * rq_respages[RPCSVC_MAXPAGES];
- int rq_restailpage;
- short rq_argused; /* pages used for argument */
- short rq_arghi; /* pages available in argument page list */
- short rq_resused; /* pages used for result */
+ struct page * rq_pages[RPCSVC_MAXPAGES];
+ struct page * *rq_respages; /* points into rq_pages */
+ int rq_resused; /* number of pages used for result */
+
+ struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
__be32 rq_xid; /* transmission id */
u32 rq_prog; /* program number */
@@ -255,63 +274,18 @@
return vec->iov_len <= PAGE_SIZE;
}
-static inline struct page *
-svc_take_res_page(struct svc_rqst *rqstp)
+static inline void svc_free_res_pages(struct svc_rqst *rqstp)
{
- if (rqstp->rq_arghi <= rqstp->rq_argused)
- return NULL;
- rqstp->rq_arghi--;
- rqstp->rq_respages[rqstp->rq_resused] =
- rqstp->rq_argpages[rqstp->rq_arghi];
- return rqstp->rq_respages[rqstp->rq_resused++];
-}
-
-static inline void svc_take_page(struct svc_rqst *rqstp)
-{
- if (rqstp->rq_arghi <= rqstp->rq_argused) {
- WARN_ON(1);
- return;
- }
- rqstp->rq_arghi--;
- rqstp->rq_respages[rqstp->rq_resused] =
- rqstp->rq_argpages[rqstp->rq_arghi];
- rqstp->rq_resused++;
-}
-
-static inline void svc_pushback_allpages(struct svc_rqst *rqstp)
-{
- while (rqstp->rq_resused) {
- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
- continue;
- rqstp->rq_argpages[rqstp->rq_arghi++] =
- rqstp->rq_respages[rqstp->rq_resused];
- rqstp->rq_respages[rqstp->rq_resused] = NULL;
- }
-}
-
-static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp)
-{
- while (rqstp->rq_resused &&
- rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) {
-
- if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) {
- rqstp->rq_argpages[rqstp->rq_arghi++] =
- rqstp->rq_respages[rqstp->rq_resused];
- rqstp->rq_respages[rqstp->rq_resused] = NULL;
+ while (rqstp->rq_resused) {
+ struct page **pp = (rqstp->rq_respages +
+ --rqstp->rq_resused);
+ if (*pp) {
+ put_page(*pp);
+ *pp = NULL;
}
}
}
-static inline void svc_free_allpages(struct svc_rqst *rqstp)
-{
- while (rqstp->rq_resused) {
- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
- continue;
- put_page(rqstp->rq_respages[rqstp->rq_resused]);
- rqstp->rq_respages[rqstp->rq_resused] = NULL;
- }
-}
-
struct svc_deferred_req {
u32 prot; /* protocol (UDP or TCP) */
struct sockaddr_in addr;
@@ -347,6 +321,9 @@
struct svc_procedure * vs_proc; /* per-procedure info */
u32 vs_xdrsize; /* xdrsize needed for this version */
+ unsigned int vs_hidden : 1; /* Don't register with portmapper.
+ * Only used for nfsacl so far. */
+
/* Override dispatch function (e.g. when caching replies).
* A return value of 0 means drop the request.
* vs_dispatch == NULL means use default dispatcher.
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index a660165..de92619 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -126,6 +126,7 @@
extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
+extern void svcauth_unix_info_release(void *);
static inline unsigned long hash_str(char *name, int bits)
{
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 4c29615..98b21ad 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -54,6 +54,9 @@
int sk_reclen; /* length of record */
int sk_tcplen; /* current read length */
time_t sk_lastrecv; /* time of last received request */
+
+ /* cache of various info for TCP sockets */
+ void *sk_info_authunix;
};
/*
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 6cf6265..60394fb 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -15,6 +15,7 @@
#include <linux/kref.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/msg_prot.h>
extern unsigned int xprt_udp_slot_table_entries;
extern unsigned int xprt_tcp_slot_table_entries;
@@ -24,13 +25,6 @@
#define RPC_MAX_SLOT_TABLE (128U)
/*
- * RPC call and reply header size as number of 32bit words (verifier
- * size computed separately)
- */
-#define RPC_CALLHDRSIZE 6
-#define RPC_REPHDRSIZE 4
-
-/*
* Parameters for choosing a free port
*/
extern unsigned int xprt_min_resvport;
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
new file mode 100644
index 0000000..203dd5e
--- /dev/null
+++ b/include/linux/tifm.h
@@ -0,0 +1,158 @@
+/*
+ * tifm.h - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _TIFM_H
+#define _TIFM_H
+
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+/* Host registers (relative to pci base address): */
+enum {
+ FM_SET_INTERRUPT_ENABLE = 0x008,
+ FM_CLEAR_INTERRUPT_ENABLE = 0x00c,
+ FM_INTERRUPT_STATUS = 0x014 };
+
+/* Socket registers (relative to socket base address): */
+enum {
+ SOCK_CONTROL = 0x004,
+ SOCK_PRESENT_STATE = 0x008,
+ SOCK_DMA_ADDRESS = 0x00c,
+ SOCK_DMA_CONTROL = 0x010,
+ SOCK_DMA_FIFO_INT_ENABLE_SET = 0x014,
+ SOCK_DMA_FIFO_INT_ENABLE_CLEAR = 0x018,
+ SOCK_DMA_FIFO_STATUS = 0x020,
+ SOCK_FIFO_CONTROL = 0x024,
+ SOCK_FIFO_PAGE_SIZE = 0x028,
+ SOCK_MMCSD_COMMAND = 0x104,
+ SOCK_MMCSD_ARG_LOW = 0x108,
+ SOCK_MMCSD_ARG_HIGH = 0x10c,
+ SOCK_MMCSD_CONFIG = 0x110,
+ SOCK_MMCSD_STATUS = 0x114,
+ SOCK_MMCSD_INT_ENABLE = 0x118,
+ SOCK_MMCSD_COMMAND_TO = 0x11c,
+ SOCK_MMCSD_DATA_TO = 0x120,
+ SOCK_MMCSD_DATA = 0x124,
+ SOCK_MMCSD_BLOCK_LEN = 0x128,
+ SOCK_MMCSD_NUM_BLOCKS = 0x12c,
+ SOCK_MMCSD_BUFFER_CONFIG = 0x130,
+ SOCK_MMCSD_SPI_CONFIG = 0x134,
+ SOCK_MMCSD_SDIO_MODE_CONFIG = 0x138,
+ SOCK_MMCSD_RESPONSE = 0x144,
+ SOCK_MMCSD_SDIO_SR = 0x164,
+ SOCK_MMCSD_SYSTEM_CONTROL = 0x168,
+ SOCK_MMCSD_SYSTEM_STATUS = 0x16c,
+ SOCK_MS_COMMAND = 0x184,
+ SOCK_MS_DATA = 0x188,
+ SOCK_MS_STATUS = 0x18c,
+ SOCK_MS_SYSTEM = 0x190,
+ SOCK_FIFO_ACCESS = 0x200 };
+
+
+#define TIFM_IRQ_ENABLE 0x80000000
+#define TIFM_IRQ_SOCKMASK 0x00000001
+#define TIFM_IRQ_CARDMASK 0x00000100
+#define TIFM_IRQ_FIFOMASK 0x00010000
+#define TIFM_IRQ_SETALL 0xffffffff
+#define TIFM_IRQ_SETALLSOCK 0x0000000f
+
+#define TIFM_CTRL_LED 0x00000040
+#define TIFM_CTRL_FAST_CLK 0x00000100
+
+#define TIFM_SOCK_STATE_OCCUPIED 0x00000008
+#define TIFM_SOCK_STATE_POWERED 0x00000080
+
+#define TIFM_FIFO_ENABLE 0x00000001 /* Meaning of this constant is unverified */
+#define TIFM_FIFO_INT_SETALL 0x0000ffff
+#define TIFM_FIFO_INTMASK 0x00000005 /* Meaning of this constant is unverified */
+
+#define TIFM_DMA_RESET 0x00000002 /* Meaning of this constant is unverified */
+#define TIFM_DMA_TX 0x00008000 /* Meaning of this constant is unverified */
+#define TIFM_DMA_EN 0x00000001 /* Meaning of this constant is unverified */
+
+typedef enum {FM_NULL = 0, FM_XD = 0x01, FM_MS = 0x02, FM_SD = 0x03} tifm_media_id;
+
+struct tifm_driver;
+struct tifm_dev {
+ char __iomem *addr;
+ spinlock_t lock;
+ tifm_media_id media_id;
+ char wq_name[KOBJ_NAME_LEN];
+ struct workqueue_struct *wq;
+
+ unsigned int (*signal_irq)(struct tifm_dev *sock,
+ unsigned int sock_irq_status);
+
+ struct tifm_driver *drv;
+ struct device dev;
+};
+
+struct tifm_driver {
+ tifm_media_id *id_table;
+ int (*probe)(struct tifm_dev *dev);
+ void (*remove)(struct tifm_dev *dev);
+
+ struct device_driver driver;
+};
+
+struct tifm_adapter {
+ char __iomem *addr;
+ unsigned int irq_status;
+ unsigned int insert_mask;
+ unsigned int remove_mask;
+ spinlock_t lock;
+ unsigned int id;
+ unsigned int max_sockets;
+ char wq_name[KOBJ_NAME_LEN];
+ unsigned int inhibit_new_cards;
+ struct workqueue_struct *wq;
+ struct work_struct media_inserter;
+ struct work_struct media_remover;
+ struct tifm_dev **sockets;
+ struct class_device cdev;
+ struct device *dev;
+
+ void (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock);
+};
+
+struct tifm_adapter *tifm_alloc_adapter(void);
+void tifm_free_device(struct device *dev);
+void tifm_free_adapter(struct tifm_adapter *fm);
+int tifm_add_adapter(struct tifm_adapter *fm);
+void tifm_remove_adapter(struct tifm_adapter *fm);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id);
+int tifm_register_driver(struct tifm_driver *drv);
+void tifm_unregister_driver(struct tifm_driver *drv);
+void tifm_eject(struct tifm_dev *sock);
+int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction);
+void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction);
+
+
+static inline void *tifm_get_drvdata(struct tifm_dev *dev)
+{
+ return dev_get_drvdata(&dev->dev);
+}
+
+static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data)
+{
+ dev_set_drvdata(&dev->dev, data);
+}
+
+struct tifm_device_id {
+ tifm_media_id media_id;
+};
+
+#endif
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index 02e4b69..a4555fe 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -1,11 +1,6 @@
#ifndef _LINUX_UTSNAME_H
#define _LINUX_UTSNAME_H
-#include <linux/sched.h>
-#include <linux/kref.h>
-#include <linux/nsproxy.h>
-#include <asm/atomic.h>
-
#define __OLD_UTS_LEN 8
struct oldold_utsname {
@@ -35,6 +30,13 @@
char domainname[65];
};
+#ifdef __KERNEL__
+
+#include <linux/sched.h>
+#include <linux/kref.h>
+#include <linux/nsproxy.h>
+#include <asm/atomic.h>
+
struct uts_namespace {
struct kref kref;
struct new_utsname name;
@@ -86,4 +88,7 @@
}
extern struct rw_semaphore uts_sem;
-#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_UTSNAME_H */
diff --git a/include/linux/wavefront.h b/include/linux/wavefront.h
deleted file mode 100644
index 51ab3c9..0000000
--- a/include/linux/wavefront.h
+++ /dev/null
@@ -1,675 +0,0 @@
-#ifndef __wavefront_h__
-#define __wavefront_h__
-
-/* WaveFront header file.
- *
- * Copyright (C) by Paul Barton-Davis 1998
- *
- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-
-#if (!defined(__GNUC__) && !defined(__GNUG__))
-
- You will not be able to compile this file correctly without gcc, because
- it is necessary to pack the "wavefront_alias" structure to a size
- of 22 bytes, corresponding to 16-bit alignment (as would have been
- the case on the original platform, MS-DOS). If this is not done,
- then WavePatch-format files cannot be read/written correctly.
- The method used to do this here ("__attribute__((packed)") is
- completely compiler dependent.
-
- All other wavefront_* types end up aligned to 32 bit values and
- still have the same (correct) size.
-
-#else
-
- /* However, note that as of G++ 2.7.3.2, g++ was unable to
- correctly parse *type* __attribute__ tags. It will do the
- right thing if we use the "packed" attribute on each struct
- member, which has the same semantics anyway.
- */
-
-#endif /* __GNUC__ */
-
-/***************************** WARNING ********************************
- PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO
- BE USED WITH EITHER C *OR* C++.
- **********************************************************************/
-
-#ifndef NUM_MIDIKEYS
-#define NUM_MIDIKEYS 128
-#endif /* NUM_MIDIKEYS */
-
-#ifndef NUM_MIDICHANNELS
-#define NUM_MIDICHANNELS 16
-#endif /* NUM_MIDICHANNELS */
-
-/* These are very useful/important. the original wavefront interface
- was developed on a 16 bit system, where sizeof(int) = 2
- bytes. Defining things like this makes the code much more portable, and
- easier to understand without having to toggle back and forth
- between a 16-bit view of the world and a 32-bit one.
- */
-
-typedef short INT16;
-typedef unsigned short UINT16;
-typedef int INT32;
-typedef unsigned int UINT32;
-typedef char CHAR8;
-typedef unsigned char UCHAR8;
-
-/* Pseudo-commands not part of the WaveFront command set.
- These are used for various driver controls and direct
- hardware control.
- */
-
-#define WFC_DEBUG_DRIVER 0
-#define WFC_FX_IOCTL 1
-#define WFC_PATCH_STATUS 2
-#define WFC_PROGRAM_STATUS 3
-#define WFC_SAMPLE_STATUS 4
-#define WFC_DISABLE_INTERRUPTS 5
-#define WFC_ENABLE_INTERRUPTS 6
-#define WFC_INTERRUPT_STATUS 7
-#define WFC_ROMSAMPLES_RDONLY 8
-#define WFC_IDENTIFY_SLOT_TYPE 9
-
-/* Wavefront synth commands
- */
-
-#define WFC_DOWNLOAD_SAMPLE 0x80
-#define WFC_DOWNLOAD_BLOCK 0x81
-#define WFC_DOWNLOAD_MULTISAMPLE 0x82
-#define WFC_DOWNLOAD_SAMPLE_ALIAS 0x83
-#define WFC_DELETE_SAMPLE 0x84
-#define WFC_REPORT_FREE_MEMORY 0x85
-#define WFC_DOWNLOAD_PATCH 0x86
-#define WFC_DOWNLOAD_PROGRAM 0x87
-#define WFC_SET_SYNTHVOL 0x89
-#define WFC_SET_NVOICES 0x8B
-#define WFC_DOWNLOAD_DRUM 0x90
-#define WFC_GET_SYNTHVOL 0x92
-#define WFC_GET_NVOICES 0x94
-#define WFC_DISABLE_CHANNEL 0x9A
-#define WFC_ENABLE_CHANNEL 0x9B
-#define WFC_MISYNTH_OFF 0x9D
-#define WFC_MISYNTH_ON 0x9E
-#define WFC_FIRMWARE_VERSION 0x9F
-#define WFC_GET_NSAMPLES 0xA0
-#define WFC_DISABLE_DRUM_PROGRAM 0xA2
-#define WFC_UPLOAD_PATCH 0xA3
-#define WFC_UPLOAD_PROGRAM 0xA4
-#define WFC_SET_TUNING 0xA6
-#define WFC_GET_TUNING 0xA7
-#define WFC_VMIDI_ON 0xA8
-#define WFC_VMIDI_OFF 0xA9
-#define WFC_MIDI_STATUS 0xAA
-#define WFC_GET_CHANNEL_STATUS 0xAB
-#define WFC_DOWNLOAD_SAMPLE_HEADER 0xAC
-#define WFC_UPLOAD_SAMPLE_HEADER 0xAD
-#define WFC_UPLOAD_MULTISAMPLE 0xAE
-#define WFC_UPLOAD_SAMPLE_ALIAS 0xAF
-#define WFC_IDENTIFY_SAMPLE_TYPE 0xB0
-#define WFC_DOWNLOAD_EDRUM_PROGRAM 0xB1
-#define WFC_UPLOAD_EDRUM_PROGRAM 0xB2
-#define WFC_SET_EDRUM_CHANNEL 0xB3
-#define WFC_INSTOUT_LEVELS 0xB4
-#define WFC_PEAKOUT_LEVELS 0xB5
-#define WFC_REPORT_CHANNEL_PROGRAMS 0xB6
-#define WFC_HARDWARE_VERSION 0xCF
-#define WFC_UPLOAD_SAMPLE_PARAMS 0xD7
-#define WFC_DOWNLOAD_OS 0xF1
-#define WFC_NOOP 0xFF
-
-#define WF_MAX_SAMPLE 512
-#define WF_MAX_PATCH 256
-#define WF_MAX_PROGRAM 128
-
-#define WF_SECTION_MAX 44 /* longest OS section length */
-
-/* # of bytes we send to the board when sending it various kinds of
- substantive data, such as samples, patches and programs.
-*/
-
-#define WF_PROGRAM_BYTES 32
-#define WF_PATCH_BYTES 132
-#define WF_SAMPLE_BYTES 27
-#define WF_SAMPLE_HDR_BYTES 25
-#define WF_ALIAS_BYTES 25
-#define WF_DRUM_BYTES 9
-#define WF_MSAMPLE_BYTES 259 /* (MIDI_KEYS * 2) + 3 */
-
-#define WF_ACK 0x80
-#define WF_DMA_ACK 0x81
-
-/* OR-values for MIDI status bits */
-
-#define WF_MIDI_VIRTUAL_ENABLED 0x1
-#define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2
-#define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4
-
-/* slot indexes for struct address_info: makes code a little more mnemonic */
-
-#define WF_SYNTH_SLOT 0
-#define WF_INTERNAL_MIDI_SLOT 1
-#define WF_EXTERNAL_MIDI_SLOT 2
-
-/* Magic MIDI bytes used to switch I/O streams on the ICS2115 MPU401
- emulation. Note these NEVER show up in output from the device and
- should NEVER be used in input unless Virtual MIDI mode has been
- disabled. If they do show up as input, the results are unpredictable.
-*/
-
-#define WF_EXTERNAL_SWITCH 0xFD
-#define WF_INTERNAL_SWITCH 0xF9
-
-/* Debugging flags */
-
-#define WF_DEBUG_CMD 0x1
-#define WF_DEBUG_DATA 0x2
-#define WF_DEBUG_LOAD_PATCH 0x4
-#define WF_DEBUG_IO 0x8
-
-/* WavePatch file format stuff */
-
-#define WF_WAVEPATCH_VERSION 120; /* Current version number (1.2) */
-#define WF_MAX_COMMENT 64 /* Comment length */
-#define WF_NUM_LAYERS 4
-#define WF_NAME_LENGTH 32
-#define WF_SOURCE_LENGTH 260
-
-#define BankFileID "Bank"
-#define DrumkitFileID "DrumKit"
-#define ProgramFileID "Program"
-
-struct wf_envelope
-{
- UCHAR8 attack_time:7;
- UCHAR8 Unused1:1;
-
- UCHAR8 decay1_time:7;
- UCHAR8 Unused2:1;
-
- UCHAR8 decay2_time:7;
- UCHAR8 Unused3:1;
-
- UCHAR8 sustain_time:7;
- UCHAR8 Unused4:1;
-
- UCHAR8 release_time:7;
- UCHAR8 Unused5:1;
-
- UCHAR8 release2_time:7;
- UCHAR8 Unused6:1;
-
- CHAR8 attack_level;
- CHAR8 decay1_level;
- CHAR8 decay2_level;
- CHAR8 sustain_level;
- CHAR8 release_level;
-
- UCHAR8 attack_velocity:7;
- UCHAR8 Unused7:1;
-
- UCHAR8 volume_velocity:7;
- UCHAR8 Unused8:1;
-
- UCHAR8 keyboard_scaling:7;
- UCHAR8 Unused9:1;
-};
-typedef struct wf_envelope wavefront_envelope;
-
-struct wf_lfo
-{
- UCHAR8 sample_number;
-
- UCHAR8 frequency:7;
- UCHAR8 Unused1:1;
-
- UCHAR8 am_src:4;
- UCHAR8 fm_src:4;
-
- CHAR8 fm_amount;
- CHAR8 am_amount;
- CHAR8 start_level;
- CHAR8 end_level;
-
- UCHAR8 ramp_delay:7;
- UCHAR8 wave_restart:1; /* for LFO2 only */
-
- UCHAR8 ramp_time:7;
- UCHAR8 Unused2:1;
-};
-typedef struct wf_lfo wavefront_lfo;
-
-struct wf_patch
-{
- INT16 frequency_bias; /* ** THIS IS IN MOTOROLA FORMAT!! ** */
-
- UCHAR8 amplitude_bias:7;
- UCHAR8 Unused1:1;
-
- UCHAR8 portamento:7;
- UCHAR8 Unused2:1;
-
- UCHAR8 sample_number;
-
- UCHAR8 pitch_bend:4;
- UCHAR8 sample_msb:1;
- UCHAR8 Unused3:3;
-
- UCHAR8 mono:1;
- UCHAR8 retrigger:1;
- UCHAR8 nohold:1;
- UCHAR8 restart:1;
- UCHAR8 filterconfig:2; /* SDK says "not used" */
- UCHAR8 reuse:1;
- UCHAR8 reset_lfo:1;
-
- UCHAR8 fm_src2:4;
- UCHAR8 fm_src1:4;
-
- CHAR8 fm_amount1;
- CHAR8 fm_amount2;
-
- UCHAR8 am_src:4;
- UCHAR8 Unused4:4;
-
- CHAR8 am_amount;
-
- UCHAR8 fc1_mode:4;
- UCHAR8 fc2_mode:4;
-
- CHAR8 fc1_mod_amount;
- CHAR8 fc1_keyboard_scaling;
- CHAR8 fc1_bias;
- CHAR8 fc2_mod_amount;
- CHAR8 fc2_keyboard_scaling;
- CHAR8 fc2_bias;
-
- UCHAR8 randomizer:7;
- UCHAR8 Unused5:1;
-
- struct wf_envelope envelope1;
- struct wf_envelope envelope2;
- struct wf_lfo lfo1;
- struct wf_lfo lfo2;
-};
-typedef struct wf_patch wavefront_patch;
-
-struct wf_layer
-{
- UCHAR8 patch_number;
-
- UCHAR8 mix_level:7;
- UCHAR8 mute:1;
-
- UCHAR8 split_point:7;
- UCHAR8 play_below:1;
-
- UCHAR8 pan_mod_src:2;
- UCHAR8 pan_or_mod:1;
- UCHAR8 pan:4;
- UCHAR8 split_type:1;
-};
-typedef struct wf_layer wavefront_layer;
-
-struct wf_program
-{
- struct wf_layer layer[WF_NUM_LAYERS];
-};
-typedef struct wf_program wavefront_program;
-
-struct wf_sample_offset
-{
- INT32 Fraction:4;
- INT32 Integer:20;
- INT32 Unused:8;
-};
-typedef struct wf_sample_offset wavefront_sample_offset;
-
-/* Sample slot types */
-
-#define WF_ST_SAMPLE 0
-#define WF_ST_MULTISAMPLE 1
-#define WF_ST_ALIAS 2
-#define WF_ST_EMPTY 3
-
-/* pseudo's */
-
-#define WF_ST_DRUM 4
-#define WF_ST_PROGRAM 5
-#define WF_ST_PATCH 6
-#define WF_ST_SAMPLEHDR 7
-
-#define WF_ST_MASK 0xf
-
-/* Flags for slot status. These occupy the upper bits of the same byte
- as a sample type.
-*/
-
-#define WF_SLOT_USED 0x80 /* XXX don't rely on this being accurate */
-#define WF_SLOT_FILLED 0x40
-#define WF_SLOT_ROM 0x20
-
-#define WF_SLOT_MASK 0xf0
-
-/* channel constants */
-
-#define WF_CH_MONO 0
-#define WF_CH_LEFT 1
-#define WF_CH_RIGHT 2
-
-/* Sample formats */
-
-#define LINEAR_16BIT 0
-#define WHITE_NOISE 1
-#define LINEAR_8BIT 2
-#define MULAW_8BIT 3
-
-#define WF_SAMPLE_IS_8BIT(smpl) ((smpl)->SampleResolution&2)
-
-
-/*
-
- Because most/all of the sample data we pass in via pointers has
- never been copied (just mmap-ed into user space straight from the
- disk), it would be nice to allow handling of multi-channel sample
- data without forcing user-level extraction of the relevant bytes.
-
- So, we need a way of specifying which channel to use (the WaveFront
- only handles mono samples in a given slot), and the only way to do
- this without using some struct other than wavefront_sample as the
- interface is the awful hack of using the unused bits in a
- wavefront_sample:
-
- Val Meaning
- --- -------
- 0 no channel selection (use channel 1, sample is MONO)
- 1 use first channel, and skip one
- 2 use second channel, and skip one
- 3 use third channel, and skip two
- 4 use fourth channel, skip three
- 5 use fifth channel, skip four
- 6 use six channel, skip five
-
-
- This can handle up to 4 channels, and anyone downloading >4 channels
- of sample data just to select one of them needs to find some tools
- like sox ...
-
- NOTE: values 0, 1 and 2 correspond to WF_CH_* above. This is
- important.
-
-*/
-
-#define WF_SET_CHANNEL(samp,chn) \
- (samp)->Unused1 = chn & 0x1; \
- (samp)->Unused2 = chn & 0x2; \
- (samp)->Unused3 = chn & 0x4
-
-#define WF_GET_CHANNEL(samp) \
- (((samp)->Unused3 << 2)|((samp)->Unused2<<1)|(samp)->Unused1)
-
-typedef struct wf_sample {
- struct wf_sample_offset sampleStartOffset;
- struct wf_sample_offset loopStartOffset;
- struct wf_sample_offset loopEndOffset;
- struct wf_sample_offset sampleEndOffset;
- INT16 FrequencyBias;
- UCHAR8 SampleResolution:2; /* sample_format */
- UCHAR8 Unused1:1;
- UCHAR8 Loop:1;
- UCHAR8 Bidirectional:1;
- UCHAR8 Unused2:1;
- UCHAR8 Reverse:1;
- UCHAR8 Unused3:1;
-} wavefront_sample;
-
-typedef struct wf_multisample {
- INT16 NumberOfSamples; /* log2 of the number of samples */
- INT16 SampleNumber[NUM_MIDIKEYS];
-} wavefront_multisample;
-
-typedef struct wf_alias {
- INT16 OriginalSample;
-
- struct wf_sample_offset sampleStartOffset;
- struct wf_sample_offset loopStartOffset;
- struct wf_sample_offset sampleEndOffset;
- struct wf_sample_offset loopEndOffset;
-
- INT16 FrequencyBias;
-
- UCHAR8 SampleResolution:2;
- UCHAR8 Unused1:1;
- UCHAR8 Loop:1;
- UCHAR8 Bidirectional:1;
- UCHAR8 Unused2:1;
- UCHAR8 Reverse:1;
- UCHAR8 Unused3:1;
-
- /* This structure is meant to be padded only to 16 bits on their
- original. Of course, whoever wrote their documentation didn't
- realize that sizeof(struct) can be >=
- sum(sizeof(struct-fields)) and so thought that giving a C level
- description of the structs used in WavePatch files was
- sufficient. I suppose it was, as long as you remember the
- standard 16->32 bit issues.
- */
-
- UCHAR8 sixteen_bit_padding;
-} __attribute__((packed)) wavefront_alias;
-
-typedef struct wf_drum {
- UCHAR8 PatchNumber;
- UCHAR8 MixLevel:7;
- UCHAR8 Unmute:1;
- UCHAR8 Group:4;
- UCHAR8 Unused1:4;
- UCHAR8 PanModSource:2;
- UCHAR8 PanModulated:1;
- UCHAR8 PanAmount:4;
- UCHAR8 Unused2:1;
-} wavefront_drum;
-
-typedef struct wf_drumkit {
- struct wf_drum drum[NUM_MIDIKEYS];
-} wavefront_drumkit;
-
-typedef struct wf_channel_programs {
- UCHAR8 Program[NUM_MIDICHANNELS];
-} wavefront_channel_programs;
-
-/* How to get MIDI channel status from the data returned by
- a WFC_GET_CHANNEL_STATUS command (a struct wf_channel_programs)
-*/
-
-#define WF_CHANNEL_STATUS(ch,wcp) (wcp)[(ch/7)] & (1<<((ch)%7))
-
-typedef union wf_any {
- wavefront_sample s;
- wavefront_multisample ms;
- wavefront_alias a;
- wavefront_program pr;
- wavefront_patch p;
- wavefront_drum d;
-} wavefront_any;
-
-/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h
- might work for other wave-table based patch loading situations.
- Alas, his fears were correct. The WaveFront doesn't even come with
- just "patches", but several different kind of structures that
- control the sound generation process.
- */
-
-typedef struct wf_patch_info {
-
- /* the first two fields are used by the OSS "patch loading" interface
- only, and are unused by the current user-level library.
- */
-
- INT16 key; /* Use WAVEFRONT_PATCH here */
- UINT16 devno; /* fill in when sending */
- UCHAR8 subkey; /* WF_ST_{SAMPLE,ALIAS,etc.} */
-
-#define WAVEFRONT_FIND_FREE_SAMPLE_SLOT 999
-
- UINT16 number; /* patch/sample/prog number */
-
- UINT32 size; /* size of any data included in
- one of the fields in `hdrptr', or
- as `dataptr'.
-
- NOTE: for actual samples, this is
- the size of the *SELECTED CHANNEL*
- even if more data is actually available.
-
- So, a stereo sample (2 channels) of
- 6000 bytes total has `size' = 3000.
-
- See the macros and comments for
- WF_{GET,SET}_CHANNEL above.
-
- */
- wavefront_any __user *hdrptr; /* user-space ptr to hdr bytes */
- UINT16 __user *dataptr; /* actual sample data */
-
- wavefront_any hdr; /* kernel-space copy of hdr bytes */
-} wavefront_patch_info;
-
-/* The maximum number of bytes we will ever move to or from user space
- in response to a WFC_* command. This obviously doesn't cover
- actual sample data.
-*/
-
-#define WF_MAX_READ sizeof(wavefront_multisample)
-#define WF_MAX_WRITE sizeof(wavefront_multisample)
-
-/*
- This allows us to execute any WF command except the download/upload
- ones, which are handled differently due to copyin/copyout issues as
- well as data-nybbling to/from the card.
- */
-
-typedef struct wavefront_control {
- int cmd; /* WFC_* */
- char status; /* return status to user-space */
- unsigned char rbuf[WF_MAX_READ]; /* bytes read from card */
- unsigned char wbuf[WF_MAX_WRITE]; /* bytes written to card */
-} wavefront_control;
-
-#define WFCTL_WFCMD 0x1
-#define WFCTL_LOAD_SPP 0x2
-
-/* Modulator table */
-
-#define WF_MOD_LFO1 0
-#define WF_MOD_LFO2 1
-#define WF_MOD_ENV1 2
-#define WF_MOD_ENV2 3
-#define WF_MOD_KEYBOARD 4
-#define WF_MOD_LOGKEY 5
-#define WF_MOD_VELOCITY 6
-#define WF_MOD_LOGVEL 7
-#define WF_MOD_RANDOM 8
-#define WF_MOD_PRESSURE 9
-#define WF_MOD_MOD_WHEEL 10
-#define WF_MOD_1 WF_MOD_MOD_WHEEL
-#define WF_MOD_BREATH 11
-#define WF_MOD_2 WF_MOD_BREATH
-#define WF_MOD_FOOT 12
-#define WF_MOD_4 WF_MOD_FOOT
-#define WF_MOD_VOLUME 13
-#define WF_MOD_7 WF_MOD_VOLUME
-#define WF_MOD_PAN 14
-#define WF_MOD_10 WF_MOD_PAN
-#define WF_MOD_EXPR 15
-#define WF_MOD_11 WF_MOD_EXPR
-
-/* FX-related material */
-
-typedef struct wf_fx_info {
- int request; /* see list below */
- int data[4]; /* we don't need much */
-} wavefront_fx_info;
-
-/* support for each of these will be forthcoming once I or someone
- else has figured out which of the addresses on page 6 and page 7 of
- the YSS225 control each parameter. Incidentally, these come from
- the Windows driver interface, but again, Turtle Beach didn't
- document the API to use them.
-*/
-
-#define WFFX_SETOUTGAIN 0
-#define WFFX_SETSTEREOOUTGAIN 1
-#define WFFX_SETREVERBIN1GAIN 2
-#define WFFX_SETREVERBIN2GAIN 3
-#define WFFX_SETREVERBIN3GAIN 4
-#define WFFX_SETCHORUSINPORT 5
-#define WFFX_SETREVERBIN1PORT 6
-#define WFFX_SETREVERBIN2PORT 7
-#define WFFX_SETREVERBIN3PORT 8
-#define WFFX_SETEFFECTPORT 9
-#define WFFX_SETAUXPORT 10
-#define WFFX_SETREVERBTYPE 11
-#define WFFX_SETREVERBDELAY 12
-#define WFFX_SETCHORUSLFO 13
-#define WFFX_SETCHORUSPMD 14
-#define WFFX_SETCHORUSAMD 15
-#define WFFX_SETEFFECT 16
-#define WFFX_SETBASEALL 17
-#define WFFX_SETREVERBALL 18
-#define WFFX_SETCHORUSALL 20
-#define WFFX_SETREVERBDEF 22
-#define WFFX_SETCHORUSDEF 23
-#define WFFX_DELAYSETINGAIN 24
-#define WFFX_DELAYSETFBGAIN 25
-#define WFFX_DELAYSETFBLPF 26
-#define WFFX_DELAYSETGAIN 27
-#define WFFX_DELAYSETTIME 28
-#define WFFX_DELAYSETFBTIME 29
-#define WFFX_DELAYSETALL 30
-#define WFFX_DELAYSETDEF 32
-#define WFFX_SDELAYSETINGAIN 33
-#define WFFX_SDELAYSETFBGAIN 34
-#define WFFX_SDELAYSETFBLPF 35
-#define WFFX_SDELAYSETGAIN 36
-#define WFFX_SDELAYSETTIME 37
-#define WFFX_SDELAYSETFBTIME 38
-#define WFFX_SDELAYSETALL 39
-#define WFFX_SDELAYSETDEF 41
-#define WFFX_DEQSETINGAIN 42
-#define WFFX_DEQSETFILTER 43
-#define WFFX_DEQSETALL 44
-#define WFFX_DEQSETDEF 46
-#define WFFX_MUTE 47
-#define WFFX_FLANGESETBALANCE 48
-#define WFFX_FLANGESETDELAY 49
-#define WFFX_FLANGESETDWFFX_TH 50
-#define WFFX_FLANGESETFBGAIN 51
-#define WFFX_FLANGESETINGAIN 52
-#define WFFX_FLANGESETLFO 53
-#define WFFX_FLANGESETALL 54
-#define WFFX_FLANGESETDEF 56
-#define WFFX_PITCHSETSHIFT 57
-#define WFFX_PITCHSETBALANCE 58
-#define WFFX_PITCHSETALL 59
-#define WFFX_PITCHSETDEF 61
-#define WFFX_SRSSETINGAIN 62
-#define WFFX_SRSSETSPACE 63
-#define WFFX_SRSSETCENTER 64
-#define WFFX_SRSSETGAIN 65
-#define WFFX_SRSSETMODE 66
-#define WFFX_SRSSETDEF 68
-
-/* Allow direct user-space control over FX memory/coefficient data.
- In theory this could be used to download the FX microprogram,
- but it would be a little slower, and involve some weird code.
- */
-
-#define WFFX_MEMSET 69
-
-#endif /* __wavefront_h__ */
diff --git a/kernel/Makefile b/kernel/Makefile
index d948ca1..5e3f3b7 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -8,7 +8,7 @@
signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
- hrtimer.o rwsem.o latency.o nsproxy.o
+ hrtimer.o rwsem.o latency.o nsproxy.o srcu.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += time/
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 736cb0b..4cf65f5 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -18,6 +18,69 @@
#include "internals.h"
/**
+ * dynamic_irq_init - initialize a dynamically allocated irq
+ * @irq: irq number to initialize
+ */
+void dynamic_irq_init(unsigned int irq)
+{
+ struct irq_desc *desc;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS) {
+ printk(KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
+ WARN_ON(1);
+ return;
+ }
+
+ /* Ensure we don't have left over values from a previous use of this irq */
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock, flags);
+ desc->status = IRQ_DISABLED;
+ desc->chip = &no_irq_chip;
+ desc->handle_irq = handle_bad_irq;
+ desc->depth = 1;
+ desc->handler_data = NULL;
+ desc->chip_data = NULL;
+ desc->action = NULL;
+ desc->irq_count = 0;
+ desc->irqs_unhandled = 0;
+#ifdef CONFIG_SMP
+ desc->affinity = CPU_MASK_ALL;
+#endif
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ * dynamic_irq_cleanup - cleanup a dynamically allocated irq
+ * @irq: irq number to initialize
+ */
+void dynamic_irq_cleanup(unsigned int irq)
+{
+ struct irq_desc *desc;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS) {
+ printk(KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
+ WARN_ON(1);
+ return;
+ }
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock, flags);
+ if (desc->action) {
+ spin_unlock_irqrestore(&desc->lock, flags);
+ printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n",
+ irq);
+ WARN_ON(1);
+ return;
+ }
+ desc->handle_irq = handle_bad_irq;
+ desc->chip = &no_irq_chip;
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+
+/**
* set_irq_chip - set the irq chip for an irq
* @irq: irq number
* @chip: pointer to irq chip description structure
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
index a57ebe9..4baa3bb 100644
--- a/kernel/irq/migration.c
+++ b/kernel/irq/migration.c
@@ -7,17 +7,17 @@
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
- desc->move_irq = 1;
+ desc->status |= IRQ_MOVE_PENDING;
irq_desc[irq].pending_mask = mask;
spin_unlock_irqrestore(&desc->lock, flags);
}
-void move_native_irq(int irq)
+void move_masked_irq(int irq)
{
struct irq_desc *desc = irq_desc + irq;
cpumask_t tmp;
- if (likely(!desc->move_irq))
+ if (likely(!(desc->status & IRQ_MOVE_PENDING)))
return;
/*
@@ -28,7 +28,7 @@
return;
}
- desc->move_irq = 0;
+ desc->status &= ~IRQ_MOVE_PENDING;
if (unlikely(cpus_empty(irq_desc[irq].pending_mask)))
return;
@@ -48,15 +48,29 @@
* when an active trigger is comming in. This could
* cause some ioapics to mal-function.
* Being paranoid i guess!
+ *
+ * For correct operation this depends on the caller
+ * masking the irqs.
*/
if (likely(!cpus_empty(tmp))) {
- if (likely(!(desc->status & IRQ_DISABLED)))
- desc->chip->disable(irq);
-
desc->chip->set_affinity(irq,tmp);
-
- if (likely(!(desc->status & IRQ_DISABLED)))
- desc->chip->enable(irq);
}
cpus_clear(irq_desc[irq].pending_mask);
}
+
+void move_native_irq(int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (likely(!(desc->status & IRQ_MOVE_PENDING)))
+ return;
+
+ if (likely(!(desc->status & IRQ_DISABLED)))
+ desc->chip->disable(irq);
+
+ move_masked_irq(irq);
+
+ if (likely(!(desc->status & IRQ_DISABLED)))
+ desc->chip->enable(irq);
+}
+
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 523e464..26bb5ff 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -71,9 +71,6 @@
static int blimit = 10;
static int qhimark = 10000;
static int qlowmark = 100;
-#ifdef CONFIG_SMP
-static int rsinterval = 1000;
-#endif
static atomic_t rcu_barrier_cpu_count;
static DEFINE_MUTEX(rcu_barrier_mutex);
@@ -86,8 +83,8 @@
int cpu;
cpumask_t cpumask;
set_need_resched();
- if (unlikely(rdp->qlen - rdp->last_rs_qlen > rsinterval)) {
- rdp->last_rs_qlen = rdp->qlen;
+ if (unlikely(!rcp->signaled)) {
+ rcp->signaled = 1;
/*
* Don't send IPI to itself. With irqs disabled,
* rdp->cpu is the current cpu.
@@ -301,6 +298,7 @@
smp_mb();
cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);
+ rcp->signaled = 0;
}
}
@@ -628,9 +626,6 @@
module_param(blimit, int, 0);
module_param(qhimark, int, 0);
module_param(qlowmark, int, 0);
-#ifdef CONFIG_SMP
-module_param(rsinterval, int, 0);
-#endif
EXPORT_SYMBOL_GPL(rcu_batches_completed);
EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
EXPORT_SYMBOL_GPL(call_rcu);
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 23446e9..e2bda18 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -15,9 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Copyright (C) IBM Corporation, 2005
+ * Copyright (C) IBM Corporation, 2005, 2006
*
* Authors: Paul E. McKenney <paulmck@us.ibm.com>
+ * Josh Triplett <josh@freedesktop.org>
*
* See also: Documentation/RCU/torture.txt
*/
@@ -44,19 +45,25 @@
#include <linux/delay.h>
#include <linux/byteorder/swabb.h>
#include <linux/stat.h>
+#include <linux/srcu.h>
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
+ "Josh Triplett <josh@freedesktop.org>");
static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */
+static int nfakewriters = 4; /* # fake writer threads */
static int stat_interval; /* Interval between stats, in seconds. */
/* Defaults to "only at end of test". */
static int verbose; /* Print more debug info. */
static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */
static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
-static char *torture_type = "rcu"; /* What to torture. */
+static char *torture_type = "rcu"; /* What RCU implementation to torture. */
module_param(nreaders, int, 0);
MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
+module_param(nfakewriters, int, 0);
+MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
module_param(stat_interval, int, 0);
MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
module_param(verbose, bool, 0);
@@ -66,7 +73,7 @@
module_param(shuffle_interval, int, 0);
MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
module_param(torture_type, charp, 0);
-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)");
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
#define TORTURE_FLAG "-torture:"
#define PRINTK_STRING(s) \
@@ -80,6 +87,7 @@
static int nrealreaders;
static struct task_struct *writer_task;
+static struct task_struct **fakewriter_tasks;
static struct task_struct **reader_tasks;
static struct task_struct *stats_task;
static struct task_struct *shuffler_task;
@@ -104,11 +112,12 @@
static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
{ 0 };
static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
-atomic_t n_rcu_torture_alloc;
-atomic_t n_rcu_torture_alloc_fail;
-atomic_t n_rcu_torture_free;
-atomic_t n_rcu_torture_mberror;
-atomic_t n_rcu_torture_error;
+static atomic_t n_rcu_torture_alloc;
+static atomic_t n_rcu_torture_alloc_fail;
+static atomic_t n_rcu_torture_free;
+static atomic_t n_rcu_torture_mberror;
+static atomic_t n_rcu_torture_error;
+static struct list_head rcu_torture_removed;
/*
* Allocate an element from the rcu_tortures pool.
@@ -145,7 +154,7 @@
struct rcu_random_state {
unsigned long rrs_state;
- unsigned long rrs_count;
+ long rrs_count;
};
#define RCU_RANDOM_MULT 39916801 /* prime */
@@ -158,7 +167,7 @@
* Crude but fast random-number generator. Uses a linear congruential
* generator, with occasional help from get_random_bytes().
*/
-static long
+static unsigned long
rcu_random(struct rcu_random_state *rrsp)
{
long refresh;
@@ -180,9 +189,11 @@
void (*init)(void);
void (*cleanup)(void);
int (*readlock)(void);
+ void (*readdelay)(struct rcu_random_state *rrsp);
void (*readunlock)(int idx);
int (*completed)(void);
void (*deferredfree)(struct rcu_torture *p);
+ void (*sync)(void);
int (*stats)(char *page);
char *name;
};
@@ -198,6 +209,18 @@
return 0;
}
+static void rcu_read_delay(struct rcu_random_state *rrsp)
+{
+ long delay;
+ const long longdelay = 200;
+
+ /* We want there to be long-running readers, but not all the time. */
+
+ delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay);
+ if (!delay)
+ udelay(longdelay);
+}
+
static void rcu_torture_read_unlock(int idx) __releases(RCU)
{
rcu_read_unlock();
@@ -239,13 +262,54 @@
.init = NULL,
.cleanup = NULL,
.readlock = rcu_torture_read_lock,
+ .readdelay = rcu_read_delay,
.readunlock = rcu_torture_read_unlock,
.completed = rcu_torture_completed,
.deferredfree = rcu_torture_deferred_free,
+ .sync = synchronize_rcu,
.stats = NULL,
.name = "rcu"
};
+static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
+{
+ int i;
+ struct rcu_torture *rp;
+ struct rcu_torture *rp1;
+
+ cur_ops->sync();
+ list_add(&p->rtort_free, &rcu_torture_removed);
+ list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
+ i = rp->rtort_pipe_count;
+ if (i > RCU_TORTURE_PIPE_LEN)
+ i = RCU_TORTURE_PIPE_LEN;
+ atomic_inc(&rcu_torture_wcount[i]);
+ if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
+ rp->rtort_mbtest = 0;
+ list_del(&rp->rtort_free);
+ rcu_torture_free(rp);
+ }
+ }
+}
+
+static void rcu_sync_torture_init(void)
+{
+ INIT_LIST_HEAD(&rcu_torture_removed);
+}
+
+static struct rcu_torture_ops rcu_sync_ops = {
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = rcu_torture_read_lock,
+ .readdelay = rcu_read_delay,
+ .readunlock = rcu_torture_read_unlock,
+ .completed = rcu_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = synchronize_rcu,
+ .stats = NULL,
+ .name = "rcu_sync"
+};
+
/*
* Definitions for rcu_bh torture testing.
*/
@@ -271,19 +335,176 @@
call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
}
+struct rcu_bh_torture_synchronize {
+ struct rcu_head head;
+ struct completion completion;
+};
+
+static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
+{
+ struct rcu_bh_torture_synchronize *rcu;
+
+ rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
+ complete(&rcu->completion);
+}
+
+static void rcu_bh_torture_synchronize(void)
+{
+ struct rcu_bh_torture_synchronize rcu;
+
+ init_completion(&rcu.completion);
+ call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
+ wait_for_completion(&rcu.completion);
+}
+
static struct rcu_torture_ops rcu_bh_ops = {
.init = NULL,
.cleanup = NULL,
.readlock = rcu_bh_torture_read_lock,
+ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
.readunlock = rcu_bh_torture_read_unlock,
.completed = rcu_bh_torture_completed,
.deferredfree = rcu_bh_torture_deferred_free,
+ .sync = rcu_bh_torture_synchronize,
.stats = NULL,
.name = "rcu_bh"
};
+static struct rcu_torture_ops rcu_bh_sync_ops = {
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = rcu_bh_torture_read_lock,
+ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = rcu_bh_torture_read_unlock,
+ .completed = rcu_bh_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = rcu_bh_torture_synchronize,
+ .stats = NULL,
+ .name = "rcu_bh_sync"
+};
+
+/*
+ * Definitions for srcu torture testing.
+ */
+
+static struct srcu_struct srcu_ctl;
+
+static void srcu_torture_init(void)
+{
+ init_srcu_struct(&srcu_ctl);
+ rcu_sync_torture_init();
+}
+
+static void srcu_torture_cleanup(void)
+{
+ synchronize_srcu(&srcu_ctl);
+ cleanup_srcu_struct(&srcu_ctl);
+}
+
+static int srcu_torture_read_lock(void)
+{
+ return srcu_read_lock(&srcu_ctl);
+}
+
+static void srcu_read_delay(struct rcu_random_state *rrsp)
+{
+ long delay;
+ const long uspertick = 1000000 / HZ;
+ const long longdelay = 10;
+
+ /* We want there to be long-running readers, but not all the time. */
+
+ delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
+ if (!delay)
+ schedule_timeout_interruptible(longdelay);
+}
+
+static void srcu_torture_read_unlock(int idx)
+{
+ srcu_read_unlock(&srcu_ctl, idx);
+}
+
+static int srcu_torture_completed(void)
+{
+ return srcu_batches_completed(&srcu_ctl);
+}
+
+static void srcu_torture_synchronize(void)
+{
+ synchronize_srcu(&srcu_ctl);
+}
+
+static int srcu_torture_stats(char *page)
+{
+ int cnt = 0;
+ int cpu;
+ int idx = srcu_ctl.completed & 0x1;
+
+ cnt += sprintf(&page[cnt], "%s%s per-CPU(idx=%d):",
+ torture_type, TORTURE_FLAG, idx);
+ for_each_possible_cpu(cpu) {
+ cnt += sprintf(&page[cnt], " %d(%d,%d)", cpu,
+ per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
+ per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
+ }
+ cnt += sprintf(&page[cnt], "\n");
+ return cnt;
+}
+
+static struct rcu_torture_ops srcu_ops = {
+ .init = srcu_torture_init,
+ .cleanup = srcu_torture_cleanup,
+ .readlock = srcu_torture_read_lock,
+ .readdelay = srcu_read_delay,
+ .readunlock = srcu_torture_read_unlock,
+ .completed = srcu_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = srcu_torture_synchronize,
+ .stats = srcu_torture_stats,
+ .name = "srcu"
+};
+
+/*
+ * Definitions for sched torture testing.
+ */
+
+static int sched_torture_read_lock(void)
+{
+ preempt_disable();
+ return 0;
+}
+
+static void sched_torture_read_unlock(int idx)
+{
+ preempt_enable();
+}
+
+static int sched_torture_completed(void)
+{
+ return 0;
+}
+
+static void sched_torture_synchronize(void)
+{
+ synchronize_sched();
+}
+
+static struct rcu_torture_ops sched_ops = {
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = sched_torture_read_lock,
+ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = sched_torture_read_unlock,
+ .completed = sched_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = sched_torture_synchronize,
+ .stats = NULL,
+ .name = "sched"
+};
+
static struct rcu_torture_ops *torture_ops[] =
- { &rcu_ops, &rcu_bh_ops, NULL };
+ { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops,
+ &sched_ops, NULL };
/*
* RCU torture writer kthread. Repeatedly substitutes a new structure
@@ -330,6 +551,30 @@
}
/*
+ * RCU torture fake writer kthread. Repeatedly calls sync, with a random
+ * delay between calls.
+ */
+static int
+rcu_torture_fakewriter(void *arg)
+{
+ DEFINE_RCU_RANDOM(rand);
+
+ VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
+ set_user_nice(current, 19);
+
+ do {
+ schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
+ udelay(rcu_random(&rand) & 0x3ff);
+ cur_ops->sync();
+ } while (!kthread_should_stop() && !fullstop);
+
+ VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
+ while (!kthread_should_stop())
+ schedule_timeout_uninterruptible(1);
+ return 0;
+}
+
+/*
* RCU torture reader kthread. Repeatedly dereferences rcu_torture_current,
* incrementing the corresponding element of the pipeline array. The
* counter in the element should never be greater than 1, otherwise, the
@@ -359,7 +604,7 @@
}
if (p->rtort_mbtest == 0)
atomic_inc(&n_rcu_torture_mberror);
- udelay(rcu_random(&rand) & 0x7f);
+ cur_ops->readdelay(&rand);
preempt_disable();
pipe_count = p->rtort_pipe_count;
if (pipe_count > RCU_TORTURE_PIPE_LEN) {
@@ -483,7 +728,7 @@
/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
* is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
*/
-void rcu_torture_shuffle_tasks(void)
+static void rcu_torture_shuffle_tasks(void)
{
cpumask_t tmp_mask = CPU_MASK_ALL;
int i;
@@ -507,6 +752,12 @@
set_cpus_allowed(reader_tasks[i], tmp_mask);
}
+ if (fakewriter_tasks != NULL) {
+ for (i = 0; i < nfakewriters; i++)
+ if (fakewriter_tasks[i])
+ set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
+ }
+
if (writer_task)
set_cpus_allowed(writer_task, tmp_mask);
@@ -540,11 +791,12 @@
static inline void
rcu_torture_print_module_parms(char *tag)
{
- printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
+ printk(KERN_ALERT "%s" TORTURE_FLAG
+ "--- %s: nreaders=%d nfakewriters=%d "
"stat_interval=%d verbose=%d test_no_idle_hz=%d "
"shuffle_interval = %d\n",
- torture_type, tag, nrealreaders, stat_interval, verbose,
- test_no_idle_hz, shuffle_interval);
+ torture_type, tag, nrealreaders, nfakewriters,
+ stat_interval, verbose, test_no_idle_hz, shuffle_interval);
}
static void
@@ -579,6 +831,19 @@
}
rcu_torture_current = NULL;
+ if (fakewriter_tasks != NULL) {
+ for (i = 0; i < nfakewriters; i++) {
+ if (fakewriter_tasks[i] != NULL) {
+ VERBOSE_PRINTK_STRING(
+ "Stopping rcu_torture_fakewriter task");
+ kthread_stop(fakewriter_tasks[i]);
+ }
+ fakewriter_tasks[i] = NULL;
+ }
+ kfree(fakewriter_tasks);
+ fakewriter_tasks = NULL;
+ }
+
if (stats_task != NULL) {
VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
kthread_stop(stats_task);
@@ -666,7 +931,25 @@
writer_task = NULL;
goto unwind;
}
- reader_tasks = kmalloc(nrealreaders * sizeof(reader_tasks[0]),
+ fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
+ GFP_KERNEL);
+ if (fakewriter_tasks == NULL) {
+ VERBOSE_PRINTK_ERRSTRING("out of memory");
+ firsterr = -ENOMEM;
+ goto unwind;
+ }
+ for (i = 0; i < nfakewriters; i++) {
+ VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
+ fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
+ "rcu_torture_fakewriter");
+ if (IS_ERR(fakewriter_tasks[i])) {
+ firsterr = PTR_ERR(fakewriter_tasks[i]);
+ VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
+ fakewriter_tasks[i] = NULL;
+ goto unwind;
+ }
+ }
+ reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
GFP_KERNEL);
if (reader_tasks == NULL) {
VERBOSE_PRINTK_ERRSTRING("out of memory");
diff --git a/kernel/srcu.c b/kernel/srcu.c
new file mode 100644
index 0000000..3507cab
--- /dev/null
+++ b/kernel/srcu.c
@@ -0,0 +1,258 @@
+/*
+ * Sleepable Read-Copy Update mechanism for mutual exclusion.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Paul McKenney <paulmck@us.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * Documentation/RCU/ *.txt
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/percpu.h>
+#include <linux/preempt.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/srcu.h>
+
+/**
+ * init_srcu_struct - initialize a sleep-RCU structure
+ * @sp: structure to initialize.
+ *
+ * Must invoke this on a given srcu_struct before passing that srcu_struct
+ * to any other function. Each srcu_struct represents a separate domain
+ * of SRCU protection.
+ */
+int init_srcu_struct(struct srcu_struct *sp)
+{
+ sp->completed = 0;
+ mutex_init(&sp->mutex);
+ sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
+ return (sp->per_cpu_ref ? 0 : -ENOMEM);
+}
+
+/*
+ * srcu_readers_active_idx -- returns approximate number of readers
+ * active on the specified rank of per-CPU counters.
+ */
+
+static int srcu_readers_active_idx(struct srcu_struct *sp, int idx)
+{
+ int cpu;
+ int sum;
+
+ sum = 0;
+ for_each_possible_cpu(cpu)
+ sum += per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx];
+ return sum;
+}
+
+/**
+ * srcu_readers_active - returns approximate number of readers.
+ * @sp: which srcu_struct to count active readers (holding srcu_read_lock).
+ *
+ * Note that this is not an atomic primitive, and can therefore suffer
+ * severe errors when invoked on an active srcu_struct. That said, it
+ * can be useful as an error check at cleanup time.
+ */
+int srcu_readers_active(struct srcu_struct *sp)
+{
+ return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1);
+}
+
+/**
+ * cleanup_srcu_struct - deconstruct a sleep-RCU structure
+ * @sp: structure to clean up.
+ *
+ * Must invoke this after you are finished using a given srcu_struct that
+ * was initialized via init_srcu_struct(), else you leak memory.
+ */
+void cleanup_srcu_struct(struct srcu_struct *sp)
+{
+ int sum;
+
+ sum = srcu_readers_active(sp);
+ WARN_ON(sum); /* Leakage unless caller handles error. */
+ if (sum != 0)
+ return;
+ free_percpu(sp->per_cpu_ref);
+ sp->per_cpu_ref = NULL;
+}
+
+/**
+ * srcu_read_lock - register a new reader for an SRCU-protected structure.
+ * @sp: srcu_struct in which to register the new reader.
+ *
+ * Counts the new reader in the appropriate per-CPU element of the
+ * srcu_struct. Must be called from process context.
+ * Returns an index that must be passed to the matching srcu_read_unlock().
+ */
+int srcu_read_lock(struct srcu_struct *sp)
+{
+ int idx;
+
+ preempt_disable();
+ idx = sp->completed & 0x1;
+ barrier(); /* ensure compiler looks -once- at sp->completed. */
+ per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]++;
+ srcu_barrier(); /* ensure compiler won't misorder critical section. */
+ preempt_enable();
+ return idx;
+}
+
+/**
+ * srcu_read_unlock - unregister a old reader from an SRCU-protected structure.
+ * @sp: srcu_struct in which to unregister the old reader.
+ * @idx: return value from corresponding srcu_read_lock().
+ *
+ * Removes the count for the old reader from the appropriate per-CPU
+ * element of the srcu_struct. Note that this may well be a different
+ * CPU than that which was incremented by the corresponding srcu_read_lock().
+ * Must be called from process context.
+ */
+void srcu_read_unlock(struct srcu_struct *sp, int idx)
+{
+ preempt_disable();
+ srcu_barrier(); /* ensure compiler won't misorder critical section. */
+ per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--;
+ preempt_enable();
+}
+
+/**
+ * synchronize_srcu - wait for prior SRCU read-side critical-section completion
+ * @sp: srcu_struct with which to synchronize.
+ *
+ * Flip the completed counter, and wait for the old count to drain to zero.
+ * As with classic RCU, the updater must use some separate means of
+ * synchronizing concurrent updates. Can block; must be called from
+ * process context.
+ *
+ * Note that it is illegal to call synchornize_srcu() from the corresponding
+ * SRCU read-side critical section; doing so will result in deadlock.
+ * However, it is perfectly legal to call synchronize_srcu() on one
+ * srcu_struct from some other srcu_struct's read-side critical section.
+ */
+void synchronize_srcu(struct srcu_struct *sp)
+{
+ int idx;
+
+ idx = sp->completed;
+ mutex_lock(&sp->mutex);
+
+ /*
+ * Check to see if someone else did the work for us while we were
+ * waiting to acquire the lock. We need -two- advances of
+ * the counter, not just one. If there was but one, we might have
+ * shown up -after- our helper's first synchronize_sched(), thus
+ * having failed to prevent CPU-reordering races with concurrent
+ * srcu_read_unlock()s on other CPUs (see comment below). So we
+ * either (1) wait for two or (2) supply the second ourselves.
+ */
+
+ if ((sp->completed - idx) >= 2) {
+ mutex_unlock(&sp->mutex);
+ return;
+ }
+
+ synchronize_sched(); /* Force memory barrier on all CPUs. */
+
+ /*
+ * The preceding synchronize_sched() ensures that any CPU that
+ * sees the new value of sp->completed will also see any preceding
+ * changes to data structures made by this CPU. This prevents
+ * some other CPU from reordering the accesses in its SRCU
+ * read-side critical section to precede the corresponding
+ * srcu_read_lock() -- ensuring that such references will in
+ * fact be protected.
+ *
+ * So it is now safe to do the flip.
+ */
+
+ idx = sp->completed & 0x1;
+ sp->completed++;
+
+ synchronize_sched(); /* Force memory barrier on all CPUs. */
+
+ /*
+ * At this point, because of the preceding synchronize_sched(),
+ * all srcu_read_lock() calls using the old counters have completed.
+ * Their corresponding critical sections might well be still
+ * executing, but the srcu_read_lock() primitives themselves
+ * will have finished executing.
+ */
+
+ while (srcu_readers_active_idx(sp, idx))
+ schedule_timeout_interruptible(1);
+
+ synchronize_sched(); /* Force memory barrier on all CPUs. */
+
+ /*
+ * The preceding synchronize_sched() forces all srcu_read_unlock()
+ * primitives that were executing concurrently with the preceding
+ * for_each_possible_cpu() loop to have completed by this point.
+ * More importantly, it also forces the corresponding SRCU read-side
+ * critical sections to have also completed, and the corresponding
+ * references to SRCU-protected data items to be dropped.
+ *
+ * Note:
+ *
+ * Despite what you might think at first glance, the
+ * preceding synchronize_sched() -must- be within the
+ * critical section ended by the following mutex_unlock().
+ * Otherwise, a task taking the early exit can race
+ * with a srcu_read_unlock(), which might have executed
+ * just before the preceding srcu_readers_active() check,
+ * and whose CPU might have reordered the srcu_read_unlock()
+ * with the preceding critical section. In this case, there
+ * is nothing preventing the synchronize_sched() task that is
+ * taking the early exit from freeing a data structure that
+ * is still being referenced (out of order) by the task
+ * doing the srcu_read_unlock().
+ *
+ * Alternatively, the comparison with "2" on the early exit
+ * could be changed to "3", but this increases synchronize_srcu()
+ * latency for bulk loads. So the current code is preferred.
+ */
+
+ mutex_unlock(&sp->mutex);
+}
+
+/**
+ * srcu_batches_completed - return batches completed.
+ * @sp: srcu_struct on which to report batch completion.
+ *
+ * Report the number of batches, correlated with, but not necessarily
+ * precisely the same as, the number of grace periods that have elapsed.
+ */
+
+long srcu_batches_completed(struct srcu_struct *sp)
+{
+ return sp->completed;
+}
+
+EXPORT_SYMBOL_GPL(init_srcu_struct);
+EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
+EXPORT_SYMBOL_GPL(srcu_read_lock);
+EXPORT_SYMBOL_GPL(srcu_read_unlock);
+EXPORT_SYMBOL_GPL(synchronize_srcu);
+EXPORT_SYMBOL_GPL(srcu_batches_completed);
+EXPORT_SYMBOL_GPL(srcu_readers_active);
diff --git a/kernel/sys.c b/kernel/sys.c
index 2314867..98489d8 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -153,7 +153,7 @@
/*
* Atomic notifier chain routines. Registration and unregistration
- * use a mutex, and call_chain is synchronized by RCU (no locks).
+ * use a spinlock, and call_chain is synchronized by RCU (no locks).
*/
/**
@@ -401,6 +401,129 @@
EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
+/*
+ * SRCU notifier chain routines. Registration and unregistration
+ * use a mutex, and call_chain is synchronized by SRCU (no locks).
+ */
+
+/**
+ * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain
+ * @nh: Pointer to head of the SRCU notifier chain
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to an SRCU notifier chain.
+ * Must be called in process context.
+ *
+ * Currently always returns zero.
+ */
+
+int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+ struct notifier_block *n)
+{
+ int ret;
+
+ /*
+ * This code gets used during boot-up, when task switching is
+ * not yet working and interrupts must remain disabled. At
+ * such times we must not call mutex_lock().
+ */
+ if (unlikely(system_state == SYSTEM_BOOTING))
+ return notifier_chain_register(&nh->head, n);
+
+ mutex_lock(&nh->mutex);
+ ret = notifier_chain_register(&nh->head, n);
+ mutex_unlock(&nh->mutex);
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_chain_register);
+
+/**
+ * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain
+ * @nh: Pointer to head of the SRCU notifier chain
+ * @n: Entry to remove from notifier chain
+ *
+ * Removes a notifier from an SRCU notifier chain.
+ * Must be called from process context.
+ *
+ * Returns zero on success or %-ENOENT on failure.
+ */
+int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+ struct notifier_block *n)
+{
+ int ret;
+
+ /*
+ * This code gets used during boot-up, when task switching is
+ * not yet working and interrupts must remain disabled. At
+ * such times we must not call mutex_lock().
+ */
+ if (unlikely(system_state == SYSTEM_BOOTING))
+ return notifier_chain_unregister(&nh->head, n);
+
+ mutex_lock(&nh->mutex);
+ ret = notifier_chain_unregister(&nh->head, n);
+ mutex_unlock(&nh->mutex);
+ synchronize_srcu(&nh->srcu);
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
+
+/**
+ * srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ * @nh: Pointer to head of the SRCU notifier chain
+ * @val: Value passed unmodified to notifier function
+ * @v: Pointer passed unmodified to notifier function
+ *
+ * Calls each function in a notifier chain in turn. The functions
+ * run in a process context, so they are allowed to block.
+ *
+ * If the return value of the notifier can be and'ed
+ * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain
+ * will return immediately, with the return value of
+ * the notifier function which halted execution.
+ * Otherwise the return value is the return value
+ * of the last notifier function called.
+ */
+
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+ unsigned long val, void *v)
+{
+ int ret;
+ int idx;
+
+ idx = srcu_read_lock(&nh->srcu);
+ ret = notifier_call_chain(&nh->head, val, v);
+ srcu_read_unlock(&nh->srcu, idx);
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
+
+/**
+ * srcu_init_notifier_head - Initialize an SRCU notifier head
+ * @nh: Pointer to head of the srcu notifier chain
+ *
+ * Unlike other sorts of notifier heads, SRCU notifier heads require
+ * dynamic initialization. Be sure to call this routine before
+ * calling any of the other SRCU notifier routines for this head.
+ *
+ * If an SRCU notifier head is deallocated, it must first be cleaned
+ * up by calling srcu_cleanup_notifier_head(). Otherwise the head's
+ * per-cpu data (used by the SRCU mechanism) will leak.
+ */
+
+void srcu_init_notifier_head(struct srcu_notifier_head *nh)
+{
+ mutex_init(&nh->mutex);
+ if (init_srcu_struct(&nh->srcu) < 0)
+ BUG();
+ nh->head = NULL;
+}
+
+EXPORT_SYMBOL_GPL(srcu_init_notifier_head);
+
/**
* register_reboot_notifier - Register function to be called at reboot time
* @nb: Info about notifier function to be called
diff --git a/mm/filemap.c b/mm/filemap.c
index ec4692359..f789500 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1139,11 +1139,11 @@
}
/**
- * __generic_file_aio_read - generic filesystem read routine
+ * generic_file_aio_read - generic filesystem read routine
* @iocb: kernel I/O control block
* @iov: io vector request
* @nr_segs: number of segments in the iovec
- * @ppos: current file position
+ * @pos: current file position
*
* This is the "read()" routine for all filesystems
* that can use the page cache directly.
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7c7d03d..1d709ff 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -364,6 +364,8 @@
pte_t *ptep;
pte_t pte;
struct page *page;
+ struct page *tmp;
+ LIST_HEAD(page_list);
WARN_ON(!is_vm_hugetlb_page(vma));
BUG_ON(start & ~HPAGE_MASK);
@@ -384,12 +386,16 @@
continue;
page = pte_page(pte);
- put_page(page);
+ list_add(&page->lru, &page_list);
add_mm_counter(mm, file_rss, (int) -(HPAGE_SIZE / PAGE_SIZE));
}
spin_unlock(&mm->page_table_lock);
flush_tlb_range(vma, start, end);
+ list_for_each_entry_safe(page, tmp, &page_list, lru) {
+ list_del(&page->lru);
+ put_page(page);
+ }
}
static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 4f59d90..a8c003e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -900,7 +900,8 @@
int classzone_idx, int alloc_flags)
{
/* free_pages my go negative - that's OK */
- long min = mark, free_pages = z->free_pages - (1 << order) + 1;
+ unsigned long min = mark;
+ long free_pages = z->free_pages - (1 << order) + 1;
int o;
if (alloc_flags & ALLOC_HIGH)
@@ -2050,8 +2051,8 @@
/**
* free_bootmem_with_active_regions - Call free_bootmem_node for each active range
- * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed
- * @max_low_pfn: The highest PFN that till be passed to free_bootmem_node
+ * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed.
+ * @max_low_pfn: The highest PFN that will be passed to free_bootmem_node
*
* If an architecture guarantees that all ranges registered with
* add_active_ranges() contain no holes and may be freed, this
@@ -2081,11 +2082,11 @@
/**
* sparse_memory_present_with_active_regions - Call memory_present for each active range
- * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used
+ * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used.
*
* If an architecture guarantees that all ranges registered with
* add_active_ranges() contain no holes and may be freed, this
- * this function may be used instead of calling memory_present() manually.
+ * function may be used instead of calling memory_present() manually.
*/
void __init sparse_memory_present_with_active_regions(int nid)
{
@@ -2155,14 +2156,14 @@
/**
* get_pfn_range_for_nid - Return the start and end page frames for a node
- * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned
- * @start_pfn: Passed by reference. On return, it will have the node start_pfn
- * @end_pfn: Passed by reference. On return, it will have the node end_pfn
+ * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned.
+ * @start_pfn: Passed by reference. On return, it will have the node start_pfn.
+ * @end_pfn: Passed by reference. On return, it will have the node end_pfn.
*
* It returns the start and end page frame of a node based on information
* provided by an arch calling add_active_range(). If called for a node
* with no available memory, a warning is printed and the start and end
- * PFNs will be 0
+ * PFNs will be 0.
*/
void __init get_pfn_range_for_nid(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn)
@@ -2215,7 +2216,7 @@
/*
* Return the number of holes in a range on a node. If nid is MAX_NUMNODES,
- * then all holes in the requested range will be accounted for
+ * then all holes in the requested range will be accounted for.
*/
unsigned long __init __absent_pages_in_range(int nid,
unsigned long range_start_pfn,
@@ -2268,7 +2269,7 @@
* @start_pfn: The start PFN to start searching for holes
* @end_pfn: The end PFN to stop searching for holes
*
- * It returns the number of pages frames in memory holes within a range
+ * It returns the number of pages frames in memory holes within a range.
*/
unsigned long __init absent_pages_in_range(unsigned long start_pfn,
unsigned long end_pfn)
@@ -2582,11 +2583,12 @@
/**
* remove_all_active_ranges - Remove all currently registered regions
+ *
* During discovery, it may be found that a table like SRAT is invalid
* and an alternative discovery method must be used. This function removes
* all currently registered regions.
*/
-void __init remove_all_active_ranges()
+void __init remove_all_active_ranges(void)
{
memset(early_node_map, 0, sizeof(early_node_map));
nr_nodemap_entries = 0;
@@ -2636,7 +2638,7 @@
* find_min_pfn_with_active_regions - Find the minimum PFN registered
*
* It returns the minimum PFN based on information provided via
- * add_active_range()
+ * add_active_range().
*/
unsigned long __init find_min_pfn_with_active_regions(void)
{
@@ -2647,7 +2649,7 @@
* find_max_pfn_with_active_regions - Find the maximum PFN registered
*
* It returns the maximum PFN based on information provided via
- * add_active_range()
+ * add_active_range().
*/
unsigned long __init find_max_pfn_with_active_regions(void)
{
@@ -2662,10 +2664,7 @@
/**
* free_area_init_nodes - Initialise all pg_data_t and zone data
- * @arch_max_dma_pfn: The maximum PFN usable for ZONE_DMA
- * @arch_max_dma32_pfn: The maximum PFN usable for ZONE_DMA32
- * @arch_max_low_pfn: The maximum PFN usable for ZONE_NORMAL
- * @arch_max_high_pfn: The maximum PFN usable for ZONE_HIGHMEM
+ * @max_zone_pfn: an array of max PFNs for each zone
*
* This will call free_area_init_node() for each active node in the system.
* Using the page ranges provided by add_active_range(), the size of each
@@ -2723,14 +2722,15 @@
#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
/**
- * set_dma_reserve - Account the specified number of pages reserved in ZONE_DMA
- * @new_dma_reserve - The number of pages to mark reserved
+ * set_dma_reserve - set the specified number of pages reserved in the first zone
+ * @new_dma_reserve: The number of pages to mark reserved
*
* The per-cpu batchsize and zone watermarks are determined by present_pages.
* In the DMA zone, a significant percentage may be consumed by kernel image
* and other unfreeable allocations which can skew the watermarks badly. This
- * function may optionally be used to account for unfreeable pages in
- * ZONE_DMA. The effect will be lower watermarks and smaller per-cpu batchsize
+ * function may optionally be used to account for unfreeable pages in the
+ * first zone (e.g., ZONE_DMA). The effect will be lower watermarks and
+ * smaller per-cpu batchsize.
*/
void __init set_dma_reserve(unsigned long new_dma_reserve)
{
@@ -2843,10 +2843,11 @@
calculate_totalreserve_pages();
}
-/*
- * setup_per_zone_pages_min - called when min_free_kbytes changes. Ensures
- * that the pages_{min,low,high} values for each zone are set correctly
- * with respect to min_free_kbytes.
+/**
+ * setup_per_zone_pages_min - called when min_free_kbytes changes.
+ *
+ * Ensures that the pages_{min,low,high} values for each zone are set correctly
+ * with respect to min_free_kbytes.
*/
void setup_per_zone_pages_min(void)
{
diff --git a/mm/slab.c b/mm/slab.c
index 3dbd6f4..c23b992 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3488,22 +3488,25 @@
}
+#ifdef CONFIG_DEBUG_SLAB
void *__kmalloc(size_t size, gfp_t flags)
{
-#ifndef CONFIG_DEBUG_SLAB
- return __do_kmalloc(size, flags, NULL);
-#else
return __do_kmalloc(size, flags, __builtin_return_address(0));
-#endif
}
EXPORT_SYMBOL(__kmalloc);
-#ifdef CONFIG_DEBUG_SLAB
void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller)
{
return __do_kmalloc(size, flags, caller);
}
EXPORT_SYMBOL(__kmalloc_track_caller);
+
+#else
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ return __do_kmalloc(size, flags, NULL);
+}
+EXPORT_SYMBOL(__kmalloc);
#endif
/**
diff --git a/mm/util.c b/mm/util.c
index e14fa84..ace2aea 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -11,7 +11,7 @@
*/
void *__kzalloc(size_t size, gfp_t flags)
{
- void *ret = ____kmalloc(size, flags);
+ void *ret = kmalloc_track_caller(size, flags);
if (ret)
memset(ret, 0, size);
return ret;
@@ -33,7 +33,7 @@
return NULL;
len = strlen(s) + 1;
- buf = ____kmalloc(len, gfp);
+ buf = kmalloc_track_caller(len, gfp);
if (buf)
memcpy(buf, s, len);
return buf;
@@ -51,7 +51,7 @@
{
void *p;
- p = ____kmalloc(len, gfp);
+ p = kmalloc_track_caller(len, gfp);
if (p)
memcpy(p, src, len);
return p;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c448c7f..3c23760 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -156,7 +156,8 @@
/* Get the DATA. Size must match skb_add_mtu(). */
size = SKB_DATA_ALIGN(size);
- data = ____kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+ data = kmalloc_track_caller(size + sizeof(struct skb_shared_info),
+ gfp_mask);
if (!data)
goto nodata;
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 638c0b5..447d9ae 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -903,9 +903,9 @@
struct gss_svc_data {
/* decoded gss client cred: */
struct rpc_gss_wire_cred clcred;
- /* pointer to the beginning of the procedure-specific results,
- * which may be encrypted/checksummed in svcauth_gss_release: */
- __be32 *body_start;
+ /* save a pointer to the beginning of the encoded verifier,
+ * for use in encryption/checksumming in svcauth_gss_release: */
+ __be32 *verf_start;
struct rsc *rsci;
};
@@ -968,7 +968,7 @@
if (!svcdata)
goto auth_err;
rqstp->rq_auth_data = svcdata;
- svcdata->body_start = NULL;
+ svcdata->verf_start = NULL;
svcdata->rsci = NULL;
gc = &svcdata->clcred;
@@ -1097,6 +1097,7 @@
goto complete;
case RPC_GSS_PROC_DATA:
*authp = rpcsec_gsserr_ctxproblem;
+ svcdata->verf_start = resv->iov_base + resv->iov_len;
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
goto auth_err;
rqstp->rq_cred = rsci->cred;
@@ -1110,7 +1111,6 @@
gc->gc_seq, rsci->mechctx))
goto auth_err;
/* placeholders for length and seq. number: */
- svcdata->body_start = resv->iov_base + resv->iov_len;
svc_putnl(resv, 0);
svc_putnl(resv, 0);
break;
@@ -1119,7 +1119,6 @@
gc->gc_seq, rsci->mechctx))
goto auth_err;
/* placeholders for length and seq. number: */
- svcdata->body_start = resv->iov_base + resv->iov_len;
svc_putnl(resv, 0);
svc_putnl(resv, 0);
break;
@@ -1147,6 +1146,32 @@
return ret;
}
+u32 *
+svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd)
+{
+ u32 *p, verf_len;
+
+ p = gsd->verf_start;
+ gsd->verf_start = NULL;
+
+ /* If the reply stat is nonzero, don't wrap: */
+ if (*(p-1) != rpc_success)
+ return NULL;
+ /* Skip the verifier: */
+ p += 1;
+ verf_len = ntohl(*p++);
+ p += XDR_QUADLEN(verf_len);
+ /* move accept_stat to right place: */
+ memcpy(p, p + 2, 4);
+ /* Also don't wrap if the accept stat is nonzero: */
+ if (*p != rpc_success) {
+ resbuf->head[0].iov_len -= 2 * 4;
+ return NULL;
+ }
+ p++;
+ return p;
+}
+
static inline int
svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
{
@@ -1160,17 +1185,9 @@
int integ_offset, integ_len;
int stat = -EINVAL;
- p = gsd->body_start;
- gsd->body_start = NULL;
- /* move accept_stat to right place: */
- memcpy(p, p + 2, 4);
- /* Don't wrap in failure case: */
- /* Counting on not getting here if call was not even accepted! */
- if (*p != rpc_success) {
- resbuf->head[0].iov_len -= 2 * 4;
+ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+ if (p == NULL)
goto out;
- }
- p++;
integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
integ_len = resbuf->len - integ_offset;
BUG_ON(integ_len % 4);
@@ -1191,7 +1208,6 @@
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ resbuf->head[0].iov_len;
resbuf->tail[0].iov_len = 0;
- rqstp->rq_restailpage = 0;
resv = &resbuf->tail[0];
} else {
resv = &resbuf->tail[0];
@@ -1223,24 +1239,16 @@
int offset;
int pad;
- p = gsd->body_start;
- gsd->body_start = NULL;
- /* move accept_stat to right place: */
- memcpy(p, p + 2, 4);
- /* Don't wrap in failure case: */
- /* Counting on not getting here if call was not even accepted! */
- if (*p != rpc_success) {
- resbuf->head[0].iov_len -= 2 * 4;
+ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+ if (p == NULL)
return 0;
- }
- p++;
len = p++;
offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
*p++ = htonl(gc->gc_seq);
inpages = resbuf->pages;
/* XXX: Would be better to write some xdr helper functions for
* nfs{2,3,4}xdr.c that place the data right, instead of copying: */
- if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) {
+ if (resbuf->tail[0].iov_base) {
BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
+ PAGE_SIZE);
BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
@@ -1258,7 +1266,6 @@
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
resbuf->tail[0].iov_len = 0;
- rqstp->rq_restailpage = 0;
}
if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
return -ENOMEM;
@@ -1282,7 +1289,7 @@
if (gc->gc_proc != RPC_GSS_PROC_DATA)
goto out;
/* Release can be called twice, but we only wrap once. */
- if (gsd->body_start == NULL)
+ if (gsd->verf_start == NULL)
goto out;
/* normally not set till svc_send, but we need it here: */
/* XXX: what for? Do we mess it up the moment we call svc_putu32
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index a99e67b..c2c8bb2 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -417,18 +417,15 @@
if (size > RPCSVC_MAXPAYLOAD)
size = RPCSVC_MAXPAYLOAD;
pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE;
- rqstp->rq_argused = 0;
- rqstp->rq_resused = 0;
arghi = 0;
BUG_ON(pages > RPCSVC_MAXPAGES);
while (pages) {
struct page *p = alloc_page(GFP_KERNEL);
if (!p)
break;
- rqstp->rq_argpages[arghi++] = p;
+ rqstp->rq_pages[arghi++] = p;
pages--;
}
- rqstp->rq_arghi = arghi;
return ! pages;
}
@@ -438,14 +435,10 @@
static void
svc_release_buffer(struct svc_rqst *rqstp)
{
- while (rqstp->rq_arghi)
- put_page(rqstp->rq_argpages[--rqstp->rq_arghi]);
- while (rqstp->rq_resused) {
- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
- continue;
- put_page(rqstp->rq_respages[rqstp->rq_resused]);
- }
- rqstp->rq_argused = 0;
+ int i;
+ for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
+ if (rqstp->rq_pages[i])
+ put_page(rqstp->rq_pages[i]);
}
/*
@@ -651,23 +644,32 @@
unsigned long flags;
int i, error = 0, dummy;
- progp = serv->sv_program;
-
- dprintk("RPC: svc_register(%s, %s, %d)\n",
- progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
-
if (!port)
clear_thread_flag(TIF_SIGPENDING);
- for (i = 0; i < progp->pg_nvers; i++) {
- if (progp->pg_vers[i] == NULL)
- continue;
- error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
- if (error < 0)
- break;
- if (port && !dummy) {
- error = -EACCES;
- break;
+ for (progp = serv->sv_program; progp; progp = progp->pg_next) {
+ for (i = 0; i < progp->pg_nvers; i++) {
+ if (progp->pg_vers[i] == NULL)
+ continue;
+
+ dprintk("RPC: svc_register(%s, %s, %d, %d)%s\n",
+ progp->pg_name,
+ proto == IPPROTO_UDP? "udp" : "tcp",
+ port,
+ i,
+ progp->pg_vers[i]->vs_hidden?
+ " (but not telling portmap)" : "");
+
+ if (progp->pg_vers[i]->vs_hidden)
+ continue;
+
+ error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
+ if (error < 0)
+ break;
+ if (port && !dummy) {
+ error = -EACCES;
+ break;
+ }
}
}
@@ -697,7 +699,7 @@
u32 dir, prog, vers, proc;
__be32 auth_stat, rpc_stat;
int auth_res;
- __be32 *accept_statp;
+ __be32 *reply_statp;
rpc_stat = rpc_success;
@@ -707,10 +709,10 @@
/* setup response xdr_buf.
* Initially it has just one page
*/
- svc_take_page(rqstp); /* must succeed */
+ rqstp->rq_resused = 1;
resv->iov_base = page_address(rqstp->rq_respages[0]);
resv->iov_len = 0;
- rqstp->rq_res.pages = rqstp->rq_respages+1;
+ rqstp->rq_res.pages = rqstp->rq_respages + 1;
rqstp->rq_res.len = 0;
rqstp->rq_res.page_base = 0;
rqstp->rq_res.page_len = 0;
@@ -738,7 +740,7 @@
goto err_bad_rpc;
/* Save position in case we later decide to reject: */
- accept_statp = resv->iov_base + resv->iov_len;
+ reply_statp = resv->iov_base + resv->iov_len;
svc_putnl(resv, 0); /* ACCEPT */
@@ -886,7 +888,7 @@
dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
serv->sv_stats->rpcbadauth++;
/* Restore write pointer to location of accept status: */
- xdr_ressize_check(rqstp, accept_statp);
+ xdr_ressize_check(rqstp, reply_statp);
svc_putnl(resv, 1); /* REJECT */
svc_putnl(resv, 1); /* AUTH_ERROR */
svc_putnl(resv, ntohl(auth_stat)); /* status */
@@ -926,3 +928,18 @@
svc_putnl(resv, ntohl(rpc_stat));
goto sendit;
}
+
+/*
+ * Return (transport-specific) limit on the rpc payload.
+ */
+u32 svc_max_payload(const struct svc_rqst *rqstp)
+{
+ int max = RPCSVC_MAXPAYLOAD_TCP;
+
+ if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM)
+ max = RPCSVC_MAXPAYLOAD_UDP;
+ if (rqstp->rq_server->sv_bufsz < max)
+ max = rqstp->rq_server->sv_bufsz;
+ return max;
+}
+EXPORT_SYMBOL_GPL(svc_max_payload);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 40d41a2..e1bd933 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -9,6 +9,7 @@
#include <linux/seq_file.h>
#include <linux/hash.h>
#include <linux/string.h>
+#include <net/sock.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
@@ -375,6 +376,44 @@
cache_purge(&ip_map_cache);
}
+static inline struct ip_map *
+ip_map_cached_get(struct svc_rqst *rqstp)
+{
+ struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix;
+ if (ipm != NULL) {
+ if (!cache_valid(&ipm->h)) {
+ /*
+ * The entry has been invalidated since it was
+ * remembered, e.g. by a second mount from the
+ * same IP address.
+ */
+ rqstp->rq_sock->sk_info_authunix = NULL;
+ cache_put(&ipm->h, &ip_map_cache);
+ return NULL;
+ }
+ cache_get(&ipm->h);
+ }
+ return ipm;
+}
+
+static inline void
+ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
+{
+ struct svc_sock *svsk = rqstp->rq_sock;
+
+ if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL)
+ svsk->sk_info_authunix = ipm; /* newly cached, keep the reference */
+ else
+ cache_put(&ipm->h, &ip_map_cache);
+}
+
+void
+svcauth_unix_info_release(void *info)
+{
+ struct ip_map *ipm = info;
+ cache_put(&ipm->h, &ip_map_cache);
+}
+
static int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
@@ -384,8 +423,10 @@
if (rqstp->rq_proc == 0)
return SVC_OK;
- ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- rqstp->rq_addr.sin_addr);
+ ipm = ip_map_cached_get(rqstp);
+ if (ipm == NULL)
+ ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
+ rqstp->rq_addr.sin_addr);
if (ipm == NULL)
return SVC_DENIED;
@@ -400,7 +441,7 @@
case 0:
rqstp->rq_client = &ipm->m_client->h;
kref_get(&rqstp->rq_client->ref);
- cache_put(&ipm->h, &ip_map_cache);
+ ip_map_cached_put(rqstp, ipm);
break;
}
return SVC_OK;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index cba85d1..b39e7e2 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -313,7 +313,7 @@
svc_release_skb(rqstp);
- svc_free_allpages(rqstp);
+ svc_free_res_pages(rqstp);
rqstp->rq_res.page_len = 0;
rqstp->rq_res.page_base = 0;
@@ -412,7 +412,8 @@
/* send head */
if (slen == xdr->head[0].iov_len)
flags = 0;
- len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags);
+ len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
+ xdr->head[0].iov_len, flags);
if (len != xdr->head[0].iov_len)
goto out;
slen -= xdr->head[0].iov_len;
@@ -437,8 +438,9 @@
}
/* send tail */
if (xdr->tail[0].iov_len) {
- result = kernel_sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage],
- ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1),
+ result = kernel_sendpage(sock, rqstp->rq_respages[0],
+ ((unsigned long)xdr->tail[0].iov_base)
+ & (PAGE_SIZE-1),
xdr->tail[0].iov_len, 0);
if (result > 0)
@@ -492,7 +494,12 @@
}
spin_unlock(&serv->sv_lock);
if (closesk)
+ /* Should unregister with portmap, but you cannot
+ * unregister just one protocol...
+ */
svc_delete_socket(closesk);
+ else if (toclose)
+ return -ENOENT;
return len;
}
EXPORT_SYMBOL(svc_sock_names);
@@ -703,9 +710,11 @@
if (len <= rqstp->rq_arg.head[0].iov_len) {
rqstp->rq_arg.head[0].iov_len = len;
rqstp->rq_arg.page_len = 0;
+ rqstp->rq_respages = rqstp->rq_pages+1;
} else {
rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
- rqstp->rq_argused += (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
+ rqstp->rq_respages = rqstp->rq_pages + 1 +
+ (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
}
if (serv->sv_stats)
@@ -946,7 +955,7 @@
struct svc_sock *svsk = rqstp->rq_sock;
struct svc_serv *serv = svsk->sk_server;
int len;
- struct kvec vec[RPCSVC_MAXPAGES];
+ struct kvec *vec;
int pnum, vlen;
dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
@@ -1044,15 +1053,17 @@
len = svsk->sk_reclen;
set_bit(SK_DATA, &svsk->sk_flags);
+ vec = rqstp->rq_vec;
vec[0] = rqstp->rq_arg.head[0];
vlen = PAGE_SIZE;
pnum = 1;
while (vlen < len) {
- vec[pnum].iov_base = page_address(rqstp->rq_argpages[rqstp->rq_argused++]);
+ vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]);
vec[pnum].iov_len = PAGE_SIZE;
pnum++;
vlen += PAGE_SIZE;
}
+ rqstp->rq_respages = &rqstp->rq_pages[pnum];
/* Now receive data */
len = svc_recvfrom(rqstp, vec, pnum, len);
@@ -1204,7 +1215,7 @@
struct svc_sock *svsk =NULL;
struct svc_serv *serv = rqstp->rq_server;
struct svc_pool *pool = rqstp->rq_pool;
- int len;
+ int len, i;
int pages;
struct xdr_buf *arg;
DECLARE_WAITQUEUE(wait, current);
@@ -1221,27 +1232,22 @@
"svc_recv: service %p, wait queue active!\n",
rqstp);
- /* Initialize the buffers */
- /* first reclaim pages that were moved to response list */
- svc_pushback_allpages(rqstp);
/* now allocate needed pages. If we get a failure, sleep briefly */
pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE;
- while (rqstp->rq_arghi < pages) {
- struct page *p = alloc_page(GFP_KERNEL);
- if (!p) {
- schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- continue;
+ for (i=0; i < pages ; i++)
+ while (rqstp->rq_pages[i] == NULL) {
+ struct page *p = alloc_page(GFP_KERNEL);
+ if (!p)
+ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+ rqstp->rq_pages[i] = p;
}
- rqstp->rq_argpages[rqstp->rq_arghi++] = p;
- }
/* Make arg->head point to first page and arg->pages point to rest */
arg = &rqstp->rq_arg;
- arg->head[0].iov_base = page_address(rqstp->rq_argpages[0]);
+ arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
arg->head[0].iov_len = PAGE_SIZE;
- rqstp->rq_argused = 1;
- arg->pages = rqstp->rq_argpages + 1;
+ arg->pages = rqstp->rq_pages + 1;
arg->page_base = 0;
/* save at least one page for response */
arg->page_len = (pages-2)*PAGE_SIZE;
@@ -1604,6 +1610,8 @@
sockfd_put(svsk->sk_sock);
else
sock_release(svsk->sk_sock);
+ if (svsk->sk_info_authunix != NULL)
+ svcauth_unix_info_release(svsk->sk_info_authunix);
kfree(svsk);
} else {
spin_unlock_bh(&serv->sv_lock);
@@ -1699,6 +1707,7 @@
rqstp->rq_prot = dr->prot;
rqstp->rq_addr = dr->addr;
rqstp->rq_daddr = dr->daddr;
+ rqstp->rq_respages = rqstp->rq_pages;
return dr->argslen<<2;
}
diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
index cac8f21..6a026f6 100644
--- a/scripts/Makefile.headersinst
+++ b/scripts/Makefile.headersinst
@@ -97,7 +97,7 @@
| $(HDRSED) > $@ || :
quiet_cmd_check = CHECK $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/.check.%,$(_dst)/%,$@)
- cmd_check = $(srctree)/scripts/hdrcheck.sh \
+ cmd_check = $(CONFIG_SHELL) $(srctree)/scripts/hdrcheck.sh \
$(INSTALL_HDR_PATH)/include $(subst /.check.,/,$@) $@
quiet_cmd_remove = REMOVE $(_dst)/$@
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 8681179..2489bd6 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -15,71 +15,42 @@
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_OPL3SA1) += opl3sa.o ad1848.o uart401.o
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.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
obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o
-obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o
-obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
obj-$(CONFIG_SOUND_UART6850) += uart6850.o
-obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o
obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o
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_SGALAXY) += sgalaxy.o ad1848.o
obj-$(CONFIG_SOUND_AD1816) += ad1816.o
obj-$(CONFIG_SOUND_AD1889) += ad1889.o ac97_codec.o
obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o
-obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.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_YMFPCI) += ymfpci.o ac97_codec.o
-ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y)
- obj-$(CONFIG_SOUND_YMFPCI) += opl3.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_NM256) += nm256_audio.o ac97.o
obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
-obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
-obj-$(CONFIG_SOUND_CMPCI) += cmpci.o
-ifeq ($(CONFIG_SOUND_CMPCI_FM),y)
- obj-$(CONFIG_SOUND_CMPCI) += sound.o opl3.o
-endif
-ifeq ($(CONFIG_SOUND_CMPCI_MIDI),y)
- obj-$(CONFIG_SOUND_CMPCI) += sound.o mpu401.o
-endif
-obj-$(CONFIG_SOUND_ES1370) += es1370.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o
obj-$(CONFIG_SOUND_VRC5477) += nec_vrc5477.o ac97_codec.o
-obj-$(CONFIG_SOUND_AU1000) += au1000.o ac97_codec.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
-obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
-obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
-obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
-obj-$(CONFIG_SOUND_HARMONY) += harmony.o
obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
-obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o
obj-$(CONFIG_SOUND_BT878) += btaudio.o
-obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o
-obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o
-obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o ac97_codec.o
obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
ifeq ($(CONFIG_MIDI_EMU10K1),y)
@@ -87,28 +58,25 @@
endif
obj-$(CONFIG_SOUND_EMU10K1) += emu10k1/
-obj-$(CONFIG_SOUND_CS4281) += cs4281/
obj-$(CONFIG_DMASOUND) += dmasound/
# Declare multi-part drivers.
sound-objs := \
- dev_table.o soundcard.o sound_syms.o \
- audio.o audio_syms.o dmabuf.o \
- midi_syms.o midi_synth.o midibuf.o \
- sequencer.o sequencer_syms.o sound_timer.o sys_timer.o
+ dev_table.o soundcard.o \
+ audio.o dmabuf.o \
+ midi_synth.o midibuf.o \
+ sequencer.o sound_timer.o sys_timer.o
-gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
sb-objs := sb_card.o
sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o
vidc_mod-objs := vidc.o vidc_fill.o
-wavefront-objs := wavfront.o wf_midi.o yss225.o
hostprogs-y := bin2hex hex2hex
# Files generated that shall be removed upon make clean
-clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \
+clean-files := msndperm.c msndinit.c pndsperm.c pndspini.c \
pss_boot.h trix_boot.h
# Firmware files that need translation
@@ -118,21 +86,6 @@
# will be forced to be remade.
#
-# Turtle Beach Maui / Tropez
-
-$(obj)/maui.o: $(obj)/maui_boot.h
-
-ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
- $(obj)/maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) $(obj)/bin2hex
- $(obj)/bin2hex -i maui_os < $< > $@
-else
- $(obj)/maui_boot.h:
- ( \
- echo 'static unsigned char * maui_os = NULL;'; \
- echo 'static int maui_osLen = 0;'; \
- ) > $@
-endif
-
# Turtle Beach MultiSound
ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y)
diff --git a/sound/oss/ac97.c b/sound/oss/ac97.c
index 3ba6d91..72cf4ed 100644
--- a/sound/oss/ac97.c
+++ b/sound/oss/ac97.c
@@ -112,25 +112,6 @@
return 0;
}
-/* Reset the mixer to the currently saved settings. */
-int
-ac97_reset (struct ac97_hwint *dev)
-{
- int x;
-
- if (dev->reset_device (dev))
- return -1;
-
- /* Now set the registers back to their last-written values. */
- for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
- int regnum = mixerRegs[x].ac97_regnum;
- int value = dev->last_written_mixer_values [regnum / 2];
- if (value >= 0)
- ac97_put_register (dev, regnum, value);
- }
- return 0;
-}
-
/* Return the contents of register REG; use the cache if the value in it
is valid. Returns a negative error code on failure. */
static int
@@ -441,7 +422,6 @@
EXPORT_SYMBOL(ac97_set_values);
EXPORT_SYMBOL(ac97_put_register);
EXPORT_SYMBOL(ac97_mixer_ioctl);
-EXPORT_SYMBOL(ac97_reset);
MODULE_LICENSE("GPL");
diff --git a/sound/oss/ac97.h b/sound/oss/ac97.h
index 77d454e..01837a9 100644
--- a/sound/oss/ac97.h
+++ b/sound/oss/ac97.h
@@ -192,9 +192,6 @@
extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
void __user * arg);
-/* Do a complete reset on the AC97 mixer, restoring all mixer registers to
- the current values. Normally used after an APM resume event. */
-extern int ac97_reset (struct ac97_hwint *dev);
#endif
/*
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index 972327c..602db49 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -1399,95 +1399,6 @@
EXPORT_SYMBOL(ac97_set_adc_rate);
-int ac97_save_state(struct ac97_codec *codec)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(ac97_save_state);
-
-int ac97_restore_state(struct ac97_codec *codec)
-{
- int i;
- unsigned int left, right, val;
-
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!supported_mixer(codec, i))
- continue;
-
- val = codec->mixer_state[i];
- right = val >> 8;
- left = val & 0xff;
- codec->write_mixer(codec, i, left, right);
- }
- return 0;
-}
-
-EXPORT_SYMBOL(ac97_restore_state);
-
-/**
- * ac97_register_driver - register a codec helper
- * @driver: Driver handler
- *
- * Register a handler for codecs matching the codec id. The handler
- * attach function is called for all present codecs and will be
- * called when new codecs are discovered.
- */
-
-int ac97_register_driver(struct ac97_driver *driver)
-{
- struct list_head *l;
- struct ac97_codec *c;
-
- mutex_lock(&codec_mutex);
- INIT_LIST_HEAD(&driver->list);
- list_add(&driver->list, &codec_drivers);
-
- list_for_each(l, &codecs)
- {
- c = list_entry(l, struct ac97_codec, list);
- if(c->driver != NULL || ((c->model ^ driver->codec_id) & driver->codec_mask))
- continue;
- if(driver->probe(c, driver))
- continue;
- c->driver = driver;
- }
- mutex_unlock(&codec_mutex);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ac97_register_driver);
-
-/**
- * ac97_unregister_driver - unregister a codec helper
- * @driver: Driver handler
- *
- * Unregister a handler for codecs matching the codec id. The handler
- * remove function is called for all matching codecs.
- */
-
-void ac97_unregister_driver(struct ac97_driver *driver)
-{
- struct list_head *l;
- struct ac97_codec *c;
-
- mutex_lock(&codec_mutex);
- list_del_init(&driver->list);
-
- list_for_each(l, &codecs)
- {
- c = list_entry(l, struct ac97_codec, list);
- if (c->driver == driver) {
- driver->remove(c, driver);
- c->driver = NULL;
- }
- }
-
- mutex_unlock(&codec_mutex);
-}
-
-EXPORT_SYMBOL_GPL(ac97_unregister_driver);
-
static int swap_headphone(int remove_master)
{
struct list_head *l;
diff --git a/sound/oss/ac97_plugin_ad1980.c b/sound/oss/ac97_plugin_ad1980.c
deleted file mode 100644
index 24a9acd..0000000
--- a/sound/oss/ac97_plugin_ad1980.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- ac97_plugin_ad1980.c Copyright (C) 2003 Red Hat, Inc. All rights reserved.
-
- The contents of this file are subject to the Open Software License version 1.1
- that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is
- included herein by reference.
-
- Alternatively, the contents of this file may be used under the
- terms of the GNU General Public License version 2 (the "GPL") as
- distributed in the kernel source COPYING file, in which
- case the provisions of the GPL are applicable instead of the
- above. If you wish to allow the use of your version of this file
- only under the terms of the GPL and not to allow others to use
- your version of this file under the OSL, indicate your decision
- by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the OSL or the GPL.
-
- Authors: Alan Cox <alan@redhat.com>
-
- This is an example codec plugin. This one switches the connections
- around to match the setups some vendors use with audio switched to
- non standard front connectors not the normal rear ones
-
- This code primarily exists to demonstrate how to use the codec
- interface
-
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ac97_codec.h>
-
-/**
- * ad1980_remove - codec remove callback
- * @codec: The codec that is being removed
- *
- * This callback occurs when an AC97 codec is being removed. A
- * codec remove call will not occur for a codec during that codec
- * probe callback.
- *
- * Most drivers will need to lock their remove versus their
- * use of the codec after the probe function.
- */
-
-static void __devexit ad1980_remove(struct ac97_codec *codec, struct ac97_driver *driver)
-{
- /* Nothing to do in the simple example */
-}
-
-
-/**
- * ad1980_probe - codec found callback
- * @codec: ac97 codec matching the idents
- * @driver: ac97_driver it matched
- *
- * This entry point is called when a codec is found which matches
- * the driver. At the point it is called the codec is basically
- * operational, mixer operations have been initialised and can
- * be overriden. Called in process context. The field driver_private
- * is available for the driver to use to store stuff.
- *
- * The caller can claim the device by returning zero, or return
- * a negative error code.
- */
-
-static int ad1980_probe(struct ac97_codec *codec, struct ac97_driver *driver)
-{
- u16 control;
-
-#define AC97_AD_MISC 0x76
-
- /* Switch the inputs/outputs over (from Dell code) */
- control = codec->codec_read(codec, AC97_AD_MISC);
- codec->codec_write(codec, AC97_AD_MISC, control | 0x4420);
-
- /* We could refuse the device since we dont need to hang around,
- but we will claim it */
- return 0;
-}
-
-
-static struct ac97_driver ad1980_driver = {
- .codec_id = 0x41445370,
- .codec_mask = 0xFFFFFFFF,
- .name = "AD1980 example",
- .probe = ad1980_probe,
- .remove = __devexit_p(ad1980_remove),
-};
-
-/**
- * ad1980_exit - module exit path
- *
- * Our module is being unloaded. At this point unregister_driver
- * will call back our remove handler for any existing codecs. You
- * may not unregister_driver from interrupt context or from a
- * probe/remove callback.
- */
-
-static void ad1980_exit(void)
-{
- ac97_unregister_driver(&ad1980_driver);
-}
-
-/**
- * ad1980_init - set up ad1980 handlers
- *
- * After we call the register function it will call our probe
- * function for each existing matching device before returning to us.
- * Any devices appearing afterwards whose id's match the codec_id
- * will also cause the probe function to be called.
- * You may not register_driver from interrupt context or from a
- * probe/remove callback.
- */
-
-static int ad1980_init(void)
-{
- return ac97_register_driver(&ad1980_driver);
-}
-
-module_init(ad1980_init);
-module_exit(ad1980_exit);
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index f6b6b88..257b753 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -195,6 +195,7 @@
static void ad1848_halt_input(int dev);
static void ad1848_halt_output(int dev);
static void ad1848_trigger(int dev, int bits);
+static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy);
#ifndef EXCLUDE_TIMERS
static int ad1848_tmr_install(int dev);
@@ -2195,7 +2196,7 @@
printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);
}
-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
{
unsigned char status;
ad1848_info *devc;
@@ -2802,7 +2803,6 @@
EXPORT_SYMBOL(ad1848_init);
EXPORT_SYMBOL(ad1848_unload);
EXPORT_SYMBOL(ad1848_control);
-EXPORT_SYMBOL(adintr);
EXPORT_SYMBOL(probe_ms_sound);
EXPORT_SYMBOL(attach_ms_sound);
EXPORT_SYMBOL(unload_ms_sound);
diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h
index d0573b0..b95ebe2 100644
--- a/sound/oss/ad1848.h
+++ b/sound/oss/ad1848.h
@@ -18,7 +18,6 @@
int ad1848_detect (struct resource *ports, int *flags, int *osp);
int ad1848_control(int cmd, int arg);
-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs * dummy);
void attach_ms_sound(struct address_info * hw_config, struct resource *ports, struct module * owner);
int probe_ms_sound(struct address_info *hw_config, struct resource *ports);
diff --git a/sound/oss/ali5455.c b/sound/oss/ali5455.c
deleted file mode 100644
index 70dcd70..0000000
--- a/sound/oss/ali5455.c
+++ /dev/null
@@ -1,3735 +0,0 @@
-/*
- * ALI ali5455 and friends ICH driver for Linux
- * LEI HU <Lei_Hu@ali.com.tw>
- *
- * Built from:
- * drivers/sound/i810_audio
- *
- * The ALi 5455 is similar but not quite identical to the Intel ICH
- * series of controllers. Its easier to keep the driver separated from
- * the i810 driver.
- *
- * 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.
- *
- *
- * ALi 5455 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.
- *
- * If you need to force a specific rate set the clocking= option
- *
- */
-
-#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 <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/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-
-#ifndef PCI_DEVICE_ID_ALI_5455
-#define PCI_DEVICE_ID_ALI_5455 0x5455
-#endif
-
-#ifndef PCI_VENDOR_ID_ALI
-#define PCI_VENDOR_ID_ALI 0x10b9
-#endif
-
-static int strict_clocking = 0;
-static unsigned int clocking = 0;
-static unsigned int codec_pcmout_share_spdif_locked = 0;
-static unsigned int codec_independent_spdif_locked = 0;
-static unsigned int controller_pcmout_share_spdif_locked = 0;
-static unsigned int controller_independent_spdif_locked = 0;
-static unsigned int globel = 0;
-
-#define ADC_RUNNING 1
-#define DAC_RUNNING 2
-#define CODEC_SPDIFOUT_RUNNING 8
-#define CONTROLLER_SPDIFOUT_RUNNING 4
-
-#define SPDIF_ENABLE_OUTPUT 4 /* bits 0,1 are PCM */
-
-#define ALI5455_FMT_16BIT 1
-#define ALI5455_FMT_STEREO 2
-#define ALI5455_FMT_MASK 3
-
-#define SPDIF_ON 0x0004
-#define SURR_ON 0x0010
-#define CENTER_LFE_ON 0x0020
-#define VOL_MUTED 0x8000
-
-
-#define ALI_SPDIF_OUT_CH_STATUS 0xbf
-/* 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 ali channel */
-#define SG_LEN 32
-struct ali_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.
- */
-
-#define ENUM_ENGINE(PRE,DIG) \
-enum { \
- 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##_CR = 0x##DIG##b /* Control Register */ \
-}
-
-ENUM_ENGINE(OFF, 0); /* Offsets */
-ENUM_ENGINE(PI, 4); /* PCM In */
-ENUM_ENGINE(PO, 5); /* PCM Out */
-ENUM_ENGINE(MC, 6); /* Mic In */
-ENUM_ENGINE(CODECSPDIFOUT, 7); /* CODEC SPDIF OUT */
-ENUM_ENGINE(CONTROLLERSPDIFIN, A); /* CONTROLLER SPDIF In */
-ENUM_ENGINE(CONTROLLERSPDIFOUT, B); /* CONTROLLER SPDIF OUT */
-
-
-enum {
- ALI_SCR = 0x00, /* System Control Register */
- ALI_SSR = 0x04, /* System Status Register */
- ALI_DMACR = 0x08, /* DMA Control Register */
- ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */
- ALI_INTERFACECR = 0x10, /* Interface Control Register */
- ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */
- ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */
- ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */
- ALI_CPR = 0x20, /* Command Port Register */
- ALI_SPR = 0x24, /* Status Port Register */
- ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */
- ALI_TTSR = 0x30, /* Transmit Tag Slot Register */
- ALI_RTSR = 0x34, /* Receive Tag Slot Register */
- ALI_CSPSR = 0x38, /* Command/Status Port Status Register */
- ALI_CAS = 0x3c, /* Codec Write Semaphore Register */
- ALI_SPDIFCSR = 0xf8, /* spdif channel status register */
- ALI_SPDIFICS = 0xfc /* spdif interface control/status */
-};
-
-// x-status register(x:pcm in ,pcm out, mic in,)
-/* 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) */ //not eqult intel
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */// by interrupt status register finish
-
-#define INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */
-#define INT_SPDIFIN (1<<22)
-#define INT_CODECSPDIFOUT (1<<19)
-#define INT_MICIN (1<<18)
-#define INT_PCMOUT (1<<17)
-#define INT_PCMIN (1<<16)
-#define INT_CPRAIS (1<<7)
-#define INT_SPRAIS (1<<5)
-#define INT_GPIO (1<<1)
-#define INT_MASK (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
-
-#define DRIVER_VERSION "0.02ac"
-
-/* magic numbers to protect our data structures */
-#define ALI5455_CARD_MAGIC 0x5072696E /* "Prin" */
-#define ALI5455_STATE_MAGIC 0x63657373 /* "cess" */
-#define ALI5455_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH 5 //I think 5 channel
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 2
-
-/* 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 };
-
-#define ALI5455
-static char *card_names[] = {
- "ALI 5455"
-};
-
-static struct pci_device_id ali_pci_tbl[] = {
- {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, ali_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 ali_state {
- unsigned int magic;
- struct ali_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 ali_channel *read_channel;
- struct ali_channel *write_channel;
- struct ali_channel *codec_spdifout_channel;
- struct ali_channel *controller_spdifout_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 ali_card {
- struct ali_channel channel[5];
- unsigned int magic;
-
- /* We keep ali5455 cards in a linked list */
- struct ali_card *next;
-
- /* The ali has a certain amount of cross channel interaction
- so we use a single per card lock */
- spinlock_t lock;
- spinlock_t ac97_lock;
-
- /* PCI device stuff */
- struct pci_dev *pci_dev;
- u16 pci_id;
-#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 */
- struct ac97_codec *ac97_codec[NR_AC97];
- struct ali_state *states[NR_HW_CH];
-
- u16 ac97_features;
- u16 ac97_status;
- u16 channels;
-
- /* hardware resources */
- unsigned long iobase;
-
- u32 irq;
-
- /* Function support */
- struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);
- struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);
- struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);
- struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);
- struct ali_channel *(*alloc_controller_spdifout_channel) (struct ali_card *);
- void (*free_pcm_channel) (struct ali_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;
-};
-
-
-static struct ali_card *devs = NULL;
-
-static int ali_open_mixdev(struct inode *inode, struct file *file);
-static int ali_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);
-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card)
-{
- if (card->channel[1].used == 1)
- return NULL;
- card->channel[1].used = 1;
- return &card->channel[1];
-}
-
-static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card)
-{
- if (card->channel[0].used == 1)
- return NULL;
- card->channel[0].used = 1;
- return &card->channel[0];
-}
-
-static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card)
-{
- if (card->channel[2].used == 1)
- return NULL;
- card->channel[2].used = 1;
- return &card->channel[2];
-}
-
-static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card)
-{
- if (card->channel[3].used == 1)
- return NULL;
- card->channel[3].used = 1;
- return &card->channel[3];
-}
-
-static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card)
-{
- if (card->channel[4].used == 1)
- return NULL;
- card->channel[4].used = 1;
- return &card->channel[4];
-}
-static void ali_free_pcm_channel(struct ali_card *card, int channel)
-{
- card->channel[channel].used = 0;
-}
-
-
-//add support codec spdif out
-static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
-{
- unsigned long id = 0L;
-
- id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);
- id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
- switch (id) {
- case 0x41445361: /* AD1886 */
- if (rate == 48000) {
- return 1;
- }
- break;
- case 0x414c4720: /* ALC650 */
- 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);
-}
-
-/* ali_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 void ali_set_spdif_output(struct ali_state *state, int slots,
- int rate)
-{
- int vol;
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if (!(state->card->ac97_features & 4)) {
- state->card->ac97_status &= ~SPDIF_ON;
- } else {
- if (slots == -1) { /* Turn off S/PDIF */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-
- /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
- if (!(state->card->ac97_status & VOL_MUTED)) {
- aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
- (aud_reg & ~VOL_MUTED));
- }
- state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
- return;
- }
-
- vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- state->card->ac97_status = vol & VOL_MUTED;
-
- /* Set S/PDIF transmitter sample rate */
- aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
- switch (rate) {
- case 32000:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
- break;
- case 44100:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
- break;
- case 48000:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
- break;
- default:
- /* turn off S/PDIF */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
- state->card->ac97_status &= ~SPDIF_ON;
- return;
- }
-
- ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
-
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
- aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
- aud_reg |= 0x0002;
- ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg);
- udelay(1);
-
- state->card->ac97_status |= SPDIF_ON;
-
- /* Check to make sure the configuration is valid */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- if (!(aud_reg & 0x0400)) {
- /* turn off S/PDIF */
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
- state->card->ac97_status &= ~SPDIF_ON;
- return;
- }
- if (codec_independent_spdif_locked > 0) {
- aud_reg = ali_ac97_get(codec, 0x6a);
- ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
- }
- /* Mute the analog output */
- /* Should this only mute the PCM volume??? */
- }
-}
-
-/* ali_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 ali_set_dac_channels(struct ali_state *state, int channel)
-{
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- aud_reg = ali_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;
- }
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-/* set playback sample rate */
-static unsigned int ali_set_dac_rate(struct ali_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_dac_rate(codec, rate);
- if (new_rate != rate) {
- dmabuf->rate = (new_rate * 48000) / clocking;
- }
- rate = new_rate;
- return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int ali_set_adc_rate(struct ali_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;
- }
- return dmabuf->rate;
-}
-
-/* set codec independent spdifout sample rate */
-static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
- unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (!(state->card->ac97_features & 0x0001)) {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- return dmabuf->rate;
-}
-
-/* set controller independent spdif out function sample rate */
-static void ali_set_spdifout_rate(struct ali_state *state,
- 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;
- }
-
- ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out
-
- ch_st_sel |= 0x80; //select right
- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
- outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2));
-
- ch_st_sel &= (~0x80); //select left
- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
- outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
- called with spinlock held! */
-
-static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int civ, offset, port, port_picb;
- unsigned int data;
-
- if (!dmabuf->enable)
- return 0;
-
- if (rec == 1)
- port = state->card->iobase + dmabuf->read_channel->port;
- else if (rec == 2)
- port = state->card->iobase + dmabuf->codec_spdifout_channel->port;
- else if (rec == 3)
- port = state->card->iobase + dmabuf->controller_spdifout_channel->port;
- else
- port = state->card->iobase + dmabuf->write_channel->port;
-
- port_picb = port + OFF_PICB;
-
- do {
- civ = inb(port + OFF_CIV) & 31;
- offset = inw(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 thdelay is more than long enough
- * that we won't have to worry about the chip still being
- * out of sync with reality ;-)
- */
- } while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb));
-
- data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
- if (inw(port_picb) == 0)
- data -= 2048;
-
- return data;
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- dmabuf->enable &= ~ADC_RUNNING;
-
- outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR);
- udelay(1);
-
- outb(0, card->iobase + PI_CR);
- while (inb(card->iobase + PI_CR) != 0);
-
- // now clear any latent interrupt bits (like the halt bit)
- outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_adc(struct ali_state *state)
-{
- struct ali_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 ali_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;
- outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
- if (state->card->channel[0].used == 1)
- outl(1, state->card->iobase + ALI_DMACR); // DMA CONTROL REGISTRER
- udelay(100);
- if (state->card->channel[2].used == 1)
- outl((1 << 2), state->card->iobase + ALI_DMACR); //DMA CONTROL REGISTER
- udelay(100);
- }
-}
-
-static void start_adc(struct ali_state *state)
-{
- struct ali_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 ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- dmabuf->enable &= ~DAC_RUNNING;
- outl(0x00020000, card->iobase + 0x08);
- outb(0, card->iobase + PO_CR);
- while (inb(card->iobase + PO_CR) != 0)
- cpu_relax();
-
- outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR);
-
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_dac(struct ali_state *state)
-{
- struct ali_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 ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->enable |= DAC_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR);
- outl((1 << 1), state->card->iobase + 0x08); //dma control register
- }
-}
-
-static void start_dac(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __start_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop codec and controller spdif out (lock held) */
-static inline void __stop_spdifout(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- if (codec_independent_spdif_locked > 0) {
- dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING;
- outl((1 << 19), card->iobase + 0x08);
- outb(0, card->iobase + CODECSPDIFOUT_CR);
-
- while (inb(card->iobase + CODECSPDIFOUT_CR) != 0)
- cpu_relax();
-
- outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR);
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING;
- outl((1 << 23), card->iobase + 0x08);
- outb(0, card->iobase + CONTROLLERSPDIFOUT_CR);
- while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0)
- cpu_relax();
- outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR);
- }
- }
-}
-
-static void stop_spdifout(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __stop_spdifout(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_spdifout(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- if (codec_independent_spdif_locked > 0) {
- dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);
- outl((1 << 3), state->card->iobase + 0x08); //dma control register
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);
- outl((1 << 7), state->card->iobase + 0x08); //dma control register
- }
- }
- }
-}
-
-static void start_spdifout(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __start_spdifout(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback , recording,spdif out buffer should be allocated separately */
-static int alloc_dmabuf(struct ali_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;
-
- 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 ali_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 ali_state *state, unsigned rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_channel *c = NULL;
- 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);
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- __stop_spdifout(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->userfragsize = dmabuf->ossfragsize;
- dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;
-
- memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
- if (dmabuf->ossmaxfrags == 4) {
- fragint = 8;
- dmabuf->fragshift = 2;
- } else if (dmabuf->ossmaxfrags == 8) {
- fragint = 4;
- dmabuf->fragshift = 3;
- } else if (dmabuf->ossmaxfrags == 16) {
- fragint = 2;
- dmabuf->fragshift = 4;
- } else {
- fragint = 1;
- dmabuf->fragshift = 5;
- }
- /*
- * Now set up the ring
- */
-
- if (rec == 1)
- c = dmabuf->read_channel;
- else if (rec == 2)
- c = dmabuf->codec_spdifout_channel;
- else if (rec == 3)
- c = dmabuf->controller_spdifout_channel;
- else if (rec == 0)
- c = dmabuf->write_channel;
- if (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 =
- virt_to_bus(dmabuf->rawbuf +
- dmabuf->fragsize * i);
- // the card will always be doing 16bit stereo
- sg->control = dmabuf->fragsamples;
- sg->control |= CON_BUFPAD; //I modify
- // 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);
- outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */
- outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
- outb(0, state->card->iobase + c->port + OFF_CIV);
- outb(0, state->card->iobase + c->port + OFF_LVI);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
- return 0;
-}
-
-static void __ali_update_lvi(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int x, port;
- port = state->card->iobase;
- if (rec == 1)
- port += dmabuf->read_channel->port;
- else if (rec == 2)
- port += dmabuf->codec_spdifout_channel->port;
- else if (rec == 3)
- port += dmabuf->controller_spdifout_channel->port;
- else if (rec == 0)
- port += dmabuf->write_channel->port;
- /* 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_{dac,adc}, things will operate properly
- */
- if (!dmabuf->enable && dmabuf->ready) {
- if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_adc(state);
- while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_dac(state);
- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- if (codec_independent_spdif_locked > 0) {
- // outb((inb(port+OFF_CIV))&31, port+OFF_LVI);
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_spdifout(state);
- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else {
- if (controller_independent_spdif_locked > 0) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_spdifout(state);
- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- }
- }
- }
- }
-
- /* swptr - 1 is the tail of our transfer */
- x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
- x /= dmabuf->fragsize;
- outb(x, port + OFF_LVI);
-}
-
-static void ali_update_lvi(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- if (!dmabuf->ready)
- return;
- spin_lock_irqsave(&state->card->lock, flags);
- __ali_update_lvi(state, rec);
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void ali_update_ptr(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned hwptr;
- int diff;
-
- /* error handling and process wake up for DAC */
- if (dmabuf->enable == ADC_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 1);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- 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 ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) {
- printk(KERN_WARNING "ali_audio: DMA overrun on read\n");
- dmabuf->error++;
- }
- }
- if (dmabuf->count > dmabuf->userfragsize)
- wake_up(&dmabuf->wait);
- }
- /* error handling and process wake up for DAC */
- if (dmabuf->enable == DAC_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 0);
- diff =
- (dmabuf->dmasize + hwptr -
- dmabuf->hwptr) % dmabuf->dmasize;
-#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 ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) {
- printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
- printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
- inb(state->card->iobase + PO_CIV) & 31,
- inb(state->card->iobase + PO_LVI) & 31,
- dmabuf->hwptr,
- dmabuf->count);
- dmabuf->error++;
- }
- }
- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
- wake_up(&dmabuf->wait);
- }
-
- /* error handling and process wake up for CODEC SPDIF OUT */
- if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 2);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- 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 ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) {
- printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
- printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
- inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31,
- inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31,
- dmabuf->hwptr, dmabuf->count);
- dmabuf->error++;
- }
- }
- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
- wake_up(&dmabuf->wait);
- }
- /* error handling and process wake up for CONTROLLER SPDIF OUT */
- if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 3);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- 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 ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) {
- printk(KERN_WARNING
- "ali_audio: DMA overrun on write\n");
- printk("ali_audio: CIV %d, LVI %d, hwptr %x, "
- "count %d\n",
- inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31,
- inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31,
- dmabuf->hwptr, dmabuf->count);
- dmabuf->error++;
- }
- }
- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
- wake_up(&dmabuf->wait);
- }
-}
-
-static inline int ali_get_free_write_space(struct
- ali_state
- *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int free;
-
- if (dmabuf->count < 0) {
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- }
- free = dmabuf->dmasize - dmabuf->swptr;
- if ((dmabuf->count + free) > dmabuf->dmasize){
- free = dmabuf->dmasize - dmabuf->count;
- }
- return free;
-}
-
-static inline int ali_get_available_read_data(struct
- ali_state
- *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int avail;
- ali_update_ptr(state);
- // catch overruns during record
- if (dmabuf->count > dmabuf->dmasize) {
- dmabuf->count = dmabuf->dmasize;
- dmabuf->swptr = dmabuf->hwptr;
- }
- avail = dmabuf->count;
- avail -= (dmabuf->hwptr % dmabuf->fragsize);
- if (avail < 0)
- return (0);
- return (avail);
-}
-
-static int drain_dac(struct ali_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;
- }
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
-
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- count = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
- if (count <= 0)
- break;
- /*
- * 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.
- */
- if (!dmabuf->enable) {
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- ali_update_lvi(state, 0);
- }
- if (signal_pending(current) && signals_allowed) {
- break;
- }
-
- /* 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(TASK_INTERRUPTIBLE);
- /*
- * 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 "ali_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 int drain_spdifout(struct ali_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_spdifout(state);
- return 0;
- }
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
-
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- count = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
- if (count <= 0)
- break;
- /*
- * 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.
- */
- if (!dmabuf->enable) {
- if (codec_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 2);
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 3);
- }
- }
- }
- if (signal_pending(current) && signals_allowed) {
- break;
- }
-
- /* 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(TASK_INTERRUPTIBLE);
- /*
- * 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 "ali_audio: drain_spdifout, 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_spdifout(state);
- return 0;
-}
-
-static void ali_channel_interrupt(struct ali_card *card)
-{
- int i, count;
-
- for (i = 0; i < NR_HW_CH; i++) {
- struct ali_state *state = card->states[i];
- struct ali_channel *c = NULL;
- struct dmabuf *dmabuf;
- unsigned long port = card->iobase;
- u16 status;
- if (!state)
- continue;
- if (!state->dmabuf.ready)
- continue;
- dmabuf = &state->dmabuf;
- if (codec_independent_spdif_locked > 0) {
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
- c = dmabuf->codec_spdifout_channel;
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- c = dmabuf->controller_spdifout_channel;
- } else {
- if (dmabuf->enable & DAC_RUNNING) {
- c = dmabuf->write_channel;
- } else if (dmabuf->enable & ADC_RUNNING) {
- c = dmabuf->read_channel;
- } else
- continue;
- }
- }
- port += c->port;
-
- status = inw(port + OFF_SR);
-
- if (status & DMA_INT_COMPLETE) {
- /* only wake_up() waiters if this interrupt signals
- * us being beyond a userfragsize of data open or
- * available, and ali_update_ptr() does that for
- * us
- */
- ali_update_ptr(state);
- }
-
- if (status & DMA_INT_LVI) {
- ali_update_ptr(state);
- wake_up(&dmabuf->wait);
-
- if (dmabuf->enable & DAC_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & ADC_RUNNING)
- count = dmabuf->dmasize - dmabuf->count;
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else count = 0;
-
- if (count > 0) {
- if (dmabuf->enable & DAC_RUNNING)
- outl((1 << 1), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- outl((1 << 3), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- outl((1 << 7), state->card->iobase + ALI_DMACR);
- } else {
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- dmabuf->enable = 0;
- wake_up(&dmabuf->wait);
- }
-
- }
- if (!(status & DMA_INT_DCH)) {
- ali_update_ptr(state);
- wake_up(&dmabuf->wait);
- if (dmabuf->enable & DAC_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & ADC_RUNNING)
- count = dmabuf->dmasize - dmabuf->count;
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else
- count = 0;
-
- if (count > 0) {
- if (dmabuf->enable & DAC_RUNNING)
- outl((1 << 1), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- outl((1 << 3), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- outl((1 << 7), state->card->iobase + ALI_DMACR);
- } else {
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- dmabuf->enable = 0;
- wake_up(&dmabuf->wait);
- }
- }
- outw(status & DMA_INT_MASK, port + OFF_SR);
- }
-}
-
-static irqreturn_t ali_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct ali_card *card = (struct ali_card *) dev_id;
- u32 status;
- u16 status2;
-
- spin_lock(&card->lock);
- status = inl(card->iobase + ALI_INTERRUPTSR);
- if (!(status & INT_MASK)) {
- spin_unlock(&card->lock);
- return IRQ_NONE; /* not for us */
- }
-
- if (codec_independent_spdif_locked > 0) {
- if (globel == 0) {
- globel += 1;
- status2 = inw(card->iobase + 0x76);
- outw(status2 | 0x000c, card->iobase + 0x76);
- } else {
- if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
- ali_channel_interrupt(card);
- }
- } else {
- if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
- ali_channel_interrupt(card);
- }
-
- /* clear 'em */
- outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
- 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 ali_read(struct file *file, char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_card *card = state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt;
- DECLARE_WAITQUEUE(waita, current);
-#ifdef DEBUG2
- printk("ali_audio: ali_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;
- 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;
- }
- swptr = dmabuf->swptr;
- cnt = ali_get_available_read_data(state);
- // 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;
- /* Lop off the last two bits to force the code to always
- * write in full samples. This keeps software that sets
- * O_NONBLOCK but doesn't check the return value of the
- * write call from getting things out of state where they
- * think a full 4 byte sample was written when really only
- * a portion was, resulting in odd sound and stereo
- * hysteresis.
- */
- cnt &= ~0x3;
- 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.
- */
- ali_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)) {
- printk(KERN_ERR
- "ali_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);
- /* 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 = (swptr + cnt) % dmabuf->dmasize;
- spin_lock_irqsave(&card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- continue;
- }
- dmabuf->swptr = swptr;
- dmabuf->count -= cnt;
- spin_unlock_irqrestore(&card->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
-done:
- ali_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 ali_write(struct file *file,
- const char __user *buffer, size_t count, loff_t * ppos)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_card *card = state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr = 0;
- int cnt, x;
- DECLARE_WAITQUEUE(waita, current);
-#ifdef DEBUG2
- printk("ali_audio: ali_write called, count = %d\n", count);
-#endif
- if (dmabuf->mapped)
- return -ENXIO;
- if (dmabuf->enable & ADC_RUNNING)
- return -ENODEV;
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->codec_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card);
- if (!dmabuf->codec_spdifout_channel)
- return -EBUSY;
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->controller_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card);
- if (!dmabuf->controller_spdifout_channel)
- return -EBUSY;
- }
- } else {
- if (!dmabuf->write_channel) {
- dmabuf->ready = 0;
- dmabuf->write_channel =
- card->alloc_pcm_channel(card);
- if (!dmabuf->write_channel)
- return -EBUSY;
- }
- }
- }
-
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
- return ret;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
- return ret;
- } else {
-
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- }
- }
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 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;
- }
-
- swptr = dmabuf->swptr;
- cnt = ali_get_free_write_space(state);
- /* 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
- "ali_audio: ali_write: %d bytes available space\n",
- cnt);
-#endif
- if (cnt > count)
- cnt = count;
- /* Lop off the last two bits to force the code to always
- * write in full samples. This keeps software that sets
- * O_NONBLOCK but doesn't check the return value of the
- * write call from getting things out of state where they
- * think a full 4 byte sample was written when really only
- * a portion was, resulting in odd sound and stereo
- * hysteresis.
- */
- cnt &= ~0x3;
- 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
- */
- if (codec_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 2);
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 3);
- } else {
-
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- ali_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. */
-
- /* FIXME - do timeout handling here !! */
- schedule_timeout(tmo >= 2 ? tmo : 2);
-
- 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 = (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;
- dmabuf->count += cnt;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- if (swptr % dmabuf->fragsize) {
- x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
- memset(dmabuf->rawbuf + swptr, '\0', x);
- }
-ret:
- if (codec_independent_spdif_locked > 0) {
- ali_update_lvi(state, 2);
- } else {
- if (controller_independent_spdif_locked > 0) {
- ali_update_lvi(state, 3);
- } else {
- ali_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 ali_poll(struct file *file, struct poll_table_struct
- *wait)
-{
- struct ali_state *state = (struct ali_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);
- ali_update_ptr(state);
- if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
- if (dmabuf->count >= (signed) dmabuf->fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) {
- if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
- return mask;
-}
-
-static int ali_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct ali_state *state = (struct ali_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;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_channel *c = NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- unsigned int i_scr;
- 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("ali_audio: ali_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 (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
- c = dmabuf->codec_spdifout_channel;
- __stop_spdifout(state);
- }
- if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
- c = dmabuf->controller_spdifout_channel;
- __stop_spdifout(state);
- }
- if (c != NULL) {
- outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */
- outl(virt_to_bus(&c->sg[0]),
- state->card->iobase + c->port + OFF_BDBAR);
- outb(0, state->card->iobase + c->port + OFF_CIV);
- outb(0, state->card->iobase + c->port + OFF_LVI);
- }
-
- 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 (codec_independent_spdif_locked > 0) {
- if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING
- || file->f_flags & O_NONBLOCK)
- return 0;
- if ((val = drain_spdifout(state, 1)))
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (dmabuf->enable !=
- CONTROLLER_SPDIFOUT_RUNNING
- || file->f_flags & O_NONBLOCK)
- return 0;
- if ((val = drain_spdifout(state, 1)))
- return val;
- } else {
- 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 */
- /* RELTEK ALC650 only support 48000, need to check that */
- if (ali_valid_spdif_rate(codec, val)) {
- if (codec_independent_spdif_locked > 0) {
- ali_set_spdif_output(state, -1, 0);
- stop_spdifout(state);
- dmabuf->ready = 0;
- /* I add test codec independent spdif out */
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_codecspdifout_rate(state, val); // I modified
- spin_unlock_irqrestore(&state->card->lock, flags);
- /* Set S/PDIF transmitter rate. */
- i_scr = inl(state->card->iobase + ALI_SCR);
- if ((i_scr & 0x00300000) == 0x00100000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- } else {
- if ((i_scr&0x00300000) == 0x00200000)
- {
- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00300000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
- } else {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- }
- }
- }
-
- if (!(state->card->ac97_status & SPDIF_ON)) {
- val = dmabuf->rate;
- }
- } else {
- if (controller_independent_spdif_locked > 0)
- {
- stop_spdifout(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_spdifout_rate(state, controller_independent_spdif_locked);
- spin_unlock_irqrestore(&state->card->lock, flags);
- } else {
- /* Set DAC rate */
- ali_set_spdif_output(state, -1, 0);
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- /* Set S/PDIF transmitter rate. */
- ali_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);
- ali_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);
- ali_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);
- }
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- return put_user(1, p);
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)))
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)))
- return val;
- } else {
- 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: // add support 4,6 channel
-#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 & CODEC_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (dmabuf->enable & ADC_RUNNING) {
- stop_adc(state);
- }
- } else {
- return put_user(state->card->channels, p);
- }
-
- i_scr = inl(state->card->iobase + ALI_SCR);
- /* Current # of channels enabled */
- if (i_scr & 0x00000100)
- ret = 4;
- else if (i_scr & 0x00000200)
- ret = 6;
- else
- ret = 2;
- switch (val) {
- case 2: /* 2 channels is always supported */
- if (codec_independent_spdif_locked > 0) {
- outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR));
- } else
- outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR));
- /* Do we need to change mixer settings???? */
- break;
- case 4: /* Supported on some chipsets, better check first */
- if (codec_independent_spdif_locked > 0) {
- outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR));
- } else
- outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR));
- break;
- case 6: /* Supported on some chipsets, better check first */
- if (codec_independent_spdif_locked > 0) {
- outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR));
- } else
- outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR));
- 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 (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING))
- return 0;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING))
- return 0;
- } else {
- 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 (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
- return val;
- } else {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- }
- }
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- abinfo.fragsize = dmabuf->userfragsize;
- abinfo.fragstotal = dmabuf->userfrags;
- if (dmabuf->mapped)
- abinfo.bytes = dmabuf->dmasize;
- else
- abinfo.bytes = ali_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 (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
- return val;
- } else {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- }
- }
- spin_lock_irqsave(&state->card->lock, flags);
- val = ali_get_free_write_space(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.ptr = dmabuf->hwptr;
- cinfo.blocks = val / dmabuf->userfragsize;
- if (codec_independent_spdif_locked > 0) {
- if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __ali_update_lvi(state, 2);
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __ali_update_lvi(state, 3);
- }
- } else {
- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __ali_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 = ali_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 = ali_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;
- __ali_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
- if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
- stop_adc(state);
- }
- if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
- stop_dac(state);
- }
- if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
- stop_spdifout(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);
- ali_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = ali_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- __ali_update_lvi(state, 0);
- spin_unlock_irqrestore(&state->card->lock,
- flags);
- } else
- start_dac(state);
- }
- if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) {
- if (!dmabuf->codec_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card);
- if (!dmabuf->codec_spdifout_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = ali_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- __ali_update_lvi(state, 2);
- spin_unlock_irqrestore(&state->card->lock,
- flags);
- } else
- start_spdifout(state);
- }
- if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) {
- if (!dmabuf->controller_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card);
- if (!dmabuf->controller_spdifout_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = ali_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- __ali_update_lvi(state, 3);
- spin_unlock_irqrestore(&state->card->lock, flags);
- } else
- start_spdifout(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);
- ali_update_ptr(state);
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- ali_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);
- ali_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 = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
- val |= (ret & 0x3000);
- ali_ac97_set(codec, AC97_SPDIF_CONTROL, val);
- if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) {
- printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
- return -EFAULT;
- }
- }
-#ifdef DEBUG
- else
- printk(KERN_WARNING "ali_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 "ali_audio: S/PDIF transmitter not avalible.\n");
-#endif
- val = 0;
- } else {
- val = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
- }
-
- return put_user(val, p);
-//end add support spdif out
-//add support 4,6 channel
- 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.
- */
- i_scr = inl(state->card->iobase + ALI_SCR);
- if (codec_independent_spdif_locked > 0) {
-
- if ((i_scr & 0x00300000) == 0x00100000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00200000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00300000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
- }
- }
- }
- } else { /* codec spdif out (pcm out share ) */
- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate); //I do not modify
- }
-
- 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)
- ali_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;
- }
- ali_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:
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-static int ali_open(struct inode *inode, struct file *file)
-{
- int i = 0;
- struct ali_card *card = devs;
- struct ali_state *state = NULL;
- struct dmabuf *dmabuf = NULL;
- unsigned int i_scr;
-
- /* find an available 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 ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL);
- if (state == NULL)
- return -ENOMEM;
- memset(state, 0, sizeof(struct ali_state));
- 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 = ALI5455_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;
- ali_set_adc_rate(state, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (codec_independent_spdif_locked > 0) {
- if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) {
- kfree(card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
- ali_set_codecspdifout_rate(state, codec_independent_spdif_locked); //It must add
- i_scr = inl(state->card->iobase + ALI_SCR);
- if ((i_scr & 0x00300000) == 0x00100000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00200000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00300000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
- } else {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- }
- }
-
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) {
- kfree(card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
- ali_set_spdifout_rate(state, controller_independent_spdif_locked);
- } else {
- if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
- 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 (codec_pcmout_share_spdif_locked) {
- ali_set_dac_rate(state, codec_pcmout_share_spdif_locked);
- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked);
- } else {
- ali_set_dac_rate(state, 8000);
- }
- }
-
- }
- }
-
- /* 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 |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO;
- dmabuf->ossfragsize = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
- state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
- outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
- return nonseekable_open(inode, file);
-}
-
-static int ali_release(struct inode *inode, struct file *file)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_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 & SPDIF_ENABLE_OUTPUT)
- drain_spdifout(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) {
- if (codec_independent_spdif_locked > 0) {
- state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num);
- } else {
- if (controller_independent_spdif_locked > 0)
- state->card->free_pcm_channel(state->card,
- dmabuf->controller_spdifout_channel->num);
- else 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 ali_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ali_read,
- .write = ali_write,
- .poll = ali_poll,
- .ioctl = ali_ioctl,
- .mmap = ali_mmap,
- .open = ali_open,
- .release = ali_release,
-};
-
-/* Read AC97 codec registers */
-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg)
-{
- struct ali_card *card = dev->private_data;
- int count1 = 100;
- char val;
- unsigned short int data = 0, count, addr1, addr2 = 0;
-
- spin_lock(&card->ac97_lock);
- while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
- udelay(1);
-
- addr1 = reg;
- reg |= 0x0080;
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x08)
- break;
- }
- if (count == 0x7f)
- {
- spin_unlock(&card->ac97_lock);
- return -1;
- }
- outw(reg, (card->iobase + ALI_CPR) + 2);
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x02) {
- data = inw(card->iobase + ALI_SPR);
- addr2 = inw((card->iobase + ALI_SPR) + 2);
- break;
- }
- }
- spin_unlock(&card->ac97_lock);
- if (count == 0x7f)
- return -1;
- if (addr2 != addr1)
- return -1;
- return ((u16) data);
-}
-
-/* write ac97 codec register */
-
-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct ali_card *card = dev->private_data;
- int count1 = 100;
- char val;
- unsigned short int count;
-
- spin_lock(&card->ac97_lock);
- while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
- udelay(1);
-
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x08)
- break;
- }
- if (count == 0x7f) {
- printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
- spin_unlock(&card->ac97_lock);
- return;
- }
- outw(data, (card->iobase + ALI_CPR));
- outb(reg, (card->iobase + ALI_CPR) + 2);
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x01)
- break;
- }
- spin_unlock(&card->ac97_lock);
- if (count == 0x7f)
- printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
- return;
-}
-
-/* OSS /dev/mixer file operation methods */
-
-static int ali_open_mixdev(struct inode *inode, struct file *file)
-{
- int i;
- int minor = iminor(inode);
- struct ali_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 ali_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 ali_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = ali_ioctl_mixdev,
- .open = ali_open_mixdev,
-};
-
-/* AC97 codec initialisation. These small functions exist so we don't
- duplicate code between module init and apm resume */
-
-static inline int ali_ac97_exists(struct ali_card *card, int ac97_number)
-{
- unsigned int i = 1;
- u32 reg = inl(card->iobase + ALI_RTSR);
- if (ac97_number) {
- while (i < 100) {
-
- reg = inl(card->iobase + ALI_RTSR);
- if (reg & 0x40) {
- break;
- } else {
- outl(reg | 0x00000040,
- card->iobase + 0x34);
- udelay(1);
- }
- i++;
- }
-
- } else {
- while (i < 100) {
- reg = inl(card->iobase + ALI_RTSR);
- if (reg & 0x80) {
- break;
- } else {
- outl(reg | 0x00000080,
- card->iobase + 0x34);
- udelay(1);
- }
- i++;
- }
- }
-
- if (ac97_number)
- return reg & 0x40;
- else
- return reg & 0x80;
-}
-
-static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec)
-{
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800);
- return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1);
-}
-
-
-static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec)
-{
- /* Returns 0 on failure */
- int i;
- u16 addr;
- if (ac97_probe_codec(codec) == 0)
- return 0;
- /* ac97_probe_codec is success ,then begin to init codec */
- ali_ac97_set(codec, AC97_RESET, 0xffff);
- if (card->channel[0].used == 1) {
- ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
- ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808);
- ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
- }
-
- if (card->channel[2].used == 1) //if MICin then init codec
- {
- ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
- ali_ac97_set(codec, AC97_MIC_VOL, 0x8808);
- ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
- ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000);
- }
-
- ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000);
- ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000);
- ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000);
- ali_ac97_set(codec, AC97_CD_VOL, 0x0808);
- ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808);
- ali_ac97_set(codec, AC97_AUX_VOL, 0x0808);
- ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048);
- ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000);
- ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX);
- ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000);
- ali_ac97_set(codec, 0x38, 0x0000);
- addr = ali_ac97_get(codec, 0x2a);
- ali_ac97_set(codec, 0x2a, addr | 0x0001);
- addr = ali_ac97_get(codec, 0x2a);
- addr = ali_ac97_get(codec, 0x28);
- ali_ac97_set(codec, 0x2c, 0xbb80);
- addr = ali_ac97_get(codec, 0x2c);
- /* power it all up */
- ali_ac97_set(codec, AC97_POWER_CONTROL,
- ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
- /* wait for analog ready */
- for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 20);
- }
- /* FIXME !! */
- i++;
- return i;
-}
-
-
-/* I clone ali5455(2.4.7 ) not clone i810_audio(2.4.18) */
-
-static int ali_reset_5455(struct ali_card *card)
-{
- outl(0x80000003, card->iobase + ALI_SCR);
- outl(0x83838383, card->iobase + ALI_FIFOCR1);
- outl(0x83838383, card->iobase + ALI_FIFOCR2);
- if (controller_pcmout_share_spdif_locked > 0) {
- outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
- card->iobase + ALI_SPDIFICS);
- outl(0x0408000a, card->iobase + ALI_INTERFACECR);
- } else {
- if (codec_independent_spdif_locked > 0) {
- outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR); // now I select slot 7 & 8
- outl(0x00200000, card->iobase + ALI_INTERFACECR); //enable codec independent spdifout
- } else
- outl(0x04080002, card->iobase + ALI_INTERFACECR);
- }
-
- outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
- outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
- if (controller_independent_spdif_locked > 0)
- outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
- card->iobase + ALI_SPDIFICS);
- return 1;
-}
-
-
-static int ali_ac97_random_init_stuff(struct ali_card
- *card)
-{
- u32 reg = inl(card->iobase + ALI_SCR);
- int i = 0;
- reg = inl(card->iobase + ALI_SCR);
- if ((reg & 2) == 0) /* Cold required */
- reg |= 2;
- else
- reg |= 1; /* Warm */
- reg &= ~0x80000000; /* ACLink on */
- outl(reg, card->iobase + ALI_SCR);
-
- while (i < 10) {
- if ((inl(card->iobase + 0x18) & (1 << 1)) == 0)
- break;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(HZ / 20);
- i++;
- }
- if (i == 10) {
- printk(KERN_ERR "ali_audio: AC'97 reset failed.\n");
- return 0;
- }
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 2);
- return 1;
-}
-
-/* AC97 codec initialisation. */
-
-static int __devinit ali_ac97_init(struct ali_card *card)
-{
- int num_ac97 = 0;
- int total_channels = 0;
- struct ac97_codec *codec;
- u16 eid;
-
- if (!ali_ac97_random_init_stuff(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.... */
- inl(card->iobase + ALI_CPR);
- card->channels = 2;
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-
- /* Assume codec isn't available until we go through the
- * gauntlet below */
- card->ac97_codec[num_ac97] = NULL;
- /* 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 (!ali_ac97_exists(card, num_ac97)) {
- if (num_ac97 == 0)
- printk(KERN_ERR "ali_audio: Primary codec not ready.\n");
- break;
- }
-
- 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;
- codec->codec_read = ali_ac97_get;
- codec->codec_write = ali_ac97_set;
- if (!ali_ac97_probe_and_powerup(card, codec)) {
- printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready",
- num_ac97);
- kfree(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 = ali_ac97_get(codec, AC97_EXTENDED_ID);
- if (eid == 0xFFFF) {
- printk(KERN_ERR "ali_audio: no codec attached ?\n");
- kfree(codec);
- break;
- }
-
- card->ac97_features = eid;
- /* Now check the codec for useful features to make up for
- the dumbness of the ali5455 hardware engine */
- if (!(eid & 0x0001))
- printk(KERN_WARNING
- "ali_audio: only 48Khz playback available.\n");
- else {
- if (!ali_ac97_enable_variable_rate(codec)) {
- printk(KERN_WARNING
- "ali_audio: Codec refused to allow VRA, using 48Khz only.\n");
- card->ac97_features &= ~1;
- }
- }
-
- /* 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 ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "ali_audio: couldn't register mixer!\n");
- kfree(codec);
- break;
- }
- card->ac97_codec[num_ac97] = codec;
- }
- /* 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 ali_configure_clocking(void)
-{
- struct ali_card *card;
- struct ali_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 ali in a machine? Besides, clocking is global, so unless
- * someone actually thinks more than one ali 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 ali_state *)
- kmalloc(sizeof(struct ali_state), GFP_KERNEL);
- if (state == NULL)
- return;
- memset(state, 0, sizeof(struct ali_state));
- dmabuf = &state->dmabuf;
- dmabuf->write_channel = card->alloc_pcm_channel(card);
- state->virt = 0;
- state->card = card;
- state->magic = ALI5455_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT;
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- ali_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;
- outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI);
-
- local_irq_save(flags);
- start_dac(state);
- offset = ali_get_dma_addr(state, 0);
- mdelay(50);
- new_offset = ali_get_dma_addr(state, 0);
- stop_dac(state);
-
- outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR);
- local_irq_restore(flags);
-
- i = new_offset - offset;
-
- if (i == 0)
- goto config_out;
- i = i / 4 * 20;
- if (i > 48500 || i < 47500) {
- clocking = clocking * clocking / i;
- }
-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 ali_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- struct ali_card *card;
- if (pci_enable_device(pci_dev))
- return -EIO;
- if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) {
- printk(KERN_ERR "ali5455: architecture does not support"
- " 32bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "ali_audio: out of memory\n");
- return -ENOMEM;
- }
- memset(card, 0, sizeof(*card));
- card->initializing = 1;
- card->iobase = pci_resource_start(pci_dev, 0);
- card->pci_dev = pci_dev;
- card->pci_id = pci_id->device;
- card->irq = pci_dev->irq;
- card->next = devs;
- card->magic = ALI5455_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 "ali: %s found at IO 0x%04lx, IRQ %d\n",
- card_names[pci_id->driver_data], card->iobase, card->irq);
- card->alloc_pcm_channel = ali_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
- card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel;
- card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel;
- card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel;
- card->free_pcm_channel = ali_free_pcm_channel;
- card->channel[0].offset = 0;
- card->channel[0].port = 0x40;
- card->channel[0].num = 0;
- card->channel[1].offset = 0;
- card->channel[1].port = 0x50;
- card->channel[1].num = 1;
- card->channel[2].offset = 0;
- card->channel[2].port = 0x60;
- card->channel[2].num = 2;
- card->channel[3].offset = 0;
- card->channel[3].port = 0x70;
- card->channel[3].num = 3;
- card->channel[4].offset = 0;
- card->channel[4].port = 0xb0;
- card->channel[4].num = 4;
- /* claim our iospace and irq */
- request_region(card->iobase, 256, card_names[pci_id->driver_data]);
- if (request_irq(card->irq, &ali_interrupt, IRQF_SHARED,
- card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "ali_audio: unable to allocate irq %d\n",
- card->irq);
- release_region(card->iobase, 256);
- kfree(card);
- return -ENODEV;
- }
-
- if (ali_reset_5455(card) <= 0) {
- unregister_sound_dsp(card->dev_audio);
- release_region(card->iobase, 256);
- free_irq(card->irq, card);
- kfree(card);
- return -ENODEV;
- }
-
- /* initialize AC97 codec and register /dev/mixer */
- if (ali_ac97_init(card) < 0) {
- release_region(card->iobase, 256);
- free_irq(card->irq, card);
- kfree(card);
- return -ENODEV;
- }
-
- pci_set_drvdata(pci_dev, card);
-
- if (clocking == 0) {
- clocking = 48000;
- ali_configure_clocking();
- }
-
- /* register /dev/dsp */
- if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) {
- int i;
- printk(KERN_ERR"ali_audio: couldn't register DSP device!\n");
- release_region(card->iobase, 256);
- free_irq(card->irq, card);
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- kfree(card->ac97_codec[i]);
- }
- kfree(card);
- return -ENODEV;
- }
- card->initializing = 0;
- return 0;
-}
-
-static void __devexit ali_remove(struct pci_dev *pci_dev)
-{
- int i;
- struct ali_card *card = pci_get_drvdata(pci_dev);
- /* free hardware resources */
- free_irq(card->irq, devs);
- 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]);
- card->ac97_codec[i] = NULL;
- }
- unregister_sound_dsp(card->dev_audio);
- kfree(card);
-}
-
-#ifdef CONFIG_PM
-static int ali_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
-{
- struct ali_card *card = pci_get_drvdata(dev);
- struct ali_state *state;
- unsigned long flags;
- struct dmabuf *dmabuf;
- int i, num_ac97;
-
- 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 ali_pm_resume(struct pci_dev *dev)
-{
- int num_ac97, i = 0;
- struct ali_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 */
- ali_ac97_random_init_stuff(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 || !ali_ac97_exists(card, num_ac97)) {
- if (num_ac97)
- continue;
- else
- BUG();
- }
- if (!ali_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 (!ali_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 ali_state *state = card->states[i];
- if (state) {
- if (state->pm_saved_adc_rate)
- ali_set_adc_rate(state, state->pm_saved_adc_rate);
- if (state->pm_saved_dac_rate)
- ali_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 ali_state *state = card->states[i];
- if (state)
- wake_up(&state->dmabuf.wait);
- }
- return 0;
-}
-#endif /* CONFIG_PM */
-
-MODULE_AUTHOR("");
-MODULE_DESCRIPTION("ALI 5455 audio support");
-MODULE_LICENSE("GPL");
-module_param(clocking, int, 0);
-/* FIXME: bool? */
-module_param(strict_clocking, uint, 0);
-module_param(codec_pcmout_share_spdif_locked, uint, 0);
-module_param(codec_independent_spdif_locked, uint, 0);
-module_param(controller_pcmout_share_spdif_locked, uint, 0);
-module_param(controller_independent_spdif_locked, uint, 0);
-#define ALI5455_MODULE_NAME "ali5455"
-static struct pci_driver ali_pci_driver = {
- .name = ALI5455_MODULE_NAME,
- .id_table = ali_pci_tbl,
- .probe = ali_probe,
- .remove = __devexit_p(ali_remove),
-#ifdef CONFIG_PM
- .suspend = ali_pm_suspend,
- .resume = ali_pm_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init ali_init_module(void)
-{
- printk(KERN_INFO "ALI 5455 + AC97 Audio, version "
- DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
- if (codec_independent_spdif_locked > 0) {
- if (codec_independent_spdif_locked == 32000
- || codec_independent_spdif_locked == 44100
- || codec_independent_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- codec_independent_spdif_locked = 0;
- }
- }
- if (controller_independent_spdif_locked > 0) {
- if (controller_independent_spdif_locked == 32000
- || controller_independent_spdif_locked == 44100
- || controller_independent_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- controller_independent_spdif_locked = 0;
- }
- }
-
- if (codec_pcmout_share_spdif_locked > 0) {
- if (codec_pcmout_share_spdif_locked == 32000
- || codec_pcmout_share_spdif_locked == 44100
- || codec_pcmout_share_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- codec_pcmout_share_spdif_locked = 0;
- }
- }
- if (controller_pcmout_share_spdif_locked > 0) {
- if (controller_pcmout_share_spdif_locked == 32000
- || controller_pcmout_share_spdif_locked == 44100
- || controller_pcmout_share_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- controller_pcmout_share_spdif_locked = 0;
- }
- }
- return pci_register_driver(&ali_pci_driver);
-}
-
-static void __exit ali_cleanup_module(void)
-{
- pci_unregister_driver(&ali_pci_driver);
-}
-
-module_init(ali_init_module);
-module_exit(ali_cleanup_module);
-/*
-Local Variables:
-c-basic-offset: 8
-End:
-*/
diff --git a/sound/oss/au1000.c b/sound/oss/au1000.c
deleted file mode 100644
index e379623..0000000
--- a/sound/oss/au1000.c
+++ /dev/null
@@ -1,2216 +0,0 @@
-/*
- * au1000.c -- Sound driver for Alchemy Au1000 MIPS Internet Edge
- * Processor.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.com
- *
- * 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.
- *
- *
- * Module command line parameters:
- *
- * Supported devices:
- * /dev/dsp standard OSS /dev/dsp device
- * /dev/mixer standard OSS /dev/mixer device
- *
- * Notes:
- *
- * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are
- * taken, slightly modified or not at all, from the ES1371 driver,
- * so refer to the credits in es1371.c for those. The rest of the
- * code (probe, open, read, write, the ISR, etc.) is new.
- *
- * Revision history
- * 06.27.2001 Initial version
- * 03.20.2002 Added mutex locks around read/write methods, to prevent
- * simultaneous access on SMP or preemptible kernels. Also
- * removed the counter/pointer fragment aligning at the end
- * of read/write methods [stevel].
- * 03.21.2002 Add support for coherent DMA on the audio read/write DMA
- * channels [stevel].
- *
- */
-#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/page-flags.h>
-#include <linux/poll.h>
-#include <linux/pci.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/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1000_dma.h>
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#undef AU1000_DEBUG
-#undef AU1000_VERBOSE_DEBUG
-
-#define AU1000_MODULE_NAME "Au1000 audio"
-#define PFX AU1000_MODULE_NAME
-
-#ifdef AU1000_DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
-
-
-/* misc stuff */
-#define POLL_COUNT 0x5000
-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
-
-/* Boot options */
-static int vra = 0; // 0 = no VRA, 1 = use VRA if codec supports it
-module_param(vra, bool, 0);
-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
-
-
-/* --------------------------------------------------------------------- */
-
-struct au1000_state {
- /* soundcore stuff */
- int dev_audio;
-
-#ifdef AU1000_DEBUG
- /* debug /proc entry */
- struct proc_dir_entry *ps;
- struct proc_dir_entry *ac97_ps;
-#endif /* AU1000_DEBUG */
-
- 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 {
- unsigned int dmanr; // DMA Channel number
- unsigned sample_rate; // Hz
- unsigned src_factor; // SRC interp/decimation (no vra)
- unsigned sample_size; // 8 or 16
- int num_channels; // 1 = mono, 2 = stereo, 4, 6
- int dma_bytes_per_sample;// DMA bytes per audio sample frame
- int user_bytes_per_sample;// User bytes per audio sample frame
- int cnt_factor; // user-to-DMA bytes per audio
- // sample frame
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag; // # of DMA fragments in DMA buffer
- unsigned fragshift;
- void *nextIn; // ptr to next-in to DMA buffer
- void *nextOut;// ptr to next-out from DMA buffer
- int count; // current byte count in DMA buffer
- unsigned total_bytes; // total bytes written or read
- unsigned error; // over/underrun
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize; // user perception of fragment size
- unsigned dma_fragsize; // DMA (real) fragment size
- unsigned dmasize; // Total DMA buffer size
- // (mult. of DMA fragsize)
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned stopped:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac , dma_adc;
-} au1000_state;
-
-/* --------------------------------------------------------------------- */
-
-
-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 void au1000_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 au1000_state *s = (struct au1000_state *)codec->private_data;
- unsigned long flags;
- u32 cmd;
- u16 data;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++)
- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
- break;
- if (i == POLL_COUNT)
- err("rdcodec: codec cmd pending expired!");
-
- cmd = (u32) addr & AC97C_INDEX_MASK;
- cmd |= AC97C_READ; // read command
- au_writel(cmd, AC97C_CMD);
-
- /* now wait for the data */
- for (i = 0; i < POLL_COUNT; i++)
- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
- break;
- if (i == POLL_COUNT) {
- err("rdcodec: read poll expired!");
- return 0;
- }
-
- data = au_readl(AC97C_CMD) & 0xffff;
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- return data;
-}
-
-
-static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
- struct au1000_state *s = (struct au1000_state *)codec->private_data;
- unsigned long flags;
- u32 cmd;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++)
- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
- break;
- if (i == POLL_COUNT)
- err("wrcodec: codec cmd pending expired!");
-
- cmd = (u32) addr & AC97C_INDEX_MASK;
- cmd &= ~AC97C_READ; // write command
- cmd |= ((u32) data << AC97C_WD_BIT); // OR in the data word
- au_writel(cmd, AC97C_CMD);
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void waitcodec(struct ac97_codec *codec)
-{
- u16 temp;
- int i;
-
- /* codec_wait is used to wait for a ready state after
- an AC97C_RESET. */
- au1000_delay(10);
-
- // first poll the CODEC_READY tag bit
- for (i = 0; i < POLL_COUNT; i++)
- if (au_readl(AC97C_STATUS) & AC97C_READY)
- 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);
- au1000_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 au1000_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);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("%s: set to %d Hz", __FUNCTION__, adc_rate);
-#endif
-
- // 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 au1000_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);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("%s: set to %d Hz", __FUNCTION__, dac_rate);
-#endif
-
- // 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 au1000_state *s)
-{
- struct dmabuf *db = &s->dma_dac;
- unsigned long flags;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- disable_dma(db->dmanr);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void stop_adc(struct au1000_state *s)
-{
- struct dmabuf *db = &s->dma_adc;
- unsigned long flags;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- disable_dma(db->dmanr);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void set_xmit_slots(int num_channels)
-{
- u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_XMIT_SLOTS_MASK;
-
- switch (num_channels) {
- case 1: // mono
- case 2: // stereo, slots 3,4
- ac97_config |= (0x3 << AC97C_XMIT_SLOTS_BIT);
- break;
- case 4: // stereo with surround, slots 3,4,7,8
- ac97_config |= (0x33 << AC97C_XMIT_SLOTS_BIT);
- break;
- case 6: // stereo with surround and center/LFE, slots 3,4,6,7,8,9
- ac97_config |= (0x7b << AC97C_XMIT_SLOTS_BIT);
- break;
- }
-
- au_writel(ac97_config, AC97C_CONFIG);
-}
-
-static void set_recv_slots(int num_channels)
-{
- u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_RECV_SLOTS_MASK;
-
- /*
- * Always enable slots 3 and 4 (stereo). Slot 6 is
- * optional Mic ADC, which I don't support yet.
- */
- ac97_config |= (0x3 << AC97C_RECV_SLOTS_BIT);
-
- au_writel(ac97_config, AC97C_CONFIG);
-}
-
-static void start_dac(struct au1000_state *s)
-{
- struct dmabuf *db = &s->dma_dac;
- unsigned long flags;
- unsigned long buf1, buf2;
-
- if (!db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- au_readl(AC97C_STATUS); // read status to clear sticky bits
-
- // reset Buffer 1 and 2 pointers to nextOut and nextOut+dma_fragsize
- buf1 = virt_to_phys(db->nextOut);
- buf2 = buf1 + db->dma_fragsize;
- if (buf2 >= db->dmaaddr + db->dmasize)
- buf2 -= db->dmasize;
-
- set_xmit_slots(db->num_channels);
-
- init_dma(db->dmanr);
- if (get_dma_active_buffer(db->dmanr) == 0) {
- clear_dma_done0(db->dmanr); // clear DMA done bit
- set_dma_addr0(db->dmanr, buf1);
- set_dma_addr1(db->dmanr, buf2);
- } else {
- clear_dma_done1(db->dmanr); // clear DMA done bit
- set_dma_addr1(db->dmanr, buf1);
- set_dma_addr0(db->dmanr, buf2);
- }
- set_dma_count(db->dmanr, db->dma_fragsize>>1);
- enable_dma_buffers(db->dmanr);
-
- start_dma(db->dmanr);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dump_au1000_dma_channel(db->dmanr);
-#endif
-
- db->stopped = 0;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct au1000_state *s)
-{
- struct dmabuf *db = &s->dma_adc;
- unsigned long flags;
- unsigned long buf1, buf2;
-
- if (!db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- au_readl(AC97C_STATUS); // read status to clear sticky bits
-
- // reset Buffer 1 and 2 pointers to nextIn and nextIn+dma_fragsize
- buf1 = virt_to_phys(db->nextIn);
- buf2 = buf1 + db->dma_fragsize;
- if (buf2 >= db->dmaaddr + db->dmasize)
- buf2 -= db->dmasize;
-
- set_recv_slots(db->num_channels);
-
- init_dma(db->dmanr);
- if (get_dma_active_buffer(db->dmanr) == 0) {
- clear_dma_done0(db->dmanr); // clear DMA done bit
- set_dma_addr0(db->dmanr, buf1);
- set_dma_addr1(db->dmanr, buf2);
- } else {
- clear_dma_done1(db->dmanr); // clear DMA done bit
- set_dma_addr1(db->dmanr, buf1);
- set_dma_addr0(db->dmanr, buf2);
- }
- set_dma_count(db->dmanr, db->dma_fragsize>>1);
- enable_dma_buffers(db->dmanr);
-
- start_dma(db->dmanr);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dump_au1000_dma_channel(db->dmanr);
-#endif
-
- db->stopped = 0;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct au1000_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);
- dma_free_noncoherent(NULL,
- PAGE_SIZE << db->buforder,
- db->rawbuf,
- db->dmaaddr);
- }
- db->rawbuf = db->nextIn = db->nextOut = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db)
-{
- int order;
- unsigned user_bytes_per_sec;
- unsigned bufs;
- struct page *page, *pend;
- unsigned rate = db->sample_rate;
-
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER;
- order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = dma_alloc_noncoherent(NULL,
- PAGE_SIZE << order,
- &db->dmaaddr,
- 0)))
- 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);
- }
-
- 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->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);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("rate=%d, samplesize=%d, channels=%d",
- rate, db->sample_size, db->num_channels);
- dbg("fragsize=%d, cnt_factor=%d, dma_fragsize=%d",
- db->fragsize, db->cnt_factor, db->dma_fragsize);
- dbg("numfrag=%d, dmasize=%d", db->numfrag, db->dmasize);
-#endif
-
- db->ready = 1;
- return 0;
-}
-
-static inline int prog_dmabuf_adc(struct au1000_state *s)
-{
- stop_adc(s);
- return prog_dmabuf(s, &s->dma_adc);
-
-}
-
-static inline int prog_dmabuf_dac(struct au1000_state *s)
-{
- stop_dac(s);
- return prog_dmabuf(s, &s->dma_dac);
-}
-
-
-/* hold spinlock for the following */
-static irqreturn_t dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct au1000_state *s = (struct au1000_state *) dev_id;
- struct dmabuf *dac = &s->dma_dac;
- unsigned long newptr;
- u32 ac97c_stat, buff_done;
-
- ac97c_stat = au_readl(AC97C_STATUS);
-#ifdef AU1000_VERBOSE_DEBUG
- if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
- dbg("AC97C status = 0x%08x", ac97c_stat);
-#endif
-
- if ((buff_done = get_dma_buffer_done(dac->dmanr)) == 0) {
- /* fastpath out, to ease interrupt sharing */
- return IRQ_HANDLED;
- }
-
- spin_lock(&s->lock);
-
- if (buff_done != (DMA_D0 | DMA_D1)) {
- dac->nextOut += dac->dma_fragsize;
- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
- dac->nextOut -= dac->dmasize;
-
- /* update playback pointers */
- newptr = virt_to_phys(dac->nextOut) + dac->dma_fragsize;
- if (newptr >= dac->dmaaddr + dac->dmasize)
- newptr -= dac->dmasize;
-
- dac->count -= dac->dma_fragsize;
- dac->total_bytes += dac->dma_fragsize;
-
- if (dac->count <= 0) {
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("dac underrun");
-#endif
- spin_unlock(&s->lock);
- stop_dac(s);
- spin_lock(&s->lock);
- dac->count = 0;
- dac->nextIn = dac->nextOut;
- } else if (buff_done == DMA_D0) {
- clear_dma_done0(dac->dmanr); // clear DMA done bit
- set_dma_count0(dac->dmanr, dac->dma_fragsize>>1);
- set_dma_addr0(dac->dmanr, newptr);
- enable_dma_buffer0(dac->dmanr); // reenable
- } else {
- clear_dma_done1(dac->dmanr); // clear DMA done bit
- set_dma_count1(dac->dmanr, dac->dma_fragsize>>1);
- set_dma_addr1(dac->dmanr, newptr);
- enable_dma_buffer1(dac->dmanr); // reenable
- }
- } else {
- // both done bits set, we missed an interrupt
- spin_unlock(&s->lock);
- stop_dac(s);
- spin_lock(&s->lock);
-
- dac->nextOut += 2*dac->dma_fragsize;
- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
- dac->nextOut -= dac->dmasize;
-
- dac->count -= 2*dac->dma_fragsize;
- dac->total_bytes += 2*dac->dma_fragsize;
-
- if (dac->count > 0) {
- spin_unlock(&s->lock);
- start_dac(s);
- spin_lock(&s->lock);
- }
- }
-
- /* wake up anybody listening */
- if (waitqueue_active(&dac->wait))
- wake_up(&dac->wait);
-
- spin_unlock(&s->lock);
-
- return IRQ_HANDLED;
-}
-
-
-static irqreturn_t adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct au1000_state *s = (struct au1000_state *) dev_id;
- struct dmabuf *adc = &s->dma_adc;
- unsigned long newptr;
- u32 ac97c_stat, buff_done;
-
- ac97c_stat = au_readl(AC97C_STATUS);
-#ifdef AU1000_VERBOSE_DEBUG
- if (ac97c_stat & (AC97C_RU | AC97C_RO))
- dbg("AC97C status = 0x%08x", ac97c_stat);
-#endif
-
- if ((buff_done = get_dma_buffer_done(adc->dmanr)) == 0) {
- /* fastpath out, to ease interrupt sharing */
- return IRQ_HANDLED;
- }
-
- spin_lock(&s->lock);
-
- if (buff_done != (DMA_D0 | DMA_D1)) {
- if (adc->count + adc->dma_fragsize > adc->dmasize) {
- // Overrun. Stop ADC and log the error
- spin_unlock(&s->lock);
- stop_adc(s);
- adc->error++;
- err("adc overrun");
- return IRQ_NONE;
- }
-
- adc->nextIn += adc->dma_fragsize;
- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
- adc->nextIn -= adc->dmasize;
-
- /* update capture pointers */
- newptr = virt_to_phys(adc->nextIn) + adc->dma_fragsize;
- if (newptr >= adc->dmaaddr + adc->dmasize)
- newptr -= adc->dmasize;
-
- adc->count += adc->dma_fragsize;
- adc->total_bytes += adc->dma_fragsize;
-
- if (buff_done == DMA_D0) {
- clear_dma_done0(adc->dmanr); // clear DMA done bit
- set_dma_count0(adc->dmanr, adc->dma_fragsize>>1);
- set_dma_addr0(adc->dmanr, newptr);
- enable_dma_buffer0(adc->dmanr); // reenable
- } else {
- clear_dma_done1(adc->dmanr); // clear DMA done bit
- set_dma_count1(adc->dmanr, adc->dma_fragsize>>1);
- set_dma_addr1(adc->dmanr, newptr);
- enable_dma_buffer1(adc->dmanr); // reenable
- }
- } else {
- // both done bits set, we missed an interrupt
- spin_unlock(&s->lock);
- stop_adc(s);
- spin_lock(&s->lock);
-
- if (adc->count + 2*adc->dma_fragsize > adc->dmasize) {
- // Overrun. Log the error
- adc->error++;
- err("adc overrun");
- spin_unlock(&s->lock);
- return IRQ_NONE;
- }
-
- adc->nextIn += 2*adc->dma_fragsize;
- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
- adc->nextIn -= adc->dmasize;
-
- adc->count += 2*adc->dma_fragsize;
- adc->total_bytes += 2*adc->dma_fragsize;
-
- spin_unlock(&s->lock);
- start_adc(s);
- spin_lock(&s->lock);
- }
-
- /* wake up anybody listening */
- if (waitqueue_active(&adc->wait))
- wake_up(&adc->wait);
-
- spin_unlock(&s->lock);
-
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static loff_t au1000_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
-
-static int au1000_open_mixdev(struct inode *inode, struct file *file)
-{
- file->private_data = &au1000_state;
- return nonseekable_open(inode, file);
-}
-
-static int au1000_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 au1000_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- struct ac97_codec *codec = &s->codec;
-
- return mixdev_ioctl(codec, cmd, arg);
-}
-
-static /*const */ struct file_operations au1000_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = au1000_llseek,
- .ioctl = au1000_ioctl_mixdev,
- .open = au1000_open_mixdev,
- .release = au1000_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct au1000_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 <= 0)
- 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;
- au1000_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)) {
- dbg("%s: fault", __FUNCTION__);
- 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)) {
- dbg("%s: fault", __FUNCTION__);
- 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 au1000_read(struct file *file, char *buffer,
- size_t count, loff_t *ppos)
-{
- struct au1000_state *s = (struct au1000_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 {
- if (db->stopped)
- start_adc(s);
- spin_lock_irqsave(&s->lock, flags);
- 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 au1000_write(struct file *file, const char *buffer,
- size_t count, loff_t * ppos)
-{
- struct au1000_state *s = (struct au1000_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;
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("write: count=%d", count);
-#endif
-
- 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;
- spin_unlock_irqrestore(&s->lock, flags);
- if (db->stopped)
- start_dac(s);
-
- 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 au1000_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct au1000_state *s = (struct au1000_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 au1000_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- struct dmabuf *db;
- unsigned long size;
- int ret = 0;
-
- dbg("%s", __FUNCTION__);
-
- 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, virt_to_phys(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 AU1000_VERBOSE_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
-
-// Need to hold a spin-lock before calling this!
-static int dma_count_done(struct dmabuf *db)
-{
- if (db->stopped)
- return 0;
-
- return db->dma_fragsize - get_dma_residue(db->dmanr);
-}
-
-
-static int au1000_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct au1000_state *s = (struct au1000_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 AU1000_VERBOSE_DEBUG
- for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
- if (ioctl_str[count].cmd == cmd)
- break;
- }
- if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))
- dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg);
- else
- dbg("ioctl 0x%x unknown, arg=0x%lx", 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)
- start_adc(s);
- else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT)
- start_dac(s);
- 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;
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);
-#endif
- 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 -
- s->dma_adc.dmaaddr;
- } else
- cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
- s->dma_adc.dmaaddr;
- 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)) ? -EFAULT : 0;
-
- 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 -
- s->dma_dac.dmaaddr;
- } else
- cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
- s->dma_dac.dmaaddr;
- 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)) ? -EFAULT : 0;
-
- 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 au1000_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct au1000_state *s = &au1000_state;
- int ret;
-
-#ifdef AU1000_VERBOSE_DEBUG
- if (file->f_flags & O_NONBLOCK)
- dbg("%s: non-blocking", __FUNCTION__);
- else
- dbg("%s: blocking", __FUNCTION__);
-#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 nonseekable_open(inode, file);
-}
-
-static int au1000_release(struct inode *inode, struct file *file)
-{
- struct au1000_state *s = (struct au1000_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);
- dealloc_dmabuf(s, &s->dma_dac);
- }
- 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 au1000_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = au1000_llseek,
- .read = au1000_read,
- .write = au1000_write,
- .poll = au1000_poll,
- .ioctl = au1000_ioctl,
- .mmap = au1000_mmap,
- .open = au1000_open,
- .release = au1000_release,
-};
-
-
-/* --------------------------------------------------------------------- */
-
-
-/* --------------------------------------------------------------------- */
-
-/*
- * for debugging purposes, we'll create a proc device that dumps the
- * CODEC chipstate
- */
-
-#ifdef AU1000_DEBUG
-static int proc_au1000_dump(char *buf, char **start, off_t fpos,
- int length, int *eof, void *data)
-{
- struct au1000_state *s = &au1000_state;
- int cnt, len = 0;
-
- /* print out header */
- len += sprintf(buf + len, "\n\t\tAU1000 Audio Debug\n\n");
-
- // print out digital controller state
- len += sprintf(buf + len, "AU1000 Audio Controller registers\n");
- len += sprintf(buf + len, "---------------------------------\n");
- len += sprintf (buf + len, "AC97C_CONFIG = %08x\n",
- au_readl(AC97C_CONFIG));
- len += sprintf (buf + len, "AC97C_STATUS = %08x\n",
- au_readl(AC97C_STATUS));
- len += sprintf (buf + len, "AC97C_CNTRL = %08x\n",
- au_readl(AC97C_CNTRL));
-
- /* print out CODEC state */
- len += sprintf(buf + len, "\nAC97 CODEC registers\n");
- len += sprintf(buf + len, "----------------------\n");
- for (cnt = 0; cnt <= 0x7e; cnt += 2)
- len += sprintf(buf + len, "reg %02x = %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 /* AU1000_DEBUG */
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com");
-MODULE_DESCRIPTION("Au1000 Audio Driver");
-
-/* --------------------------------------------------------------------- */
-
-static int __devinit au1000_probe(void)
-{
- struct au1000_state *s = &au1000_state;
- int val;
-#ifdef AU1000_DEBUG
- char proc_str[80];
-#endif
-
- memset(s, 0, sizeof(struct au1000_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.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(AC97C_CONFIG),
- 0x14, AU1000_MODULE_NAME)) {
- err("AC'97 ports in use");
- return -1;
- }
- // Allocate the DMA Channels
- if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX,
- "audio DAC",
- dac_dma_interrupt,
- IRQF_DISABLED, s)) < 0) {
- err("Can't get DAC DMA");
- goto err_dma1;
- }
- if ((s->dma_adc.dmanr = request_au1000_dma(DMA_ID_AC97C_RX,
- "audio ADC",
- adc_dma_interrupt,
- IRQF_DISABLED, s)) < 0) {
- err("Can't get ADC DMA");
- goto err_dma2;
- }
-
- info("DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d",
- s->dma_dac.dmanr, get_dma_done_irq(s->dma_dac.dmanr),
- s->dma_adc.dmanr, get_dma_done_irq(s->dma_adc.dmanr));
-
- // enable DMA coherency in read/write DMA channels
- set_dma_mode(s->dma_dac.dmanr,
- get_dma_mode(s->dma_dac.dmanr) & ~DMA_NC);
- set_dma_mode(s->dma_adc.dmanr,
- get_dma_mode(s->dma_adc.dmanr) & ~DMA_NC);
-
- /* register devices */
-
- if ((s->dev_audio = register_sound_dsp(&au1000_audio_fops, -1)) < 0)
- goto err_dev1;
- if ((s->codec.dev_mixer =
- register_sound_mixer(&au1000_mixer_fops, -1)) < 0)
- goto err_dev2;
-
-#ifdef AU1000_DEBUG
- /* intialize the debug proc device */
- s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL,
- proc_au1000_dump, NULL);
-#endif /* AU1000_DEBUG */
-
- // configure pins for AC'97
- au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
-
- // Assert reset for 10msec to the AC'97 controller, and enable clock
- au_writel(AC97C_RS | AC97C_CE, AC97C_CNTRL);
- au1000_delay(10);
- au_writel(AC97C_CE, AC97C_CNTRL);
- au1000_delay(10); // wait for clock to stabilize
-
- /* cold reset the AC'97 */
- au_writel(AC97C_RESET, AC97C_CONFIG);
- au1000_delay(10);
- au_writel(0, AC97C_CONFIG);
- /* need to delay around 500msec(bleech) to give
- some CODECs enough time to wakeup */
- au1000_delay(500);
-
- /* warm reset the AC'97 to start the bitclk */
- au_writel(AC97C_SG | AC97C_SYNC, AC97C_CONFIG);
- udelay(100);
- au_writel(0, AC97C_CONFIG);
-
- /* 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);
- info("AC'97 Base/Extended ID = %04x/%04x",
- s->codec_base_caps, s->codec_ext_caps);
-
- /*
- * On the Pb1000, audio playback is on the AUX_OUT
- * channel (which defaults to LNLVL_OUT in AC'97
- * rev 2.2) so make sure this channel is listed
- * as supported (soundcard.h calls this channel
- * ALTPCM). ac97_codec.c does not handle detection
- * of this channel correctly.
- */
- s->codec.supported_mixers |= SOUND_MASK_ALTPCM;
- /*
- * Now set AUX_OUT's default volume.
- */
- val = 0x4343;
- mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_ALTPCM,
- (unsigned long) &val);
-
- 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)
- 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);
-
-#ifdef AU1000_DEBUG
- sprintf(proc_str, "driver/%s/%d/ac97", AU1000_MODULE_NAME,
- s->codec.id);
- s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,
- ac97_read_proc, &s->codec);
-#endif
-
-#ifdef CONFIG_MIPS_XXS1500
- /* deassert eapd */
- wrcodec(&s->codec, AC97_POWER_CONTROL,
- rdcodec(&s->codec, AC97_POWER_CONTROL) & ~0x8000);
- /* mute a number of signals which seem to be causing problems
- * if not muted.
- */
- wrcodec(&s->codec, AC97_PCBEEP_VOL, 0x8000);
- wrcodec(&s->codec, AC97_PHONE_VOL, 0x8008);
- wrcodec(&s->codec, AC97_MIC_VOL, 0x8008);
- wrcodec(&s->codec, AC97_LINEIN_VOL, 0x8808);
- wrcodec(&s->codec, AC97_CD_VOL, 0x8808);
- wrcodec(&s->codec, AC97_VIDEO_VOL, 0x8808);
- wrcodec(&s->codec, AC97_AUX_VOL, 0x8808);
- wrcodec(&s->codec, AC97_PCMOUT_VOL, 0x0808);
- wrcodec(&s->codec, AC97_GENERAL_PURPOSE, 0x2000);
-#endif
-
- return 0;
-
- err_dev3:
- unregister_sound_mixer(s->codec.dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- free_au1000_dma(s->dma_adc.dmanr);
- err_dma2:
- free_au1000_dma(s->dma_dac.dmanr);
- err_dma1:
- release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
- return -1;
-}
-
-static void au1000_remove(void)
-{
- struct au1000_state *s = &au1000_state;
-
- if (!s)
- return;
-#ifdef AU1000_DEBUG
- if (s->ps)
- remove_proc_entry(AU1000_MODULE_NAME, NULL);
-#endif /* AU1000_DEBUG */
- synchronize_irq();
- free_au1000_dma(s->dma_adc.dmanr);
- free_au1000_dma(s->dma_dac.dmanr);
- release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->codec.dev_mixer);
-}
-
-static int __init init_au1000(void)
-{
- info("stevel@mvista.com, built " __TIME__ " on " __DATE__);
- return au1000_probe();
-}
-
-static void __exit cleanup_au1000(void)
-{
- info("unloading");
- au1000_remove();
-}
-
-module_init(init_au1000);
-module_exit(cleanup_au1000);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-static int __init au1000_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("au1000_audio=", au1000_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/audio_syms.c b/sound/oss/audio_syms.c
deleted file mode 100644
index 5da217f..0000000
--- a/sound/oss/audio_syms.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Exported symbols for audio driver.
- */
-
-#include <linux/module.h>
-
-char audio_syms_symbol;
-
-#include "sound_config.h"
-#include "sound_calls.h"
-
-EXPORT_SYMBOL(DMAbuf_start_dma);
-EXPORT_SYMBOL(DMAbuf_open_dma);
-EXPORT_SYMBOL(DMAbuf_close_dma);
-EXPORT_SYMBOL(DMAbuf_inputintr);
-EXPORT_SYMBOL(DMAbuf_outputintr);
diff --git a/sound/oss/awe_hw.h b/sound/oss/awe_hw.h
deleted file mode 100644
index ab00c3c..0000000
--- a/sound/oss/awe_hw.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * sound/oss/awe_hw.h
- *
- * Access routines and definitions for the low level driver for the
- * Creative AWE32/SB32/AWE64 wave table synth.
- * version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-2000 Takashi Iwai
- *
- * 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.
- */
-
-#ifndef AWE_HW_H_DEF
-#define AWE_HW_H_DEF
-
-/*
- * Emu-8000 control registers
- * name(channel) reg, port
- */
-
-#define awe_cmd_idx(reg,ch) (((reg)<< 5) | (ch))
-
-#define Data0 0 /* 0x620: doubleword r/w */
-#define Data1 1 /* 0xA20: doubleword r/w */
-#define Data2 2 /* 0xA22: word r/w */
-#define Data3 3 /* 0xE20: word r/w */
-#define Pointer 4 /* 0xE22 register pointer r/w */
-
-#define AWE_CPF(ch) awe_cmd_idx(0,ch), Data0 /* DW: current pitch and fractional address */
-#define AWE_PTRX(ch) awe_cmd_idx(1,ch), Data0 /* DW: pitch target and reverb send */
-#define AWE_CVCF(ch) awe_cmd_idx(2,ch), Data0 /* DW: current volume and filter cutoff */
-#define AWE_VTFT(ch) awe_cmd_idx(3,ch), Data0 /* DW: volume and filter cutoff targets */
-#define AWE_0080(ch) awe_cmd_idx(4,ch), Data0 /* DW: ?? */
-#define AWE_00A0(ch) awe_cmd_idx(5,ch), Data0 /* DW: ?? */
-#define AWE_PSST(ch) awe_cmd_idx(6,ch), Data0 /* DW: pan send and loop start address */
-#define AWE_CSL(ch) awe_cmd_idx(7,ch), Data0 /* DW: chorus send and loop end address */
-#define AWE_CCCA(ch) awe_cmd_idx(0,ch), Data1 /* DW: Q, control bits, and current address */
-#define AWE_HWCF4 awe_cmd_idx(1,9), Data1 /* DW: config dw 4 */
-#define AWE_HWCF5 awe_cmd_idx(1,10), Data1 /* DW: config dw 5 */
-#define AWE_HWCF6 awe_cmd_idx(1,13), Data1 /* DW: config dw 6 */
-#define AWE_HWCF7 awe_cmd_idx(1,14), Data1 /* DW: config dw 7? (not documented) */
-#define AWE_SMALR awe_cmd_idx(1,20), Data1 /* DW: sound memory address for left read */
-#define AWE_SMARR awe_cmd_idx(1,21), Data1 /* DW: for right read */
-#define AWE_SMALW awe_cmd_idx(1,22), Data1 /* DW: sound memory address for left write */
-#define AWE_SMARW awe_cmd_idx(1,23), Data1 /* DW: for right write */
-#define AWE_SMLD awe_cmd_idx(1,26), Data1 /* W: sound memory left data */
-#define AWE_SMRD awe_cmd_idx(1,26), Data2 /* W: right data */
-#define AWE_WC awe_cmd_idx(1,27), Data2 /* W: sample counter */
-#define AWE_WC_Cmd awe_cmd_idx(1,27)
-#define AWE_WC_Port Data2
-#define AWE_HWCF1 awe_cmd_idx(1,29), Data1 /* W: config w 1 */
-#define AWE_HWCF2 awe_cmd_idx(1,30), Data1 /* W: config w 2 */
-#define AWE_HWCF3 awe_cmd_idx(1,31), Data1 /* W: config w 3 */
-#define AWE_INIT1(ch) awe_cmd_idx(2,ch), Data1 /* W: init array 1 */
-#define AWE_INIT2(ch) awe_cmd_idx(2,ch), Data2 /* W: init array 2 */
-#define AWE_INIT3(ch) awe_cmd_idx(3,ch), Data1 /* W: init array 3 */
-#define AWE_INIT4(ch) awe_cmd_idx(3,ch), Data2 /* W: init array 4 */
-#define AWE_ENVVOL(ch) awe_cmd_idx(4,ch), Data1 /* W: volume envelope delay */
-#define AWE_DCYSUSV(ch) awe_cmd_idx(5,ch), Data1 /* W: volume envelope sustain and decay */
-#define AWE_ENVVAL(ch) awe_cmd_idx(6,ch), Data1 /* W: modulation envelope delay */
-#define AWE_DCYSUS(ch) awe_cmd_idx(7,ch), Data1 /* W: modulation envelope sustain and decay */
-#define AWE_ATKHLDV(ch) awe_cmd_idx(4,ch), Data2 /* W: volume envelope attack and hold */
-#define AWE_LFO1VAL(ch) awe_cmd_idx(5,ch), Data2 /* W: LFO#1 Delay */
-#define AWE_ATKHLD(ch) awe_cmd_idx(6,ch), Data2 /* W: modulation envelope attack and hold */
-#define AWE_LFO2VAL(ch) awe_cmd_idx(7,ch), Data2 /* W: LFO#2 Delay */
-#define AWE_IP(ch) awe_cmd_idx(0,ch), Data3 /* W: initial pitch */
-#define AWE_IFATN(ch) awe_cmd_idx(1,ch), Data3 /* W: initial filter cutoff and attenuation */
-#define AWE_PEFE(ch) awe_cmd_idx(2,ch), Data3 /* W: pitch and filter envelope heights */
-#define AWE_FMMOD(ch) awe_cmd_idx(3,ch), Data3 /* W: vibrato and filter modulation freq */
-#define AWE_TREMFRQ(ch) awe_cmd_idx(4,ch), Data3 /* W: LFO#1 tremolo amount and freq */
-#define AWE_FM2FRQ2(ch) awe_cmd_idx(5,ch), Data3 /* W: LFO#2 vibrato amount and freq */
-
-/* used during detection (returns ROM version?; not documented in ADIP) */
-#define AWE_U1 0xE0, Data3 /* (R)(W) used in initialization */
-#define AWE_U2(ch) 0xC0+(ch), Data3 /* (W)(W) used in init envelope */
-
-
-#define AWE_MAX_VOICES 32
-#define AWE_NORMAL_VOICES 30 /*30&31 are reserved for DRAM refresh*/
-
-#define AWE_MAX_CHANNELS 32 /* max midi channels (must >= voices) */
-#define AWE_MAX_LAYERS AWE_MAX_VOICES /* maximum number of multiple layers */
-
-#define AWE_DRAM_OFFSET 0x200000
-#define AWE_MAX_DRAM_SIZE (28 * 1024) /* 28 MB is max onboard memory */
-
-#endif
diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c
deleted file mode 100644
index 01c592c..0000000
--- a/sound/oss/awe_wave.c
+++ /dev/null
@@ -1,6149 +0,0 @@
-/*
- * sound/oss/awe_wave.c
- *
- * The low level driver for the AWE32/SB32/AWE64 wave table synth.
- * version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-2000 Takashi Iwai
- *
- * 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.
- */
-
-/*
- * Changelog:
- * Aug 18, 2003, Adam Belay <ambx1@neo.rr.com>
- * - detection code rewrite
- */
-
-#include <linux/awe_voice.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/pnp.h>
-
-#include "sound_config.h"
-
-#include "awe_wave.h"
-#include "awe_hw.h"
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-#include "tuning.h"
-#include <linux/ultrasound.h>
-#endif
-
-/*
- * debug message
- */
-
-#ifdef AWE_DEBUG_ON
-#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
-#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
-#define FATALERR(XXX) XXX
-#else
-#define DEBUG(LVL,XXX) /**/
-#define ERRMSG(XXX) XXX
-#define FATALERR(XXX) XXX
-#endif
-
-/*
- * bank and voice record
- */
-
-typedef struct _sf_list sf_list;
-typedef struct _awe_voice_list awe_voice_list;
-typedef struct _awe_sample_list awe_sample_list;
-
-/* soundfont record */
-struct _sf_list {
- unsigned short sf_id; /* id number */
- unsigned short type; /* lock & shared flags */
- int num_info; /* current info table index */
- int num_sample; /* current sample table index */
- int mem_ptr; /* current word byte pointer */
- awe_voice_list *infos, *last_infos; /* instruments */
- awe_sample_list *samples, *last_samples; /* samples */
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- sf_list *shared; /* shared list */
- unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */
-#endif
- sf_list *next, *prev;
-};
-
-/* instrument list */
-struct _awe_voice_list {
- awe_voice_info v; /* instrument information */
- sf_list *holder; /* parent sf_list of this record */
- unsigned char bank, instr; /* preset number information */
- char type, disabled; /* type=normal/mapped, disabled=boolean */
- awe_voice_list *next; /* linked list with same sf_id */
- awe_voice_list *next_instr; /* instrument list */
- awe_voice_list *next_bank; /* hash table list */
-};
-
-/* voice list type */
-#define V_ST_NORMAL 0
-#define V_ST_MAPPED 1
-
-/* sample list */
-struct _awe_sample_list {
- awe_sample_info v; /* sample information */
- sf_list *holder; /* parent sf_list of this record */
- awe_sample_list *next; /* linked list with same sf_id */
-};
-
-/* sample and information table */
-static int current_sf_id; /* current number of fonts */
-static int locked_sf_id; /* locked position */
-static sf_list *sfhead, *sftail; /* linked-lists */
-
-#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0)
-#define awe_free_info() (sftail ? sftail->num_info : 0)
-#define awe_free_sample() (sftail ? sftail->num_sample : 0)
-
-#define AWE_MAX_PRESETS 256
-#define AWE_DEFAULT_PRESET 0
-#define AWE_DEFAULT_BANK 0
-#define AWE_DEFAULT_DRUM 0
-#define AWE_DRUM_BANK 128
-
-#define MAX_LAYERS AWE_MAX_VOICES
-
-/* preset table index */
-static awe_voice_list *preset_table[AWE_MAX_PRESETS];
-
-/*
- * voice table
- */
-
-/* effects table */
-typedef struct FX_Rec { /* channel effects */
- unsigned char flags[AWE_FX_END];
- short val[AWE_FX_END];
-} FX_Rec;
-
-
-/* channel parameters */
-typedef struct _awe_chan_info {
- int channel; /* channel number */
- int bank; /* current tone bank */
- int instr; /* current program */
- int bender; /* midi pitchbend (-8192 - 8192) */
- int bender_range; /* midi bender range (x100) */
- int panning; /* panning (0-127) */
- int main_vol; /* channel volume (0-127) */
- int expression_vol; /* midi expression (0-127) */
- int chan_press; /* channel pressure */
- int sustained; /* sustain status in MIDI */
- FX_Rec fx; /* effects */
- FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
-} awe_chan_info;
-
-/* voice parameters */
-typedef struct _voice_info {
- int state;
-#define AWE_ST_OFF (1<<0) /* no sound */
-#define AWE_ST_ON (1<<1) /* playing */
-#define AWE_ST_STANDBY (1<<2) /* stand by for playing */
-#define AWE_ST_SUSTAINED (1<<3) /* sustained */
-#define AWE_ST_MARK (1<<4) /* marked for allocation */
-#define AWE_ST_DRAM (1<<5) /* DRAM read/write */
-#define AWE_ST_FM (1<<6) /* reserved for FM */
-#define AWE_ST_RELEASED (1<<7) /* released */
-
- int ch; /* midi channel */
- int key; /* internal key for search */
- int layer; /* layer number (for channel mode only) */
- int time; /* allocated time */
- awe_chan_info *cinfo; /* channel info */
-
- int note; /* midi key (0-127) */
- int velocity; /* midi velocity (0-127) */
- int sostenuto; /* sostenuto on/off */
- awe_voice_info *sample; /* assigned voice */
-
- /* EMU8000 parameters */
- int apitch; /* pitch parameter */
- int avol; /* volume parameter */
- int apan; /* panning parameter */
- int acutoff; /* cutoff parameter */
- short aaux; /* aux word */
-} voice_info;
-
-/* voice information */
-static voice_info voices[AWE_MAX_VOICES];
-
-#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))
-#define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON)
-#define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))
-#define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))
-
-
-/* MIDI channel effects information (for hw control) */
-static awe_chan_info channels[AWE_MAX_CHANNELS];
-
-
-/*
- * global variables
- */
-
-#ifndef AWE_DEFAULT_BASE_ADDR
-#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */
-#endif
-
-#ifndef AWE_DEFAULT_MEM_SIZE
-#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */
-#endif
-
-static int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
-static int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
-#ifdef CONFIG_PNP
-static int isapnp = -1;
-#else
-static int isapnp;
-#endif
-
-MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
-MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "base i/o port of Emu8000");
-module_param(memsize, int, 0);
-MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp, "use ISAPnP detection");
-
-/* DRAM start offset */
-static int awe_mem_start = AWE_DRAM_OFFSET;
-
-/* maximum channels for playing */
-static int awe_max_voices = AWE_MAX_VOICES;
-
-static int patch_opened; /* sample already loaded? */
-
-static char atten_relative = FALSE;
-static short atten_offset;
-
-static int awe_present = FALSE; /* awe device present? */
-static int awe_busy = FALSE; /* awe device opened? */
-
-static int my_dev = -1;
-
-#define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25))
-#define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c)))
-#define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c)))
-#define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c)))
-static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */
-
-static int playing_mode = AWE_PLAY_INDIRECT;
-#define SINGLE_LAYER_MODE() (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT)
-#define MULTI_LAYER_MODE() (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2)
-
-static int current_alloc_time; /* voice allocation index for channel mode */
-
-static struct synth_info awe_info = {
- "AWE32 Synth", /* name */
- 0, /* device */
- SYNTH_TYPE_SAMPLE, /* synth_type */
- SAMPLE_TYPE_AWE32, /* synth_subtype */
- 0, /* perc_mode (obsolete) */
- AWE_MAX_VOICES, /* nr_voices */
- 0, /* nr_drums (obsolete) */
- 400 /* instr_bank_size */
-};
-
-
-static struct voice_alloc_info *voice_alloc; /* set at initialization */
-
-
-/*
- * function prototypes
- */
-
-static int awe_request_region(void);
-static void awe_release_region(void);
-
-static void awe_reset_samples(void);
-/* emu8000 chip i/o access */
-static void setup_ports(int p1, int p2, int p3);
-static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);
-static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data);
-static unsigned short awe_peek(unsigned short cmd, unsigned short port);
-static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port);
-static void awe_wait(unsigned short delay);
-
-/* initialize emu8000 chip */
-static void awe_initialize(void);
-
-/* set voice parameters */
-static void awe_init_ctrl_parms(int init_all);
-static void awe_init_voice_info(awe_voice_info *vp);
-static void awe_init_voice_parm(awe_voice_parm *pp);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int freq_to_note(int freq);
-static int calc_rate_offset(int Hz);
-/*static int calc_parm_delay(int msec);*/
-static int calc_parm_hold(int msec);
-static int calc_parm_attack(int msec);
-static int calc_parm_decay(int msec);
-static int calc_parm_search(int msec, short *table);
-#endif /* gus compat */
-
-/* turn on/off note */
-static void awe_note_on(int voice);
-static void awe_note_off(int voice);
-static void awe_terminate(int voice);
-static void awe_exclusive_off(int voice);
-static void awe_note_off_all(int do_sustain);
-
-/* calculate voice parameters */
-typedef void (*fx_affect_func)(int voice, int forced);
-static void awe_set_pitch(int voice, int forced);
-static void awe_set_voice_pitch(int voice, int forced);
-static void awe_set_volume(int voice, int forced);
-static void awe_set_voice_vol(int voice, int forced);
-static void awe_set_pan(int voice, int forced);
-static void awe_fx_fmmod(int voice, int forced);
-static void awe_fx_tremfrq(int voice, int forced);
-static void awe_fx_fm2frq2(int voice, int forced);
-static void awe_fx_filterQ(int voice, int forced);
-static void awe_calc_pitch(int voice);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_calc_pitch_from_freq(int voice, int freq);
-#endif
-static void awe_calc_volume(int voice);
-static void awe_update_volume(void);
-static void awe_change_master_volume(short val);
-static void awe_voice_init(int voice, int init_all);
-static void awe_channel_init(int ch, int init_all);
-static void awe_fx_init(int ch);
-static void awe_send_effect(int voice, int layer, int type, int val);
-static void awe_modwheel_change(int voice, int value);
-
-/* sequencer interface */
-static int awe_open(int dev, int mode);
-static void awe_close(int dev);
-static int awe_ioctl(int dev, unsigned int cmd, void __user * arg);
-static int awe_kill_note(int dev, int voice, int note, int velocity);
-static int awe_start_note(int dev, int v, int note_num, int volume);
-static int awe_set_instr(int dev, int voice, int instr_no);
-static int awe_set_instr_2(int dev, int voice, int instr_no);
-static void awe_reset(int dev);
-static void awe_hw_control(int dev, unsigned char *event);
-static int awe_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag);
-static void awe_aftertouch(int dev, int voice, int pressure);
-static void awe_controller(int dev, int voice, int ctrl_num, int value);
-static void awe_panning(int dev, int voice, int value);
-static void awe_volume_method(int dev, int mode);
-static void awe_bender(int dev, int voice, int value);
-static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
-static void awe_setup_voice(int dev, int voice, int chn);
-
-#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press)
-
-/* hardware controls */
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_hw_gus_control(int dev, int cmd, unsigned char *event);
-#endif
-static void awe_hw_awe_control(int dev, int cmd, unsigned char *event);
-static void awe_voice_change(int voice, fx_affect_func func);
-static void awe_sostenuto_on(int voice, int forced);
-static void awe_sustain_off(int voice, int forced);
-static void awe_terminate_and_init(int voice, int forced);
-
-/* voice search */
-static int awe_search_key(int bank, int preset, int note);
-static awe_voice_list *awe_search_instr(int bank, int preset, int note);
-static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist);
-static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
-static void awe_alloc_one_voice(int voice, int note, int velocity);
-static int awe_clear_voice(void);
-
-/* load / remove patches */
-static int awe_open_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_close_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_info(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_remove_info(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_data(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_replace_data(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_map(awe_patch_info *patch, const char __user *addr, int count);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag);
-#endif
-/*static int awe_probe_info(awe_patch_info *patch, const char __user *addr, int count);*/
-static int awe_probe_data(awe_patch_info *patch, const char __user *addr, int count);
-static sf_list *check_patch_opened(int type, char *name);
-static int awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *sp, int channels);
-static int awe_create_sf(int type, char *name);
-static void awe_free_sf(sf_list *sf);
-static void add_sf_info(sf_list *sf, awe_voice_list *rec);
-static void add_sf_sample(sf_list *sf, awe_sample_list *smp);
-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next);
-static void add_info_list(awe_voice_list *rec);
-static void awe_remove_samples(int sf_id);
-static void rebuild_preset_list(void);
-static short awe_set_sample(awe_voice_list *rec);
-static awe_sample_list *search_sample_index(sf_list *sf, int sample);
-
-static int is_identical_holder(sf_list *sf1, sf_list *sf2);
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-static int is_identical_name(unsigned char *name, sf_list *p);
-static int is_shared_sf(unsigned char *name);
-static int info_duplicated(sf_list *sf, awe_voice_list *rec);
-#endif /* allow sharing */
-
-/* lowlevel functions */
-static void awe_init_audio(void);
-static void awe_init_dma(void);
-static void awe_init_array(void);
-static void awe_send_array(unsigned short *data);
-static void awe_tweak_voice(int voice);
-static void awe_tweak(void);
-static void awe_init_fm(void);
-static int awe_open_dram_for_write(int offset, int channels);
-static void awe_open_dram_for_check(void);
-static void awe_close_dram(void);
-/*static void awe_write_dram(unsigned short c);*/
-static int awe_detect_base(int addr);
-static int awe_detect(void);
-static void awe_check_dram(void);
-static int awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count);
-static void awe_set_chorus_mode(int mode);
-static void awe_update_chorus_mode(void);
-static int awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count);
-static void awe_set_reverb_mode(int mode);
-static void awe_update_reverb_mode(void);
-static void awe_equalizer(int bass, int treble);
-static void awe_update_equalizer(void);
-
-#ifdef CONFIG_AWE32_MIXER
-static void attach_mixer(void);
-static void unload_mixer(void);
-#endif
-
-#ifdef CONFIG_AWE32_MIDIEMU
-static void attach_midiemu(void);
-static void unload_midiemu(void);
-#endif
-
-#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)
-
-/*
- * control parameters
- */
-
-
-#ifdef AWE_USE_NEW_VOLUME_CALC
-#define DEF_VOLUME_CALC TRUE
-#else
-#define DEF_VOLUME_CALC FALSE
-#endif /* new volume */
-
-#define DEF_ZERO_ATTEN 32 /* 12dB below */
-#define DEF_MOD_SENSE 18
-#define DEF_CHORUS_MODE 2
-#define DEF_REVERB_MODE 4
-#define DEF_BASS_LEVEL 5
-#define DEF_TREBLE_LEVEL 9
-
-static struct CtrlParmsDef {
- int value;
- int init_each_time;
- void (*update)(void);
-} ctrl_parms[AWE_MD_END] = {
- {0,0, NULL}, {0,0, NULL}, /* <-- not used */
- {AWE_VERSION_NUMBER, FALSE, NULL},
- {TRUE, FALSE, NULL}, /* exclusive */
- {TRUE, FALSE, NULL}, /* realpan */
- {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */
- {FALSE, TRUE, NULL}, /* keep effect */
- {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */
- {FALSE, FALSE, NULL}, /* chn_prior */
- {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */
- {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */
- {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */
- {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */
- {FALSE, FALSE, NULL}, /* toggle_drum_bank */
- {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */
- {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */
- {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */
- {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */
- {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */
- {0, FALSE, NULL}, /* debug mode */
- {FALSE, FALSE, NULL}, /* pan exchange */
-};
-
-static int ctrls[AWE_MD_END];
-
-
-/*
- * synth operation table
- */
-
-static struct synth_operations awe_operations =
-{
- .owner = THIS_MODULE,
- .id = "EMU8K",
- .info = &awe_info,
- .midi_dev = 0,
- .synth_type = SYNTH_TYPE_SAMPLE,
- .synth_subtype = SAMPLE_TYPE_AWE32,
- .open = awe_open,
- .close = awe_close,
- .ioctl = awe_ioctl,
- .kill_note = awe_kill_note,
- .start_note = awe_start_note,
- .set_instr = awe_set_instr_2,
- .reset = awe_reset,
- .hw_control = awe_hw_control,
- .load_patch = awe_load_patch,
- .aftertouch = awe_aftertouch,
- .controller = awe_controller,
- .panning = awe_panning,
- .volume_method = awe_volume_method,
- .bender = awe_bender,
- .alloc_voice = awe_alloc,
- .setup_voice = awe_setup_voice
-};
-
-static void free_tables(void)
-{
- if (sftail) {
- sf_list *p, *prev;
- for (p = sftail; p; p = prev) {
- prev = p->prev;
- awe_free_sf(p);
- }
- }
- sfhead = sftail = NULL;
-}
-
-/*
- * clear sample tables
- */
-
-static void
-awe_reset_samples(void)
-{
- /* free all bank tables */
- memset(preset_table, 0, sizeof(preset_table));
- free_tables();
-
- current_sf_id = 0;
- locked_sf_id = 0;
- patch_opened = 0;
-}
-
-
-/*
- * EMU register access
- */
-
-/* select a given AWE32 pointer */
-static int awe_ports[5];
-static int port_setuped = FALSE;
-static int awe_cur_cmd = -1;
-#define awe_set_cmd(cmd) \
-if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
-
-/* write 16bit data */
-static void
-awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
-{
- awe_set_cmd(cmd);
- outw(data, awe_ports[port]);
-}
-
-/* write 32bit data */
-static void
-awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
-{
- unsigned short addr = awe_ports[port];
- awe_set_cmd(cmd);
- outw(data, addr); /* write lower 16 bits */
- outw(data >> 16, addr + 2); /* write higher 16 bits */
-}
-
-/* read 16bit data */
-static unsigned short
-awe_peek(unsigned short cmd, unsigned short port)
-{
- unsigned short k;
- awe_set_cmd(cmd);
- k = inw(awe_ports[port]);
- return k;
-}
-
-/* read 32bit data */
-static unsigned int
-awe_peek_dw(unsigned short cmd, unsigned short port)
-{
- unsigned int k1, k2;
- unsigned short addr = awe_ports[port];
- awe_set_cmd(cmd);
- k1 = inw(addr);
- k2 = inw(addr + 2);
- k1 |= k2 << 16;
- return k1;
-}
-
-/* wait delay number of AWE32 44100Hz clocks */
-#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */
-static void
-awe_wait(unsigned short delay)
-{
- unsigned short clock, target;
- unsigned short port = awe_ports[AWE_WC_Port];
- int counter;
-
- /* sample counter */
- awe_set_cmd(AWE_WC_Cmd);
- clock = (unsigned short)inw(port);
- target = clock + delay;
- counter = 0;
- if (target < clock) {
- for (; (unsigned short)inw(port) > target; counter++)
- if (counter > 65536)
- break;
- }
- for (; (unsigned short)inw(port) < target; counter++)
- if (counter > 65536)
- break;
-}
-#else
-
-static void awe_wait(unsigned short delay)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
-}
-/*
-static void awe_wait(unsigned short delay)
-{
- udelay(((unsigned long)delay * 1000000L + 44099) / 44100);
-}
-*/
-#endif /* wait by loop */
-
-/* write a word data */
-#define awe_write_dram(c) awe_poke(AWE_SMLD, c)
-
-/*
- * AWE32 voice parameters
- */
-
-/* initialize voice_info record */
-static void
-awe_init_voice_info(awe_voice_info *vp)
-{
- vp->sample = 0;
- vp->rate_offset = 0;
-
- vp->start = 0;
- vp->end = 0;
- vp->loopstart = 0;
- vp->loopend = 0;
- vp->mode = 0;
- vp->root = 60;
- vp->tune = 0;
- vp->low = 0;
- vp->high = 127;
- vp->vellow = 0;
- vp->velhigh = 127;
-
- vp->fixkey = -1;
- vp->fixvel = -1;
- vp->fixpan = -1;
- vp->pan = -1;
-
- vp->exclusiveClass = 0;
- vp->amplitude = 127;
- vp->attenuation = 0;
- vp->scaleTuning = 100;
-
- awe_init_voice_parm(&vp->parm);
-}
-
-/* initialize voice_parm record:
- * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
- * Vibrato and Tremolo effects are zero.
- * Cutoff is maximum.
- * Chorus and Reverb effects are zero.
- */
-static void
-awe_init_voice_parm(awe_voice_parm *pp)
-{
- pp->moddelay = 0x8000;
- pp->modatkhld = 0x7f7f;
- pp->moddcysus = 0x7f7f;
- pp->modrelease = 0x807f;
- pp->modkeyhold = 0;
- pp->modkeydecay = 0;
-
- pp->voldelay = 0x8000;
- pp->volatkhld = 0x7f7f;
- pp->voldcysus = 0x7f7f;
- pp->volrelease = 0x807f;
- pp->volkeyhold = 0;
- pp->volkeydecay = 0;
-
- pp->lfo1delay = 0x8000;
- pp->lfo2delay = 0x8000;
- pp->pefe = 0;
-
- pp->fmmod = 0;
- pp->tremfrq = 0;
- pp->fm2frq2 = 0;
-
- pp->cutoff = 0xff;
- pp->filterQ = 0;
-
- pp->chorus = 0;
- pp->reverb = 0;
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* convert frequency mHz to abstract cents (= midi key * 100) */
-static int
-freq_to_note(int mHz)
-{
- /* abscents = log(mHz/8176) / log(2) * 1200 */
- unsigned int max_val = (unsigned int)0xffffffff / 10000;
- int i, times;
- unsigned int base;
- unsigned int freq;
- int note, tune;
-
- if (mHz == 0)
- return 0;
- if (mHz < 0)
- return 12799; /* maximum */
-
- freq = mHz;
- note = 0;
- for (base = 8176 * 2; freq >= base; base *= 2) {
- note += 12;
- if (note >= 128) /* over maximum */
- return 12799;
- }
- base /= 2;
-
- /* to avoid overflow... */
- times = 10000;
- while (freq > max_val) {
- max_val *= 10;
- times /= 10;
- base /= 10;
- }
-
- freq = freq * times / base;
- for (i = 0; i < 12; i++) {
- if (freq < semitone_tuning[i+1])
- break;
- note++;
- }
-
- tune = 0;
- freq = freq * 10000 / semitone_tuning[i];
- for (i = 0; i < 100; i++) {
- if (freq < cent_tuning[i+1])
- break;
- tune++;
- }
-
- return note * 100 + tune;
-}
-
-
-/* convert Hz to AWE32 rate offset:
- * sample pitch offset for the specified sample rate
- * rate=44100 is no offset, each 4096 is 1 octave (twice).
- * eg, when rate is 22050, this offset becomes -4096.
- */
-static int
-calc_rate_offset(int Hz)
-{
- /* offset = log(Hz / 44100) / log(2) * 4096 */
- int freq, base, i;
-
- /* maybe smaller than max (44100Hz) */
- if (Hz <= 0 || Hz >= 44100) return 0;
-
- base = 0;
- for (freq = Hz * 2; freq < 44100; freq *= 2)
- base++;
- base *= 1200;
-
- freq = 44100 * 10000 / (freq/2);
- for (i = 0; i < 12; i++) {
- if (freq < semitone_tuning[i+1])
- break;
- base += 100;
- }
- freq = freq * 10000 / semitone_tuning[i];
- for (i = 0; i < 100; i++) {
- if (freq < cent_tuning[i+1])
- break;
- base++;
- }
- return -base * 4096 / 1200;
-}
-
-
-/*
- * convert envelope time parameter to AWE32 raw parameter
- */
-
-/* attack & decay/release time table (msec) */
-static short attack_time_tbl[128] = {
-32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,
-707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,
-361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,
-180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,
-90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,
-45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,
-22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
-11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,
-};
-
-static short decay_time_tbl[128] = {
-32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
-2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
-1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,
-691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,
-345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,
-172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,
-86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,
-43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,
-};
-
-#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725);
-
-/* delay time = 0x8000 - msec/92 */
-static int
-calc_parm_hold(int msec)
-{
- int val = (0x7f * 92 - msec) / 92;
- if (val < 1) val = 1;
- if (val > 127) val = 127;
- return val;
-}
-
-/* attack time: search from time table */
-static int
-calc_parm_attack(int msec)
-{
- return calc_parm_search(msec, attack_time_tbl);
-}
-
-/* decay/release time: search from time table */
-static int
-calc_parm_decay(int msec)
-{
- return calc_parm_search(msec, decay_time_tbl);
-}
-
-/* search an index for specified time from given time table */
-static int
-calc_parm_search(int msec, short *table)
-{
- int left = 1, right = 127, mid;
- while (left < right) {
- mid = (left + right) / 2;
- if (msec < (int)table[mid])
- left = mid + 1;
- else
- right = mid;
- }
- return left;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*
- * effects table
- */
-
-/* set an effect value */
-#define FX_FLAG_OFF 0
-#define FX_FLAG_SET 1
-#define FX_FLAG_ADD 2
-
-#define FX_SET(rec,type,value) \
- ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value))
-#define FX_ADD(rec,type,value) \
- ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value))
-#define FX_UNSET(rec,type) \
- ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0)
-
-/* check the effect value is set */
-#define FX_ON(rec,type) ((rec)->flags[type])
-
-#define PARM_BYTE 0
-#define PARM_WORD 1
-#define PARM_SIGN 2
-
-static struct PARM_DEFS {
- int type; /* byte or word */
- int low, high; /* value range */
- fx_affect_func realtime; /* realtime paramater change */
-} parm_defs[] = {
- {PARM_WORD, 0, 0x8000, NULL}, /* env1 delay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 attack */
- {PARM_BYTE, 0, 0x7e, NULL}, /* env1 hold */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 decay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 release */
- {PARM_BYTE, 0, 0x7f, NULL}, /* env1 sustain */
- {PARM_BYTE, 0, 0xff, NULL}, /* env1 pitch */
- {PARM_BYTE, 0, 0xff, NULL}, /* env1 cutoff */
-
- {PARM_WORD, 0, 0x8000, NULL}, /* env2 delay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 attack */
- {PARM_BYTE, 0, 0x7e, NULL}, /* env2 hold */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 decay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 release */
- {PARM_BYTE, 0, 0x7f, NULL}, /* env2 sustain */
-
- {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */
- {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */
- {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */
- {PARM_SIGN, -128, 127, awe_fx_fmmod}, /* lfo1 pitch */
- {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff */
-
- {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */
- {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */
- {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */
-
- {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */
- {PARM_BYTE, 0, 0xff, NULL}, /* chorus */
- {PARM_BYTE, 0, 0xff, NULL}, /* reverb */
- {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial cutoff */
- {PARM_BYTE, 0, 15, awe_fx_filterQ}, /* initial resonance */
-
- {PARM_WORD, 0, 0xffff, NULL}, /* sample start */
- {PARM_WORD, 0, 0xffff, NULL}, /* loop start */
- {PARM_WORD, 0, 0xffff, NULL}, /* loop end */
- {PARM_WORD, 0, 0xffff, NULL}, /* coarse sample start */
- {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop start */
- {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop end */
- {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial attenuation */
-};
-
-
-static unsigned char
-FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value)
-{
- int effect = 0;
- int on = 0;
- if (lay && (on = FX_ON(lay, type)) != 0)
- effect = lay->val[type];
- if (!on && (on = FX_ON(rec, type)) != 0)
- effect = rec->val[type];
- if (on == FX_FLAG_ADD) {
- if (parm_defs[type].type == PARM_SIGN) {
- if (value > 0x7f)
- effect += (int)value - 0x100;
- else
- effect += (int)value;
- } else {
- effect += (int)value;
- }
- }
- if (on) {
- if (effect < parm_defs[type].low)
- effect = parm_defs[type].low;
- else if (effect > parm_defs[type].high)
- effect = parm_defs[type].high;
- return (unsigned char)effect;
- }
- return value;
-}
-
-/* get word effect value */
-static unsigned short
-FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value)
-{
- int effect = 0;
- int on = 0;
- if (lay && (on = FX_ON(lay, type)) != 0)
- effect = lay->val[type];
- if (!on && (on = FX_ON(rec, type)) != 0)
- effect = rec->val[type];
- if (on == FX_FLAG_ADD)
- effect += (int)value;
- if (on) {
- if (effect < parm_defs[type].low)
- effect = parm_defs[type].low;
- else if (effect > parm_defs[type].high)
- effect = parm_defs[type].high;
- return (unsigned short)effect;
- }
- return value;
-}
-
-/* get word (upper=type1/lower=type2) effect value */
-static unsigned short
-FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value)
-{
- unsigned short tmp;
- tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8));
- tmp <<= 8;
- tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff));
- return tmp;
-}
-
-/* address offset */
-static int
-FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode)
-{
- int addr = 0;
- if (lay && FX_ON(lay, hi))
- addr = (short)lay->val[hi];
- else if (FX_ON(rec, hi))
- addr = (short)rec->val[hi];
- addr = addr << 15;
- if (lay && FX_ON(lay, lo))
- addr += (short)lay->val[lo];
- else if (FX_ON(rec, lo))
- addr += (short)rec->val[lo];
- if (!(mode & AWE_SAMPLE_8BITS))
- addr /= 2;
- return addr;
-}
-
-
-/*
- * turn on/off sample
- */
-
-/* table for volume target calculation */
-static unsigned short voltarget[16] = {
- 0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58,
- 0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90
-};
-
-static void
-awe_note_on(int voice)
-{
- unsigned int temp;
- int addr;
- int vtarget, ftarget, ptarget, pitch;
- awe_voice_info *vp;
- awe_voice_parm_block *parm;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- /* A voice sample must assigned before calling */
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- parm = (awe_voice_parm_block*)&vp->parm;
-
- /* channel to be silent and idle */
- awe_poke(AWE_DCYSUSV(voice), 0x0080);
- awe_poke(AWE_VTFT(voice), 0x0000FFFF);
- awe_poke(AWE_CVCF(voice), 0x0000FFFF);
- awe_poke(AWE_PTRX(voice), 0);
- awe_poke(AWE_CPF(voice), 0);
-
- /* set pitch offset */
- awe_set_pitch(voice, TRUE);
-
- /* modulation & volume envelope */
- if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) {
- awe_poke(AWE_ENVVAL(voice), 0xBFFF);
- pitch = (parm->env1pit<<4) + voices[voice].apitch;
- if (pitch > 0xffff) pitch = 0xffff;
- /* calculate filter target */
- ftarget = parm->cutoff + parm->env1fc;
- limitvalue(ftarget, 0, 255);
- ftarget <<= 8;
- } else {
- awe_poke(AWE_ENVVAL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay));
- ftarget = parm->cutoff;
- ftarget <<= 8;
- pitch = voices[voice].apitch;
- }
-
- /* calcualte pitch target */
- if (pitch != 0xffff) {
- ptarget = 1 << (pitch >> 12);
- if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710;
- if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710;
- if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710;
- ptarget += (ptarget>>1);
- if (ptarget > 0xffff) ptarget = 0xffff;
-
- } else ptarget = 0xffff;
- if (parm->modatk >= 0x80)
- awe_poke(AWE_ATKHLD(voice),
- FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f);
- else
- awe_poke(AWE_ATKHLD(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK,
- vp->parm.modatkhld));
- awe_poke(AWE_DCYSUS(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY,
- vp->parm.moddcysus));
-
- if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) {
- awe_poke(AWE_ENVVOL(voice), 0xBFFF);
- vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4);
- } else {
- awe_poke(AWE_ENVVOL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay));
- vtarget = 0;
- }
- if (parm->volatk >= 0x80)
- awe_poke(AWE_ATKHLDV(voice),
- FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f);
- else
- awe_poke(AWE_ATKHLDV(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK,
- vp->parm.volatkhld));
- /* decay/sustain parameter for volume envelope must be set at last */
-
- /* cutoff and volume */
- awe_set_volume(voice, TRUE);
-
- /* modulation envelope heights */
- awe_poke(AWE_PEFE(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF,
- vp->parm.pefe));
-
- /* lfo1/2 delay */
- awe_poke(AWE_LFO1VAL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay));
- awe_poke(AWE_LFO2VAL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay));
-
- /* lfo1 pitch & cutoff shift */
- awe_fx_fmmod(voice, TRUE);
- /* lfo1 volume & freq */
- awe_fx_tremfrq(voice, TRUE);
- /* lfo2 pitch & freq */
- awe_fx_fm2frq2(voice, TRUE);
- /* pan & loop start */
- awe_set_pan(voice, TRUE);
-
- /* chorus & loop end (chorus 8bit, MSB) */
- addr = vp->loopend - 1;
- addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END,
- AWE_FX_COARSE_LOOP_END, vp->mode);
- temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus);
- temp = (temp <<24) | (unsigned int)addr;
- awe_poke_dw(AWE_CSL(voice), temp);
- DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr));
-
- /* Q & current address (Q 4bit value, MSB) */
- addr = vp->start - 1;
- addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START,
- AWE_FX_COARSE_SAMPLE_START, vp->mode);
- temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ);
- temp = (temp<<28) | (unsigned int)addr;
- awe_poke_dw(AWE_CCCA(voice), temp);
- DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr));
-
- /* clear unknown registers */
- awe_poke_dw(AWE_00A0(voice), 0);
- awe_poke_dw(AWE_0080(voice), 0);
-
- /* reset volume */
- awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
- awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
-
- /* set reverb */
- temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
- temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
- awe_poke_dw(AWE_PTRX(voice), temp);
- awe_poke_dw(AWE_CPF(voice), ptarget << 16);
- /* turn on envelope */
- awe_poke(AWE_DCYSUSV(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
- vp->parm.voldcysus));
-
- voices[voice].state = AWE_ST_ON;
-
- /* clear voice position for the next note on this channel */
- if (SINGLE_LAYER_MODE()) {
- FX_UNSET(fx, AWE_FX_SAMPLE_START);
- FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START);
- }
-}
-
-
-/* turn off the voice */
-static void
-awe_note_off(int voice)
-{
- awe_voice_info *vp;
- unsigned short tmp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if ((vp = voices[voice].sample) == NULL) {
- voices[voice].state = AWE_ST_OFF;
- return;
- }
-
- tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE,
- (unsigned char)vp->parm.modrelease);
- awe_poke(AWE_DCYSUS(voice), tmp);
- tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE,
- (unsigned char)vp->parm.volrelease);
- awe_poke(AWE_DCYSUSV(voice), tmp);
- voices[voice].state = AWE_ST_RELEASED;
-}
-
-/* force to terminate the voice (no releasing echo) */
-static void
-awe_terminate(int voice)
-{
- awe_poke(AWE_DCYSUSV(voice), 0x807F);
- awe_tweak_voice(voice);
- voices[voice].state = AWE_ST_OFF;
-}
-
-/* turn off other voices with the same exclusive class (for drums) */
-static void
-awe_exclusive_off(int voice)
-{
- int i, exclass;
-
- if (voices[voice].sample == NULL)
- return;
- if ((exclass = voices[voice].sample->exclusiveClass) == 0)
- return; /* not exclusive */
-
- /* turn off voices with the same class */
- for (i = 0; i < awe_max_voices; i++) {
- if (i != voice && IS_PLAYING(i) &&
- voices[i].sample && voices[i].ch == voices[voice].ch &&
- voices[i].sample->exclusiveClass == exclass) {
- DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
- awe_terminate(i);
- awe_voice_init(i, TRUE);
- }
- }
-}
-
-
-/*
- * change the parameters of an audible voice
- */
-
-/* change pitch */
-static void
-awe_set_pitch(int voice, int forced)
-{
- if (IS_NO_EFFECT(voice) && !forced) return;
- awe_poke(AWE_IP(voice), voices[voice].apitch);
- DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch));
-}
-
-/* calculate & change pitch */
-static void
-awe_set_voice_pitch(int voice, int forced)
-{
- awe_calc_pitch(voice);
- awe_set_pitch(voice, forced);
-}
-
-/* change volume & cutoff */
-static void
-awe_set_volume(int voice, int forced)
-{
- awe_voice_info *vp;
- unsigned short tmp2;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (!IS_PLAYING(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
- (unsigned char)voices[voice].acutoff);
- tmp2 = (tmp2 << 8);
- tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN,
- (unsigned char)voices[voice].avol);
- awe_poke(AWE_IFATN(voice), tmp2);
-}
-
-/* calculate & change volume */
-static void
-awe_set_voice_vol(int voice, int forced)
-{
- if (IS_EMPTY(voice))
- return;
- awe_calc_volume(voice);
- awe_set_volume(voice, forced);
-}
-
-
-/* change pan; this could make a click noise.. */
-static void
-awe_set_pan(int voice, int forced)
-{
- unsigned int temp;
- int addr;
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
- if (vp->fixpan > 0) /* 0-127 */
- temp = 255 - (int)vp->fixpan * 2;
- else {
- int pos = 0;
- if (vp->pan >= 0) /* 0-127 */
- pos = (int)vp->pan * 2 - 128;
- pos += voices[voice].cinfo->panning; /* -128 - 127 */
- temp = 127 - pos;
- }
- limitvalue(temp, 0, 255);
- if (ctrls[AWE_MD_PAN_EXCHANGE]) {
- temp = 255 - temp;
- }
- if (forced || temp != voices[voice].apan) {
- voices[voice].apan = temp;
- if (temp == 0)
- voices[voice].aaux = 0xff;
- else
- voices[voice].aaux = (-temp) & 0xff;
- addr = vp->loopstart - 1;
- addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
- AWE_FX_COARSE_LOOP_START, vp->mode);
- temp = (temp<<24) | (unsigned int)addr;
- awe_poke_dw(AWE_PSST(voice), temp);
- DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
- }
-}
-
-/* effects change during playing */
-static void
-awe_fx_fmmod(int voice, int forced)
-{
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
- awe_poke(AWE_FMMOD(voice),
- FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
- vp->parm.fmmod));
-}
-
-/* set tremolo (lfo1) volume & frequency */
-static void
-awe_fx_tremfrq(int voice, int forced)
-{
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
- awe_poke(AWE_TREMFRQ(voice),
- FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
- vp->parm.tremfrq));
-}
-
-/* set lfo2 pitch & frequency */
-static void
-awe_fx_fm2frq2(int voice, int forced)
-{
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
- awe_poke(AWE_FM2FRQ2(voice),
- FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
- vp->parm.fm2frq2));
-}
-
-
-/* Q & current address (Q 4bit value, MSB) */
-static void
-awe_fx_filterQ(int voice, int forced)
-{
- unsigned int addr;
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
- addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28);
- awe_poke_dw(AWE_CCCA(voice), addr);
-}
-
-/*
- * calculate pitch offset
- *
- * 0xE000 is no pitch offset at 44100Hz sample.
- * Every 4096 is one octave.
- */
-
-static void
-awe_calc_pitch(int voice)
-{
- voice_info *vp = &voices[voice];
- awe_voice_info *ap;
- awe_chan_info *cp = voices[voice].cinfo;
- int offset;
-
- /* search voice information */
- if ((ap = vp->sample) == NULL)
- return;
- if (ap->index == 0) {
- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample((awe_voice_list*)ap) == 0)
- return;
- }
-
- /* calculate offset */
- if (ap->fixkey >= 0) {
- DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune));
- offset = (ap->fixkey - ap->root) * 4096 / 12;
- } else {
- DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune));
- offset = (vp->note - ap->root) * 4096 / 12;
- DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
- }
- offset = (offset * ap->scaleTuning) / 100;
- DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
- offset += ap->tune * 4096 / 1200;
- DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
- if (cp->bender != 0) {
- DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender));
- /* (819200: 1 semitone) ==> (4096: 12 semitones) */
- offset += cp->bender * cp->bender_range / 2400;
- }
-
- /* add initial pitch correction */
- if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH))
- offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH];
- else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH))
- offset += cp->fx.val[AWE_FX_INIT_PITCH];
-
- /* 0xe000: root pitch */
- vp->apitch = 0xe000 + ap->rate_offset + offset;
- DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset));
- if (vp->apitch > 0xffff)
- vp->apitch = 0xffff;
- if (vp->apitch < 0)
- vp->apitch = 0;
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* calculate MIDI key and semitone from the specified frequency */
-static void
-awe_calc_pitch_from_freq(int voice, int freq)
-{
- voice_info *vp = &voices[voice];
- awe_voice_info *ap;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- int offset;
- int note;
-
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- /* search voice information */
- if ((ap = vp->sample) == NULL)
- return;
- if (ap->index == 0) {
- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample((awe_voice_list*)ap) == 0)
- return;
- }
- note = freq_to_note(freq);
- offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200;
- offset = (offset * ap->scaleTuning) / 100;
- if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH))
- offset += fx_lay->val[AWE_FX_INIT_PITCH];
- else if (FX_ON(fx, AWE_FX_INIT_PITCH))
- offset += fx->val[AWE_FX_INIT_PITCH];
- vp->apitch = 0xe000 + ap->rate_offset + offset;
- if (vp->apitch > 0xffff)
- vp->apitch = 0xffff;
- if (vp->apitch < 0)
- vp->apitch = 0;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*
- * calculate volume attenuation
- *
- * Voice volume is controlled by volume attenuation parameter.
- * So volume becomes maximum when avol is 0 (no attenuation), and
- * minimum when 255 (-96dB or silence).
- */
-
-static int vol_table[128] = {
- 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
- 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
- 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
- 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
- 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
- 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
- 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
- 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
-};
-
-/* tables for volume->attenuation calculation */
-static unsigned char voltab1[128] = {
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
- 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
- 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
- 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
- 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
- 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
- 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char voltab2[128] = {
- 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
- 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
- 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
- 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
- 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
- 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
- 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
- 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
- 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char expressiontab[128] = {
- 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
- 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
- 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
- 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
- 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
- 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
- 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
- 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
- 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
- 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
- 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
- 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static void
-awe_calc_volume(int voice)
-{
- voice_info *vp = &voices[voice];
- awe_voice_info *ap;
- awe_chan_info *cp = voices[voice].cinfo;
- int vol;
-
- /* search voice information */
- if ((ap = vp->sample) == NULL)
- return;
-
- ap = vp->sample;
- if (ap->index == 0) {
- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample((awe_voice_list*)ap) == 0)
- return;
- }
-
- if (ctrls[AWE_MD_NEW_VOLUME_CALC]) {
- int main_vol = cp->main_vol * ap->amplitude / 127;
- limitvalue(vp->velocity, 0, 127);
- limitvalue(main_vol, 0, 127);
- limitvalue(cp->expression_vol, 0, 127);
-
- vol = voltab1[main_vol] + voltab2[vp->velocity];
- vol = (vol * 8) / 3;
- vol += ap->attenuation;
- if (cp->expression_vol < 127)
- vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128;
- vol += atten_offset;
- if (atten_relative)
- vol += ctrls[AWE_MD_ZERO_ATTEN];
- limitvalue(vol, 0, 255);
- vp->avol = vol;
-
- } else {
- /* 0 - 127 */
- vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127);
- vol = vol * ap->amplitude / 127;
-
- if (vol < 0) vol = 0;
- if (vol > 127) vol = 127;
-
- /* calc to attenuation */
- vol = vol_table[vol];
- vol += (int)ap->attenuation;
- vol += atten_offset;
- if (atten_relative)
- vol += ctrls[AWE_MD_ZERO_ATTEN];
- if (vol > 255) vol = 255;
-
- vp->avol = vol;
- }
- if (cp->bank != AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) {
- int atten;
- if (vp->velocity < 70) atten = 70;
- else atten = vp->velocity;
- vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7;
- } else {
- vp->acutoff = ap->parm.cutoff;
- }
- DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));
-}
-
-/* change master volume */
-static void
-awe_change_master_volume(short val)
-{
- limitvalue(val, 0, 127);
- atten_offset = vol_table[val];
- atten_relative = TRUE;
- awe_update_volume();
-}
-
-/* update volumes of all available channels */
-static void awe_update_volume(void)
-{
- int i;
- for (i = 0; i < awe_max_voices; i++)
- awe_set_voice_vol(i, TRUE);
-}
-
-/* set sostenuto on */
-static void awe_sostenuto_on(int voice, int forced)
-{
- if (IS_NO_EFFECT(voice) && !forced) return;
- voices[voice].sostenuto = 127;
-}
-
-
-/* drop sustain */
-static void awe_sustain_off(int voice, int forced)
-{
- if (voices[voice].state == AWE_ST_SUSTAINED) {
- awe_note_off(voice);
- awe_fx_init(voices[voice].ch);
- awe_voice_init(voice, FALSE);
- }
-}
-
-
-/* terminate and initialize voice */
-static void awe_terminate_and_init(int voice, int forced)
-{
- awe_terminate(voice);
- awe_fx_init(voices[voice].ch);
- awe_voice_init(voice, TRUE);
-}
-
-
-/*
- * synth operation routines
- */
-
-#define AWE_VOICE_KEY(v) (0x8000 | (v))
-#define AWE_CHAN_KEY(c,n) (((c) << 8) | ((n) + 1))
-#define KEY_CHAN_MATCH(key,c) (((key) >> 8) == (c))
-
-/* initialize the voice */
-static void
-awe_voice_init(int voice, int init_all)
-{
- voice_info *vp = &voices[voice];
-
- /* reset voice search key */
- if (playing_mode == AWE_PLAY_DIRECT)
- vp->key = AWE_VOICE_KEY(voice);
- else
- vp->key = 0;
-
- /* clear voice mapping */
- voice_alloc->map[voice] = 0;
-
- /* touch the timing flag */
- vp->time = current_alloc_time;
-
- /* initialize other parameters if necessary */
- if (init_all) {
- vp->note = -1;
- vp->velocity = 0;
- vp->sostenuto = 0;
-
- vp->sample = NULL;
- vp->cinfo = &channels[voice];
- vp->ch = voice;
- vp->state = AWE_ST_OFF;
-
- /* emu8000 parameters */
- vp->apitch = 0;
- vp->avol = 255;
- vp->apan = -1;
- }
-}
-
-/* clear effects */
-static void awe_fx_init(int ch)
-{
- if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) {
- memset(&channels[ch].fx, 0, sizeof(channels[ch].fx));
- memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer));
- }
-}
-
-/* initialize channel info */
-static void awe_channel_init(int ch, int init_all)
-{
- awe_chan_info *cp = &channels[ch];
- cp->channel = ch;
- if (init_all) {
- cp->panning = 0; /* zero center */
- cp->bender_range = 200; /* sense * 100 */
- cp->main_vol = 127;
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) {
- cp->instr = ctrls[AWE_MD_DEF_DRUM];
- cp->bank = AWE_DRUM_BANK;
- } else {
- cp->instr = ctrls[AWE_MD_DEF_PRESET];
- cp->bank = ctrls[AWE_MD_DEF_BANK];
- }
- }
-
- cp->bender = 0; /* zero tune skew */
- cp->expression_vol = 127;
- cp->chan_press = 0;
- cp->sustained = 0;
-
- if (! ctrls[AWE_MD_KEEP_EFFECT]) {
- memset(&cp->fx, 0, sizeof(cp->fx));
- memset(&cp->fx_layer, 0, sizeof(cp->fx_layer));
- }
-}
-
-
-/* change the voice parameters; voice = channel */
-static void awe_voice_change(int voice, fx_affect_func func)
-{
- int i;
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- func(voice, FALSE);
- break;
- case AWE_PLAY_INDIRECT:
- for (i = 0; i < awe_max_voices; i++)
- if (voices[i].key == AWE_VOICE_KEY(voice))
- func(i, FALSE);
- break;
- default:
- for (i = 0; i < awe_max_voices; i++)
- if (KEY_CHAN_MATCH(voices[i].key, voice))
- func(i, FALSE);
- break;
- }
-}
-
-
-/*
- * device open / close
- */
-
-/* open device:
- * reset status of all voices, and clear sample position flag
- */
-static int
-awe_open(int dev, int mode)
-{
- if (awe_busy)
- return -EBUSY;
-
- awe_busy = TRUE;
-
- /* set default mode */
- awe_init_ctrl_parms(FALSE);
- atten_relative = TRUE;
- atten_offset = 0;
- drum_flags = DEFAULT_DRUM_FLAGS;
- playing_mode = AWE_PLAY_INDIRECT;
-
- /* reset voices & channels */
- awe_reset(dev);
-
- patch_opened = 0;
-
- return 0;
-}
-
-
-/* close device:
- * reset all voices again (terminate sounds)
- */
-static void
-awe_close(int dev)
-{
- awe_reset(dev);
- awe_busy = FALSE;
-}
-
-
-/* set miscellaneous mode parameters
- */
-static void
-awe_init_ctrl_parms(int init_all)
-{
- int i;
- for (i = 0; i < AWE_MD_END; i++) {
- if (init_all || ctrl_parms[i].init_each_time)
- ctrls[i] = ctrl_parms[i].value;
- }
-}
-
-
-/* sequencer I/O control:
- */
-static int
-awe_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- switch (cmd) {
- case SNDCTL_SYNTH_INFO:
- if (playing_mode == AWE_PLAY_DIRECT)
- awe_info.nr_voices = awe_max_voices;
- else
- awe_info.nr_voices = AWE_MAX_CHANNELS;
- if (copy_to_user(arg, &awe_info, sizeof(awe_info)))
- return -EFAULT;
- return 0;
- break;
-
- case SNDCTL_SEQ_RESETSAMPLES:
- awe_reset(dev);
- awe_reset_samples();
- return 0;
- break;
-
- case SNDCTL_SEQ_PERCMODE:
- /* what's this? */
- return 0;
- break;
-
- case SNDCTL_SYNTH_MEMAVL:
- return memsize - awe_free_mem_ptr() * 2;
- break;
-
- default:
- printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd);
- return -EINVAL;
- break;
- }
-}
-
-
-static int voice_in_range(int voice)
-{
- if (playing_mode == AWE_PLAY_DIRECT) {
- if (voice < 0 || voice >= awe_max_voices)
- return FALSE;
- } else {
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return FALSE;
- }
- return TRUE;
-}
-
-static void release_voice(int voice, int do_sustain)
-{
- if (IS_NO_SOUND(voice))
- return;
- if (do_sustain && (voices[voice].cinfo->sustained == 127 ||
- voices[voice].sostenuto == 127))
- voices[voice].state = AWE_ST_SUSTAINED;
- else {
- awe_note_off(voice);
- awe_fx_init(voices[voice].ch);
- awe_voice_init(voice, FALSE);
- }
-}
-
-/* release all notes */
-static void awe_note_off_all(int do_sustain)
-{
- int i;
- for (i = 0; i < awe_max_voices; i++)
- release_voice(i, do_sustain);
-}
-
-/* kill a voice:
- * not terminate, just release the voice.
- */
-static int
-awe_kill_note(int dev, int voice, int note, int velocity)
-{
- int i, v2, key;
-
- DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity));
- if (! voice_in_range(voice))
- return -EINVAL;
-
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- case AWE_PLAY_INDIRECT:
- key = AWE_VOICE_KEY(voice);
- break;
-
- case AWE_PLAY_MULTI2:
- v2 = voice_alloc->map[voice] >> 8;
- voice_alloc->map[voice] = 0;
- voice = v2;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return -EINVAL;
- /* continue to below */
- default:
- key = AWE_CHAN_KEY(voice, note);
- break;
- }
-
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key)
- release_voice(i, TRUE);
- }
- return 0;
-}
-
-
-static void start_or_volume_change(int voice, int velocity)
-{
- voices[voice].velocity = velocity;
- awe_calc_volume(voice);
- if (voices[voice].state == AWE_ST_STANDBY)
- awe_note_on(voice);
- else if (voices[voice].state == AWE_ST_ON)
- awe_set_volume(voice, FALSE);
-}
-
-static void set_and_start_voice(int voice, int state)
-{
- /* calculate pitch & volume parameters */
- voices[voice].state = state;
- awe_calc_pitch(voice);
- awe_calc_volume(voice);
- if (state == AWE_ST_ON)
- awe_note_on(voice);
-}
-
-/* start a voice:
- * if note is 255, identical with aftertouch function.
- * Otherwise, start a voice with specified not and volume.
- */
-static int
-awe_start_note(int dev, int voice, int note, int velocity)
-{
- int i, key, state, volonly;
-
- DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity));
- if (! voice_in_range(voice))
- return -EINVAL;
-
- if (velocity == 0)
- state = AWE_ST_STANDBY; /* stand by for playing */
- else
- state = AWE_ST_ON; /* really play */
- volonly = FALSE;
-
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- case AWE_PLAY_INDIRECT:
- key = AWE_VOICE_KEY(voice);
- if (note == 255)
- volonly = TRUE;
- break;
-
- case AWE_PLAY_MULTI2:
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return -EINVAL;
- /* continue to below */
- default:
- if (note >= 128) { /* key volume mode */
- note -= 128;
- volonly = TRUE;
- }
- key = AWE_CHAN_KEY(voice, note);
- break;
- }
-
- /* dynamic volume change */
- if (volonly) {
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key)
- start_or_volume_change(i, velocity);
- }
- return 0;
- }
-
- /* if the same note still playing, stop it */
- if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) {
- for (i = 0; i < awe_max_voices; i++)
- if (voices[i].key == key) {
- if (voices[i].state == AWE_ST_ON) {
- awe_note_off(i);
- awe_voice_init(i, FALSE);
- } else if (voices[i].state == AWE_ST_STANDBY)
- awe_voice_init(i, TRUE);
- }
- }
-
- /* allocate voices */
- if (playing_mode == AWE_PLAY_DIRECT)
- awe_alloc_one_voice(voice, note, velocity);
- else
- awe_alloc_multi_voices(voice, note, velocity, key);
-
- /* turn off other voices exlusively (for drums) */
- for (i = 0; i < awe_max_voices; i++)
- if (voices[i].key == key)
- awe_exclusive_off(i);
-
- /* set up pitch and volume parameters */
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key && voices[i].state == AWE_ST_OFF)
- set_and_start_voice(i, state);
- }
-
- return 0;
-}
-
-
-/* calculate hash key */
-static int
-awe_search_key(int bank, int preset, int note)
-{
- unsigned int key;
-
-#if 1 /* new hash table */
- if (bank == AWE_DRUM_BANK)
- key = preset + note + 128;
- else
- key = bank + preset;
-#else
- key = preset;
-#endif
- key %= AWE_MAX_PRESETS;
-
- return (int)key;
-}
-
-
-/* search instrument from hash table */
-static awe_voice_list *
-awe_search_instr(int bank, int preset, int note)
-{
- awe_voice_list *p;
- int key, key2;
-
- key = awe_search_key(bank, preset, note);
- for (p = preset_table[key]; p; p = p->next_bank) {
- if (p->instr == preset && p->bank == bank)
- return p;
- }
- key2 = awe_search_key(bank, preset, 0); /* search default */
- if (key == key2)
- return NULL;
- for (p = preset_table[key2]; p; p = p->next_bank) {
- if (p->instr == preset && p->bank == bank)
- return p;
- }
- return NULL;
-}
-
-
-/* assign the instrument to a voice */
-static int
-awe_set_instr_2(int dev, int voice, int instr_no)
-{
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return -EINVAL;
- }
- return awe_set_instr(dev, voice, instr_no);
-}
-
-/* assign the instrument to a channel; voice is the channel number */
-static int
-awe_set_instr(int dev, int voice, int instr_no)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return -EINVAL;
-
- if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
- return -EINVAL;
-
- cinfo = &channels[voice];
- cinfo->instr = instr_no;
- DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no));
-
- return 0;
-}
-
-
-/* reset all voices; terminate sounds and initialize parameters */
-static void
-awe_reset(int dev)
-{
- int i;
- current_alloc_time = 0;
- /* don't turn off voice 31 and 32. they are used also for FM voices */
- for (i = 0; i < awe_max_voices; i++) {
- awe_terminate(i);
- awe_voice_init(i, TRUE);
- }
- for (i = 0; i < AWE_MAX_CHANNELS; i++)
- awe_channel_init(i, TRUE);
- for (i = 0; i < 16; i++) {
- awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127;
- awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127;
- }
- awe_init_fm();
- awe_tweak();
-}
-
-
-/* hardware specific control:
- * GUS specific and AWE32 specific controls are available.
- */
-static void
-awe_hw_control(int dev, unsigned char *event)
-{
- int cmd = event[2];
- if (cmd & _AWE_MODE_FLAG)
- awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
- else
- awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#endif
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* GUS compatible controls */
-static void
-awe_hw_gus_control(int dev, int cmd, unsigned char *event)
-{
- int voice, i, key;
- unsigned short p1;
- short p2;
- int plong;
-
- if (MULTI_LAYER_MODE())
- return;
- if (cmd == _GUS_NUMVOICES)
- return;
-
- voice = event[3];
- if (! voice_in_range(voice))
- return;
-
- p1 = *(unsigned short *) &event[4];
- p2 = *(short *) &event[6];
- plong = *(int*) &event[4];
-
- switch (cmd) {
- case _GUS_VOICESAMPLE:
- awe_set_instr(dev, voice, p1);
- return;
-
- case _GUS_VOICEBALA:
- /* 0 to 15 --> -128 to 127 */
- awe_panning(dev, voice, ((int)p1 << 4) - 128);
- return;
-
- case _GUS_VOICEVOL:
- case _GUS_VOICEVOL2:
- /* not supported yet */
- return;
-
- case _GUS_RAMPRANGE:
- case _GUS_RAMPRATE:
- case _GUS_RAMPMODE:
- case _GUS_RAMPON:
- case _GUS_RAMPOFF:
- /* volume ramping not supported */
- return;
-
- case _GUS_VOLUME_SCALE:
- return;
-
- case _GUS_VOICE_POS:
- FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START,
- (short)(plong & 0x7fff));
- FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START,
- (plong >> 15) & 0xffff);
- return;
- }
-
- key = AWE_VOICE_KEY(voice);
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key) {
- switch (cmd) {
- case _GUS_VOICEON:
- awe_note_on(i);
- break;
-
- case _GUS_VOICEOFF:
- awe_terminate(i);
- awe_fx_init(voices[i].ch);
- awe_voice_init(i, TRUE);
- break;
-
- case _GUS_VOICEFADE:
- awe_note_off(i);
- awe_fx_init(voices[i].ch);
- awe_voice_init(i, FALSE);
- break;
-
- case _GUS_VOICEFREQ:
- awe_calc_pitch_from_freq(i, plong);
- break;
- }
- }
- }
-}
-
-#endif /* gus_compat */
-
-
-/* AWE32 specific controls */
-static void
-awe_hw_awe_control(int dev, int cmd, unsigned char *event)
-{
- int voice;
- unsigned short p1;
- short p2;
- int i;
-
- voice = event[3];
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- p1 = *(unsigned short *) &event[4];
- p2 = *(short *) &event[6];
-
- switch (cmd) {
- case _AWE_DEBUG_MODE:
- ctrls[AWE_MD_DEBUG_MODE] = p1;
- printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
- break;
- case _AWE_REVERB_MODE:
- ctrls[AWE_MD_REVERB_MODE] = p1;
- awe_update_reverb_mode();
- break;
-
- case _AWE_CHORUS_MODE:
- ctrls[AWE_MD_CHORUS_MODE] = p1;
- awe_update_chorus_mode();
- break;
-
- case _AWE_REMOVE_LAST_SAMPLES:
- DEBUG(0,printk("AWE32: remove last samples\n"));
- awe_reset(0);
- if (locked_sf_id > 0)
- awe_remove_samples(locked_sf_id);
- break;
-
- case _AWE_INITIALIZE_CHIP:
- awe_initialize();
- break;
-
- case _AWE_SEND_EFFECT:
- i = -1;
- if (p1 >= 0x100) {
- i = (p1 >> 8);
- if (i < 0 || i >= MAX_LAYERS)
- break;
- }
- awe_send_effect(voice, i, p1, p2);
- break;
-
- case _AWE_RESET_CHANNEL:
- awe_channel_init(voice, !p1);
- break;
-
- case _AWE_TERMINATE_ALL:
- awe_reset(0);
- break;
-
- case _AWE_TERMINATE_CHANNEL:
- awe_voice_change(voice, awe_terminate_and_init);
- break;
-
- case _AWE_RELEASE_ALL:
- awe_note_off_all(FALSE);
- break;
- case _AWE_NOTEOFF_ALL:
- awe_note_off_all(TRUE);
- break;
-
- case _AWE_INITIAL_VOLUME:
- DEBUG(0,printk("AWE32: init attenuation %d\n", p1));
- atten_relative = (char)p2;
- atten_offset = (short)p1;
- awe_update_volume();
- break;
-
- case _AWE_CHN_PRESSURE:
- channels[voice].chan_press = p1;
- awe_modwheel_change(voice, p1);
- break;
-
- case _AWE_CHANNEL_MODE:
- DEBUG(0,printk("AWE32: channel mode = %d\n", p1));
- playing_mode = p1;
- awe_reset(0);
- break;
-
- case _AWE_DRUM_CHANNELS:
- DEBUG(0,printk("AWE32: drum flags = %x\n", p1));
- drum_flags = *(unsigned int*)&event[4];
- break;
-
- case _AWE_MISC_MODE:
- DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2));
- if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) {
- ctrls[p1] = p2;
- if (ctrl_parms[p1].update)
- ctrl_parms[p1].update();
- }
- break;
-
- case _AWE_EQUALIZER:
- ctrls[AWE_MD_BASS_LEVEL] = p1;
- ctrls[AWE_MD_TREBLE_LEVEL] = p2;
- awe_update_equalizer();
- break;
-
- default:
- DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice));
- break;
- }
-}
-
-
-/* change effects */
-static void
-awe_send_effect(int voice, int layer, int type, int val)
-{
- awe_chan_info *cinfo;
- FX_Rec *fx;
- int mode;
-
- cinfo = &channels[voice];
- if (layer >= 0 && layer < MAX_LAYERS)
- fx = &cinfo->fx_layer[layer];
- else
- fx = &cinfo->fx;
-
- if (type & 0x40)
- mode = FX_FLAG_OFF;
- else if (type & 0x80)
- mode = FX_FLAG_ADD;
- else
- mode = FX_FLAG_SET;
- type &= 0x3f;
-
- if (type >= 0 && type < AWE_FX_END) {
- DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val));
- if (mode == FX_FLAG_SET)
- FX_SET(fx, type, val);
- else if (mode == FX_FLAG_ADD)
- FX_ADD(fx, type, val);
- else
- FX_UNSET(fx, type);
- if (mode != FX_FLAG_OFF && parm_defs[type].realtime) {
- DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice));
- awe_voice_change(voice, parm_defs[type].realtime);
- }
- }
-}
-
-
-/* change modulation wheel; voice is already mapped on multi2 mode */
-static void
-awe_modwheel_change(int voice, int value)
-{
- int i;
- awe_chan_info *cinfo;
-
- cinfo = &channels[voice];
- i = value * ctrls[AWE_MD_MOD_SENSE] / 1200;
- FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i);
- awe_voice_change(voice, awe_fx_fmmod);
- FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i);
- awe_voice_change(voice, awe_fx_fm2frq2);
-}
-
-
-/* voice pressure change */
-static void
-awe_aftertouch(int dev, int voice, int pressure)
-{
- int note;
-
- DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure));
- if (! voice_in_range(voice))
- return;
-
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- case AWE_PLAY_INDIRECT:
- awe_start_note(dev, voice, 255, pressure);
- break;
- case AWE_PLAY_MULTI2:
- note = (voice_alloc->map[voice] & 0xff) - 1;
- awe_key_pressure(dev, voice, note + 0x80, pressure);
- break;
- }
-}
-
-
-/* voice control change */
-static void
-awe_controller(int dev, int voice, int ctrl_num, int value)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- cinfo = &channels[voice];
-
- switch (ctrl_num) {
- case CTL_BANK_SELECT: /* MIDI control #0 */
- DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
- !ctrls[AWE_MD_TOGGLE_DRUM_BANK])
- break;
- if (value < 0 || value > 255)
- break;
- cinfo->bank = value;
- if (cinfo->bank == AWE_DRUM_BANK)
- DRUM_CHANNEL_ON(cinfo->channel);
- else
- DRUM_CHANNEL_OFF(cinfo->channel);
- awe_set_instr(dev, voice, cinfo->instr);
- break;
-
- case CTL_MODWHEEL: /* MIDI control #1 */
- DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value));
- awe_modwheel_change(voice, value);
- break;
-
- case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */
- DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value));
- /* zero centered */
- cinfo->bender = value;
- awe_voice_change(voice, awe_set_voice_pitch);
- break;
-
- case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */
- DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value));
- /* value = sense x 100 */
- cinfo->bender_range = value;
- /* no audible pitch change yet.. */
- break;
-
- case CTL_EXPRESSION: /* MIDI control #11 */
- if (SINGLE_LAYER_MODE())
- value /= 128;
- case CTRL_EXPRESSION: /* SEQ1 V2 control */
- DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value));
- /* 0 - 127 */
- cinfo->expression_vol = value;
- awe_voice_change(voice, awe_set_voice_vol);
- break;
-
- case CTL_PAN: /* MIDI control #10 */
- DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value));
- /* (0-127) -> signed 8bit */
- cinfo->panning = value * 2 - 128;
- if (ctrls[AWE_MD_REALTIME_PAN])
- awe_voice_change(voice, awe_set_pan);
- break;
-
- case CTL_MAIN_VOLUME: /* MIDI control #7 */
- if (SINGLE_LAYER_MODE())
- value = (value * 100) / 16383;
- case CTRL_MAIN_VOLUME: /* SEQ1 V2 control */
- DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value));
- /* 0 - 127 */
- cinfo->main_vol = value;
- awe_voice_change(voice, awe_set_voice_vol);
- break;
-
- case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */
- DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value));
- FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2);
- break;
-
- case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */
- DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value));
- FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2);
- break;
-
- case 120: /* all sounds off */
- awe_note_off_all(FALSE);
- break;
- case 123: /* all notes off */
- awe_note_off_all(TRUE);
- break;
-
- case CTL_SUSTAIN: /* MIDI control #64 */
- cinfo->sustained = value;
- if (value != 127)
- awe_voice_change(voice, awe_sustain_off);
- break;
-
- case CTL_SOSTENUTO: /* MIDI control #66 */
- if (value == 127)
- awe_voice_change(voice, awe_sostenuto_on);
- else
- awe_voice_change(voice, awe_sustain_off);
- break;
-
- default:
- DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n",
- voice, ctrl_num, value));
- break;
- }
-}
-
-
-/* voice pan change (value = -128 - 127) */
-static void
-awe_panning(int dev, int voice, int value)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- cinfo = &channels[voice];
- cinfo->panning = value;
- DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning));
- if (ctrls[AWE_MD_REALTIME_PAN])
- awe_voice_change(voice, awe_set_pan);
-}
-
-
-/* volume mode change */
-static void
-awe_volume_method(int dev, int mode)
-{
- /* not impremented */
- DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode));
-}
-
-
-/* pitch wheel change: 0-16384 */
-static void
-awe_bender(int dev, int voice, int value)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- /* convert to zero centered value */
- cinfo = &channels[voice];
- cinfo->bender = value - 8192;
- DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender));
- awe_voice_change(voice, awe_set_voice_pitch);
-}
-
-
-/*
- * load a sound patch:
- * three types of patches are accepted: AWE, GUS, and SYSEX.
- */
-
-static int
-awe_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
- awe_patch_info patch;
- int rc = 0;
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
- if (format == GUS_PATCH) {
- return awe_load_guspatch(addr, offs, count, pmgr_flag);
- } else
-#endif
- if (format == SYSEX_PATCH) {
- /* no system exclusive message supported yet */
- return 0;
- } else if (format != AWE_PATCH) {
- printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format);
- return -EINVAL;
- }
-
- if (count < AWE_PATCH_INFO_SIZE) {
- printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
- return -EINVAL;
- }
- if (copy_from_user(((char*)&patch) + offs, addr + offs,
- AWE_PATCH_INFO_SIZE - offs))
- return -EFAULT;
-
- count -= AWE_PATCH_INFO_SIZE;
- if (count < patch.len) {
- printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n",
- count, patch.len);
- return -EINVAL;
- }
-
- switch (patch.type) {
- case AWE_LOAD_INFO:
- rc = awe_load_info(&patch, addr, count);
- break;
- case AWE_LOAD_DATA:
- rc = awe_load_data(&patch, addr, count);
- break;
- case AWE_OPEN_PATCH:
- rc = awe_open_patch(&patch, addr, count);
- break;
- case AWE_CLOSE_PATCH:
- rc = awe_close_patch(&patch, addr, count);
- break;
- case AWE_UNLOAD_PATCH:
- rc = awe_unload_patch(&patch, addr, count);
- break;
- case AWE_REPLACE_DATA:
- rc = awe_replace_data(&patch, addr, count);
- break;
- case AWE_MAP_PRESET:
- rc = awe_load_map(&patch, addr, count);
- break;
- /* case AWE_PROBE_INFO:
- rc = awe_probe_info(&patch, addr, count);
- break;*/
- case AWE_PROBE_DATA:
- rc = awe_probe_data(&patch, addr, count);
- break;
- case AWE_REMOVE_INFO:
- rc = awe_remove_info(&patch, addr, count);
- break;
- case AWE_LOAD_CHORUS_FX:
- rc = awe_load_chorus_fx(&patch, addr, count);
- break;
- case AWE_LOAD_REVERB_FX:
- rc = awe_load_reverb_fx(&patch, addr, count);
- break;
-
- default:
- printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n",
- patch.type);
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-
-/* create an sf list record */
-static int
-awe_create_sf(int type, char *name)
-{
- sf_list *rec;
-
- /* terminate sounds */
- awe_reset(0);
- rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL);
- if (rec == NULL)
- return 1; /* no memory */
- rec->sf_id = current_sf_id + 1;
- rec->type = type;
- if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0)
- locked_sf_id = current_sf_id + 1;
- rec->num_info = awe_free_info();
- rec->num_sample = awe_free_sample();
- rec->mem_ptr = awe_free_mem_ptr();
- rec->infos = rec->last_infos = NULL;
- rec->samples = rec->last_samples = NULL;
-
- /* add to linked-list */
- rec->next = NULL;
- rec->prev = sftail;
- if (sftail)
- sftail->next = rec;
- else
- sfhead = rec;
- sftail = rec;
- current_sf_id++;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- rec->shared = NULL;
- if (name)
- memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
- else
- strcpy(rec->name, "*TEMPORARY*");
- if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) {
- /* is the current font really a shared font? */
- if (is_shared_sf(rec->name)) {
- /* check if the shared font is already installed */
- sf_list *p;
- for (p = rec->prev; p; p = p->prev) {
- if (is_identical_name(rec->name, p)) {
- rec->shared = p;
- break;
- }
- }
- }
- }
-#endif /* allow sharing */
-
- return 0;
-}
-
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-
-/* check if the given name is a valid shared name */
-#define ASC_TO_KEY(c) ((c) - 'A' + 1)
-static int is_shared_sf(unsigned char *name)
-{
- static unsigned char id_head[4] = {
- ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
- AWE_MAJOR_VERSION,
- };
- if (memcmp(name, id_head, 4) == 0)
- return TRUE;
- return FALSE;
-}
-
-/* check if the given name matches to the existing list */
-static int is_identical_name(unsigned char *name, sf_list *p)
-{
- char *id = p->name;
- if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
- return TRUE;
- return FALSE;
-}
-
-/* check if the given voice info exists */
-static int info_duplicated(sf_list *sf, awe_voice_list *rec)
-{
- /* search for all sharing lists */
- for (; sf; sf = sf->shared) {
- awe_voice_list *p;
- for (p = sf->infos; p; p = p->next) {
- if (p->type == V_ST_NORMAL &&
- p->bank == rec->bank &&
- p->instr == rec->instr &&
- p->v.low == rec->v.low &&
- p->v.high == rec->v.high &&
- p->v.sample == rec->v.sample)
- return TRUE;
- }
- }
- return FALSE;
-}
-
-#endif /* AWE_ALLOW_SAMPLE_SHARING */
-
-
-/* free sf_list record */
-/* linked-list in this function is not cared */
-static void
-awe_free_sf(sf_list *sf)
-{
- if (sf->infos) {
- awe_voice_list *p, *next;
- for (p = sf->infos; p; p = next) {
- next = p->next;
- kfree(p);
- }
- }
- if (sf->samples) {
- awe_sample_list *p, *next;
- for (p = sf->samples; p; p = next) {
- next = p->next;
- kfree(p);
- }
- }
- kfree(sf);
-}
-
-
-/* open patch; create sf list and set opened flag */
-static int
-awe_open_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
- awe_open_parm parm;
- int shared;
-
- if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm)))
- return -EFAULT;
- shared = FALSE;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (sftail && (parm.type & AWE_PAT_SHARED) != 0) {
- /* is the previous font the same font? */
- if (is_identical_name(parm.name, sftail)) {
- /* then append to the previous */
- shared = TRUE;
- awe_reset(0);
- if (parm.type & AWE_PAT_LOCKED)
- locked_sf_id = current_sf_id;
- }
- }
-#endif /* allow sharing */
- if (! shared) {
- if (awe_create_sf(parm.type, parm.name)) {
- printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n");
- return -ENOMEM;
- }
- }
- patch_opened = TRUE;
- return current_sf_id;
-}
-
-/* check if the patch is already opened */
-static sf_list *
-check_patch_opened(int type, char *name)
-{
- if (! patch_opened) {
- if (awe_create_sf(type, name)) {
- printk(KERN_ERR "AWE32: failed to alloc new list\n");
- return NULL;
- }
- patch_opened = TRUE;
- return sftail;
- }
- return sftail;
-}
-
-/* close the patch; if no voice is loaded, remove the patch */
-static int
-awe_close_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (patch_opened && sftail) {
- /* if no voice is loaded, release the current patch */
- if (sftail->infos == NULL) {
- awe_reset(0);
- awe_remove_samples(current_sf_id - 1);
- }
- }
- patch_opened = 0;
- return 0;
-}
-
-
-/* remove the latest patch */
-static int
-awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (current_sf_id > 0 && current_sf_id > locked_sf_id) {
- awe_reset(0);
- awe_remove_samples(current_sf_id - 1);
- }
- return 0;
-}
-
-/* allocate voice info list records */
-static awe_voice_list *
-alloc_new_info(void)
-{
- awe_voice_list *newlist;
-
- newlist = kmalloc(sizeof(*newlist), GFP_KERNEL);
- if (newlist == NULL) {
- printk(KERN_ERR "AWE32: can't alloc info table\n");
- return NULL;
- }
- return newlist;
-}
-
-/* allocate sample info list records */
-static awe_sample_list *
-alloc_new_sample(void)
-{
- awe_sample_list *newlist;
-
- newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
- if (newlist == NULL) {
- printk(KERN_ERR "AWE32: can't alloc sample table\n");
- return NULL;
- }
- return newlist;
-}
-
-/* load voice map */
-static int
-awe_load_map(awe_patch_info *patch, const char __user *addr, int count)
-{
- awe_voice_map map;
- awe_voice_list *rec, *p;
- sf_list *sf;
-
- /* get the link info */
- if (count < sizeof(map)) {
- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
- return -EINVAL;
- }
- if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
- return -EFAULT;
-
- /* check if the identical mapping already exists */
- p = awe_search_instr(map.map_bank, map.map_instr, map.map_key);
- for (; p; p = p->next_instr) {
- if (p->type == V_ST_MAPPED &&
- p->v.start == map.src_instr &&
- p->v.end == map.src_bank &&
- p->v.fixkey == map.src_key)
- return 0; /* already present! */
- }
-
- if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL)
- return -ENOMEM;
-
- if ((rec = alloc_new_info()) == NULL)
- return -ENOMEM;
-
- rec->bank = map.map_bank;
- rec->instr = map.map_instr;
- rec->type = V_ST_MAPPED;
- rec->disabled = FALSE;
- awe_init_voice_info(&rec->v);
- if (map.map_key >= 0) {
- rec->v.low = map.map_key;
- rec->v.high = map.map_key;
- }
- rec->v.start = map.src_instr;
- rec->v.end = map.src_bank;
- rec->v.fixkey = map.src_key;
- add_sf_info(sf, rec);
- add_info_list(rec);
-
- return 0;
-}
-
-#if 0
-/* probe preset in the current list -- nothing to be loaded */
-static int
-awe_probe_info(awe_patch_info *patch, const char __user *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- awe_voice_map map;
- awe_voice_list *p;
-
- if (! patch_opened)
- return -EINVAL;
-
- /* get the link info */
- if (count < sizeof(map)) {
- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
- return -EINVAL;
- }
- if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
- return -EFAULT;
-
- /* check if the identical mapping already exists */
- if (sftail == NULL)
- return -EINVAL;
- p = awe_search_instr(map.src_bank, map.src_instr, map.src_key);
- for (; p; p = p->next_instr) {
- if (p->type == V_ST_NORMAL &&
- is_identical_holder(p->holder, sftail) &&
- p->v.low <= map.src_key &&
- p->v.high >= map.src_key)
- return 0; /* already present! */
- }
-#endif /* allow sharing */
- return -EINVAL;
-}
-#endif
-
-/* probe sample in the current list -- nothing to be loaded */
-static int
-awe_probe_data(awe_patch_info *patch, const char __user *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (! patch_opened)
- return -EINVAL;
-
- /* search the specified sample by optarg */
- if (search_sample_index(sftail, patch->optarg) != NULL)
- return 0;
-#endif /* allow sharing */
- return -EINVAL;
-}
-
-
-/* remove the present instrument layers */
-static int
-remove_info(sf_list *sf, int bank, int instr)
-{
- awe_voice_list *prev, *next, *p;
- int removed = 0;
-
- prev = NULL;
- for (p = sf->infos; p; p = next) {
- next = p->next;
- if (p->type == V_ST_NORMAL &&
- p->bank == bank && p->instr == instr) {
- /* remove this layer */
- if (prev)
- prev->next = next;
- else
- sf->infos = next;
- if (p == sf->last_infos)
- sf->last_infos = prev;
- sf->num_info--;
- removed++;
- kfree(p);
- } else
- prev = p;
- }
- if (removed)
- rebuild_preset_list();
- return removed;
-}
-
-/* load voice information data */
-static int
-awe_load_info(awe_patch_info *patch, const char __user *addr, int count)
-{
- int offset;
- awe_voice_rec_hdr hdr;
- int i;
- int total_size;
- sf_list *sf;
- awe_voice_list *rec;
-
- if (count < AWE_VOICE_REC_SIZE) {
- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
- return -EINVAL;
- }
-
- offset = AWE_PATCH_INFO_SIZE;
- if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE))
- return -EFAULT;
- offset += AWE_VOICE_REC_SIZE;
-
- if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
- printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices);
- return -EINVAL;
- }
- total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
- if (count < total_size) {
- printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
- count, hdr.nvoices);
- return -EINVAL;
- }
-
- if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
- return -ENOMEM;
-
- switch (hdr.write_mode) {
- case AWE_WR_EXCLUSIVE:
- /* exclusive mode - if the instrument already exists,
- return error */
- for (rec = sf->infos; rec; rec = rec->next) {
- if (rec->type == V_ST_NORMAL &&
- rec->bank == hdr.bank &&
- rec->instr == hdr.instr)
- return -EINVAL;
- }
- break;
- case AWE_WR_REPLACE:
- /* replace mode - remove the instrument if it already exists */
- remove_info(sf, hdr.bank, hdr.instr);
- break;
- }
-
- /* append new layers */
- for (i = 0; i < hdr.nvoices; i++) {
- rec = alloc_new_info();
- if (rec == NULL)
- return -ENOMEM;
-
- rec->bank = hdr.bank;
- rec->instr = hdr.instr;
- rec->type = V_ST_NORMAL;
- rec->disabled = FALSE;
-
- /* copy awe_voice_info parameters */
- if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) {
- kfree(rec);
- return -EFAULT;
- }
- offset += AWE_VOICE_INFO_SIZE;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (sf && sf->shared) {
- if (info_duplicated(sf, rec)) {
- kfree(rec);
- continue;
- }
- }
-#endif /* allow sharing */
- if (rec->v.mode & AWE_MODE_INIT_PARM)
- awe_init_voice_parm(&rec->v.parm);
- add_sf_info(sf, rec);
- awe_set_sample(rec);
- add_info_list(rec);
- }
-
- return 0;
-}
-
-
-/* remove instrument layers */
-static int
-awe_remove_info(awe_patch_info *patch, const char __user *addr, int count)
-{
- unsigned char bank, instr;
- sf_list *sf;
-
- if (! patch_opened || (sf = sftail) == NULL) {
- printk(KERN_WARNING "AWE32: remove_info: patch not opened\n");
- return -EINVAL;
- }
-
- bank = ((unsigned short)patch->optarg >> 8) & 0xff;
- instr = (unsigned short)patch->optarg & 0xff;
- if (! remove_info(sf, bank, instr))
- return -EINVAL;
- return 0;
-}
-
-
-/* load wave sample data */
-static int
-awe_load_data(awe_patch_info *patch, const char __user *addr, int count)
-{
- int offset, size;
- int rc;
- awe_sample_info tmprec;
- awe_sample_list *rec;
- sf_list *sf;
-
- if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
- return -ENOMEM;
-
- size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
- offset = AWE_PATCH_INFO_SIZE;
- if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE))
- return -EFAULT;
- offset += AWE_SAMPLE_INFO_SIZE;
- if (size != tmprec.size) {
- printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n",
- tmprec.size, size);
- return -EINVAL;
- }
-
- if (search_sample_index(sf, tmprec.sample) != NULL) {
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- /* if shared sample, skip this data */
- if (sf->type & AWE_PAT_SHARED)
- return 0;
-#endif /* allow sharing */
- DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
- return -EINVAL;
- }
-
- if ((rec = alloc_new_sample()) == NULL)
- return -ENOMEM;
-
- memcpy(&rec->v, &tmprec, sizeof(tmprec));
-
- if (rec->v.size > 0) {
- if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) {
- kfree(rec);
- return rc;
- }
- sf->mem_ptr += rc;
- }
-
- add_sf_sample(sf, rec);
- return 0;
-}
-
-
-/* replace wave sample data */
-static int
-awe_replace_data(awe_patch_info *patch, const char __user *addr, int count)
-{
- int offset;
- int size;
- int rc;
- int channels;
- awe_sample_info cursmp;
- int save_mem_ptr;
- sf_list *sf;
- awe_sample_list *rec;
-
- if (! patch_opened || (sf = sftail) == NULL) {
- printk(KERN_WARNING "AWE32: replace: patch not opened\n");
- return -EINVAL;
- }
-
- size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
- offset = AWE_PATCH_INFO_SIZE;
- if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE))
- return -EFAULT;
- offset += AWE_SAMPLE_INFO_SIZE;
- if (cursmp.size == 0 || size != cursmp.size) {
- printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n",
- cursmp.size, size);
- return -EINVAL;
- }
- channels = patch->optarg;
- if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
- printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels);
- return -EINVAL;
- }
-
- for (rec = sf->samples; rec; rec = rec->next) {
- if (rec->v.sample == cursmp.sample)
- break;
- }
- if (rec == NULL) {
- printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n",
- cursmp.sample);
- return -EINVAL;
- }
-
- if (rec->v.size != cursmp.size) {
- printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n",
- rec->v.size, cursmp.size);
- return -EINVAL;
- }
-
- save_mem_ptr = awe_free_mem_ptr();
- sftail->mem_ptr = rec->v.start - awe_mem_start;
- memcpy(&rec->v, &cursmp, sizeof(cursmp));
- rec->v.sf_id = current_sf_id;
- if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0)
- return rc;
- sftail->mem_ptr = save_mem_ptr;
-
- return 0;
-}
-
-
-/*----------------------------------------------------------------*/
-
-static const char __user *readbuf_addr;
-static int readbuf_offs;
-static int readbuf_flags;
-
-/* initialize read buffer */
-static int
-readbuf_init(const char __user *addr, int offset, awe_sample_info *sp)
-{
- readbuf_addr = addr;
- readbuf_offs = offset;
- readbuf_flags = sp->mode_flags;
- return 0;
-}
-
-/* read directly from user buffer */
-static unsigned short
-readbuf_word(int pos)
-{
- unsigned short c;
- /* read from user buffer */
- if (readbuf_flags & AWE_SAMPLE_8BITS) {
- unsigned char cc;
- get_user(cc, (unsigned char __user *)(readbuf_addr + readbuf_offs + pos));
- c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */
- } else {
- get_user(c, (unsigned short __user *)(readbuf_addr + readbuf_offs + pos * 2));
- }
- if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
- c ^= 0x8000; /* unsigned -> signed */
- return c;
-}
-
-#define readbuf_word_cache readbuf_word
-#define readbuf_end() /**/
-
-/*----------------------------------------------------------------*/
-
-#define BLANK_LOOP_START 8
-#define BLANK_LOOP_END 40
-#define BLANK_LOOP_SIZE 48
-
-/* loading onto memory - return the actual written size */
-static int
-awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *list, int channels)
-{
- int i, truesize, dram_offset;
- awe_sample_info *sp = &list->v;
- int rc;
-
- /* be sure loop points start < end */
- if (sp->loopstart > sp->loopend) {
- int tmp = sp->loopstart;
- sp->loopstart = sp->loopend;
- sp->loopend = tmp;
- }
-
- /* compute true data size to be loaded */
- truesize = sp->size;
- if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))
- truesize += sp->loopend - sp->loopstart;
- if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
- truesize += BLANK_LOOP_SIZE;
- if (awe_free_mem_ptr() + truesize >= memsize/2) {
- DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
- return -ENOSPC;
- }
-
- /* recalculate address offset */
- sp->end -= sp->start;
- sp->loopstart -= sp->start;
- sp->loopend -= sp->start;
-
- dram_offset = awe_free_mem_ptr() + awe_mem_start;
- sp->start = dram_offset;
- sp->end += dram_offset;
- sp->loopstart += dram_offset;
- sp->loopend += dram_offset;
-
- /* set the total size (store onto obsolete checksum value) */
- if (sp->size == 0)
- sp->checksum = 0;
- else
- sp->checksum = truesize;
-
- if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0)
- return rc;
-
- if (readbuf_init(addr, offset, sp) < 0)
- return -ENOSPC;
-
- for (i = 0; i < sp->size; i++) {
- unsigned short c;
- c = readbuf_word(i);
- awe_write_dram(c);
- if (i == sp->loopend &&
- (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) {
- int looplen = sp->loopend - sp->loopstart;
- /* copy reverse loop */
- int k;
- for (k = 1; k <= looplen; k++) {
- c = readbuf_word_cache(i - k);
- awe_write_dram(c);
- }
- if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) {
- sp->end += looplen;
- } else {
- sp->start += looplen;
- sp->end += looplen;
- }
- }
- }
- readbuf_end();
-
- /* if no blank loop is attached in the sample, add it */
- if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) {
- for (i = 0; i < BLANK_LOOP_SIZE; i++)
- awe_write_dram(0);
- if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) {
- sp->loopstart = sp->end + BLANK_LOOP_START;
- sp->loopend = sp->end + BLANK_LOOP_END;
- }
- }
-
- awe_close_dram();
-
- /* initialize FM */
- awe_init_fm();
-
- return truesize;
-}
-
-
-/*----------------------------------------------------------------*/
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* calculate GUS envelope time:
- * is this correct? i have no idea..
- */
-static int
-calc_gus_envelope_time(int rate, int start, int end)
-{
- int r, p, t;
- r = (3 - ((rate >> 6) & 3)) * 3;
- p = rate & 0x3f;
- t = end - start;
- if (t < 0) t = -t;
- if (13 > r)
- t = t << (13 - r);
- else
- t = t >> (r - 13);
- return (t * 10) / (p * 441);
-}
-
-#define calc_gus_sustain(val) (0x7f - vol_table[(val)/2])
-#define calc_gus_attenuation(val) vol_table[(val)/2]
-
-/* load GUS patch */
-static int
-awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag)
-{
- struct patch_info patch;
- awe_voice_info *rec;
- awe_sample_info *smp;
- awe_voice_list *vrec;
- awe_sample_list *smprec;
- int sizeof_patch;
- int note, rc;
- sf_list *sf;
-
- sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
- if (size < sizeof_patch) {
- printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
- return -EINVAL;
- }
- if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs))
- return -EFAULT;
- size -= sizeof_patch;
- if (size < patch.len) {
- printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n",
- size, patch.len);
- return -EINVAL;
- }
- if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL)
- return -ENOMEM;
- if ((smprec = alloc_new_sample()) == NULL)
- return -ENOMEM;
- if ((vrec = alloc_new_info()) == NULL) {
- kfree(smprec);
- return -ENOMEM;
- }
-
- smp = &smprec->v;
- smp->sample = sf->num_sample;
- smp->start = 0;
- smp->end = patch.len;
- smp->loopstart = patch.loop_start;
- smp->loopend = patch.loop_end;
- smp->size = patch.len;
-
- /* set up mode flags */
- smp->mode_flags = 0;
- if (!(patch.mode & WAVE_16_BITS))
- smp->mode_flags |= AWE_SAMPLE_8BITS;
- if (patch.mode & WAVE_UNSIGNED)
- smp->mode_flags |= AWE_SAMPLE_UNSIGNED;
- smp->mode_flags |= AWE_SAMPLE_NO_BLANK;
- if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))
- smp->mode_flags |= AWE_SAMPLE_SINGLESHOT;
- if (patch.mode & WAVE_BIDIR_LOOP)
- smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP;
- if (patch.mode & WAVE_LOOP_BACK)
- smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP;
-
- DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags));
- if (patch.mode & WAVE_16_BITS) {
- /* convert to word offsets */
- smp->size /= 2;
- smp->end /= 2;
- smp->loopstart /= 2;
- smp->loopend /= 2;
- }
- smp->checksum_flag = 0;
- smp->checksum = 0;
-
- if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) {
- kfree(vrec);
- return rc;
- }
- sf->mem_ptr += rc;
- add_sf_sample(sf, smprec);
-
- /* set up voice info */
- rec = &vrec->v;
- awe_init_voice_info(rec);
- rec->sample = sf->num_info; /* the last sample */
- rec->rate_offset = calc_rate_offset(patch.base_freq);
- note = freq_to_note(patch.base_note);
- rec->root = note / 100;
- rec->tune = -(note % 100);
- rec->low = freq_to_note(patch.low_note) / 100;
- rec->high = freq_to_note(patch.high_note) / 100;
- DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n",
- rec->rate_offset, note,
- rec->low, rec->high,
- patch.low_note, patch.high_note));
- /* panning position; -128 - 127 => 0-127 */
- rec->pan = (patch.panning + 128) / 2;
-
- /* detuning is ignored */
- /* 6points volume envelope */
- if (patch.mode & WAVE_ENVELOPES) {
- int attack, hold, decay, release;
- attack = calc_gus_envelope_time
- (patch.env_rate[0], 0, patch.env_offset[0]);
- hold = calc_gus_envelope_time
- (patch.env_rate[1], patch.env_offset[0],
- patch.env_offset[1]);
- decay = calc_gus_envelope_time
- (patch.env_rate[2], patch.env_offset[1],
- patch.env_offset[2]);
- release = calc_gus_envelope_time
- (patch.env_rate[3], patch.env_offset[1],
- patch.env_offset[4]);
- release += calc_gus_envelope_time
- (patch.env_rate[4], patch.env_offset[3],
- patch.env_offset[4]);
- release += calc_gus_envelope_time
- (patch.env_rate[5], patch.env_offset[4],
- patch.env_offset[5]);
- rec->parm.volatkhld = (calc_parm_hold(hold) << 8) |
- calc_parm_attack(attack);
- rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
- calc_parm_decay(decay);
- rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
- DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release));
- rec->attenuation = calc_gus_attenuation(patch.env_offset[0]);
- }
-
- /* tremolo effect */
- if (patch.mode & WAVE_TREMOLO) {
- int rate = (patch.tremolo_rate * 1000 / 38) / 42;
- rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
- DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n",
- patch.tremolo_rate, patch.tremolo_depth,
- rec->parm.tremfrq));
- }
- /* vibrato effect */
- if (patch.mode & WAVE_VIBRATO) {
- int rate = (patch.vibrato_rate * 1000 / 38) / 42;
- rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
- DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n",
- patch.tremolo_rate, patch.tremolo_depth,
- rec->parm.tremfrq));
- }
-
- /* scale_freq, scale_factor, volume, and fractions not implemented */
-
- /* append to the tail of the list */
- vrec->bank = ctrls[AWE_MD_GUS_BANK];
- vrec->instr = patch.instr_no;
- vrec->disabled = FALSE;
- vrec->type = V_ST_NORMAL;
-
- add_sf_info(sf, vrec);
- add_info_list(vrec);
-
- /* set the voice index */
- awe_set_sample(vrec);
-
- return 0;
-}
-
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-/*
- * sample and voice list handlers
- */
-
-/* append this to the current sf list */
-static void add_sf_info(sf_list *sf, awe_voice_list *rec)
-{
- if (sf == NULL)
- return;
- rec->holder = sf;
- rec->v.sf_id = sf->sf_id;
- if (sf->last_infos)
- sf->last_infos->next = rec;
- else
- sf->infos = rec;
- sf->last_infos = rec;
- rec->next = NULL;
- sf->num_info++;
-}
-
-/* prepend this sample to sf list */
-static void add_sf_sample(sf_list *sf, awe_sample_list *rec)
-{
- if (sf == NULL)
- return;
- rec->holder = sf;
- rec->v.sf_id = sf->sf_id;
- if (sf->last_samples)
- sf->last_samples->next = rec;
- else
- sf->samples = rec;
- sf->last_samples = rec;
- rec->next = NULL;
- sf->num_sample++;
-}
-
-/* purge the old records which don't belong with the same file id */
-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next)
-{
- rec->next_instr = next;
- if (rec->bank == AWE_DRUM_BANK) {
- /* remove samples with the same note range */
- awe_voice_list *cur, *prev = rec;
- int low = rec->v.low;
- int high = rec->v.high;
- for (cur = next; cur; cur = cur->next_instr) {
- if (cur->v.low == low &&
- cur->v.high == high &&
- ! is_identical_holder(cur->holder, rec->holder))
- prev->next_instr = cur->next_instr;
- else
- prev = cur;
- }
- } else {
- if (! is_identical_holder(next->holder, rec->holder))
- /* remove all samples */
- rec->next_instr = NULL;
- }
-}
-
-/* prepend to top of the preset table */
-static void add_info_list(awe_voice_list *rec)
-{
- awe_voice_list *prev, *cur;
- int key;
-
- if (rec->disabled)
- return;
-
- key = awe_search_key(rec->bank, rec->instr, rec->v.low);
- prev = NULL;
- for (cur = preset_table[key]; cur; cur = cur->next_bank) {
- /* search the first record with the same bank number */
- if (cur->instr == rec->instr && cur->bank == rec->bank) {
- /* replace the list with the new record */
- rec->next_bank = cur->next_bank;
- if (prev)
- prev->next_bank = rec;
- else
- preset_table[key] = rec;
- purge_old_list(rec, cur);
- return;
- }
- prev = cur;
- }
-
- /* this is the first bank record.. just add this */
- rec->next_instr = NULL;
- rec->next_bank = preset_table[key];
- preset_table[key] = rec;
-}
-
-/* remove samples later than the specified sf_id */
-static void
-awe_remove_samples(int sf_id)
-{
- sf_list *p, *prev;
-
- if (sf_id <= 0) {
- awe_reset_samples();
- return;
- }
- /* already removed? */
- if (current_sf_id <= sf_id)
- return;
-
- for (p = sftail; p; p = prev) {
- if (p->sf_id <= sf_id)
- break;
- prev = p->prev;
- awe_free_sf(p);
- }
- sftail = p;
- if (sftail) {
- sf_id = sftail->sf_id;
- sftail->next = NULL;
- } else {
- sf_id = 0;
- sfhead = NULL;
- }
- current_sf_id = sf_id;
- if (locked_sf_id > sf_id)
- locked_sf_id = sf_id;
-
- rebuild_preset_list();
-}
-
-/* rebuild preset search list */
-static void rebuild_preset_list(void)
-{
- sf_list *p;
- awe_voice_list *rec;
-
- memset(preset_table, 0, sizeof(preset_table));
-
- for (p = sfhead; p; p = p->next) {
- for (rec = p->infos; rec; rec = rec->next)
- add_info_list(rec);
- }
-}
-
-/* compare the given sf_id pair */
-static int is_identical_holder(sf_list *sf1, sf_list *sf2)
-{
- if (sf1 == NULL || sf2 == NULL)
- return FALSE;
- if (sf1 == sf2)
- return TRUE;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- {
- /* compare with the sharing id */
- sf_list *p;
- int counter = 0;
- if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */
- sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp;
- }
- for (p = sf1->shared; p; p = p->shared) {
- if (counter++ > current_sf_id)
- break; /* strange sharing loop.. quit */
- if (p == sf2)
- return TRUE;
- }
- }
-#endif /* allow sharing */
- return FALSE;
-}
-
-/* search the sample index matching with the given sample id */
-static awe_sample_list *
-search_sample_index(sf_list *sf, int sample)
-{
- awe_sample_list *p;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- int counter = 0;
- while (sf) {
- for (p = sf->samples; p; p = p->next) {
- if (p->v.sample == sample)
- return p;
- }
- sf = sf->shared;
- if (counter++ > current_sf_id)
- break; /* strange sharing loop.. quit */
- }
-#else
- if (sf) {
- for (p = sf->samples; p; p = p->next) {
- if (p->v.sample == sample)
- return p;
- }
- }
-#endif
- return NULL;
-}
-
-/* search the specified sample */
-/* non-zero = found */
-static short
-awe_set_sample(awe_voice_list *rec)
-{
- awe_sample_list *smp;
- awe_voice_info *vp = &rec->v;
-
- vp->index = 0;
- if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL)
- return 0;
-
- /* set the actual sample offsets */
- vp->start += smp->v.start;
- vp->end += smp->v.end;
- vp->loopstart += smp->v.loopstart;
- vp->loopend += smp->v.loopend;
- /* copy mode flags */
- vp->mode = smp->v.mode_flags;
- /* set flag */
- vp->index = 1;
-
- return 1;
-}
-
-
-/*
- * voice allocation
- */
-
-/* look for all voices associated with the specified note & velocity */
-static int
-awe_search_multi_voices(awe_voice_list *rec, int note, int velocity,
- awe_voice_info **vlist)
-{
- int nvoices;
-
- nvoices = 0;
- for (; rec; rec = rec->next_instr) {
- if (note >= rec->v.low &&
- note <= rec->v.high &&
- velocity >= rec->v.vellow &&
- velocity <= rec->v.velhigh) {
- if (rec->type == V_ST_MAPPED) {
- /* mapper */
- vlist[0] = &rec->v;
- return -1;
- }
- vlist[nvoices++] = &rec->v;
- if (nvoices >= AWE_MAX_VOICES)
- break;
- }
- }
- return nvoices;
-}
-
-/* store the voice list from the specified note and velocity.
- if the preset is mapped, seek for the destination preset, and rewrite
- the note number if necessary.
- */
-static int
-really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist)
-{
- int nvoices;
- awe_voice_list *vrec;
- int level = 0;
-
- for (;;) {
- vrec = awe_search_instr(bank, instr, *note);
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- if (nvoices == 0) {
- if (bank == AWE_DRUM_BANK)
- /* search default drumset */
- vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note);
- else
- /* search default preset */
- vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note);
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- }
- if (nvoices == 0) {
- if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0)
- /* search default drumset */
- vrec = awe_search_instr(bank, 0, *note);
- else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0)
- /* search default preset */
- vrec = awe_search_instr(0, instr, *note);
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- }
- if (nvoices < 0) { /* mapping */
- int key = vlist[0]->fixkey;
- instr = vlist[0]->start;
- bank = vlist[0]->end;
- if (level++ > 5) {
- printk(KERN_ERR "AWE32: too deep mapping level\n");
- return 0;
- }
- if (key >= 0)
- *note = key;
- } else
- break;
- }
-
- return nvoices;
-}
-
-/* allocate voices corresponding note and velocity; supports multiple insts. */
-static void
-awe_alloc_multi_voices(int ch, int note, int velocity, int key)
-{
- int i, v, nvoices, bank;
- awe_voice_info *vlist[AWE_MAX_VOICES];
-
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch))
- bank = AWE_DRUM_BANK; /* always search drumset */
- else
- bank = channels[ch].bank;
-
- /* check the possible voices; note may be changeable if mapped */
- nvoices = really_alloc_voices(bank, channels[ch].instr,
- ¬e, velocity, vlist);
-
- /* set the voices */
- current_alloc_time++;
- for (i = 0; i < nvoices; i++) {
- v = awe_clear_voice();
- voices[v].key = key;
- voices[v].ch = ch;
- voices[v].note = note;
- voices[v].velocity = velocity;
- voices[v].time = current_alloc_time;
- voices[v].cinfo = &channels[ch];
- voices[v].sample = vlist[i];
- voices[v].state = AWE_ST_MARK;
- voices[v].layer = nvoices - i - 1; /* in reverse order */
- }
-
- /* clear the mark in allocated voices */
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].state == AWE_ST_MARK)
- voices[i].state = AWE_ST_OFF;
-
- }
-}
-
-
-/* search an empty voice.
- if no empty voice is found, at least terminate a voice
- */
-static int
-awe_clear_voice(void)
-{
- enum {
- OFF=0, RELEASED, SUSTAINED, PLAYING, END
- };
- struct voice_candidate_t {
- int best;
- int time;
- int vtarget;
- } candidate[END];
- int i, type, vtarget;
-
- vtarget = 0xffff;
- for (type = OFF; type < END; type++) {
- candidate[type].best = -1;
- candidate[type].time = current_alloc_time + 1;
- candidate[type].vtarget = vtarget;
- }
-
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].state & AWE_ST_OFF)
- type = OFF;
- else if (voices[i].state & AWE_ST_RELEASED)
- type = RELEASED;
- else if (voices[i].state & AWE_ST_SUSTAINED)
- type = SUSTAINED;
- else if (voices[i].state & ~AWE_ST_MARK)
- type = PLAYING;
- else
- continue;
-#ifdef AWE_CHECK_VTARGET
- /* get current volume */
- vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
-#endif
- if (candidate[type].best < 0 ||
- vtarget < candidate[type].vtarget ||
- (vtarget == candidate[type].vtarget &&
- voices[i].time < candidate[type].time)) {
- candidate[type].best = i;
- candidate[type].time = voices[i].time;
- candidate[type].vtarget = vtarget;
- }
- }
-
- for (type = OFF; type < END; type++) {
- if ((i = candidate[type].best) >= 0) {
- if (voices[i].state != AWE_ST_OFF)
- awe_terminate(i);
- awe_voice_init(i, TRUE);
- return i;
- }
- }
- return 0;
-}
-
-
-/* search sample for the specified note & velocity and set it on the voice;
- * note that voice is the voice index (not channel index)
- */
-static void
-awe_alloc_one_voice(int voice, int note, int velocity)
-{
- int ch, nvoices, bank;
- awe_voice_info *vlist[AWE_MAX_VOICES];
-
- ch = voices[voice].ch;
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
- bank = AWE_DRUM_BANK; /* always search drumset */
- else
- bank = voices[voice].cinfo->bank;
-
- nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr,
- ¬e, velocity, vlist);
- if (nvoices > 0) {
- voices[voice].time = ++current_alloc_time;
- voices[voice].sample = vlist[0]; /* use the first one */
- voices[voice].layer = 0;
- voices[voice].note = note;
- voices[voice].velocity = velocity;
- }
-}
-
-
-/*
- * sequencer2 functions
- */
-
-/* search an empty voice; used by sequencer2 */
-static int
-awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
- playing_mode = AWE_PLAY_MULTI2;
- awe_info.nr_voices = AWE_MAX_CHANNELS;
- return awe_clear_voice();
-}
-
-
-/* set up voice; used by sequencer2 */
-static void
-awe_setup_voice(int dev, int voice, int chn)
-{
- struct channel_info *info;
- if (synth_devs[dev] == NULL ||
- (info = &synth_devs[dev]->chn_info[chn]) == NULL)
- return;
-
- if (voice < 0 || voice >= awe_max_voices)
- return;
-
- DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn));
- channels[chn].expression_vol = info->controllers[CTL_EXPRESSION];
- channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME];
- channels[chn].panning =
- info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */
- channels[chn].bender = info->bender_value; /* zero center */
- channels[chn].bank = info->controllers[CTL_BANK_SELECT];
- channels[chn].sustained = info->controllers[CTL_SUSTAIN];
- if (info->controllers[CTL_EXT_EFF_DEPTH]) {
- FX_SET(&channels[chn].fx, AWE_FX_REVERB,
- info->controllers[CTL_EXT_EFF_DEPTH] * 2);
- }
- if (info->controllers[CTL_CHORUS_DEPTH]) {
- FX_SET(&channels[chn].fx, AWE_FX_CHORUS,
- info->controllers[CTL_CHORUS_DEPTH] * 2);
- }
- awe_set_instr(dev, chn, info->pgm_num);
-}
-
-
-#ifdef CONFIG_AWE32_MIXER
-/*
- * AWE32 mixer device control
- */
-
-static int awe_mixer_ioctl(int dev, unsigned int cmd, void __user *arg);
-
-static int my_mixerdev = -1;
-
-static struct mixer_operations awe_mixer_operations = {
- .owner = THIS_MODULE,
- .id = "AWE",
- .name = "AWE32 Equalizer",
- .ioctl = awe_mixer_ioctl,
-};
-
-static void __init attach_mixer(void)
-{
- if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
- mixer_devs[my_mixerdev] = &awe_mixer_operations;
- }
-}
-
-static void unload_mixer(void)
-{
- if (my_mixerdev >= 0)
- sound_unload_mixerdev(my_mixerdev);
-}
-
-static int
-awe_mixer_ioctl(int dev, unsigned int cmd, void __user * arg)
-{
- int i, level, value;
-
- if (((cmd >> 8) & 0xff) != 'M')
- return -EINVAL;
-
- if (get_user(level, (int __user *)arg))
- return -EFAULT;
- level = ((level & 0xff) + (level >> 8)) / 2;
- DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
- switch (cmd & 0xff) {
- case SOUND_MIXER_BASS:
- value = level * 12 / 100;
- if (value >= 12)
- value = 11;
- ctrls[AWE_MD_BASS_LEVEL] = value;
- awe_update_equalizer();
- break;
- case SOUND_MIXER_TREBLE:
- value = level * 12 / 100;
- if (value >= 12)
- value = 11;
- ctrls[AWE_MD_TREBLE_LEVEL] = value;
- awe_update_equalizer();
- break;
- case SOUND_MIXER_VOLUME:
- level = level * 127 / 100;
- if (level >= 128) level = 127;
- atten_relative = FALSE;
- atten_offset = vol_table[level];
- awe_update_volume();
- break;
- }
- }
- switch (cmd & 0xff) {
- case SOUND_MIXER_BASS:
- level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24;
- level = (level << 8) | level;
- break;
- case SOUND_MIXER_TREBLE:
- level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24;
- level = (level << 8) | level;
- break;
- case SOUND_MIXER_VOLUME:
- value = atten_offset;
- if (atten_relative)
- value += ctrls[AWE_MD_ZERO_ATTEN];
- for (i = 127; i > 0; i--) {
- if (value <= vol_table[i])
- break;
- }
- level = i * 100 / 127;
- level = (level << 8) | level;
- break;
- case SOUND_MIXER_DEVMASK:
- level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME;
- break;
- default:
- level = 0;
- break;
- }
- if (put_user(level, (int __user *)arg))
- return -EFAULT;
- return level;
-}
-#endif /* CONFIG_AWE32_MIXER */
-
-
-/*
- * initialization of Emu8000
- */
-
-/* intiailize audio channels */
-static void
-awe_init_audio(void)
-{
- int ch;
-
- /* turn off envelope engines */
- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
- awe_poke(AWE_DCYSUSV(ch), 0x80);
- }
-
- /* reset all other parameters to zero */
- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
- awe_poke(AWE_ENVVOL(ch), 0);
- awe_poke(AWE_ENVVAL(ch), 0);
- awe_poke(AWE_DCYSUS(ch), 0);
- awe_poke(AWE_ATKHLDV(ch), 0);
- awe_poke(AWE_LFO1VAL(ch), 0);
- awe_poke(AWE_ATKHLD(ch), 0);
- awe_poke(AWE_LFO2VAL(ch), 0);
- awe_poke(AWE_IP(ch), 0);
- awe_poke(AWE_IFATN(ch), 0);
- awe_poke(AWE_PEFE(ch), 0);
- awe_poke(AWE_FMMOD(ch), 0);
- awe_poke(AWE_TREMFRQ(ch), 0);
- awe_poke(AWE_FM2FRQ2(ch), 0);
- awe_poke_dw(AWE_PTRX(ch), 0);
- awe_poke_dw(AWE_VTFT(ch), 0);
- awe_poke_dw(AWE_PSST(ch), 0);
- awe_poke_dw(AWE_CSL(ch), 0);
- awe_poke_dw(AWE_CCCA(ch), 0);
- }
-
- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
- awe_poke_dw(AWE_CPF(ch), 0);
- awe_poke_dw(AWE_CVCF(ch), 0);
- }
-}
-
-
-/* initialize DMA address */
-static void
-awe_init_dma(void)
-{
- awe_poke_dw(AWE_SMALR, 0);
- awe_poke_dw(AWE_SMARR, 0);
- awe_poke_dw(AWE_SMALW, 0);
- awe_poke_dw(AWE_SMARW, 0);
-}
-
-
-/* initialization arrays; from ADIP */
-
-static unsigned short init1[128] = {
- 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
- 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
- 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
- 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30,
-
- 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330,
- 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730,
- 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30,
- 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30,
-
- 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330,
- 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730,
- 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30,
- 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30,
-
- 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330,
- 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730,
- 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30,
- 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
-};
-
-static unsigned short init2[128] = {
- 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
- 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
- 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
- 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
-
- 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
- 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
- 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
- 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
-
- 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
- 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
- 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
- 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
-
- 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
- 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
- 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
- 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
-};
-
-static unsigned short init3[128] = {
- 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
- 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
- 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
- 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
-
- 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
- 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
- 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
- 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
-
- 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
- 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
- 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
- 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
-
- 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
- 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
- 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
- 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-static unsigned short init4[128] = {
- 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
- 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
- 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
- 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
-
- 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
- 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
- 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
- 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
-
- 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
- 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
- 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
- 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
-
- 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
- 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
- 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
- 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-
-/* send initialization arrays to start up */
-static void
-awe_init_array(void)
-{
- awe_send_array(init1);
- awe_wait(1024);
- awe_send_array(init2);
- awe_send_array(init3);
- awe_poke_dw(AWE_HWCF4, 0);
- awe_poke_dw(AWE_HWCF5, 0x83);
- awe_poke_dw(AWE_HWCF6, 0x8000);
- awe_send_array(init4);
-}
-
-/* send an initialization array */
-static void
-awe_send_array(unsigned short *data)
-{
- int i;
- unsigned short *p;
-
- p = data;
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT1(i), *p);
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT2(i), *p);
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT3(i), *p);
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT4(i), *p);
-}
-
-
-/*
- * set up awe32 channels to some known state.
- */
-
-/* set the envelope & LFO parameters to the default values; see ADIP */
-static void
-awe_tweak_voice(int i)
-{
- /* set all mod/vol envelope shape to minimum */
- awe_poke(AWE_ENVVOL(i), 0x8000);
- awe_poke(AWE_ENVVAL(i), 0x8000);
- awe_poke(AWE_DCYSUS(i), 0x7F7F);
- awe_poke(AWE_ATKHLDV(i), 0x7F7F);
- awe_poke(AWE_ATKHLD(i), 0x7F7F);
- awe_poke(AWE_PEFE(i), 0); /* mod envelope height to zero */
- awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */
- awe_poke(AWE_LFO2VAL(i), 0x8000);
- awe_poke(AWE_IP(i), 0xE000); /* no pitch shift */
- awe_poke(AWE_IFATN(i), 0xFF00); /* volume to minimum */
- awe_poke(AWE_FMMOD(i), 0);
- awe_poke(AWE_TREMFRQ(i), 0);
- awe_poke(AWE_FM2FRQ2(i), 0);
-}
-
-static void
-awe_tweak(void)
-{
- int i;
- /* reset all channels */
- for (i = 0; i < awe_max_voices; i++)
- awe_tweak_voice(i);
-}
-
-
-/*
- * initializes the FM section of AWE32;
- * see Vince Vu's unofficial AWE32 programming guide
- */
-
-static void
-awe_init_fm(void)
-{
-#ifndef AWE_ALWAYS_INIT_FM
- /* if no extended memory is on board.. */
- if (memsize <= 0)
- return;
-#endif
- DEBUG(3,printk("AWE32: initializing FM\n"));
-
- /* Initialize the last two channels for DRAM refresh and producing
- the reverb and chorus effects for Yamaha OPL-3 synthesizer */
-
- /* 31: FM left channel, 0xffffe0-0xffffe8 */
- awe_poke(AWE_DCYSUSV(30), 0x80);
- awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */
- awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 |
- (DEF_FM_CHORUS_DEPTH << 24));
- awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8));
- awe_poke_dw(AWE_CPF(30), 0);
- awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3);
-
- /* 32: FM right channel, 0xfffff0-0xfffff8 */
- awe_poke(AWE_DCYSUSV(31), 0x80);
- awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */
- awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 |
- (DEF_FM_CHORUS_DEPTH << 24));
- awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8));
- awe_poke_dw(AWE_CPF(31), 0x8000);
- awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3);
-
- /* skew volume & cutoff */
- awe_poke_dw(AWE_VTFT(30), 0x8000FFFF);
- awe_poke_dw(AWE_VTFT(31), 0x8000FFFF);
-
- voices[30].state = AWE_ST_FM;
- voices[31].state = AWE_ST_FM;
-
- /* change maximum channels to 30 */
- awe_max_voices = AWE_NORMAL_VOICES;
- if (playing_mode == AWE_PLAY_DIRECT)
- awe_info.nr_voices = awe_max_voices;
- else
- awe_info.nr_voices = AWE_MAX_CHANNELS;
- voice_alloc->max_voice = awe_max_voices;
-}
-
-/*
- * AWE32 DRAM access routines
- */
-
-/* open DRAM write accessing mode */
-static int
-awe_open_dram_for_write(int offset, int channels)
-{
- int vidx[AWE_NORMAL_VOICES];
- int i;
-
- if (channels < 0 || channels >= AWE_NORMAL_VOICES) {
- channels = AWE_NORMAL_VOICES;
- for (i = 0; i < AWE_NORMAL_VOICES; i++)
- vidx[i] = i;
- } else {
- for (i = 0; i < channels; i++) {
- vidx[i] = awe_clear_voice();
- voices[vidx[i]].state = AWE_ST_MARK;
- }
- }
-
- /* use all channels for DMA transfer */
- for (i = 0; i < channels; i++) {
- if (vidx[i] < 0) continue;
- awe_poke(AWE_DCYSUSV(vidx[i]), 0x80);
- awe_poke_dw(AWE_VTFT(vidx[i]), 0);
- awe_poke_dw(AWE_CVCF(vidx[i]), 0);
- awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000);
- awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000);
- awe_poke_dw(AWE_PSST(vidx[i]), 0);
- awe_poke_dw(AWE_CSL(vidx[i]), 0);
- awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000);
- voices[vidx[i]].state = AWE_ST_DRAM;
- }
- /* point channels 31 & 32 to ROM samples for DRAM refresh */
- awe_poke_dw(AWE_VTFT(30), 0);
- awe_poke_dw(AWE_PSST(30), 0x1d8);
- awe_poke_dw(AWE_CSL(30), 0x1e0);
- awe_poke_dw(AWE_CCCA(30), 0x1d8);
- awe_poke_dw(AWE_VTFT(31), 0);
- awe_poke_dw(AWE_PSST(31), 0x1d8);
- awe_poke_dw(AWE_CSL(31), 0x1e0);
- awe_poke_dw(AWE_CCCA(31), 0x1d8);
- voices[30].state = AWE_ST_FM;
- voices[31].state = AWE_ST_FM;
-
- /* if full bit is on, not ready to write on */
- if (awe_peek_dw(AWE_SMALW) & 0x80000000) {
- for (i = 0; i < channels; i++) {
- awe_poke_dw(AWE_CCCA(vidx[i]), 0);
- voices[vidx[i]].state = AWE_ST_OFF;
- }
- printk("awe: not ready to write..\n");
- return -EPERM;
- }
-
- /* set address to write */
- awe_poke_dw(AWE_SMALW, offset);
-
- return 0;
-}
-
-/* open DRAM for RAM size detection */
-static void
-awe_open_dram_for_check(void)
-{
- int i;
- for (i = 0; i < AWE_NORMAL_VOICES; i++) {
- awe_poke(AWE_DCYSUSV(i), 0x80);
- awe_poke_dw(AWE_VTFT(i), 0);
- awe_poke_dw(AWE_CVCF(i), 0);
- awe_poke_dw(AWE_PTRX(i), 0x40000000);
- awe_poke_dw(AWE_CPF(i), 0x40000000);
- awe_poke_dw(AWE_PSST(i), 0);
- awe_poke_dw(AWE_CSL(i), 0);
- if (i & 1) /* DMA write */
- awe_poke_dw(AWE_CCCA(i), 0x06000000);
- else /* DMA read */
- awe_poke_dw(AWE_CCCA(i), 0x04000000);
- voices[i].state = AWE_ST_DRAM;
- }
-}
-
-
-/* close dram access */
-static void
-awe_close_dram(void)
-{
- int i;
- /* wait until FULL bit in SMAxW register be false */
- for (i = 0; i < 10000; i++) {
- if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
- break;
- awe_wait(10);
- }
-
- for (i = 0; i < AWE_NORMAL_VOICES; i++) {
- if (voices[i].state == AWE_ST_DRAM) {
- awe_poke_dw(AWE_CCCA(i), 0);
- awe_poke(AWE_DCYSUSV(i), 0x807F);
- voices[i].state = AWE_ST_OFF;
- }
- }
-}
-
-
-/*
- * check dram size on AWE board
- */
-
-/* any three numbers you like */
-#define UNIQUE_ID1 0x1234
-#define UNIQUE_ID2 0x4321
-#define UNIQUE_ID3 0xABCD
-
-static void __init
-awe_check_dram(void)
-{
- if (awe_present) /* already initialized */
- return;
-
- if (memsize >= 0) { /* given by config file or module option */
- memsize *= 1024; /* convert to Kbytes */
- return;
- }
-
- awe_open_dram_for_check();
-
- memsize = 0;
-
- /* set up unique two id numbers */
- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
- awe_poke(AWE_SMLD, UNIQUE_ID1);
- awe_poke(AWE_SMLD, UNIQUE_ID2);
-
- while (memsize < AWE_MAX_DRAM_SIZE) {
- awe_wait(5);
- /* read a data on the DRAM start address */
- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
- awe_peek(AWE_SMLD); /* discard stale data */
- if (awe_peek(AWE_SMLD) != UNIQUE_ID1)
- break;
- if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
- break;
- memsize += 512; /* increment 512kbytes */
- /* Write a unique data on the test address;
- * if the address is out of range, the data is written on
- * 0x200000(=AWE_DRAM_OFFSET). Then the two id words are
- * broken by this data.
- */
- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L);
- awe_poke(AWE_SMLD, UNIQUE_ID3);
- awe_wait(5);
- /* read a data on the just written DRAM address */
- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L);
- awe_peek(AWE_SMLD); /* discard stale data */
- if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
- break;
- }
- awe_close_dram();
-
- DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize));
-
- /* convert to Kbytes */
- memsize *= 1024;
-}
-
-
-/*----------------------------------------------------------------*/
-
-/*
- * chorus and reverb controls; from VV's guide
- */
-
-/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
-static char chorus_defined[AWE_CHORUS_NUMBERS];
-static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = {
- {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
- {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
- {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
- {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
- {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
- {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
- {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */
- {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */
-};
-
-static int
-awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
- printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg);
- return -EINVAL;
- }
- if (count < sizeof(awe_chorus_fx_rec)) {
- printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n");
- return -EINVAL;
- }
- if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_chorus_fx_rec)))
- return -EFAULT;
- chorus_defined[patch->optarg] = TRUE;
- return 0;
-}
-
-static void
-awe_set_chorus_mode(int effect)
-{
- if (effect < 0 || effect >= AWE_CHORUS_NUMBERS ||
- (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect]))
- return;
- awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback);
- awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset);
- awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth);
- awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay);
- awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq);
- awe_poke_dw(AWE_HWCF6, 0x8000);
- awe_poke_dw(AWE_HWCF7, 0x0000);
-}
-
-static void
-awe_update_chorus_mode(void)
-{
- awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]);
-}
-
-/*----------------------------------------------------------------*/
-
-/* reverb mode settings; write the following 28 data of 16 bit length
- * on the corresponding ports in the reverb_cmds array
- */
-static char reverb_defined[AWE_CHORUS_NUMBERS];
-static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = {
-{{ /* room 1 */
- 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
- 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
- 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* room 2 */
- 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* room 3 */
- 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
- 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
- 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
-}},
-{{ /* hall 1 */
- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
- 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
-}},
-{{ /* hall 2 */
- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
- 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
- 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* plate */
- 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
- 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* delay */
- 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-{{ /* panning delay */
- 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-};
-
-static struct ReverbCmdPair {
- unsigned short cmd, port;
-} reverb_cmds[28] = {
- {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
- {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
- {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
- {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
- {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
- {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
- {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
-};
-
-static int
-awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
- printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg);
- return -EINVAL;
- }
- if (count < sizeof(awe_reverb_fx_rec)) {
- printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n");
- return -EINVAL;
- }
- if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_reverb_fx_rec)))
- return -EFAULT;
- reverb_defined[patch->optarg] = TRUE;
- return 0;
-}
-
-static void
-awe_set_reverb_mode(int effect)
-{
- int i;
- if (effect < 0 || effect >= AWE_REVERB_NUMBERS ||
- (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect]))
- return;
- for (i = 0; i < 28; i++)
- awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port,
- reverb_parm[effect].parms[i]);
-}
-
-static void
-awe_update_reverb_mode(void)
-{
- awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
-}
-
-/*
- * treble/bass equalizer control
- */
-
-static unsigned short bass_parm[12][3] = {
- {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
- {0xD25B, 0xD35B, 0x0000}, /* -8 */
- {0xD24C, 0xD34C, 0x0000}, /* -6 */
- {0xD23D, 0xD33D, 0x0000}, /* -4 */
- {0xD21F, 0xD31F, 0x0000}, /* -2 */
- {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
- {0xC219, 0xC319, 0x0001}, /* +2 */
- {0xC22A, 0xC32A, 0x0001}, /* +4 */
- {0xC24C, 0xC34C, 0x0001}, /* +6 */
- {0xC26E, 0xC36E, 0x0001}, /* +8 */
- {0xC248, 0xC348, 0x0002}, /* +10 */
- {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
-};
-
-static unsigned short treble_parm[12][9] = {
- {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
- {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
- {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
- {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */
-};
-
-
-/*
- * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
- */
-static void
-awe_equalizer(int bass, int treble)
-{
- unsigned short w;
-
- if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
- return;
- awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]);
- awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]);
- awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]);
- awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]);
- awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]);
- awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]);
- awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]);
- awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]);
- awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]);
- awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]);
- w = bass_parm[bass][2] + treble_parm[treble][8];
- awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262));
- awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362));
-}
-
-static void awe_update_equalizer(void)
-{
- awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]);
-}
-
-
-/*----------------------------------------------------------------*/
-
-#ifdef CONFIG_AWE32_MIDIEMU
-
-/*
- * Emu8000 MIDI Emulation
- */
-
-/*
- * midi queue record
- */
-
-/* queue type */
-enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
-
-#define MAX_MIDIBUF 64
-
-/* midi status */
-typedef struct MidiStatus {
- int queue; /* queue type */
- int qlen; /* queue length */
- int read; /* chars read */
- int status; /* current status */
- int chan; /* current channel */
- unsigned char buf[MAX_MIDIBUF];
-} MidiStatus;
-
-/* MIDI mode type */
-enum { MODE_GM, MODE_GS, MODE_XG, };
-
-/* NRPN / CC -> Emu8000 parameter converter */
-typedef struct {
- int control;
- int awe_effect;
- unsigned short (*convert)(int val);
-} ConvTable;
-
-
-/*
- * prototypes
- */
-
-static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
-static void awe_midi_close(int dev);
-static int awe_midi_ioctl(int dev, unsigned cmd, void __user * arg);
-static int awe_midi_outputc(int dev, unsigned char midi_byte);
-
-static void init_midi_status(MidiStatus *st);
-static void clear_rpn(void);
-static void get_midi_char(MidiStatus *st, int c);
-/*static void queue_varlen(MidiStatus *st, int c);*/
-static void special_event(MidiStatus *st, int c);
-static void queue_read(MidiStatus *st, int c);
-static void midi_note_on(MidiStatus *st);
-static void midi_note_off(MidiStatus *st);
-static void midi_key_pressure(MidiStatus *st);
-static void midi_channel_pressure(MidiStatus *st);
-static void midi_pitch_wheel(MidiStatus *st);
-static void midi_program_change(MidiStatus *st);
-static void midi_control_change(MidiStatus *st);
-static void midi_select_bank(MidiStatus *st, int val);
-static void midi_nrpn_event(MidiStatus *st);
-static void midi_rpn_event(MidiStatus *st);
-static void midi_detune(int chan, int coarse, int fine);
-static void midi_system_exclusive(MidiStatus *st);
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int xg_control_change(MidiStatus *st, int cmd, int val);
-
-#define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
-
-
-/*
- * OSS Midi device record
- */
-
-static struct midi_operations awe_midi_operations =
-{
- .owner = THIS_MODULE,
- .info = {"AWE Midi Emu", 0, 0, SNDCARD_SB},
- .in_info = {0},
- .open = awe_midi_open, /*open*/
- .close = awe_midi_close, /*close*/
- .ioctl = awe_midi_ioctl, /*ioctl*/
- .outputc = awe_midi_outputc, /*outputc*/
-};
-
-static int my_mididev = -1;
-
-static void __init attach_midiemu(void)
-{
- if ((my_mididev = sound_alloc_mididev()) < 0)
- printk ("Sound: Too many midi devices detected\n");
- else
- midi_devs[my_mididev] = &awe_midi_operations;
-}
-
-static void unload_midiemu(void)
-{
- if (my_mididev >= 0)
- sound_unload_mididev(my_mididev);
-}
-
-
-/*
- * open/close midi device
- */
-
-static int midi_opened = FALSE;
-
-static int midi_mode;
-static int coarsetune, finetune;
-
-static int xg_mapping = TRUE;
-static int xg_bankmode;
-
-/* effect sensitivity */
-
-#define FX_CUTOFF 0
-#define FX_RESONANCE 1
-#define FX_ATTACK 2
-#define FX_RELEASE 3
-#define FX_VIBRATE 4
-#define FX_VIBDEPTH 5
-#define FX_VIBDELAY 6
-#define FX_NUMS 7
-
-#define DEF_FX_CUTOFF 170
-#define DEF_FX_RESONANCE 6
-#define DEF_FX_ATTACK 50
-#define DEF_FX_RELEASE 50
-#define DEF_FX_VIBRATE 30
-#define DEF_FX_VIBDEPTH 4
-#define DEF_FX_VIBDELAY 1500
-
-/* effect sense: */
-static int gs_sense[] =
-{
- DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
- DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-static int xg_sense[] =
-{
- DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
- DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-
-
-/* current status */
-static MidiStatus curst;
-
-
-static int
-awe_midi_open (int dev, int mode,
- void (*input)(int,unsigned char),
- void (*output)(int))
-{
- if (midi_opened)
- return -EBUSY;
-
- midi_opened = TRUE;
-
- midi_mode = MODE_GM;
-
- curst.queue = Q_NONE;
- curst.qlen = 0;
- curst.read = 0;
- curst.status = 0;
- curst.chan = 0;
- memset(curst.buf, 0, sizeof(curst.buf));
-
- init_midi_status(&curst);
-
- return 0;
-}
-
-static void
-awe_midi_close (int dev)
-{
- midi_opened = FALSE;
-}
-
-
-static int
-awe_midi_ioctl (int dev, unsigned cmd, void __user *arg)
-{
- return -EPERM;
-}
-
-static int
-awe_midi_outputc (int dev, unsigned char midi_byte)
-{
- if (! midi_opened)
- return 1;
-
- /* force to change playing mode */
- playing_mode = AWE_PLAY_MULTI;
-
- get_midi_char(&curst, midi_byte);
- return 1;
-}
-
-
-/*
- * initialize
- */
-
-static void init_midi_status(MidiStatus *st)
-{
- clear_rpn();
- coarsetune = 0;
- finetune = 0;
-}
-
-
-/*
- * RPN & NRPN
- */
-
-#define MAX_MIDI_CHANNELS 16
-
-/* RPN & NRPN */
-static unsigned char nrpn[MAX_MIDI_CHANNELS]; /* current event is NRPN? */
-static int msb_bit; /* current event is msb for RPN/NRPN */
-/* RPN & NRPN indeces */
-static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS];
-/* RPN & NRPN values */
-static int rpn_val[MAX_MIDI_CHANNELS];
-
-static void clear_rpn(void)
-{
- int i;
- for (i = 0; i < MAX_MIDI_CHANNELS; i++) {
- nrpn[i] = 0;
- rpn_msb[i] = 127;
- rpn_lsb[i] = 127;
- rpn_val[i] = 0;
- }
- msb_bit = 0;
-}
-
-
-/*
- * process midi queue
- */
-
-/* status event types */
-typedef void (*StatusEvent)(MidiStatus *st);
-static struct StatusEventList {
- StatusEvent process;
- int qlen;
-} status_event[8] = {
- {midi_note_off, 2},
- {midi_note_on, 2},
- {midi_key_pressure, 2},
- {midi_control_change, 2},
- {midi_program_change, 1},
- {midi_channel_pressure, 1},
- {midi_pitch_wheel, 2},
- {NULL, 0},
-};
-
-
-/* read a char from fifo and process it */
-static void get_midi_char(MidiStatus *st, int c)
-{
- if (c == 0xfe) {
- /* ignore active sense */
- st->queue = Q_NONE;
- return;
- }
-
- switch (st->queue) {
- /* case Q_VARLEN: queue_varlen(st, c); break;*/
- case Q_READ:
- case Q_SYSEX:
- queue_read(st, c);
- break;
- case Q_NONE:
- st->read = 0;
- if ((c & 0xf0) == 0xf0) {
- special_event(st, c);
- } else if (c & 0x80) { /* status change */
- st->status = (c >> 4) & 0x07;
- st->chan = c & 0x0f;
- st->queue = Q_READ;
- st->qlen = status_event[st->status].qlen;
- if (st->qlen == 0)
- st->queue = Q_NONE;
- }
- break;
- }
-}
-
-/* 0xfx events */
-static void special_event(MidiStatus *st, int c)
-{
- switch (c) {
- case 0xf0: /* system exclusive */
- st->queue = Q_SYSEX;
- st->qlen = 0;
- break;
- case 0xf1: /* MTC quarter frame */
- case 0xf3: /* song select */
- st->queue = Q_READ;
- st->qlen = 1;
- break;
- case 0xf2: /* song position */
- st->queue = Q_READ;
- st->qlen = 2;
- break;
- }
-}
-
-#if 0
-/* read variable length value */
-static void queue_varlen(MidiStatus *st, int c)
-{
- st->qlen += (c & 0x7f);
- if (c & 0x80) {
- st->qlen <<= 7;
- return;
- }
- if (st->qlen <= 0) {
- st->qlen = 0;
- st->queue = Q_NONE;
- }
- st->queue = Q_READ;
- st->read = 0;
-}
-#endif
-
-
-/* read a char */
-static void queue_read(MidiStatus *st, int c)
-{
- if (st->read < MAX_MIDIBUF) {
- if (st->queue != Q_SYSEX)
- c &= 0x7f;
- st->buf[st->read] = (unsigned char)c;
- }
- st->read++;
- if (st->queue == Q_SYSEX && c == 0xf7) {
- midi_system_exclusive(st);
- st->queue = Q_NONE;
- } else if (st->queue == Q_READ && st->read >= st->qlen) {
- if (status_event[st->status].process)
- status_event[st->status].process(st);
- st->queue = Q_NONE;
- }
-}
-
-
-/*
- * status events
- */
-
-/* note on */
-static void midi_note_on(MidiStatus *st)
-{
- DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
- if (st->buf[1] == 0)
- midi_note_off(st);
- else
- awe_start_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* note off */
-static void midi_note_off(MidiStatus *st)
-{
- DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
- awe_kill_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* key pressure change */
-static void midi_key_pressure(MidiStatus *st)
-{
- awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* channel pressure change */
-static void midi_channel_pressure(MidiStatus *st)
-{
- channels[st->chan].chan_press = st->buf[0];
- awe_modwheel_change(st->chan, st->buf[0]);
-}
-
-/* pitch wheel change */
-static void midi_pitch_wheel(MidiStatus *st)
-{
- int val = (int)st->buf[1] * 128 + st->buf[0];
- awe_bender(0, st->chan, val);
-}
-
-/* program change */
-static void midi_program_change(MidiStatus *st)
-{
- int preset;
- preset = st->buf[0];
- if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127)
- preset = 0;
- else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan))
- preset += 64;
-
- awe_set_instr(0, st->chan, preset);
-}
-
-#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val)
-#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val)
-#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0)
-
-/* midi control change */
-static void midi_control_change(MidiStatus *st)
-{
- int cmd = st->buf[0];
- int val = st->buf[1];
-
- DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val));
- if (midi_mode == MODE_XG) {
- if (xg_control_change(st, cmd, val))
- return;
- }
-
- /* controls #31 - #64 are LSB of #0 - #31 */
- msb_bit = 1;
- if (cmd >= 0x20 && cmd < 0x40) {
- msb_bit = 0;
- cmd -= 0x20;
- }
-
- switch (cmd) {
- case CTL_SOFT_PEDAL:
- if (val == 127)
- add_effect(st->chan, AWE_FX_CUTOFF, -160);
- else
- unset_effect(st->chan, AWE_FX_CUTOFF);
- break;
-
- case CTL_BANK_SELECT:
- midi_select_bank(st, val);
- break;
-
- /* set RPN/NRPN parameter */
- case CTL_REGIST_PARM_NUM_MSB:
- nrpn[st->chan]=0; rpn_msb[st->chan]=val;
- break;
- case CTL_REGIST_PARM_NUM_LSB:
- nrpn[st->chan]=0; rpn_lsb[st->chan]=val;
- break;
- case CTL_NONREG_PARM_NUM_MSB:
- nrpn[st->chan]=1; rpn_msb[st->chan]=val;
- break;
- case CTL_NONREG_PARM_NUM_LSB:
- nrpn[st->chan]=1; rpn_lsb[st->chan]=val;
- break;
-
- /* send RPN/NRPN entry */
- case CTL_DATA_ENTRY:
- if (msb_bit)
- rpn_val[st->chan] = val * 128;
- else
- rpn_val[st->chan] |= val;
- if (nrpn[st->chan])
- midi_nrpn_event(st);
- else
- midi_rpn_event(st);
- break;
-
- /* increase/decrease data entry */
- case CTL_DATA_INCREMENT:
- rpn_val[st->chan]++;
- midi_rpn_event(st);
- break;
- case CTL_DATA_DECREMENT:
- rpn_val[st->chan]--;
- midi_rpn_event(st);
- break;
-
- /* default */
- default:
- awe_controller(0, st->chan, cmd, val);
- break;
- }
-}
-
-/* tone bank change */
-static void midi_select_bank(MidiStatus *st, int val)
-{
- if (midi_mode == MODE_XG && msb_bit) {
- xg_bankmode = val;
- /* XG MSB value; not normal bank selection */
- switch (val) {
- case 127: /* remap to drum channel */
- awe_controller(0, st->chan, CTL_BANK_SELECT, 128);
- break;
- default: /* remap to normal channel */
- awe_controller(0, st->chan, CTL_BANK_SELECT, val);
- break;
- }
- return;
- } else if (midi_mode == MODE_GS && !msb_bit)
- /* ignore LSB bank in GS mode (used for mapping) */
- return;
-
- /* normal bank controls; accept both MSB and LSB */
- if (! IS_DRUM_CHANNEL(st->chan)) {
- if (midi_mode == MODE_XG) {
- if (xg_bankmode) return;
- if (val == 64 || val == 126)
- val = 0;
- } else if (midi_mode == MODE_GS && val == 127)
- val = 0;
- awe_controller(0, st->chan, CTL_BANK_SELECT, val);
- }
-}
-
-
-/*
- * RPN events
- */
-
-static void midi_rpn_event(MidiStatus *st)
-{
- int type;
- type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan];
- switch (type) {
- case 0x0000: /* Pitch bend sensitivity */
- /* MSB only / 1 semitone per 128 */
- if (msb_bit) {
- channels[st->chan].bender_range =
- rpn_val[st->chan] * 100 / 128;
- }
- break;
-
- case 0x0001: /* fine tuning: */
- /* MSB/LSB, 8192=center, 100/8192 cent step */
- finetune = rpn_val[st->chan] - 8192;
- midi_detune(st->chan, coarsetune, finetune);
- break;
-
- case 0x0002: /* coarse tuning */
- /* MSB only / 8192=center, 1 semitone per 128 */
- if (msb_bit) {
- coarsetune = rpn_val[st->chan] - 8192;
- midi_detune(st->chan, coarsetune, finetune);
- }
- break;
-
- case 0x7F7F: /* "lock-in" RPN */
- break;
- }
-}
-
-
-/* tuning:
- * coarse = -8192 to 8192 (100 cent per 128)
- * fine = -8192 to 8192 (max=100cent)
- */
-static void midi_detune(int chan, int coarse, int fine)
-{
- /* 4096 = 1200 cents in AWE parameter */
- int val;
- val = coarse * 4096 / (12 * 128);
- val += fine / 24;
- if (val)
- send_effect(chan, AWE_FX_INIT_PITCH, val);
- else
- unset_effect(chan, AWE_FX_INIT_PITCH);
-}
-
-
-/*
- * system exclusive message
- * GM/GS/XG macros are accepted
- */
-
-static void midi_system_exclusive(MidiStatus *st)
-{
- /* GM on */
- static unsigned char gm_on_macro[] = {
- 0x7e,0x7f,0x09,0x01,
- };
- /* XG on */
- static unsigned char xg_on_macro[] = {
- 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
- };
- /* GS prefix
- * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off
- * reverb mode: XX=0x01, YY=0x30, ZZ=0-7
- * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
- */
- static unsigned char gs_pfx_macro[] = {
- 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
- };
-
-#if 0
- /* SC88 system mode set
- * single module mode: XX=1
- * double module mode: XX=0
- */
- static unsigned char gs_mode_macro[] = {
- 0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/
- };
- /* SC88 display macro: XX=01:bitmap, 00:text
- */
- static unsigned char gs_disp_macro[] = {
- 0x41,0x10,0x45,0x12,0x10,/*XX,00*/
- };
-#endif
-
- /* GM on */
- if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
- if (midi_mode != MODE_GS && midi_mode != MODE_XG)
- midi_mode = MODE_GM;
- init_midi_status(st);
- }
-
- /* GS macros */
- else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
- if (midi_mode != MODE_GS && midi_mode != MODE_XG)
- midi_mode = MODE_GS;
-
- if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) {
- /* GS reset */
- init_midi_status(st);
- }
-
- else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) {
- /* drum pattern */
- int p = st->buf[5] & 0x0f;
- if (p == 0) p = 9;
- else if (p < 10) p--;
- if (st->buf[7] == 0)
- DRUM_CHANNEL_OFF(p);
- else
- DRUM_CHANNEL_ON(p);
-
- } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) {
- /* program */
- int p = st->buf[5] & 0x0f;
- if (p == 0) p = 9;
- else if (p < 10) p--;
- if (! IS_DRUM_CHANNEL(p))
- awe_set_instr(0, p, st->buf[7]);
-
- } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) {
- /* reverb mode */
- awe_set_reverb_mode(st->buf[7]);
-
- } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) {
- /* chorus mode */
- awe_set_chorus_mode(st->buf[7]);
-
- } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) {
- /* master volume */
- awe_change_master_volume(st->buf[7]);
-
- }
- }
-
- /* XG on */
- else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
- midi_mode = MODE_XG;
- xg_mapping = TRUE;
- xg_bankmode = 0;
- }
-}
-
-
-/*----------------------------------------------------------------*/
-
-/*
- * convert NRPN/control values
- */
-
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
- int i, cval;
- for (i = 0; i < num_tables; i++) {
- if (table[i].control == type) {
- cval = table[i].convert(val);
- send_effect(st->chan, table[i].awe_effect, cval);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
- int i, cval;
- for (i = 0; i < num_tables; i++) {
- if (table[i].control == type) {
- cval = table[i].convert(val);
- add_effect(st->chan, table[i].awe_effect|0x80, cval);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-/*
- * AWE32 NRPN effects
- */
-
-static unsigned short fx_delay(int val);
-static unsigned short fx_attack(int val);
-static unsigned short fx_hold(int val);
-static unsigned short fx_decay(int val);
-static unsigned short fx_the_value(int val);
-static unsigned short fx_twice_value(int val);
-static unsigned short fx_conv_pitch(int val);
-static unsigned short fx_conv_Q(int val);
-
-/* function for each NRPN */ /* [range] units */
-#define fx_env1_delay fx_delay /* [0,5900] 4msec */
-#define fx_env1_attack fx_attack /* [0,5940] 1msec */
-#define fx_env1_hold fx_hold /* [0,8191] 1msec */
-#define fx_env1_decay fx_decay /* [0,5940] 4msec */
-#define fx_env1_release fx_decay /* [0,5940] 4msec */
-#define fx_env1_sustain fx_the_value /* [0,127] 0.75dB */
-#define fx_env1_pitch fx_the_value /* [-127,127] 9.375cents */
-#define fx_env1_cutoff fx_the_value /* [-127,127] 56.25cents */
-
-#define fx_env2_delay fx_delay /* [0,5900] 4msec */
-#define fx_env2_attack fx_attack /* [0,5940] 1msec */
-#define fx_env2_hold fx_hold /* [0,8191] 1msec */
-#define fx_env2_decay fx_decay /* [0,5940] 4msec */
-#define fx_env2_release fx_decay /* [0,5940] 4msec */
-#define fx_env2_sustain fx_the_value /* [0,127] 0.75dB */
-
-#define fx_lfo1_delay fx_delay /* [0,5900] 4msec */
-#define fx_lfo1_freq fx_twice_value /* [0,127] 84mHz */
-#define fx_lfo1_volume fx_twice_value /* [0,127] 0.1875dB */
-#define fx_lfo1_pitch fx_the_value /* [-127,127] 9.375cents */
-#define fx_lfo1_cutoff fx_twice_value /* [-64,63] 56.25cents */
-
-#define fx_lfo2_delay fx_delay /* [0,5900] 4msec */
-#define fx_lfo2_freq fx_twice_value /* [0,127] 84mHz */
-#define fx_lfo2_pitch fx_the_value /* [-127,127] 9.375cents */
-
-#define fx_init_pitch fx_conv_pitch /* [-8192,8192] cents */
-#define fx_chorus fx_the_value /* [0,255] -- */
-#define fx_reverb fx_the_value /* [0,255] -- */
-#define fx_cutoff fx_twice_value /* [0,127] 62Hz */
-#define fx_filterQ fx_conv_Q /* [0,127] -- */
-
-static unsigned short fx_delay(int val)
-{
- return (unsigned short)calc_parm_delay(val);
-}
-
-static unsigned short fx_attack(int val)
-{
- return (unsigned short)calc_parm_attack(val);
-}
-
-static unsigned short fx_hold(int val)
-{
- return (unsigned short)calc_parm_hold(val);
-}
-
-static unsigned short fx_decay(int val)
-{
- return (unsigned short)calc_parm_decay(val);
-}
-
-static unsigned short fx_the_value(int val)
-{
- return (unsigned short)(val & 0xff);
-}
-
-static unsigned short fx_twice_value(int val)
-{
- return (unsigned short)((val * 2) & 0xff);
-}
-
-static unsigned short fx_conv_pitch(int val)
-{
- return (short)(val * 4096 / 1200);
-}
-
-static unsigned short fx_conv_Q(int val)
-{
- return (unsigned short)((val / 8) & 0xff);
-}
-
-
-static ConvTable awe_effects[] =
-{
- { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay},
- { 1, AWE_FX_LFO1_FREQ, fx_lfo1_freq},
- { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay},
- { 3, AWE_FX_LFO2_FREQ, fx_lfo2_freq},
-
- { 4, AWE_FX_ENV1_DELAY, fx_env1_delay},
- { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack},
- { 6, AWE_FX_ENV1_HOLD, fx_env1_hold},
- { 7, AWE_FX_ENV1_DECAY, fx_env1_decay},
- { 8, AWE_FX_ENV1_SUSTAIN, fx_env1_sustain},
- { 9, AWE_FX_ENV1_RELEASE, fx_env1_release},
-
- {10, AWE_FX_ENV2_DELAY, fx_env2_delay},
- {11, AWE_FX_ENV2_ATTACK, fx_env2_attack},
- {12, AWE_FX_ENV2_HOLD, fx_env2_hold},
- {13, AWE_FX_ENV2_DECAY, fx_env2_decay},
- {14, AWE_FX_ENV2_SUSTAIN, fx_env2_sustain},
- {15, AWE_FX_ENV2_RELEASE, fx_env2_release},
-
- {16, AWE_FX_INIT_PITCH, fx_init_pitch},
- {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch},
- {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch},
- {19, AWE_FX_ENV1_PITCH, fx_env1_pitch},
- {20, AWE_FX_LFO1_VOLUME, fx_lfo1_volume},
- {21, AWE_FX_CUTOFF, fx_cutoff},
- {22, AWE_FX_FILTERQ, fx_filterQ},
- {23, AWE_FX_LFO1_CUTOFF, fx_lfo1_cutoff},
- {24, AWE_FX_ENV1_CUTOFF, fx_env1_cutoff},
- {25, AWE_FX_CHORUS, fx_chorus},
- {26, AWE_FX_REVERB, fx_reverb},
-};
-
-static int num_awe_effects = numberof(awe_effects);
-
-
-/*
- * GS(SC88) NRPN effects; still experimental
- */
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short gs_cutoff(int val)
-{
- return (val - 64) * gs_sense[FX_CUTOFF] / 50;
-}
-
-/* resonance: 0 to 15(max) */
-static unsigned short gs_filterQ(int val)
-{
- return (val - 64) * gs_sense[FX_RESONANCE] / 50;
-}
-
-/* attack: */
-static unsigned short gs_attack(int val)
-{
- return -(val - 64) * gs_sense[FX_ATTACK] / 50;
-}
-
-/* decay: */
-static unsigned short gs_decay(int val)
-{
- return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* release: */
-static unsigned short gs_release(int val)
-{
- return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* vibrato freq: 0.042Hz step, max=255 */
-static unsigned short gs_vib_rate(int val)
-{
- return (val - 64) * gs_sense[FX_VIBRATE] / 50;
-}
-
-/* vibrato depth: max=127, 1 octave */
-static unsigned short gs_vib_depth(int val)
-{
- return (val - 64) * gs_sense[FX_VIBDEPTH] / 50;
-}
-
-/* vibrato delay: -0.725msec step */
-static unsigned short gs_vib_delay(int val)
-{
- return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
-}
-
-static ConvTable gs_effects[] =
-{
- {32, AWE_FX_CUTOFF, gs_cutoff},
- {33, AWE_FX_FILTERQ, gs_filterQ},
- {99, AWE_FX_ENV2_ATTACK, gs_attack},
- {100, AWE_FX_ENV2_DECAY, gs_decay},
- {102, AWE_FX_ENV2_RELEASE, gs_release},
- {8, AWE_FX_LFO1_FREQ, gs_vib_rate},
- {9, AWE_FX_LFO1_VOLUME, gs_vib_depth},
- {10, AWE_FX_LFO1_DELAY, gs_vib_delay},
-};
-
-static int num_gs_effects = numberof(gs_effects);
-
-
-/*
- * NRPN events: accept as AWE32/SC88 specific controls
- */
-
-static void midi_nrpn_event(MidiStatus *st)
-{
- if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) {
- if (! msb_bit) /* both MSB/LSB necessary */
- send_converted_effect(awe_effects, num_awe_effects,
- st, rpn_lsb[st->chan],
- rpn_val[st->chan] - 8192);
- } else if (rpn_msb[st->chan] == 1) {
- if (msb_bit) /* only MSB is valid */
- add_converted_effect(gs_effects, num_gs_effects,
- st, rpn_lsb[st->chan],
- rpn_val[st->chan] / 128);
- }
-}
-
-
-/*
- * XG control effects; still experimental
- */
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short xg_cutoff(int val)
-{
- return (val - 64) * xg_sense[FX_CUTOFF] / 64;
-}
-
-/* resonance: 0(open) to 15(most nasal) */
-static unsigned short xg_filterQ(int val)
-{
- return (val - 64) * xg_sense[FX_RESONANCE] / 64;
-}
-
-/* attack: */
-static unsigned short xg_attack(int val)
-{
- return -(val - 64) * xg_sense[FX_ATTACK] / 64;
-}
-
-/* release: */
-static unsigned short xg_release(int val)
-{
- return -(val - 64) * xg_sense[FX_RELEASE] / 64;
-}
-
-static ConvTable xg_effects[] =
-{
- {71, AWE_FX_CUTOFF, xg_cutoff},
- {74, AWE_FX_FILTERQ, xg_filterQ},
- {72, AWE_FX_ENV2_RELEASE, xg_release},
- {73, AWE_FX_ENV2_ATTACK, xg_attack},
-};
-
-static int num_xg_effects = numberof(xg_effects);
-
-static int xg_control_change(MidiStatus *st, int cmd, int val)
-{
- return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val);
-}
-
-#endif /* CONFIG_AWE32_MIDIEMU */
-
-
-/*----------------------------------------------------------------*/
-
-
-/*
- * initialization of AWE driver
- */
-
-static void
-awe_initialize(void)
-{
- DEBUG(0,printk("AWE32: initializing..\n"));
-
- /* initialize hardware configuration */
- awe_poke(AWE_HWCF1, 0x0059);
- awe_poke(AWE_HWCF2, 0x0020);
-
- /* disable audio; this seems to reduce a clicking noise a bit.. */
- awe_poke(AWE_HWCF3, 0);
-
- /* initialize audio channels */
- awe_init_audio();
-
- /* initialize DMA */
- awe_init_dma();
-
- /* initialize init array */
- awe_init_array();
-
- /* check DRAM memory size */
- awe_check_dram();
-
- /* initialize the FM section of the AWE32 */
- awe_init_fm();
-
- /* set up voice envelopes */
- awe_tweak();
-
- /* enable audio */
- awe_poke(AWE_HWCF3, 0x0004);
-
- /* set default values */
- awe_init_ctrl_parms(TRUE);
-
- /* set equalizer */
- awe_update_equalizer();
-
- /* set reverb & chorus modes */
- awe_update_reverb_mode();
- awe_update_chorus_mode();
-}
-
-
-/*
- * Core Device Management Functions
- */
-
-/* store values to i/o port array */
-static void setup_ports(int port1, int port2, int port3)
-{
- awe_ports[0] = port1;
- if (port2 == 0)
- port2 = port1 + 0x400;
- awe_ports[1] = port2;
- awe_ports[2] = port2 + 2;
- if (port3 == 0)
- port3 = port1 + 0x800;
- awe_ports[3] = port3;
- awe_ports[4] = port3 + 2;
-
- port_setuped = TRUE;
-}
-
-/*
- * port request
- * 0x620-623, 0xA20-A23, 0xE20-E23
- */
-
-static int
-awe_request_region(void)
-{
- if (! port_setuped)
- return 0;
- if (! request_region(awe_ports[0], 4, "sound driver (AWE32)"))
- return 0;
- if (! request_region(awe_ports[1], 4, "sound driver (AWE32)"))
- goto err_out;
- if (! request_region(awe_ports[3], 4, "sound driver (AWE32)"))
- goto err_out1;
- return 1;
-err_out1:
- release_region(awe_ports[1], 4);
-err_out:
- release_region(awe_ports[0], 4);
- return 0;
-}
-
-static void
-awe_release_region(void)
-{
- if (! port_setuped) return;
- release_region(awe_ports[0], 4);
- release_region(awe_ports[1], 4);
- release_region(awe_ports[3], 4);
-}
-
-static int awe_attach_device(void)
-{
- if (awe_present) return 0; /* for OSS38.. called twice? */
-
- /* reserve I/O ports for awedrv */
- if (! awe_request_region()) {
- printk(KERN_ERR "AWE32: I/O area already used.\n");
- return 0;
- }
-
- /* set buffers to NULL */
- sfhead = sftail = NULL;
-
- my_dev = sound_alloc_synthdev();
- if (my_dev == -1) {
- printk(KERN_ERR "AWE32 Error: too many synthesizers\n");
- awe_release_region();
- return 0;
- }
-
- voice_alloc = &awe_operations.alloc;
- voice_alloc->max_voice = awe_max_voices;
- synth_devs[my_dev] = &awe_operations;
-
-#ifdef CONFIG_AWE32_MIXER
- attach_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
- attach_midiemu();
-#endif
-
- /* clear all samples */
- awe_reset_samples();
-
- /* initialize AWE32 hardware */
- awe_initialize();
-
- sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
- AWEDRV_VERSION, memsize/1024);
- printk(KERN_INFO "<SoundBlaster EMU8000 (RAM%dk)>\n", memsize/1024);
-
- awe_present = TRUE;
-
- return 1;
-}
-
-static void awe_dettach_device(void)
-{
- if (awe_present) {
- awe_reset_samples();
- awe_release_region();
- free_tables();
-#ifdef CONFIG_AWE32_MIXER
- unload_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
- unload_midiemu();
-#endif
- sound_unload_synthdev(my_dev);
- awe_present = FALSE;
- }
-}
-
-
-/*
- * Legacy device Probing
- */
-
-/* detect emu8000 chip on the specified address; from VV's guide */
-
-static int __init
-awe_detect_base(int addr)
-{
- setup_ports(addr, 0, 0);
- if ((awe_peek(AWE_U1) & 0x000F) != 0x000C)
- return 0;
- if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058)
- return 0;
- if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003)
- return 0;
- DEBUG(0,printk("AWE32 found at %x\n", addr));
- return 1;
-}
-
-static int __init awe_detect_legacy_devices(void)
-{
- int base;
- for (base = 0x620; base <= 0x680; base += 0x20)
- if (awe_detect_base(base)) {
- awe_attach_device();
- return 1;
- }
- DEBUG(0,printk("AWE32 Legacy detection failed\n"));
- return 0;
-}
-
-
-/*
- * PnP device Probing
- */
-
-static struct pnp_device_id awe_pnp_ids[] = {
- {.id = "CTL0021", .driver_data = 0}, /* AWE32 WaveTable */
- {.id = "CTL0022", .driver_data = 0}, /* AWE64 WaveTable */
- {.id = "CTL0023", .driver_data = 0}, /* AWE64 Gold WaveTable */
- { } /* terminator */
-};
-
-MODULE_DEVICE_TABLE(pnp, awe_pnp_ids);
-
-static int awe_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
- int io1, io2, io3;
-
- if (awe_present) {
- printk(KERN_ERR "AWE32: This driver only supports one AWE32 device, skipping.\n");
- }
-
- if (!pnp_port_valid(dev,0) ||
- !pnp_port_valid(dev,1) ||
- !pnp_port_valid(dev,2)) {
- printk(KERN_ERR "AWE32: The PnP device does not have the required resources.\n");
- return -EINVAL;
- }
- io1 = pnp_port_start(dev,0);
- io2 = pnp_port_start(dev,1);
- io3 = pnp_port_start(dev,2);
- printk(KERN_INFO "AWE32: A PnP Wave Table was detected at IO's %#x,%#x,%#x.\n",
- io1, io2, io3);
- setup_ports(io1, io2, io3);
-
- awe_attach_device();
- return 0;
-}
-
-static void awe_pnp_remove(struct pnp_dev *dev)
-{
- awe_dettach_device();
-}
-
-static struct pnp_driver awe_pnp_driver = {
- .name = "AWE32",
- .id_table = awe_pnp_ids,
- .probe = awe_pnp_probe,
- .remove = awe_pnp_remove,
-};
-
-static int __init awe_detect_pnp_devices(void)
-{
- int ret;
-
- ret = pnp_register_driver(&awe_pnp_driver);
- if (ret<0)
- printk(KERN_ERR "AWE32: PnP support is unavailable.\n");
- return ret;
-}
-
-
-/*
- * device / lowlevel (module) interface
- */
-
-static int __init
-awe_detect(void)
-{
- printk(KERN_INFO "AWE32: Probing for WaveTable...\n");
- if (isapnp) {
- if (awe_detect_pnp_devices()>=0)
- return 1;
- } else
- printk(KERN_INFO "AWE32: Skipping PnP detection.\n");
-
- if (awe_detect_legacy_devices())
- return 1;
-
- return 0;
-}
-
-static int __init attach_awe(void)
-{
- return awe_detect() ? 0 : -ENODEV;
-}
-
-static void __exit unload_awe(void)
-{
- pnp_unregister_driver(&awe_pnp_driver);
- awe_dettach_device();
-}
-
-
-module_init(attach_awe);
-module_exit(unload_awe);
-
-#ifndef MODULE
-static int __init setup_awe(char *str)
-{
- /* io, memsize, isapnp */
- int ints[4];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- memsize = ints[2];
- isapnp = ints[3];
-
- return 1;
-}
-
-__setup("awe=", setup_awe);
-#endif
diff --git a/sound/oss/awe_wave.h b/sound/oss/awe_wave.h
deleted file mode 100644
index fe58481..0000000
--- a/sound/oss/awe_wave.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * sound/oss/awe_wave.h
- *
- * Configuration of AWE32/SB32/AWE64 wave table synth driver.
- * version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * 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.
- */
-
-/*
- * chorus & reverb effects send for FM chip: from 0 to 0xff
- * larger numbers often cause weird sounds.
- */
-
-#define DEF_FM_CHORUS_DEPTH 0x10
-#define DEF_FM_REVERB_DEPTH 0x10
-
-
-/*
- * other compile conditions
- */
-
-/* initialize FM passthrough even without extended RAM */
-#undef AWE_ALWAYS_INIT_FM
-
-/* debug on */
-#define AWE_DEBUG_ON
-
-/* GUS compatible mode */
-#define AWE_HAS_GUS_COMPATIBILITY
-
-/* add MIDI emulation by wavetable */
-#define CONFIG_AWE32_MIDIEMU
-
-/* add mixer control of emu8000 equalizer */
-#undef CONFIG_AWE32_MIXER
-
-/* use new volume calculation method as default */
-#define AWE_USE_NEW_VOLUME_CALC
-
-/* check current volume target for searching empty voices */
-#define AWE_CHECK_VTARGET
-
-/* allow sample sharing */
-#define AWE_ALLOW_SAMPLE_SHARING
-
-/*
- * AWE32 card configuration:
- * uncomment the following lines *ONLY* when auto detection doesn't
- * work properly on your machine.
- */
-
-/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */
-/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */
-
-/*
- * AWE driver version number
- */
-#define AWE_MAJOR_VERSION 0
-#define AWE_MINOR_VERSION 4
-#define AWE_TINY_VERSION 4
-#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
-#define AWEDRV_VERSION "0.4.4"
diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
deleted file mode 100644
index ea51aaf..0000000
--- a/sound/oss/cmpci.c
+++ /dev/null
@@ -1,3381 +0,0 @@
-/*
- * cmpci.c -- C-Media PCI audio driver.
- *
- * Copyright (C) 1999 C-media support (support@cmedia.com.tw)
- *
- * Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * For update, visit:
- * http://www.cmedia.com.tw
- *
- * 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 David C. Niemi, Jan Pfeifer
- *
- *
- * Module command line parameters:
- * none so far
- *
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * The card has both an FM and a Wavetable synth, but I have to figure
- * out first how to drive them...
- *
- * Revision history
- * 06.05.98 0.1 Initial release
- * 10.05.98 0.2 Fixed many bugs, esp. ADC rate calculation
- * First stab at a simple midi interface (no bells&whistles)
- * 13.05.98 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
- * set_dac_rate in the FMODE_WRITE case in cm_open
- * Fix hwptr out of bounds (now mpg123 works)
- * 14.05.98 0.4 Don't allow excessive interrupt rates
- * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice
- * 03.08.98 0.6 Do not include modversions.h
- * Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * 31.08.98 0.7 Fix realplayer problems - dac.count issues
- * 10.12.98 0.8 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs
- * 06.01.99 0.10 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 18.08.99 1.5 Only deallocate DMA buffer when unloading.
- * 02.09.99 1.6 Enable SPDIF LOOP
- * Change the mixer read back
- * 21.09.99 2.33 Use RCS version as driver version.
- * Add support for modem, S/PDIF loop and 4 channels.
- * (8738 only)
- * Fix bug cause x11amp cannot play.
- *
- * Fixes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- * 18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
- * was calling prog_dmabuf with s->lock held, call missing
- * unlock_kernel in cm_midi_release
- * 08/10/2001 - use set_current_state in some more places
- *
- * Carlos Eduardo Gorges <carlos@techlinux.com.br>
- * Fri May 25 2001
- * - SMP support ( spin[un]lock* revision )
- * - speaker mixer support
- * Mon Aug 13 2001
- * - optimizations and cleanups
- *
- * 03/01/2003 - open_mode fixes from Georg Acher <acher@in.tum.de>
- * Simon Braunschmidt <brasimon@web.de>
- * Sat Jan 31 2004
- * - provide support for opl3 FM by releasing IO range after initialization
- *
- * ChenLi Tien <cltien@cmedia.com.tw>
- * Mar 9 2004
- * - Fix S/PDIF out if spdif_loop enabled
- * - Load opl3 driver if enabled (fmio in proper range)
- * - Load mpu401 if enabled (mpuio in proper range)
- * Apr 5 2004
- * - Fix DUAL_DAC dma synchronization bug
- * - Check exist FM/MPU401 I/O before activate.
- * - Add AFTM_S16_BE format support, so MPlayer/Xine can play AC3/mutlichannel
- * on Mac
- * - Change to support kernel 2.6 so only small patch needed
- * - All parameters default to 0
- * - Add spdif_out to send PCM through S/PDIF out jack
- * - Add hw_copy to get 4-spaker output for general PCM/analog output
- *
- * Stefan Thater <stefan.thaeter@gmx.de>
- * Apr 5 2004
- * - Fix mute single channel for CD/Line-in/AUX-in
- */
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/interrupt.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/smp_lock.h>
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-#include "sound_config.h"
-#include "mpu401.h"
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
-#include "opl3.h"
-#endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-#include <linux/gameport.h>
-#include <linux/mutex.h>
-
-#endif
-
-/* --------------------------------------------------------------------- */
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#undef DMABYTEIO
-#define DBG(x) {}
-/* --------------------------------------------------------------------- */
-
-#define CM_MAGIC ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)
-
-/* CM8338 registers definition ****************/
-
-#define CODEC_CMI_FUNCTRL0 (0x00)
-#define CODEC_CMI_FUNCTRL1 (0x04)
-#define CODEC_CMI_CHFORMAT (0x08)
-#define CODEC_CMI_INT_HLDCLR (0x0C)
-#define CODEC_CMI_INT_STATUS (0x10)
-#define CODEC_CMI_LEGACY_CTRL (0x14)
-#define CODEC_CMI_MISC_CTRL (0x18)
-#define CODEC_CMI_TDMA_POS (0x1C)
-#define CODEC_CMI_MIXER (0x20)
-#define CODEC_SB16_DATA (0x22)
-#define CODEC_SB16_ADDR (0x23)
-#define CODEC_CMI_MIXER1 (0x24)
-#define CODEC_CMI_MIXER2 (0x25)
-#define CODEC_CMI_AUX_VOL (0x26)
-#define CODEC_CMI_MISC (0x27)
-#define CODEC_CMI_AC97 (0x28)
-
-#define CODEC_CMI_CH0_FRAME1 (0x80)
-#define CODEC_CMI_CH0_FRAME2 (0x84)
-#define CODEC_CMI_CH1_FRAME1 (0x88)
-#define CODEC_CMI_CH1_FRAME2 (0x8C)
-
-#define CODEC_CMI_SPDIF_CTRL (0x90)
-#define CODEC_CMI_MISC_CTRL2 (0x92)
-
-#define CODEC_CMI_EXT_REG (0xF0)
-
-/* Mixer registers for SB16 ******************/
-
-#define DSP_MIX_DATARESETIDX ((unsigned char)(0x00))
-
-#define DSP_MIX_MASTERVOLIDX_L ((unsigned char)(0x30))
-#define DSP_MIX_MASTERVOLIDX_R ((unsigned char)(0x31))
-#define DSP_MIX_VOICEVOLIDX_L ((unsigned char)(0x32))
-#define DSP_MIX_VOICEVOLIDX_R ((unsigned char)(0x33))
-#define DSP_MIX_FMVOLIDX_L ((unsigned char)(0x34))
-#define DSP_MIX_FMVOLIDX_R ((unsigned char)(0x35))
-#define DSP_MIX_CDVOLIDX_L ((unsigned char)(0x36))
-#define DSP_MIX_CDVOLIDX_R ((unsigned char)(0x37))
-#define DSP_MIX_LINEVOLIDX_L ((unsigned char)(0x38))
-#define DSP_MIX_LINEVOLIDX_R ((unsigned char)(0x39))
-
-#define DSP_MIX_MICVOLIDX ((unsigned char)(0x3A))
-#define DSP_MIX_SPKRVOLIDX ((unsigned char)(0x3B))
-
-#define DSP_MIX_OUTMIXIDX ((unsigned char)(0x3C))
-
-#define DSP_MIX_ADCMIXIDX_L ((unsigned char)(0x3D))
-#define DSP_MIX_ADCMIXIDX_R ((unsigned char)(0x3E))
-
-#define DSP_MIX_INGAINIDX_L ((unsigned char)(0x3F))
-#define DSP_MIX_INGAINIDX_R ((unsigned char)(0x40))
-#define DSP_MIX_OUTGAINIDX_L ((unsigned char)(0x41))
-#define DSP_MIX_OUTGAINIDX_R ((unsigned char)(0x42))
-
-#define DSP_MIX_AGCIDX ((unsigned char)(0x43))
-
-#define DSP_MIX_TREBLEIDX_L ((unsigned char)(0x44))
-#define DSP_MIX_TREBLEIDX_R ((unsigned char)(0x45))
-#define DSP_MIX_BASSIDX_L ((unsigned char)(0x46))
-#define DSP_MIX_BASSIDX_R ((unsigned char)(0x47))
-#define DSP_MIX_EXTENSION ((unsigned char)(0xf0))
-// pseudo register for AUX
-#define DSP_MIX_AUXVOL_L ((unsigned char)(0x50))
-#define DSP_MIX_AUXVOL_R ((unsigned char)(0x51))
-
-// I/O length
-#define CM_EXTENT_CODEC 0x100
-#define CM_EXTENT_MIDI 0x2
-#define CM_EXTENT_SYNTH 0x4
-#define CM_EXTENT_GAME 0x8
-
-// Function Control Register 0 (00h)
-#define CHADC0 0x01
-#define CHADC1 0x02
-#define PAUSE0 0x04
-#define PAUSE1 0x08
-
-// Function Control Register 0+2 (02h)
-#define CHEN0 0x01
-#define CHEN1 0x02
-#define RST_CH0 0x04
-#define RST_CH1 0x08
-
-// Function Control Register 1 (04h)
-#define JYSTK_EN 0x02
-#define UART_EN 0x04
-#define SPDO2DAC 0x40
-#define SPDFLOOP 0x80
-
-// Function Control Register 1+1 (05h)
-#define SPDF_0 0x01
-#define SPDF_1 0x02
-#define ASFC 0x1c
-#define DSFC 0xe0
-#define SPDIF2DAC (SPDF_1 << 8 | SPDO2DAC)
-
-// Channel Format Register (08h)
-#define CM_CFMT_STEREO 0x01
-#define CM_CFMT_16BIT 0x02
-#define CM_CFMT_MASK 0x03
-#define POLVALID 0x20
-#define INVSPDIFI 0x80
-
-// Channel Format Register+2 (0ah)
-#define SPD24SEL 0x20
-
-// Channel Format Register+3 (0bh)
-#define CHB3D 0x20
-#define CHB3D5C 0x80
-
-// Interrupt Hold/Clear Register+2 (0eh)
-#define CH0_INT_EN 0x01
-#define CH1_INT_EN 0x02
-
-// Interrupt Register (10h)
-#define CHINT0 0x01
-#define CHINT1 0x02
-#define CH0BUSY 0x04
-#define CH1BUSY 0x08
-
-// Legacy Control/Status Register+1 (15h)
-#define EXBASEN 0x10
-#define BASE2LIN 0x20
-#define CENTR2LIN 0x40
-#define CB2LIN (BASE2LIN | CENTR2LIN)
-#define CHB3D6C 0x80
-
-// Legacy Control/Status Register+2 (16h)
-#define DAC2SPDO 0x20
-#define SPDCOPYRHT 0x40
-#define ENSPDOUT 0x80
-
-// Legacy Control/Status Register+3 (17h)
-#define FMSEL 0x03
-#define VSBSEL 0x0c
-#define VMPU 0x60
-#define NXCHG 0x80
-
-// Miscellaneous Control Register (18h)
-#define REAR2LIN 0x20
-#define MUTECH1 0x40
-#define ENCENTER 0x80
-
-// Miscellaneous Control Register+1 (19h)
-#define SELSPDIFI2 0x01
-#define SPDF_AC97 0x80
-
-// Miscellaneous Control Register+2 (1ah)
-#define AC3_EN 0x04
-#define FM_EN 0x08
-#define SPD32SEL 0x20
-#define XCHGDAC 0x40
-#define ENDBDAC 0x80
-
-// Miscellaneous Control Register+3 (1bh)
-#define SPDIFI48K 0x01
-#define SPDO5V 0x02
-#define N4SPK3D 0x04
-#define RESET 0x40
-#define PWD 0x80
-#define SPDIF48K (SPDIFI48K << 24 | SPDF_AC97 << 8)
-
-// Mixer1 (24h)
-#define CDPLAY 0x01
-#define X3DEN 0x02
-#define REAR2FRONT 0x10
-#define SPK4 0x20
-#define WSMUTE 0x40
-#define FMMUTE 0x80
-
-// Miscellaneous Register (27h)
-#define SPDVALID 0x02
-#define CENTR2MIC 0x04
-
-// Miscellaneous Register2 (92h)
-#define SPD32KFMT 0x10
-
-#define CM_CFMT_DACSHIFT 2
-#define CM_CFMT_ADCSHIFT 0
-#define CM_FREQ_DACSHIFT 5
-#define CM_FREQ_ADCSHIFT 2
-#define RSTDAC RST_CH1
-#define RSTADC RST_CH0
-#define ENDAC CHEN1
-#define ENADC CHEN0
-#define PAUSEDAC PAUSE1
-#define PAUSEADC PAUSE0
-#define CODEC_CMI_ADC_FRAME1 CODEC_CMI_CH0_FRAME1
-#define CODEC_CMI_ADC_FRAME2 CODEC_CMI_CH0_FRAME2
-#define CODEC_CMI_DAC_FRAME1 CODEC_CMI_CH1_FRAME1
-#define CODEC_CMI_DAC_FRAME2 CODEC_CMI_CH1_FRAME2
-#define DACINT CHINT1
-#define ADCINT CHINT0
-#define DACBUSY CH1BUSY
-#define ADCBUSY CH0BUSY
-#define ENDACINT CH1_INT_EN
-#define ENADCINT CH0_INT_EN
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-#define SND_DEV_DSP16 5
-
-#define NR_DEVICE 3 /* maximum number of devices */
-
-#define set_dac1_rate set_adc_rate
-#define set_dac1_rate_unlocked set_adc_rate_unlocked
-#define stop_dac1 stop_adc
-#define stop_dac1_unlocked stop_adc_unlocked
-#define get_dmadac1 get_dmaadc
-
-static unsigned int devindex = 0;
-
-//*********************************************/
-
-struct cm_state {
- /* magic */
- unsigned int magic;
-
- /* list of cmedia devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- int dev_audio; /* soundcore stuff */
- int dev_mixer;
-
- unsigned int iosb, iobase, iosynth,
- iomidi, iogame, irq; /* hardware resources */
- unsigned short deviceid; /* pci_id */
-
- struct { /* mixer stuff */
- unsigned int modcnt;
- unsigned short vol[13];
- } mix;
-
- unsigned int rateadc, ratedac; /* wave stuff */
- unsigned char fmt, enable;
-
- 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;
-
- unsigned fragsize; /* redundant, but makes calculations easier */
- unsigned dmasize;
- unsigned fragsamples;
- unsigned dmasamples;
-
- unsigned mapped:1; /* OSS stuff */
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned enabled:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- int midi_devc;
- struct address_info mpu_data;
-#endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
- struct gameport *gameport;
-#endif
-
- int chip_version;
- int max_channels;
- int curr_channels;
- int capability; /* HW capability, various for chip versions */
-
- int status; /* HW or SW state */
-
- int spdif_counter; /* spdif frame counter */
-};
-
-/* flags used for capability */
-#define CAN_AC3_HW 0x00000001 /* 037 or later */
-#define CAN_AC3_SW 0x00000002 /* 033 or later */
-#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW)
-#define CAN_DUAL_DAC 0x00000004 /* 033 or later */
-#define CAN_MULTI_CH_HW 0x00000008 /* 039 or later */
-#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC)
-#define CAN_LINE_AS_REAR 0x00000010 /* 033 or later */
-#define CAN_LINE_AS_BASS 0x00000020 /* 039 or later */
-#define CAN_MIC_AS_BASS 0x00000040 /* 039 or later */
-
-/* flags used for status */
-#define DO_AC3_HW 0x00000001
-#define DO_AC3_SW 0x00000002
-#define DO_AC3 (DO_AC3_HW | DO_AC3_SW)
-#define DO_DUAL_DAC 0x00000004
-#define DO_MULTI_CH_HW 0x00000008
-#define DO_MULTI_CH (DO_MULTI_CH_HW | DO_DUAL_DAC)
-#define DO_LINE_AS_REAR 0x00000010 /* 033 or later */
-#define DO_LINE_AS_BASS 0x00000020 /* 039 or later */
-#define DO_MIC_AS_BASS 0x00000040 /* 039 or later */
-#define DO_SPDIF_OUT 0x00000100
-#define DO_SPDIF_IN 0x00000200
-#define DO_SPDIF_LOOP 0x00000400
-#define DO_BIGENDIAN_W 0x00001000 /* used in PowerPC */
-#define DO_BIGENDIAN_R 0x00002000 /* used in PowerPC */
-
-static LIST_HEAD(devs);
-
-static int mpuio;
-static int fmio;
-static int joystick;
-static int spdif_inverse;
-static int spdif_loop;
-static int spdif_out;
-static int use_line_as_rear;
-static int use_line_as_bass;
-static int use_mic_as_bass;
-static int mic_boost;
-static int hw_copy;
-module_param(mpuio, int, 0);
-module_param(fmio, int, 0);
-module_param(joystick, bool, 0);
-module_param(spdif_inverse, bool, 0);
-module_param(spdif_loop, bool, 0);
-module_param(spdif_out, bool, 0);
-module_param(use_line_as_rear, bool, 0);
-module_param(use_line_as_bass, bool, 0);
-module_param(use_mic_as_bass, bool, 0);
-module_param(mic_boost, bool, 0);
-module_param(hw_copy, bool, 0);
-MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
-MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
-MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
-MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
-MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");
-MODULE_PARM_DESC(spdif_out, "(1/0) Send PCM to S/PDIF-out (PCM volume will not function)");
-MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
-MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
-MODULE_PARM_DESC(use_mic_as_bass, "(1/0) Use mic-in jack as bass/center");
-MODULE_PARM_DESC(mic_boost, "(1/0) Enable microphone boost");
-MODULE_PARM_DESC(hw_copy, "Copy front channel to surround channel");
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned exp=16,l=5,r=0;
- static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000};
-
- /* num: 2, 4, 16, 256, 65536 */
- /* exp: 1, 2, 4, 8, 16 */
-
- while(l--) {
- if( x >= num[l] ) {
- if(num[l]>2) x >>= exp;
- r+=exp;
- }
- exp>>=1;
- }
-
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void maskb(unsigned int addr, unsigned int mask, unsigned int value)
-{
- outb((inb(addr) & mask) | value, addr);
-}
-
-static void maskw(unsigned int addr, unsigned int mask, unsigned int value)
-{
- outw((inw(addr) & mask) | value, addr);
-}
-
-static void maskl(unsigned int addr, unsigned int mask, unsigned int value)
-{
- outl((inl(addr) & mask) | value, addr);
-}
-
-static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
-{
- if (addr)
- outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC0, 0);
-}
-
-static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
-{
- outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC0);
-}
-
-static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
-{
- outl(addr, s->iobase + CODEC_CMI_DAC_FRAME1);
- outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2);
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, 0);
- if (s->status & DO_DUAL_DAC)
- set_dmadac1(s, 0, count);
-}
-
-static void set_countadc(struct cm_state *s, unsigned count)
-{
- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2 + 2);
-}
-
-static void set_countdac(struct cm_state *s, unsigned count)
-{
- outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2 + 2);
- if (s->status & DO_DUAL_DAC)
- set_countadc(s, count);
-}
-
-static unsigned get_dmadac(struct cm_state *s)
-{
- unsigned int curr_addr;
-
- curr_addr = inw(s->iobase + CODEC_CMI_DAC_FRAME2) + 1;
- curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
- curr_addr = s->dma_dac.dmasize - curr_addr;
-
- return curr_addr;
-}
-
-static unsigned get_dmaadc(struct cm_state *s)
-{
- unsigned int curr_addr;
-
- curr_addr = inw(s->iobase + CODEC_CMI_ADC_FRAME2) + 1;
- curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
- curr_addr = s->dma_adc.dmasize - curr_addr;
-
- return curr_addr;
-}
-
-static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
-{
- unsigned char regval, pseudo;
-
- // pseudo register
- if (idx == DSP_MIX_AUXVOL_L) {
- data >>= 4;
- data &= 0x0f;
- regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0x0f;
- outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
- return;
- }
- if (idx == DSP_MIX_AUXVOL_R) {
- data &= 0xf0;
- regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0xf0;
- outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
- return;
- }
- outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
- // pseudo bits
- if (idx == DSP_MIX_OUTMIXIDX) {
- pseudo = data & ~0x1f;
- pseudo >>= 1;
- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x30;
- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
- }
- if (idx == DSP_MIX_ADCMIXIDX_L) {
- pseudo = data & 0x80;
- pseudo >>= 1;
- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x40;
- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
- }
- if (idx == DSP_MIX_ADCMIXIDX_R) {
- pseudo = data & 0x80;
- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x80;
- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
- }
- outb(data, s->iobase + CODEC_SB16_DATA);
- udelay(10);
-}
-
-static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
-{
- unsigned char v, pseudo;
-
- // pseudo register
- if (idx == DSP_MIX_AUXVOL_L) {
- v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0x0f;
- v <<= 4;
- return v;
- }
- if (idx == DSP_MIX_AUXVOL_L) {
- v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0xf0;
- return v;
- }
- outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
- v = inb(s->iobase + CODEC_SB16_DATA);
- udelay(10);
- // pseudo bits
- if (idx == DSP_MIX_OUTMIXIDX) {
- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x30;
- pseudo <<= 1;
- v |= pseudo;
- }
- if (idx == DSP_MIX_ADCMIXIDX_L) {
- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x40;
- pseudo <<= 1;
- v |= pseudo;
- }
- if (idx == DSP_MIX_ADCMIXIDX_R) {
- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x80;
- v |= pseudo;
- }
- return v;
-}
-
-static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data)
-{
- if (mask && s->chip_version > 0) { /* 8338 cannot keep this */
- s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
- udelay(10);
- }
- s->fmt = (s->fmt & mask) | data;
- outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
- udelay(10);
-}
-
-static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_fmt_unlocked(s,mask,data);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data)
-{
- outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
- outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);
- udelay(10);
-}
-
-static struct {
- unsigned rate;
- unsigned lower;
- unsigned upper;
- unsigned char freq;
-} rate_lookup[] =
-{
- { 5512, (0 + 5512) / 2, (5512 + 8000) / 2, 0 },
- { 8000, (5512 + 8000) / 2, (8000 + 11025) / 2, 4 },
- { 11025, (8000 + 11025) / 2, (11025 + 16000) / 2, 1 },
- { 16000, (11025 + 16000) / 2, (16000 + 22050) / 2, 5 },
- { 22050, (16000 + 22050) / 2, (22050 + 32000) / 2, 2 },
- { 32000, (22050 + 32000) / 2, (32000 + 44100) / 2, 6 },
- { 44100, (32000 + 44100) / 2, (44100 + 48000) / 2, 3 },
- { 48000, (44100 + 48000) / 2, 48000, 7 }
-};
-
-static void set_spdif_copyright(struct cm_state *s, int spdif_copyright)
-{
- /* enable SPDIF-in Copyright */
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~SPDCOPYRHT, spdif_copyright ? SPDCOPYRHT : 0);
-}
-
-static void set_spdif_loop(struct cm_state *s, int spdif_loop)
-{
- /* enable SPDIF loop */
- if (spdif_loop) {
- s->status |= DO_SPDIF_LOOP;
- /* turn on spdif-in to spdif-out */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDFLOOP);
- } else {
- s->status &= ~DO_SPDIF_LOOP;
- /* turn off spdif-in to spdif-out */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDFLOOP, 0);
- }
-}
-
-static void set_spdif_monitor(struct cm_state *s, int channel)
-{
- // SPDO2DAC
- maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDO2DAC, channel == 2 ? SPDO2DAC : 0);
- // CDPLAY
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, channel ? CDPLAY : 0);
-}
-
-static void set_spdifout_level(struct cm_state *s, int level5v)
-{
- /* SPDO5V */
- if (s->chip_version > 0)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~SPDO5V, level5v ? SPDO5V : 0);
-}
-
-static void set_spdifin_inverse(struct cm_state *s, int spdif_inverse)
-{
- if (s->chip_version == 0) /* 8338 has not this feature */
- return;
- if (spdif_inverse) {
- /* turn on spdif-in inverse */
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_CHFORMAT, ~0, INVSPDIFI);
- else
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
- } else {
- /* turn off spdif-ininverse */
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_CHFORMAT, ~INVSPDIFI, 0);
- else
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
- }
-}
-
-static void set_spdifin_channel2(struct cm_state *s, int channel2)
-{
- /* SELSPDIFI2 */
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 1, ~SELSPDIFI2, channel2 ? SELSPDIFI2 : 0);
-}
-
-static void set_spdifin_valid(struct cm_state *s, int valid)
-{
- /* SPDVALID */
- maskb(s->iobase + CODEC_CMI_MISC, ~SPDVALID, valid ? SPDVALID : 0);
-}
-
-static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
-{
- if (rate != 48000 && rate != 44100)
- rate = 0;
- if (rate == 48000 || rate == 44100) {
- set_spdif_loop(s, 0);
- // SPDF_1
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
- // SPDIFI48K SPDF_AC97
- maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
- if (s->chip_version >= 55)
- // SPD32KFMT
- maskb(s->iobase + CODEC_CMI_MISC_CTRL2, ~SPD32KFMT, rate == 48000 ? SPD32KFMT : 0);
- if (s->chip_version > 0)
- // ENSPDOUT
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, ENSPDOUT);
- // monitor SPDIF out
- set_spdif_monitor(s, 2);
- s->status |= DO_SPDIF_OUT;
- } else {
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~ENSPDOUT, 0);
- // monitor none
- set_spdif_monitor(s, 0);
- s->status &= ~DO_SPDIF_OUT;
- }
-}
-
-static void set_spdifout(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_spdifout_unlocked(s,rate);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void set_spdifin_unlocked(struct cm_state *s, unsigned rate)
-{
- if (rate == 48000 || rate == 44100) {
- // SPDF_1
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
- // SPDIFI48K SPDF_AC97
- maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
- s->status |= DO_SPDIF_IN;
- } else {
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
- s->status &= ~DO_SPDIF_IN;
- }
-}
-
-static void set_spdifin(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_spdifin_unlocked(s,rate);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* find parity for bit 4~30 */
-static unsigned parity(unsigned data)
-{
- unsigned parity = 0;
- int counter = 4;
-
- data >>= 4; // start from bit 4
- while (counter <= 30) {
- if (data & 1)
- parity++;
- data >>= 1;
- counter++;
- }
- return parity & 1;
-}
-
-static void set_ac3_unlocked(struct cm_state *s, unsigned rate)
-{
- if (!(s->capability & CAN_AC3))
- return;
- /* enable AC3 */
- if (rate && rate != 44100)
- rate = 48000;
- if (rate == 48000 || rate == 44100) {
- // mute DAC
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, WSMUTE);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0, MUTECH1);
- // AC3EN for 039, 0x04
- if (s->chip_version >= 39) {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, AC3_EN);
- if (s->chip_version == 55)
- maskb(s->iobase + CODEC_CMI_SPDIF_CTRL, ~2, 0);
- // AC3EN for 037, 0x10
- } else if (s->chip_version == 37)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
- if (s->capability & CAN_AC3_HW) {
- // SPD24SEL for 039, 0x20, but cannot be set
- if (s->chip_version == 39)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, SPD24SEL);
- // SPD24SEL for 037, 0x02
- else if (s->chip_version == 37)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, 0);
-
- s->status |= DO_AC3_HW;
- } else {
- // SPD32SEL for 037 & 039
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, SPD32SEL);
- // set 176K sample rate to fix 033 HW bug
- if (s->chip_version == 33) {
- if (rate == 48000)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);
- else
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
- }
- s->status |= DO_AC3_SW;
- }
- } else {
- maskb(s->iobase + CODEC_CMI_MIXER1, ~WSMUTE, 0);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~MUTECH1, 0);
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~(SPD24SEL|0x12), 0);
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~(SPD32SEL|AC3_EN), 0);
- if (s->chip_version == 33)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, CDPLAY);
- s->status &= ~DO_AC3;
- }
- s->spdif_counter = 0;
-}
-
-static void set_line_as_rear(struct cm_state *s, int use_line_as_rear)
-{
- if (!(s->capability & CAN_LINE_AS_REAR))
- return;
- if (use_line_as_rear) {
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, SPK4);
- s->status |= DO_LINE_AS_REAR;
- } else {
- maskb(s->iobase + CODEC_CMI_MIXER1, ~SPK4, 0);
- s->status &= ~DO_LINE_AS_REAR;
- }
-}
-
-static void set_line_as_bass(struct cm_state *s, int use_line_as_bass)
-{
- if (!(s->capability & CAN_LINE_AS_BASS))
- return;
- if (use_line_as_bass) {
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, CB2LIN);
- s->status |= DO_LINE_AS_BASS;
- } else {
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CB2LIN, 0);
- s->status &= ~DO_LINE_AS_BASS;
- }
-}
-
-static void set_mic_as_bass(struct cm_state *s, int use_mic_as_bass)
-{
- if (!(s->capability & CAN_MIC_AS_BASS))
- return;
- if (use_mic_as_bass) {
- maskb(s->iobase + CODEC_CMI_MISC, ~0, 0x04);
- s->status |= DO_MIC_AS_BASS;
- } else {
- maskb(s->iobase + CODEC_CMI_MISC, ~0x04, 0);
- s->status &= ~DO_MIC_AS_BASS;
- }
-}
-
-static void set_hw_copy(struct cm_state *s, int hw_copy)
-{
- if (s->max_channels > 2 && hw_copy)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, N4SPK3D);
- else
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~N4SPK3D, 0);
-}
-
-static void set_ac3(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_spdifout_unlocked(s, rate);
- set_ac3_unlocked(s, rate);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int trans_ac3(struct cm_state *s, void *dest, const char __user *source, int size)
-{
- int i = size / 2;
- unsigned long data;
- unsigned short data16;
- unsigned long *dst = (unsigned long *) dest;
- unsigned short __user *src = (unsigned short __user *)source;
- int err;
-
- do {
- if ((err = __get_user(data16, src++)))
- return err;
- data = (unsigned long)le16_to_cpu(data16);
- data <<= 12; // ok for 16-bit data
- if (s->spdif_counter == 2 || s->spdif_counter == 3)
- data |= 0x40000000; // indicate AC-3 raw data
- if (parity(data))
- data |= 0x80000000; // parity
- if (s->spdif_counter == 0)
- data |= 3; // preamble 'M'
- else if (s->spdif_counter & 1)
- data |= 5; // odd, 'W'
- else
- data |= 9; // even, 'M'
- *dst++ = cpu_to_le32(data);
- s->spdif_counter++;
- if (s->spdif_counter == 384)
- s->spdif_counter = 0;
- } while (--i);
-
- return 0;
-}
-
-static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate)
-{
- unsigned char freq = 4;
- int i;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
- rate = rate_lookup[i].rate;
- freq = rate_lookup[i].freq;
- break;
- }
- }
- s->rateadc = rate;
- freq <<= CM_FREQ_ADCSHIFT;
-
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
-}
-
-static void set_adc_rate(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned char freq = 4;
- int i;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
- rate = rate_lookup[i].rate;
- freq = rate_lookup[i].freq;
- break;
- }
- }
- s->rateadc = rate;
- freq <<= CM_FREQ_ADCSHIFT;
-
- spin_lock_irqsave(&s->lock, flags);
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void set_dac_rate(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned char freq = 4;
- int i;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
- rate = rate_lookup[i].rate;
- freq = rate_lookup[i].freq;
- break;
- }
- }
- s->ratedac = rate;
- freq <<= CM_FREQ_DACSHIFT;
-
- spin_lock_irqsave(&s->lock, flags);
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~DSFC, freq);
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (s->curr_channels <= 2 && spdif_out)
- set_spdifout(s, rate);
- if (s->status & DO_DUAL_DAC)
- set_dac1_rate(s, rate);
-}
-
-/* --------------------------------------------------------------------- */
-static inline void reset_adc(struct cm_state *s)
-{
- /* reset bus master */
- outb(s->enable | RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- udelay(10);
- outb(s->enable & ~RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-}
-
-static inline void reset_dac(struct cm_state *s)
-{
- /* reset bus master */
- outb(s->enable | RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- udelay(10);
- outb(s->enable & ~RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- if (s->status & DO_DUAL_DAC)
- reset_adc(s);
-}
-
-static inline void pause_adc(struct cm_state *s)
-{
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEADC);
-}
-
-static inline void pause_dac(struct cm_state *s)
-{
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEDAC);
- if (s->status & DO_DUAL_DAC)
- pause_adc(s);
-}
-
-static inline void disable_adc(struct cm_state *s)
-{
- /* disable channel */
- s->enable &= ~ENADC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- reset_adc(s);
-}
-
-static inline void disable_dac(struct cm_state *s)
-{
- /* disable channel */
- s->enable &= ~ENDAC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- reset_dac(s);
- if (s->status & DO_DUAL_DAC)
- disable_adc(s);
-}
-
-static inline void enable_adc(struct cm_state *s)
-{
- if (!(s->enable & ENADC)) {
- /* enable channel */
- s->enable |= ENADC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- }
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEADC, 0);
-}
-
-static inline void enable_dac_unlocked(struct cm_state *s)
-{
- if (!(s->enable & ENDAC)) {
- /* enable channel */
- s->enable |= ENDAC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- }
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEDAC, 0);
-
- if (s->status & DO_DUAL_DAC)
- enable_adc(s);
-}
-
-static inline void stop_adc_unlocked(struct cm_state *s)
-{
- if (s->enable & ENADC) {
- /* disable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENADCINT, 0);
- disable_adc(s);
- }
-}
-
-static inline void stop_adc(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- stop_adc_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-
-}
-
-static inline void stop_dac_unlocked(struct cm_state *s)
-{
- if (s->enable & ENDAC) {
- /* disable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENDACINT, 0);
- disable_dac(s);
- }
- if (s->status & DO_DUAL_DAC)
- stop_dac1_unlocked(s);
-}
-
-static inline void stop_dac(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- stop_dac_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void start_adc_unlocked(struct cm_state *s)
-{
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- /* enable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
- enable_adc(s);
- }
-}
-
-static void start_adc(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- start_adc_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac1_unlocked(struct cm_state *s)
-{
- if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
- /* enable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
- enable_dac_unlocked(s);
- }
-}
-
-static void start_dac_unlocked(struct cm_state *s)
-{
- if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
- /* enable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENDACINT);
- enable_dac_unlocked(s);
- }
- if (s->status & DO_DUAL_DAC)
- start_dac1_unlocked(s);
-}
-
-static void start_dac(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- start_dac_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int prog_dmabuf(struct cm_state *s, unsigned rec);
-
-static int set_dac_channels(struct cm_state *s, int channels)
-{
- unsigned long flags;
- static unsigned int fmmute = 0;
-
- spin_lock_irqsave(&s->lock, flags);
-
- if ((channels > 2) && (channels <= s->max_channels)
- && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {
- set_spdifout_unlocked(s, 0);
- if (s->capability & CAN_MULTI_CH_HW) {
- // NXCHG
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, NXCHG);
- // CHB3D or CHB3D5C
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), channels > 4 ? CHB3D5C : CHB3D);
- // CHB3D6C
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, channels == 6 ? CHB3D6C : 0);
- // ENCENTER
- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~ENCENTER, channels == 6 ? ENCENTER : 0);
- s->status |= DO_MULTI_CH_HW;
- } else if (s->capability & CAN_DUAL_DAC) {
- unsigned char fmtm = ~0, fmts = 0;
- ssize_t ret;
-
- // ENDBDAC, turn on double DAC mode
- // XCHGDAC, CH0 -> back, CH1->front
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC);
- // mute FM
- fmmute = inb(s->iobase + CODEC_CMI_MIXER1) & FMMUTE;
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, FMMUTE);
- s->status |= DO_DUAL_DAC;
- // prepare secondary buffer
- spin_unlock_irqrestore(&s->lock, flags);
- ret = prog_dmabuf(s, 1);
- if (ret) return ret;
- spin_lock_irqsave(&s->lock, flags);
-
- // copy the hw state
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
- // the HW only support 16-bit stereo
- fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
- fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
- fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-
- set_fmt_unlocked(s, fmtm, fmts);
- set_adc_rate_unlocked(s, s->ratedac);
- }
- // disable 4 speaker mode (analog duplicate)
- set_hw_copy(s, 0);
- s->curr_channels = channels;
-
- // enable jack redirect
- set_line_as_rear(s, use_line_as_rear);
- if (channels > 4) {
- set_line_as_bass(s, use_line_as_bass);
- set_mic_as_bass(s, use_mic_as_bass);
- }
- } else {
- if (s->status & DO_MULTI_CH_HW) {
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0);
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), 0);
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0);
- } else if (s->status & DO_DUAL_DAC) {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0);
- maskb(s->iobase + CODEC_CMI_MIXER1, ~FMMUTE, fmmute);
- }
- // enable 4 speaker mode (analog duplicate)
- set_hw_copy(s, hw_copy);
- s->status &= ~DO_MULTI_CH;
- s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
- // disable jack redirect
- set_line_as_rear(s, hw_copy ? use_line_as_rear : 0);
- set_line_as_bass(s, 0);
- set_mic_as_bass(s, 0);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return s->curr_channels;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static void dealloc_dmabuf(struct cm_state *s, struct dmabuf *db)
-{
- struct page *pstart, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
- ClearPageReserved(pstart);
- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
- }
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-/* Ch1 is used for playback, Ch0 is used for recording */
-
-static int prog_dmabuf(struct cm_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- int order;
- unsigned bytepersec;
- unsigned bufs;
- struct page *pstart, *pend;
- unsigned char fmt;
- unsigned long flags;
-
- fmt = s->fmt;
- if (rec) {
- stop_adc(s);
- fmt >>= CM_CFMT_ADCSHIFT;
- } else {
- stop_dac(s);
- fmt >>= CM_CFMT_DACSHIFT;
- }
-
- fmt &= CM_CFMT_MASK;
- 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 || !db->dmaaddr)
- 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 (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
- SetPageReserved(pstart);
- }
- 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;
- /* to make fragsize >= 4096 */
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
- db->dmasamples = db->dmasize >> sample_shift[fmt];
- memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
- spin_lock_irqsave(&s->lock, flags);
- if (rec) {
- if (s->status & DO_DUAL_DAC)
- set_dmadac1(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
- else
- set_dmaadc(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
- /* program sample counts */
- set_countdac(s, db->fragsamples);
- } else {
- set_dmadac(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
- /* program sample counts */
- set_countdac(s, db->fragsamples);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- db->enabled = 1;
- db->ready = 1;
- return 0;
-}
-
-static inline void clear_advance(struct cm_state *s)
-{
- unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned char *buf1 = s->dma_adc.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- if (s->status & DO_DUAL_DAC)
- memset(buf1 + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
- if (s->status & DO_DUAL_DAC)
- memset(buf1 + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void cm_update_ptr(struct cm_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- if (s->status & DO_DUAL_DAC) {
- /* the dac part will finish for this */
- } else {
- hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- 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))) {
- pause_adc(s);
- s->dma_adc.error++;
- }
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = get_dmadac(s) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- }
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- wake_up(&s->dma_dac.wait);
- } else {
- s->dma_dac.count -= diff;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.count -= diff;
- if (s->dma_dac.count <= 0) {
- pause_dac(s);
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
- wake_up(&s->dma_dac.wait);
- }
- }
-}
-
-static irqreturn_t cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct cm_state *s = (struct cm_state *)dev_id;
- unsigned int intsrc, intstat;
- unsigned char mask = 0;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
- if (!(intsrc & 0x80000000))
- return IRQ_NONE;
- spin_lock(&s->lock);
- intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- /* acknowledge interrupt */
- if (intsrc & ADCINT)
- mask |= ENADCINT;
- if (intsrc & DACINT)
- mask |= ENDACINT;
- outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- cm_update_ptr(s);
- spin_unlock(&s->lock);
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- if (intsrc & 0x00010000) { // UART interrupt
- if (s->midi_devc && intchk_mpu401((void *)s->midi_devc))
- mpuintr(irq, (void *)s->midi_devc, regs);
- else
- inb(s->iomidi);// dummy read
- }
-#endif
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != CM_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-#define MT_4 1
-#define MT_5MUTE 2
-#define MT_4MUTEMONO 3
-#define MT_6MUTE 4
-#define MT_5MUTEMONO 5
-
-static const struct {
- unsigned left;
- unsigned right;
- unsigned type;
- unsigned rec;
- unsigned play;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_CD] = { DSP_MIX_CDVOLIDX_L, DSP_MIX_CDVOLIDX_R, MT_5MUTE, 0x04, 0x06 },
- [SOUND_MIXER_LINE] = { DSP_MIX_LINEVOLIDX_L, DSP_MIX_LINEVOLIDX_R, MT_5MUTE, 0x10, 0x18 },
- [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 },
- [SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 },
- [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
- [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
- [SOUND_MIXER_LINE1] = { DSP_MIX_AUXVOL_L, DSP_MIX_AUXVOL_R, MT_5MUTE, 0x80, 0x60 },
- [SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX, DSP_MIX_SPKRVOLIDX, MT_5MUTEMONO, 0x00, 0x01 }
-};
-
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
-{
- [SOUND_MIXER_CD] = 1,
- [SOUND_MIXER_LINE] = 2,
- [SOUND_MIXER_MIC] = 3,
- [SOUND_MIXER_SYNTH] = 4,
- [SOUND_MIXER_VOLUME] = 5,
- [SOUND_MIXER_PCM] = 6,
- [SOUND_MIXER_LINE1] = 7,
- [SOUND_MIXER_SPEAKER]= 8
-};
-
-static unsigned mixer_outmask(struct cm_state *s)
-{
- unsigned long flags;
- int i, j, k;
-
- spin_lock_irqsave(&s->lock, flags);
- j = rdmixer(s, DSP_MIX_OUTMIXIDX);
- spin_unlock_irqrestore(&s->lock, flags);
- for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (j & mixtable[i].play)
- k |= 1 << i;
- return k;
-}
-
-static unsigned mixer_recmask(struct cm_state *s)
-{
- unsigned long flags;
- int i, j, k;
-
- spin_lock_irqsave(&s->lock, flags);
- j = rdmixer(s, DSP_MIX_ADCMIXIDX_L);
- spin_unlock_irqrestore(&s->lock, flags);
- for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (j & mixtable[i].rec)
- k |= 1 << i;
- return k;
-}
-
-static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
-{
- unsigned long flags;
- int i, val, j;
- unsigned char l, r, rl, rr;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, "cmpci", sizeof(info.id));
- strlcpy(info.name, "C-Media PCI", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- 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, "cmpci", sizeof(info.id));
- strlcpy(info.name, "C-Media cmpci", sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- val = mixer_recmask(s);
- return put_user(val, p);
-
- case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
- val = mixer_outmask(s);
- return put_user(val, p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].rec)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_OUTMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].play)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(0, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
- if (!volidx[i])
- return -EINVAL;
- return put_user(s->mix.vol[volidx[i]-1], p);
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- i = hweight32(val);
- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (!mixtable[i].rec) {
- val &= ~(1 << i);
- continue;
- }
- j |= mixtable[i].rec;
- }
- spin_lock_irqsave(&s->lock, flags);
- wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);
- wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1) | (j & 0x80));
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (!mixtable[i].play) {
- val &= ~(1 << i);
- continue;
- }
- j |= mixtable[i].play;
- }
- spin_lock_irqsave(&s->lock, flags);
- wrmixer(s, DSP_MIX_OUTMIXIDX, j);
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- r = (val >> 8) & 0xff;
- if (l > 100)
- l = 100;
- if (r > 100)
- r = 100;
- spin_lock_irqsave(&s->lock, flags);
- switch (mixtable[i].type) {
- case MT_4:
- if (l >= 10)
- l -= 10;
- if (r >= 10)
- r -= 10;
- frobindir(s, mixtable[i].left, 0xf0, l / 6);
- frobindir(s, mixtable[i].right, 0xf0, l / 6);
- break;
-
- case MT_4MUTEMONO:
- rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
- rr = (rl >> 2) & 7;
- wrmixer(s, mixtable[i].left, rl<<3);
- if (i == SOUND_MIXER_MIC)
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
- break;
-
- case MT_5MUTEMONO:
- rl = l < 4 ? 0 : (l - 5) / 3;
- wrmixer(s, mixtable[i].left, rl<<3);
- l = rdmixer(s, DSP_MIX_OUTMIXIDX) & ~mixtable[i].play;
- r = rl ? mixtable[i].play : 0;
- wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
- /* for recording */
- if (i == SOUND_MIXER_MIC) {
- if (s->chip_version >= 37) {
- rr = rl >> 1;
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, (rr&0x07)<<1);
- frobindir(s, DSP_MIX_EXTENSION, ~0x01, rr>>3);
- } else {
- rr = rl >> 2;
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
- }
- }
- break;
-
- case MT_5MUTE:
- rl = l < 4 ? 0 : (l - 5) / 3;
- rr = r < 4 ? 0 : (r - 5) / 3;
- wrmixer(s, mixtable[i].left, rl<<3);
- wrmixer(s, mixtable[i].right, rr<<3);
- l = rdmixer(s, DSP_MIX_OUTMIXIDX);
- l &= ~mixtable[i].play;
- r = (rl|rr) ? mixtable[i].play : 0;
- wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
- break;
-
- case MT_6MUTE:
- if (l < 6)
- rl = 0x00;
- else
- rl = l * 2 / 3;
- if (r < 6)
- rr = 0x00;
- else
- rr = r * 2 / 3;
- wrmixer(s, mixtable[i].left, rl);
- wrmixer(s, mixtable[i].right, rr);
- break;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (!volidx[i])
- return -EINVAL;
- s->mix.vol[volidx[i]-1] = val;
- return put_user(s->mix.vol[volidx[i]-1], p);
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int cm_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- struct cm_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct cm_state, devs);
- if (s->dev_mixer == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int cm_release_mixdev(struct inode *inode, struct file *file)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int cm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct cm_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations cm_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = cm_ioctl_mixdev,
- .open = cm_open_mixdev,
- .release = cm_release_mixdev,
-};
-
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct cm_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "cmpci: dma timed out??\n");)
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- 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;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- spin_lock_irqsave(&s->lock, flags);
- stop_adc_unlocked(s);
- set_dmaadc(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
- /* program sample counts */
- set_countadc(s, s->dma_adc.fragsamples);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- continue;
- }
- if (s->status & DO_BIGENDIAN_R) {
- int i, err;
- unsigned char *src;
- char __user *dst = buffer;
- unsigned char data[2];
-
- src = (unsigned char *) (s->dma_adc.rawbuf + swptr);
- // copy left/right sample at one time
- for (i = 0; i < cnt / 2; i++) {
- data[0] = src[1];
- data[1] = src[0];
- if ((err = __put_user(data[0], dst++))) {
- ret = err;
- goto out;
- }
- if ((err = __put_user(data[1], dst++))) {
- ret = err;
- goto out;
- }
- src += 2;
- }
- } else 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;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_adc.enabled)
- start_adc_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
-out:
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t cm_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- if (s->status & DO_DUAL_DAC) {
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- }
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- add_wait_queue(&s->dma_dac.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.swptr = s->dma_dac.swptr;
- s->dma_adc.count = s->dma_dac.count;
- s->dma_adc.endcleared = s->dma_dac.endcleared;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize-swptr;
- if (s->status & DO_AC3_SW) {
- if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize)
- cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2;
- } else {
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
- }
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if ((s->status & DO_DUAL_DAC) && (cnt > count / 2))
- cnt = count / 2;
- if (cnt <= 0) {
- if (s->dma_dac.enabled)
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- spin_lock_irqsave(&s->lock, flags);
- stop_dac_unlocked(s);
- set_dmadac(s, s->dma_dac.dmaaddr, s->dma_dac.dmasamples);
- /* program sample counts */
- set_countdac(s, s->dma_dac.fragsamples);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- if (s->status & DO_DUAL_DAC) {
- set_dmadac1(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- continue;
- }
- if (s->status & DO_AC3_SW) {
- int err;
-
- // clip exceeded data, caught by 033 and 037
- if (swptr + 2 * cnt > s->dma_dac.dmasize)
- cnt = (s->dma_dac.dmasize - swptr) / 2;
- if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) {
- ret = err;
- goto out;
- }
- swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize;
- } else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) {
- int i, err;
- const char __user *src = buffer;
- unsigned char *dst0, *dst1;
- unsigned char data[8];
-
- dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr);
- dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr);
- // copy left/right sample at one time
- for (i = 0; i < cnt / 4; i++) {
- if ((err = __get_user(data[0], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[1], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[2], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[3], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[4], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[5], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[6], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[7], src++))) {
- ret = err;
- goto out;
- }
- dst0[0] = data[1];
- dst0[1] = data[0];
- dst0[2] = data[3];
- dst0[3] = data[2];
- dst1[0] = data[5];
- dst1[1] = data[4];
- dst1[2] = data[7];
- dst1[3] = data[6];
- dst0 += 4;
- dst1 += 4;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- } else if (s->status & DO_DUAL_DAC) {
- int i, err;
- unsigned long __user *src = (unsigned long __user *) buffer;
- unsigned long *dst0, *dst1;
-
- dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr);
- dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr);
- // copy left/right sample at one time
- for (i = 0; i < cnt / 4; i++) {
- if ((err = __get_user(*dst0++, src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(*dst1++, src++))) {
- ret = err;
- goto out;
- }
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- } else if (s->status & DO_BIGENDIAN_W) {
- int i, err;
- const char __user *src = buffer;
- unsigned char *dst;
- unsigned char data[2];
-
- dst = (unsigned char *) (s->dma_dac.rawbuf + swptr);
- // swap hi/lo bytes for each sample
- for (i = 0; i < cnt / 2; i++) {
- if ((err = __get_user(data[0], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[1], src++))) {
- ret = err;
- goto out;
- }
- dst[0] = data[1];
- dst[1] = data[0];
- dst += 2;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- } else {
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- }
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- if (s->status & DO_AC3_SW)
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->status & DO_DUAL_DAC) {
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
- if (s->dma_dac.enabled)
- start_dac(s);
- }
-out:
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf(s, 0))
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf(s, 1))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- cm_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_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int cm_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- goto out;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EINVAL;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-#define SNDCTL_SPDIF_COPYRIGHT _SIOW('S', 0, int) // set/reset S/PDIF copy protection
-#define SNDCTL_SPDIF_LOOP _SIOW('S', 1, int) // set/reset S/PDIF loop
-#define SNDCTL_SPDIF_MONITOR _SIOW('S', 2, int) // set S/PDIF monitor
-#define SNDCTL_SPDIF_LEVEL _SIOW('S', 3, int) // set/reset S/PDIF out level
-#define SNDCTL_SPDIF_INV _SIOW('S', 4, int) // set/reset S/PDIF in inverse
-#define SNDCTL_SPDIF_SEL2 _SIOW('S', 5, int) // set S/PDIF in #2
-#define SNDCTL_SPDIF_VALID _SIOW('S', 6, int) // set S/PDIF valid
-#define SNDCTL_SPDIFOUT _SIOW('S', 7, int) // set S/PDIF out
-#define SNDCTL_SPDIFIN _SIOW('S', 8, int) // set S/PDIF out
-
-static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.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_dac(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 | DSP_CAP_BIND, p);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.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) {
- spin_lock_irqsave(&s->lock, flags);
- stop_adc_unlocked(s);
- s->dma_adc.ready = 0;
- set_adc_rate_unlocked(s, val);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.ready = 0;
- set_dac_rate(s, val);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- }
- set_fmt(s, fmtm, fmtd);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- }
- set_fmt(s, fmtm, fmtd);
- if ((s->capability & CAN_MULTI_CH)
- && (file->f_mode & FMODE_WRITE)) {
- val = set_dac_channels(s, val);
- return put_user(val, p);
- }
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT)
- : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8|
- ((s->capability & CAN_AC3) ? AFMT_AC3 : 0), p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_BE || val == AFMT_S16_LE)
- fmtd |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_ADCSHIFT);
- if (val == AFMT_S16_BE)
- s->status |= DO_BIGENDIAN_R;
- else
- s->status &= ~DO_BIGENDIAN_R;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_BE || val == AFMT_S16_LE || val == AFMT_AC3)
- fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
- else
- fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
- if (val == AFMT_AC3) {
- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- set_ac3(s, 48000);
- } else
- set_ac3(s, 0);
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_BE || val == AFMT_S16_LE)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- if (val == AFMT_S16_BE)
- s->status |= DO_BIGENDIAN_W;
- else
- s->status &= ~DO_BIGENDIAN_W;
- }
- set_fmt(s, fmtm, fmtd);
- }
- if (s->status & DO_AC3) return put_user(AFMT_AC3, p);
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
- : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (s->status & DO_DUAL_DAC) {
- if (file->f_mode & FMODE_WRITE &&
- (s->enable & ENDAC) &&
- (s->enable & ENADC))
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
- }
- if (file->f_mode & FMODE_READ && s->enable & ENADC)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & ENDAC)
- 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(s, 1)))
- 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_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (s->status & DO_DUAL_DAC) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- }
- s->dma_dac.enabled = 1;
- start_dac(s);
- } else {
- s->dma_dac.enabled = 0;
- stop_dac(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!(s->enable & ENDAC) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.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->enable & ENADC) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.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;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.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);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- if (s->status & DO_DUAL_DAC) {
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(s, 0)))
- return val;
- if (s->status & DO_DUAL_DAC) {
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(2 * s->dma_dac.fragsize, p);
- }
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- 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_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 (s->status & DO_DUAL_DAC) {
- s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
- s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
- }
- }
- 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, 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_dac.subdivision = val;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.subdivision = val;
- }
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_READ_FILTER:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_GETCHANNELMASK:
- return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, p);
-
- case SNDCTL_DSP_BIND_CHANNEL:
- if (get_user(val, p))
- return -EFAULT;
- if (val == DSP_BIND_QUERY) {
- val = DSP_BIND_FRONT;
- if (s->status & DO_SPDIF_OUT)
- val |= DSP_BIND_SPDIF;
- else {
- if (s->curr_channels == 4)
- val |= DSP_BIND_SURR;
- if (s->curr_channels > 4)
- val |= DSP_BIND_CENTER_LFE;
- }
- } else {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val & DSP_BIND_SPDIF) {
- set_spdifin(s, s->rateadc);
- if (!(s->status & DO_SPDIF_OUT))
- val &= ~DSP_BIND_SPDIF;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val & DSP_BIND_SPDIF) {
- set_spdifout(s, s->ratedac);
- set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
- if (!(s->status & DO_SPDIF_OUT))
- val &= ~DSP_BIND_SPDIF;
- } else {
- int channels;
- int mask;
-
- 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:
- channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
- break;
- }
- set_dac_channels(s, channels);
- }
- }
- }
- return put_user(val, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- return -EINVAL;
- case SNDCTL_SPDIF_COPYRIGHT:
- if (get_user(val, p))
- return -EFAULT;
- set_spdif_copyright(s, val);
- return 0;
- case SNDCTL_SPDIF_LOOP:
- if (get_user(val, p))
- return -EFAULT;
- set_spdif_loop(s, val);
- return 0;
- case SNDCTL_SPDIF_MONITOR:
- if (get_user(val, p))
- return -EFAULT;
- set_spdif_monitor(s, val);
- return 0;
- case SNDCTL_SPDIF_LEVEL:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifout_level(s, val);
- return 0;
- case SNDCTL_SPDIF_INV:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin_inverse(s, val);
- return 0;
- case SNDCTL_SPDIF_SEL2:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin_channel2(s, val);
- return 0;
- case SNDCTL_SPDIF_VALID:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin_valid(s, val);
- return 0;
- case SNDCTL_SPDIFOUT:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifout(s, val ? s->ratedac : 0);
- return 0;
- case SNDCTL_SPDIFIN:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin(s, val ? s->rateadc : 0);
- return 0;
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int cm_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned char fmtm = ~0, fmts = 0;
- struct list_head *list;
- struct cm_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct cm_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->status &= ~DO_BIGENDIAN_R;
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- set_adc_rate(s, 8000);
- // spdif-in is turnned off by default
- set_spdifin(s, 0);
- }
- if (file->f_mode & FMODE_WRITE) {
- s->status &= ~DO_BIGENDIAN_W;
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- s->dma_dac.enabled = 1;
- set_dac_rate(s, 8000);
- // clear previous multichannel, spdif, ac3 state
- set_spdifout(s, 0);
- set_ac3(s, 0);
- set_dac_channels(s, 1);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int cm_release(struct inode *inode, struct file *file)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
-
- dealloc_dmabuf(s, &s->dma_dac);
- if (s->status & DO_DUAL_DAC)
- dealloc_dmabuf(s, &s->dma_adc);
-
- if (s->status & DO_MULTI_CH)
- set_dac_channels(s, 1);
- if (s->status & DO_AC3)
- set_ac3(s, 0);
- if (s->status & DO_SPDIF_OUT)
- set_spdifout(s, 0);
- /* enable SPDIF loop */
- set_spdif_loop(s, spdif_loop);
- s->status &= ~DO_BIGENDIAN_W;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- s->status &= ~DO_BIGENDIAN_R;
- }
- 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 cm_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = cm_read,
- .write = cm_write,
- .poll = cm_poll,
- .ioctl = cm_ioctl,
- .mmap = cm_mmap,
- .open = cm_open,
- .release = cm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_CD, 0x4f4f },
- { SOUND_MIXER_WRITE_LINE, 0x4f4f },
- { SOUND_MIXER_WRITE_MIC, 0x4f4f },
- { SOUND_MIXER_WRITE_SYNTH, 0x4f4f },
- { SOUND_MIXER_WRITE_VOLUME, 0x4f4f },
- { SOUND_MIXER_WRITE_PCM, 0x4f4f }
-};
-
-/* check chip version and capability */
-static int query_chip(struct cm_state *s)
-{
- int ChipVersion = -1;
- unsigned char RegValue;
-
- // check reg 0Ch, bit 24-31
- RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3);
- if (RegValue == 0) {
- // check reg 08h, bit 24-28
- RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3);
- RegValue &= 0x1f;
- if (RegValue == 0) {
- ChipVersion = 33;
- s->max_channels = 4;
- s->capability |= CAN_AC3_SW;
- s->capability |= CAN_DUAL_DAC;
- } else {
- ChipVersion = 37;
- s->max_channels = 4;
- s->capability |= CAN_AC3_HW;
- s->capability |= CAN_DUAL_DAC;
- }
- } else {
- // check reg 0Ch, bit 26
- if (RegValue & (1 << (26-24))) {
- ChipVersion = 39;
- if (RegValue & (1 << (24-24)))
- s->max_channels = 6;
- else
- s->max_channels = 4;
- s->capability |= CAN_AC3_HW;
- s->capability |= CAN_DUAL_DAC;
- s->capability |= CAN_MULTI_CH_HW;
- s->capability |= CAN_LINE_AS_BASS;
- s->capability |= CAN_MIC_AS_BASS;
- } else {
- ChipVersion = 55; // 4 or 6 channels
- s->max_channels = 6;
- s->capability |= CAN_AC3_HW;
- s->capability |= CAN_DUAL_DAC;
- s->capability |= CAN_MULTI_CH_HW;
- s->capability |= CAN_LINE_AS_BASS;
- s->capability |= CAN_MIC_AS_BASS;
- }
- }
- s->capability |= CAN_LINE_AS_REAR;
- return ChipVersion;
-}
-
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-static int __devinit cm_create_gameport(struct cm_state *s, int io_port)
-{
- struct gameport *gp;
-
- if (!request_region(io_port, CM_EXTENT_GAME, "cmpci GAME")) {
- printk(KERN_ERR "cmpci: gameport io ports 0x%#x in use\n", io_port);
- return -EBUSY;
- }
-
- if (!(s->gameport = gp = gameport_allocate_port())) {
- printk(KERN_ERR "cmpci: can not allocate memory for gameport\n");
- release_region(io_port, CM_EXTENT_GAME);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "C-Media GP");
- gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
- gp->dev.parent = &s->dev->dev;
- gp->io = io_port;
-
- /* enable joystick */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static void __devexit cm_free_gameport(struct cm_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
-
- gameport_unregister_port(s->gameport);
- s->gameport = NULL;
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
- release_region(gpio, CM_EXTENT_GAME);
- }
-}
-#else
-static inline int cm_create_gameport(struct cm_state *s, int io_port) { return -ENOSYS; }
-static inline void cm_free_gameport(struct cm_state *s) { }
-#endif
-
-#define echo_option(x)\
-if (x) strcat(options, "" #x " ")
-
-static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- struct cm_state *s;
- mm_segment_t fs;
- int i, val, ret;
- unsigned char reg_mask;
- int timeout;
- struct resource *ports;
- struct {
- unsigned short deviceid;
- char *devicename;
- } devicetable[] = {
- { PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" },
- { PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" },
- { PCI_DEVICE_ID_CMEDIA_CM8738, "CM8738" },
- { PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
- };
- char *devicename = "unknown";
- char options[256];
-
- if ((ret = pci_enable_device(pcidev)))
- return ret;
- 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 "cmpci: architecture does not support 32bit PCI busmaster DMA\n");
- return i;
- }
- s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (!s) {
- printk(KERN_WARNING "cmpci: out of memory\n");
- return -ENOMEM;
- }
- /* search device name */
- for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
- if (devicetable[i].deviceid == pcidev->device) {
- devicename = devicetable[i].devicename;
- break;
- }
- }
- memset(s, 0, sizeof(struct cm_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->magic = CM_MAGIC;
- s->dev = pcidev;
- s->iobase = pci_resource_start(pcidev, 0);
- s->iosynth = fmio;
- s->iomidi = mpuio;
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- s->midi_devc = 0;
-#endif
- s->status = 0;
- if (s->iobase == 0)
- return -ENODEV;
- s->irq = pcidev->irq;
-
- if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
- printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
- ret = -EBUSY;
- goto err_region5;
- }
- /* dump parameters */
- strcpy(options, "cmpci: ");
- echo_option(joystick);
- echo_option(spdif_inverse);
- echo_option(spdif_loop);
- echo_option(spdif_out);
- echo_option(use_line_as_rear);
- echo_option(use_line_as_bass);
- echo_option(use_mic_as_bass);
- echo_option(mic_boost);
- echo_option(hw_copy);
- printk(KERN_INFO "%s\n", options);
-
- /* initialize codec registers */
- outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
- /* reset mixer */
- wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
- /* request irq */
- if ((ret = request_irq(s->irq, cm_interrupt, IRQF_SHARED, "cmpci", s))) {
- printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_INFO "cmpci: found %s adapter at io %#x irq %u\n",
- devicename, s->iobase, s->irq);
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- pci_set_master(pcidev); /* enable bus mastering */
- /* initialize the chips */
- fs = get_fs();
- set_fs(KERNEL_DS);
- /* set mixer output */
- frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f);
- /* set mixer input */
- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD|SOUND_MASK_MIC;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- set_fs(fs);
- /* use channel 1 for playback, channel 0 for record */
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, CHADC0);
- /* turn off VMIC3 - mic boost */
- if (mic_boost)
- maskb(s->iobase + CODEC_CMI_MIXER2, ~1, 0);
- else
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0, 1);
- s->deviceid = pcidev->device;
-
- if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738
- || pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738B) {
-
- /* chip version and hw capability check */
- s->chip_version = query_chip(s);
- printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version);
-
- /* set SPDIF-in inverse before enable SPDIF loop */
- set_spdifin_inverse(s, spdif_inverse);
-
- /* use SPDIF in #1 */
- set_spdifin_channel2(s, 0);
- } else {
- s->chip_version = 0;
- /* 8338 will fall here */
- s->max_channels = 4;
- s->capability |= CAN_DUAL_DAC;
- s->capability |= CAN_LINE_AS_REAR;
- }
- /* enable SPDIF loop */
- set_spdif_loop(s, spdif_loop);
-
- // enable 4 speaker mode (analog duplicate)
- set_hw_copy(s, hw_copy);
-
- reg_mask = 0;
-#ifdef CONFIG_SOUND_CMPCI_FM
- /* disable FM */
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
- if (s->iosynth) {
- /* don't enable OPL3 if there is one */
- if (opl3_detect(s->iosynth, NULL)) {
- s->iosynth = 0;
- } else {
- /* set IO based at 0x388 */
- switch (s->iosynth) {
- case 0x388:
- reg_mask = 0;
- break;
- case 0x3C8:
- reg_mask = 0x01;
- break;
- case 0x3E0:
- reg_mask = 0x02;
- break;
- case 0x3E8:
- reg_mask = 0x03;
- break;
- default:
- s->iosynth = 0;
- break;
- }
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
- /* enable FM */
- if (s->iosynth) {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
- if (opl3_detect(s->iosynth, NULL))
- ret = opl3_init(s->iosynth, NULL, THIS_MODULE);
- else {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
- s->iosynth = 0;
- }
- }
- }
- }
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- switch (s->iomidi) {
- case 0x330:
- reg_mask = 0;
- break;
- case 0x320:
- reg_mask = 0x20;
- break;
- case 0x310:
- reg_mask = 0x40;
- break;
- case 0x300:
- reg_mask = 0x60;
- break;
- default:
- s->iomidi = 0;
- goto skip_mpu;
- }
- ports = request_region(s->iomidi, 2, "mpu401");
- if (!ports)
- goto skip_mpu;
- /* disable MPU-401 */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
- s->mpu_data.name = "cmpci mpu";
- s->mpu_data.io_base = s->iomidi;
- s->mpu_data.irq = -s->irq; // tell mpu401 to share irq
- if (probe_mpu401(&s->mpu_data, ports)) {
- release_region(s->iomidi, 2);
- s->iomidi = 0;
- goto skip_mpu;
- }
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x60, reg_mask);
- /* enable MPU-401 */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
- /* clear all previously received interrupt */
- for (timeout = 900000; timeout > 0; timeout--) {
- if ((inb(s->iomidi + 1) && 0x80) == 0)
- inb(s->iomidi);
- else
- break;
- }
- if (!probe_mpu401(&s->mpu_data, ports)) {
- release_region(s->iomidi, 2);
- s->iomidi = 0;
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
- } else {
- attach_mpu401(&s->mpu_data, THIS_MODULE);
- s->midi_devc = s->mpu_data.slots[1];
- }
-skip_mpu:
-#endif
- /* disable joystick port */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
- if (joystick)
- cm_create_gameport(s, 0x200);
-
- /* 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_dev2:
- unregister_sound_dsp(s->dev_audio);
-err_dev1:
- printk(KERN_ERR "cmpci: cannot register misc device\n");
- free_irq(s->irq, s);
-err_irq:
- release_region(s->iobase, CM_EXTENT_CODEC);
-err_region5:
- kfree(s);
- return ret;
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw");
-MODULE_DESCRIPTION("CM8x38 Audio Driver");
-MODULE_LICENSE("GPL");
-
-static void __devexit cm_remove(struct pci_dev *dev)
-{
- struct cm_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
-
- cm_free_gameport(s);
-
-#ifdef CONFIG_SOUND_CMPCI_FM
- if (s->iosynth) {
- /* disable FM */
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
- }
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- if (s->iomidi) {
- unload_mpu401(&s->mpu_data);
- /* disable MPU-401 */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
- }
-#endif
- set_spdif_loop(s, 0);
- list_del(&s->devs);
- outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
- synchronize_irq(s->irq);
- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
- free_irq(s->irq, s);
-
- /* reset mixer */
- wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
- release_region(s->iobase, CM_EXTENT_CODEC);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] __devinitdata = {
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver cm_driver = {
- .name = "cmpci",
- .id_table = id_table,
- .probe = cm_probe,
- .remove = __devexit_p(cm_remove)
-};
-
-static int __init init_cmpci(void)
-{
- printk(KERN_INFO "cmpci: version $Revision: 6.82 $ time " __TIME__ " " __DATE__ "\n");
- return pci_register_driver(&cm_driver);
-}
-
-static void __exit cleanup_cmpci(void)
-{
- printk(KERN_INFO "cmpci: unloading\n");
- pci_unregister_driver(&cm_driver);
-}
-
-module_init(init_cmpci);
-module_exit(cleanup_cmpci);
diff --git a/sound/oss/cs4281/Makefile b/sound/oss/cs4281/Makefile
deleted file mode 100644
index 6d527e8..0000000
--- a/sound/oss/cs4281/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# Makefile for Cirrus Logic-Crystal CS4281
-#
-
-obj-$(CONFIG_SOUND_CS4281) += cs4281.o
-
-cs4281-objs += cs4281m.o
diff --git a/sound/oss/cs4281/cs4281_hwdefs.h b/sound/oss/cs4281/cs4281_hwdefs.h
deleted file mode 100644
index 701d595..0000000
--- a/sound/oss/cs4281/cs4281_hwdefs.h
+++ /dev/null
@@ -1,1234 +0,0 @@
-//****************************************************************************
-//
-// HWDEFS.H - Definitions of the registers and data structures used by the
-// CS4281
-//
-// Copyright (c) 1999,2000,2001 Crystal Semiconductor Corp.
-//
-//****************************************************************************
-
-#ifndef _H_HWDEFS
-#define _H_HWDEFS
-
-//****************************************************************************
-//
-// The following define the offsets of the registers located in the PCI
-// configuration space of the CS4281 part.
-//
-//****************************************************************************
-#define PCICONFIG_DEVID_VENID 0x00000000L
-#define PCICONFIG_STATUS_COMMAND 0x00000004L
-#define PCICONFIG_CLASS_REVISION 0x00000008L
-#define PCICONFIG_LATENCY_TIMER 0x0000000CL
-#define PCICONFIG_BA0 0x00000010L
-#define PCICONFIG_BA1 0x00000014L
-#define PCICONFIG_SUBSYSID_SUBSYSVENID 0x0000002CL
-#define PCICONFIG_INTERRUPT 0x0000003CL
-
-//****************************************************************************
-//
-// The following define the offsets of the registers accessed via base address
-// register zero on the CS4281 part.
-//
-//****************************************************************************
-#define BA0_HISR 0x00000000L
-#define BA0_HICR 0x00000008L
-#define BA0_HIMR 0x0000000CL
-#define BA0_IIER 0x00000010L
-#define BA0_HDSR0 0x000000F0L
-#define BA0_HDSR1 0x000000F4L
-#define BA0_HDSR2 0x000000F8L
-#define BA0_HDSR3 0x000000FCL
-#define BA0_DCA0 0x00000110L
-#define BA0_DCC0 0x00000114L
-#define BA0_DBA0 0x00000118L
-#define BA0_DBC0 0x0000011CL
-#define BA0_DCA1 0x00000120L
-#define BA0_DCC1 0x00000124L
-#define BA0_DBA1 0x00000128L
-#define BA0_DBC1 0x0000012CL
-#define BA0_DCA2 0x00000130L
-#define BA0_DCC2 0x00000134L
-#define BA0_DBA2 0x00000138L
-#define BA0_DBC2 0x0000013CL
-#define BA0_DCA3 0x00000140L
-#define BA0_DCC3 0x00000144L
-#define BA0_DBA3 0x00000148L
-#define BA0_DBC3 0x0000014CL
-#define BA0_DMR0 0x00000150L
-#define BA0_DCR0 0x00000154L
-#define BA0_DMR1 0x00000158L
-#define BA0_DCR1 0x0000015CL
-#define BA0_DMR2 0x00000160L
-#define BA0_DCR2 0x00000164L
-#define BA0_DMR3 0x00000168L
-#define BA0_DCR3 0x0000016CL
-#define BA0_DLMR 0x00000170L
-#define BA0_DLSR 0x00000174L
-#define BA0_FCR0 0x00000180L
-#define BA0_FCR1 0x00000184L
-#define BA0_FCR2 0x00000188L
-#define BA0_FCR3 0x0000018CL
-#define BA0_FPDR0 0x00000190L
-#define BA0_FPDR1 0x00000194L
-#define BA0_FPDR2 0x00000198L
-#define BA0_FPDR3 0x0000019CL
-#define BA0_FCHS 0x0000020CL
-#define BA0_FSIC0 0x00000210L
-#define BA0_FSIC1 0x00000214L
-#define BA0_FSIC2 0x00000218L
-#define BA0_FSIC3 0x0000021CL
-#define BA0_PCICFG00 0x00000300L
-#define BA0_PCICFG04 0x00000304L
-#define BA0_PCICFG08 0x00000308L
-#define BA0_PCICFG0C 0x0000030CL
-#define BA0_PCICFG10 0x00000310L
-#define BA0_PCICFG14 0x00000314L
-#define BA0_PCICFG18 0x00000318L
-#define BA0_PCICFG1C 0x0000031CL
-#define BA0_PCICFG20 0x00000320L
-#define BA0_PCICFG24 0x00000324L
-#define BA0_PCICFG28 0x00000328L
-#define BA0_PCICFG2C 0x0000032CL
-#define BA0_PCICFG30 0x00000330L
-#define BA0_PCICFG34 0x00000334L
-#define BA0_PCICFG38 0x00000338L
-#define BA0_PCICFG3C 0x0000033CL
-#define BA0_PCICFG40 0x00000340L
-#define BA0_PMCS 0x00000344L
-#define BA0_CWPR 0x000003E0L
-#define BA0_EPPMC 0x000003E4L
-#define BA0_GPIOR 0x000003E8L
-#define BA0_SPMC 0x000003ECL
-#define BA0_CFLR 0x000003F0L
-#define BA0_IISR 0x000003F4L
-#define BA0_TMS 0x000003F8L
-#define BA0_SSVID 0x000003FCL
-#define BA0_CLKCR1 0x00000400L
-#define BA0_FRR 0x00000410L
-#define BA0_SLT12O 0x0000041CL
-#define BA0_SERMC 0x00000420L
-#define BA0_SERC1 0x00000428L
-#define BA0_SERC2 0x0000042CL
-#define BA0_SLT12M 0x0000045CL
-#define BA0_ACCTL 0x00000460L
-#define BA0_ACSTS 0x00000464L
-#define BA0_ACOSV 0x00000468L
-#define BA0_ACCAD 0x0000046CL
-#define BA0_ACCDA 0x00000470L
-#define BA0_ACISV 0x00000474L
-#define BA0_ACSAD 0x00000478L
-#define BA0_ACSDA 0x0000047CL
-#define BA0_JSPT 0x00000480L
-#define BA0_JSCTL 0x00000484L
-#define BA0_MIDCR 0x00000490L
-#define BA0_MIDCMD 0x00000494L
-#define BA0_MIDSR 0x00000494L
-#define BA0_MIDWP 0x00000498L
-#define BA0_MIDRP 0x0000049CL
-#define BA0_AODSD1 0x000004A8L
-#define BA0_AODSD2 0x000004ACL
-#define BA0_CFGI 0x000004B0L
-#define BA0_SLT12M2 0x000004DCL
-#define BA0_ACSTS2 0x000004E4L
-#define BA0_ACISV2 0x000004F4L
-#define BA0_ACSAD2 0x000004F8L
-#define BA0_ACSDA2 0x000004FCL
-#define BA0_IOTGP 0x00000500L
-#define BA0_IOTSB 0x00000504L
-#define BA0_IOTFM 0x00000508L
-#define BA0_IOTDMA 0x0000050CL
-#define BA0_IOTAC0 0x00000500L
-#define BA0_IOTAC1 0x00000504L
-#define BA0_IOTAC2 0x00000508L
-#define BA0_IOTAC3 0x0000050CL
-#define BA0_IOTPCP 0x0000052CL
-#define BA0_IOTCC 0x00000530L
-#define BA0_IOTCR 0x0000058CL
-#define BA0_PCPRR 0x00000600L
-#define BA0_PCPGR 0x00000604L
-#define BA0_PCPCR 0x00000608L
-#define BA0_PCPCIEN 0x00000608L
-#define BA0_SBMAR 0x00000700L
-#define BA0_SBMDR 0x00000704L
-#define BA0_SBRR 0x00000708L
-#define BA0_SBRDP 0x0000070CL
-#define BA0_SBWDP 0x00000710L
-#define BA0_SBWBS 0x00000710L
-#define BA0_SBRBS 0x00000714L
-#define BA0_FMSR 0x00000730L
-#define BA0_B0AP 0x00000730L
-#define BA0_FMDP 0x00000734L
-#define BA0_B1AP 0x00000738L
-#define BA0_B1DP 0x0000073CL
-#define BA0_SSPM 0x00000740L
-#define BA0_DACSR 0x00000744L
-#define BA0_ADCSR 0x00000748L
-#define BA0_SSCR 0x0000074CL
-#define BA0_FMLVC 0x00000754L
-#define BA0_FMRVC 0x00000758L
-#define BA0_SRCSA 0x0000075CL
-#define BA0_PPLVC 0x00000760L
-#define BA0_PPRVC 0x00000764L
-#define BA0_PASR 0x00000768L
-#define BA0_CASR 0x0000076CL
-
-//****************************************************************************
-//
-// The following define the offsets of the AC97 shadow registers, which appear
-// as a virtual extension to the base address register zero memory range.
-//
-//****************************************************************************
-#define AC97_REG_OFFSET_MASK 0x0000007EL
-#define AC97_CODEC_NUMBER_MASK 0x00003000L
-
-#define BA0_AC97_RESET 0x00001000L
-#define BA0_AC97_MASTER_VOLUME 0x00001002L
-#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L
-#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L
-#define BA0_AC97_MASTER_TONE 0x00001008L
-#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL
-#define BA0_AC97_PHONE_VOLUME 0x0000100CL
-#define BA0_AC97_MIC_VOLUME 0x0000100EL
-#define BA0_AC97_LINE_IN_VOLUME 0x00001010L
-#define BA0_AC97_CD_VOLUME 0x00001012L
-#define BA0_AC97_VIDEO_VOLUME 0x00001014L
-#define BA0_AC97_AUX_VOLUME 0x00001016L
-#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L
-#define BA0_AC97_RECORD_SELECT 0x0000101AL
-#define BA0_AC97_RECORD_GAIN 0x0000101CL
-#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL
-#define BA0_AC97_GENERAL_PURPOSE 0x00001020L
-#define BA0_AC97_3D_CONTROL 0x00001022L
-#define BA0_AC97_MODEM_RATE 0x00001024L
-#define BA0_AC97_POWERDOWN 0x00001026L
-#define BA0_AC97_EXT_AUDIO_ID 0x00001028L
-#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL
-#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL
-#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL
-#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L
-#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L
-#define BA0_AC97_MIC_ADC_RATE 0x00001034L
-#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L
-#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L
-#define BA0_AC97_RESERVED_3A 0x0000103AL
-#define BA0_AC97_EXT_MODEM_ID 0x0000103CL
-#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL
-#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L
-#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L
-#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L
-#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L
-#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L
-#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL
-#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL
-#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL
-#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L
-#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L
-#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L
-#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L
-#define BA0_AC97_RESERVED_58 0x00001058L
-#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL
-#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL
-#define BA0_AC97_AC_MODE 0x0000105EL
-#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L
-#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L
-#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L
-#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L
-#define BA0_AC97_SPDIF_CONTROL 0x00001068L
-#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL
-#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL
-#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL
-#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L
-#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L
-#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L
-#define BA0_AC97_CAL_ADDRESS 0x00001076L
-#define BA0_AC97_CAL_DATA 0x00001078L
-#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL
-#define BA0_AC97_VENDOR_ID1 0x0000107CL
-#define BA0_AC97_VENDOR_ID2 0x0000107EL
-
-//****************************************************************************
-//
-// The following define the offsets of the registers and memories accessed via
-// base address register one on the CS4281 part.
-//
-//****************************************************************************
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI device ID/vendor ID
-// register.
-//
-//****************************************************************************
-#define PDV_VENID_MASK 0x0000FFFFL
-#define PDV_DEVID_MASK 0xFFFF0000L
-#define PDV_VENID_SHIFT 0L
-#define PDV_DEVID_SHIFT 16L
-#define VENID_CIRRUS_LOGIC 0x1013L
-#define DEVID_CS4281 0x6005L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI status and command
-// register.
-//
-//****************************************************************************
-#define PSC_IO_SPACE_ENABLE 0x00000001L
-#define PSC_MEMORY_SPACE_ENABLE 0x00000002L
-#define PSC_BUS_MASTER_ENABLE 0x00000004L
-#define PSC_SPECIAL_CYCLES 0x00000008L
-#define PSC_MWI_ENABLE 0x00000010L
-#define PSC_VGA_PALETTE_SNOOP 0x00000020L
-#define PSC_PARITY_RESPONSE 0x00000040L
-#define PSC_WAIT_CONTROL 0x00000080L
-#define PSC_SERR_ENABLE 0x00000100L
-#define PSC_FAST_B2B_ENABLE 0x00000200L
-#define PSC_UDF_MASK 0x007F0000L
-#define PSC_FAST_B2B_CAPABLE 0x00800000L
-#define PSC_PARITY_ERROR_DETECTED 0x01000000L
-#define PSC_DEVSEL_TIMING_MASK 0x06000000L
-#define PSC_TARGET_ABORT_SIGNALLED 0x08000000L
-#define PSC_RECEIVED_TARGET_ABORT 0x10000000L
-#define PSC_RECEIVED_MASTER_ABORT 0x20000000L
-#define PSC_SIGNALLED_SERR 0x40000000L
-#define PSC_DETECTED_PARITY_ERROR 0x80000000L
-#define PSC_UDF_SHIFT 16L
-#define PSC_DEVSEL_TIMING_SHIFT 25L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI class/revision ID
-// register.
-//
-//****************************************************************************
-#define PCR_REVID_MASK 0x000000FFL
-#define PCR_INTERFACE_MASK 0x0000FF00L
-#define PCR_SUBCLASS_MASK 0x00FF0000L
-#define PCR_CLASS_MASK 0xFF000000L
-#define PCR_REVID_SHIFT 0L
-#define PCR_INTERFACE_SHIFT 8L
-#define PCR_SUBCLASS_SHIFT 16L
-#define PCR_CLASS_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI latency timer register.
-//
-//****************************************************************************
-#define PLT_CACHE_LINE_SIZE_MASK 0x000000FFL
-#define PLT_LATENCY_TIMER_MASK 0x0000FF00L
-#define PLT_HEADER_TYPE_MASK 0x00FF0000L
-#define PLT_BIST_MASK 0xFF000000L
-#define PLT_CACHE_LINE_SIZE_SHIFT 0L
-#define PLT_LATENCY_TIMER_SHIFT 8L
-#define PLT_HEADER_TYPE_SHIFT 16L
-#define PLT_BIST_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI base address registers.
-//
-//****************************************************************************
-#define PBAR_MEMORY_SPACE_INDICATOR 0x00000001L
-#define PBAR_LOCATION_TYPE_MASK 0x00000006L
-#define PBAR_NOT_PREFETCHABLE 0x00000008L
-#define PBAR_ADDRESS_MASK 0xFFFFFFF0L
-#define PBAR_LOCATION_TYPE_SHIFT 1L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI subsystem ID/subsystem
-// vendor ID register.
-//
-//****************************************************************************
-#define PSS_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFFL
-#define PSS_SUBSYSTEM_ID_MASK 0xFFFF0000L
-#define PSS_SUBSYSTEM_VENDOR_ID_SHIFT 0L
-#define PSS_SUBSYSTEM_ID_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI interrupt register.
-//
-//****************************************************************************
-#define PI_LINE_MASK 0x000000FFL
-#define PI_PIN_MASK 0x0000FF00L
-#define PI_MIN_GRANT_MASK 0x00FF0000L
-#define PI_MAX_LATENCY_MASK 0xFF000000L
-#define PI_LINE_SHIFT 0L
-#define PI_PIN_SHIFT 8L
-#define PI_MIN_GRANT_SHIFT 16L
-#define PI_MAX_LATENCY_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the host interrupt status
-// register.
-//
-//****************************************************************************
-#define HISR_HVOLMASK 0x00000003L
-#define HISR_VDNI 0x00000001L
-#define HISR_VUPI 0x00000002L
-#define HISR_GP1I 0x00000004L
-#define HISR_GP3I 0x00000008L
-#define HISR_GPSI 0x00000010L
-#define HISR_GPPI 0x00000020L
-#define HISR_DMAI 0x00040000L
-#define HISR_FIFOI 0x00100000L
-#define HISR_HVOL 0x00200000L
-#define HISR_MIDI 0x00400000L
-#define HISR_SBINT 0x00800000L
-#define HISR_INTENA 0x80000000L
-#define HISR_DMA_MASK 0x00000F00L
-#define HISR_FIFO_MASK 0x0000F000L
-#define HISR_DMA_SHIFT 8L
-#define HISR_FIFO_SHIFT 12L
-#define HISR_FIFO0 0x00001000L
-#define HISR_FIFO1 0x00002000L
-#define HISR_FIFO2 0x00004000L
-#define HISR_FIFO3 0x00008000L
-#define HISR_DMA0 0x00000100L
-#define HISR_DMA1 0x00000200L
-#define HISR_DMA2 0x00000400L
-#define HISR_DMA3 0x00000800L
-#define HISR_RESERVED 0x40000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the host interrupt control
-// register.
-//
-//****************************************************************************
-#define HICR_IEV 0x00000001L
-#define HICR_CHGM 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the DMA Mode Register n
-// (DMRn)
-//
-//****************************************************************************
-#define DMRn_TR_MASK 0x0000000CL
-#define DMRn_TR_SHIFT 2L
-#define DMRn_AUTO 0x00000010L
-#define DMRn_TR_READ 0x00000008L
-#define DMRn_TR_WRITE 0x00000004L
-#define DMRn_TYPE_MASK 0x000000C0L
-#define DMRn_TYPE_SHIFT 6L
-#define DMRn_SIZE8 0x00010000L
-#define DMRn_MONO 0x00020000L
-#define DMRn_BEND 0x00040000L
-#define DMRn_USIGN 0x00080000L
-#define DMRn_SIZE20 0x00100000L
-#define DMRn_SWAPC 0x00400000L
-#define DMRn_CBC 0x01000000L
-#define DMRn_TBC 0x02000000L
-#define DMRn_POLL 0x10000000L
-#define DMRn_DMA 0x20000000L
-#define DMRn_FSEL_MASK 0xC0000000L
-#define DMRn_FSEL_SHIFT 30L
-#define DMRn_FSEL0 0x00000000L
-#define DMRn_FSEL1 0x40000000L
-#define DMRn_FSEL2 0x80000000L
-#define DMRn_FSEL3 0xC0000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the DMA Command Register n
-// (DCRn)
-//
-//****************************************************************************
-#define DCRn_HTCIE 0x00020000L
-#define DCRn_TCIE 0x00010000L
-#define DCRn_MSK 0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the FIFO Control
-// register n.(FCRn)
-//
-//****************************************************************************
-#define FCRn_OF_MASK 0x0000007FL
-#define FCRn_OF_SHIFT 0L
-#define FCRn_SZ_MASK 0x00007F00L
-#define FCRn_SZ_SHIFT 8L
-#define FCRn_LS_MASK 0x001F0000L
-#define FCRn_LS_SHIFT 16L
-#define FCRn_RS_MASK 0x1F000000L
-#define FCRn_RS_SHIFT 24L
-#define FCRn_FEN 0x80000000L
-#define FCRn_PSH 0x20000000L
-#define FCRn_DACZ 0x40000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port Power Management
-// control register.(SPMC)
-//
-//****************************************************************************
-#define SPMC_RSTN 0x00000001L
-#define SPMC_ASYN 0x00000002L
-#define SPMC_WUP1 0x00000004L
-#define SPMC_WUP2 0x00000008L
-#define SPMC_ASDI2E 0x00000100L
-#define SPMC_ESSPD 0x00000200L
-#define SPMC_GISPEN 0x00004000L
-#define SPMC_GIPPEN 0x00008000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Configuration Load register.
-// (CFLR)
-//
-//****************************************************************************
-#define CFLR_CLOCK_SOURCE_MASK 0x00000003L
-#define CFLR_CLOCK_SOURCE_AC97 0x00000001L
-
-#define CFLR_CB0_MASK 0x000000FFL
-#define CFLR_CB1_MASK 0x0000FF00L
-#define CFLR_CB2_MASK 0x00FF0000L
-#define CFLR_CB3_MASK 0xFF000000L
-#define CFLR_CB0_SHIFT 0L
-#define CFLR_CB1_SHIFT 8L
-#define CFLR_CB2_SHIFT 16L
-#define CFLR_CB3_SHIFT 24L
-
-#define IOTCR_DMA0 0x00000000L
-#define IOTCR_DMA1 0x00000400L
-#define IOTCR_DMA2 0x00000800L
-#define IOTCR_DMA3 0x00000C00L
-#define IOTCR_CCLS 0x00000100L
-#define IOTCR_PCPCI 0x00000200L
-#define IOTCR_DDMA 0x00000300L
-
-#define SBWBS_WBB 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the SRC Slot Assignment Register
-// (SRCSA)
-//
-//****************************************************************************
-#define SRCSA_PLSS_MASK 0x0000001FL
-#define SRCSA_PLSS_SHIFT 0L
-#define SRCSA_PRSS_MASK 0x00001F00L
-#define SRCSA_PRSS_SHIFT 8L
-#define SRCSA_CLSS_MASK 0x001F0000L
-#define SRCSA_CLSS_SHIFT 16L
-#define SRCSA_CRSS_MASK 0x1F000000L
-#define SRCSA_CRSS_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound System Power Management
-// register.(SSPM)
-//
-//****************************************************************************
-#define SSPM_FPDN 0x00000080L
-#define SSPM_MIXEN 0x00000040L
-#define SSPM_CSRCEN 0x00000020L
-#define SSPM_PSRCEN 0x00000010L
-#define SSPM_JSEN 0x00000008L
-#define SSPM_ACLEN 0x00000004L
-#define SSPM_FMEN 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound System Control
-// Register. (SSCR)
-//
-//****************************************************************************
-#define SSCR_SB 0x00000004L
-#define SSCR_HVC 0x00000008L
-#define SSCR_LPFIFO 0x00000040L
-#define SSCR_LPSRC 0x00000080L
-#define SSCR_XLPSRC 0x00000100L
-#define SSCR_MVMD 0x00010000L
-#define SSCR_MVAD 0x00020000L
-#define SSCR_MVLD 0x00040000L
-#define SSCR_MVCS 0x00080000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Clock Control Register 1.
-// (CLKCR1)
-//
-//****************************************************************************
-#define CLKCR1_DLLSS_MASK 0x0000000CL
-#define CLKCR1_DLLSS_SHIFT 2L
-#define CLKCR1_DLLP 0x00000010L
-#define CLKCR1_SWCE 0x00000020L
-#define CLKCR1_DLLOS 0x00000040L
-#define CLKCR1_CKRA 0x00010000L
-#define CLKCR1_CKRN 0x00020000L
-#define CLKCR1_DLLRDY 0x01000000L
-#define CLKCR1_CLKON 0x02000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound Blaster Read Buffer
-// Status.(SBRBS)
-//
-//****************************************************************************
-#define SBRBS_RD_MASK 0x0000007FL
-#define SBRBS_RD_SHIFT 0L
-#define SBRBS_RBF 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port master control
-// register.(SERMC)
-//
-//****************************************************************************
-#define SERMC_MSPE 0x00000001L
-#define SERMC_PTC_MASK 0x0000000EL
-#define SERMC_PTC_SHIFT 1L
-#define SERMC_PTC_AC97 0x00000002L
-#define SERMC_PLB 0x00000010L
-#define SERMC_PXLB 0x00000020L
-#define SERMC_LOFV 0x00080000L
-#define SERMC_SLB 0x00100000L
-#define SERMC_SXLB 0x00200000L
-#define SERMC_ODSEN1 0x01000000L
-#define SERMC_ODSEN2 0x02000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the General Purpose I/O Register.
-// (GPIOR)
-//
-//****************************************************************************
-#define GPIOR_VDNS 0x00000001L
-#define GPIOR_VUPS 0x00000002L
-#define GPIOR_GP1S 0x00000004L
-#define GPIOR_GP3S 0x00000008L
-#define GPIOR_GPSS 0x00000010L
-#define GPIOR_GPPS 0x00000020L
-#define GPIOR_GP1D 0x00000400L
-#define GPIOR_GP3D 0x00000800L
-#define GPIOR_VDNLT 0x00010000L
-#define GPIOR_VDNPO 0x00020000L
-#define GPIOR_VDNST 0x00040000L
-#define GPIOR_VDNW 0x00080000L
-#define GPIOR_VUPLT 0x00100000L
-#define GPIOR_VUPPO 0x00200000L
-#define GPIOR_VUPST 0x00400000L
-#define GPIOR_VUPW 0x00800000L
-#define GPIOR_GP1OE 0x01000000L
-#define GPIOR_GP1PT 0x02000000L
-#define GPIOR_GP1ST 0x04000000L
-#define GPIOR_GP1W 0x08000000L
-#define GPIOR_GP3OE 0x10000000L
-#define GPIOR_GP3PT 0x20000000L
-#define GPIOR_GP3ST 0x40000000L
-#define GPIOR_GP3W 0x80000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the clock control register 1.
-//
-//****************************************************************************
-#define CLKCR1_PLLSS_MASK 0x0000000CL
-#define CLKCR1_PLLSS_SERIAL 0x00000000L
-#define CLKCR1_PLLSS_CRYSTAL 0x00000004L
-#define CLKCR1_PLLSS_PCI 0x00000008L
-#define CLKCR1_PLLSS_RESERVED 0x0000000CL
-#define CLKCR1_PLLP 0x00000010L
-#define CLKCR1_SWCE 0x00000020L
-#define CLKCR1_PLLOS 0x00000040L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the feature reporting register.
-//
-//****************************************************************************
-#define FRR_FAB_MASK 0x00000003L
-#define FRR_MASK_MASK 0x0000001CL
-#define FRR_ID_MASK 0x00003000L
-#define FRR_FAB_SHIFT 0L
-#define FRR_MASK_SHIFT 2L
-#define FRR_ID_SHIFT 12L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port 1 configuration
-// register.
-//
-//****************************************************************************
-#define SERC1_VALUE 0x00000003L
-#define SERC1_SO1EN 0x00000001L
-#define SERC1_SO1F_MASK 0x0000000EL
-#define SERC1_SO1F_CS423X 0x00000000L
-#define SERC1_SO1F_AC97 0x00000002L
-#define SERC1_SO1F_DAC 0x00000004L
-#define SERC1_SO1F_SPDIF 0x00000006L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port 2 configuration
-// register.
-//
-//****************************************************************************
-#define SERC2_VALUE 0x00000003L
-#define SERC2_SI1EN 0x00000001L
-#define SERC2_SI1F_MASK 0x0000000EL
-#define SERC2_SI1F_CS423X 0x00000000L
-#define SERC2_SI1F_AC97 0x00000002L
-#define SERC2_SI1F_ADC 0x00000004L
-#define SERC2_SI1F_SPDIF 0x00000006L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 control register.
-//
-//****************************************************************************
-#define ACCTL_ESYN 0x00000002L
-#define ACCTL_VFRM 0x00000004L
-#define ACCTL_DCV 0x00000008L
-#define ACCTL_CRW 0x00000010L
-#define ACCTL_TC 0x00000040L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status register.
-//
-//****************************************************************************
-#define ACSTS_CRDY 0x00000001L
-#define ACSTS_VSTS 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 output slot valid
-// register.
-//
-//****************************************************************************
-#define ACOSV_SLV3 0x00000001L
-#define ACOSV_SLV4 0x00000002L
-#define ACOSV_SLV5 0x00000004L
-#define ACOSV_SLV6 0x00000008L
-#define ACOSV_SLV7 0x00000010L
-#define ACOSV_SLV8 0x00000020L
-#define ACOSV_SLV9 0x00000040L
-#define ACOSV_SLV10 0x00000080L
-#define ACOSV_SLV11 0x00000100L
-#define ACOSV_SLV12 0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 command address
-// register.
-//
-//****************************************************************************
-#define ACCAD_CI_MASK 0x0000007FL
-#define ACCAD_CI_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 command data register.
-//
-//****************************************************************************
-#define ACCDA_CD_MASK 0x0000FFFFL
-#define ACCDA_CD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 input slot valid
-// register.
-//
-//****************************************************************************
-#define ACISV_ISV3 0x00000001L
-#define ACISV_ISV4 0x00000002L
-#define ACISV_ISV5 0x00000004L
-#define ACISV_ISV6 0x00000008L
-#define ACISV_ISV7 0x00000010L
-#define ACISV_ISV8 0x00000020L
-#define ACISV_ISV9 0x00000040L
-#define ACISV_ISV10 0x00000080L
-#define ACISV_ISV11 0x00000100L
-#define ACISV_ISV12 0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status address
-// register.
-//
-//****************************************************************************
-#define ACSAD_SI_MASK 0x0000007FL
-#define ACSAD_SI_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status data register.
-//
-//****************************************************************************
-#define ACSDA_SD_MASK 0x0000FFFFL
-#define ACSDA_SD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers (all 12).
-//
-//****************************************************************************
-#define IOTAC_SA_MASK 0x0000FFFFL
-#define IOTAC_MSK_MASK 0x000F0000L
-#define IOTAC_IODC_MASK 0x06000000L
-#define IOTAC_IODC_16_BIT 0x00000000L
-#define IOTAC_IODC_10_BIT 0x02000000L
-#define IOTAC_IODC_12_BIT 0x04000000L
-#define IOTAC_WSPI 0x08000000L
-#define IOTAC_RSPI 0x10000000L
-#define IOTAC_WSE 0x20000000L
-#define IOTAC_WE 0x40000000L
-#define IOTAC_RE 0x80000000L
-#define IOTAC_SA_SHIFT 0L
-#define IOTAC_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI master enable
-// register.
-//
-//****************************************************************************
-#define PCPCIEN_EN 0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the joystick poll/trigger
-// register.
-//
-//****************************************************************************
-#define JSPT_CAX 0x00000001L
-#define JSPT_CAY 0x00000002L
-#define JSPT_CBX 0x00000004L
-#define JSPT_CBY 0x00000008L
-#define JSPT_BA1 0x00000010L
-#define JSPT_BA2 0x00000020L
-#define JSPT_BB1 0x00000040L
-#define JSPT_BB2 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the joystick control register.
-// The TBF bit has been moved from MIDSR register to JSCTL register bit 8.
-//
-//****************************************************************************
-#define JSCTL_SP_MASK 0x00000003L
-#define JSCTL_SP_SLOW 0x00000000L
-#define JSCTL_SP_MEDIUM_SLOW 0x00000001L
-#define JSCTL_SP_MEDIUM_FAST 0x00000002L
-#define JSCTL_SP_FAST 0x00000003L
-#define JSCTL_ARE 0x00000004L
-#define JSCTL_TBF 0x00000100L
-
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI control register.
-//
-//****************************************************************************
-#define MIDCR_TXE 0x00000001L
-#define MIDCR_RXE 0x00000002L
-#define MIDCR_RIE 0x00000004L
-#define MIDCR_TIE 0x00000008L
-#define MIDCR_MLB 0x00000010L
-#define MIDCR_MRST 0x00000020L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI status register.
-//
-//****************************************************************************
-#define MIDSR_RBE 0x00000080L
-#define MIDSR_RDA 0x00008000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI write port register.
-//
-//****************************************************************************
-#define MIDWP_MWD_MASK 0x000000FFL
-#define MIDWP_MWD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI read port register.
-//
-//****************************************************************************
-#define MIDRP_MRD_MASK 0x000000FFL
-#define MIDRP_MRD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the configuration interface
-// register.
-//
-//****************************************************************************
-#define CFGI_CLK 0x00000001L
-#define CFGI_DOUT 0x00000002L
-#define CFGI_DIN_EEN 0x00000004L
-#define CFGI_EELD 0x00000008L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the subsystem ID and vendor ID
-// register.
-//
-//****************************************************************************
-#define SSVID_VID_MASK 0x0000FFFFL
-#define SSVID_SID_MASK 0xFFFF0000L
-#define SSVID_VID_SHIFT 0L
-#define SSVID_SID_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the GPIO pin interface register.
-//
-//****************************************************************************
-#define GPIOR_VOLDN 0x00000001L
-#define GPIOR_VOLUP 0x00000002L
-#define GPIOR_SI2D 0x00000004L
-#define GPIOR_SI2OE 0x00000008L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status register 2.
-//
-//****************************************************************************
-#define ACSTS2_CRDY 0x00000001L
-#define ACSTS2_VSTS 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 input slot valid
-// register 2.
-//
-//****************************************************************************
-#define ACISV2_ISV3 0x00000001L
-#define ACISV2_ISV4 0x00000002L
-#define ACISV2_ISV5 0x00000004L
-#define ACISV2_ISV6 0x00000008L
-#define ACISV2_ISV7 0x00000010L
-#define ACISV2_ISV8 0x00000020L
-#define ACISV2_ISV9 0x00000040L
-#define ACISV2_ISV10 0x00000080L
-#define ACISV2_ISV11 0x00000100L
-#define ACISV2_ISV12 0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status address
-// register 2.
-//
-//****************************************************************************
-#define ACSAD2_SI_MASK 0x0000007FL
-#define ACSAD2_SI_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status data register 2.
-//
-//****************************************************************************
-#define ACSDA2_SD_MASK 0x0000FFFFL
-#define ACSDA2_SD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap control register.
-//
-//****************************************************************************
-#define IOTCR_ITD 0x00000001L
-#define IOTCR_HRV 0x00000002L
-#define IOTCR_SRV 0x00000004L
-#define IOTCR_DTI 0x00000008L
-#define IOTCR_DFI 0x00000010L
-#define IOTCR_DDP 0x00000020L
-#define IOTCR_JTE 0x00000040L
-#define IOTCR_PPE 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for Hardware Master Volume.
-//
-//****************************************************************************
-#define IOTGP_SA_MASK 0x0000FFFFL
-#define IOTGP_MSK_MASK 0x000F0000L
-#define IOTGP_IODC_MASK 0x06000000L
-#define IOTGP_IODC_16_BIT 0x00000000L
-#define IOTGP_IODC_10_BIT 0x02000000L
-#define IOTGP_IODC_12_BIT 0x04000000L
-#define IOTGP_WSPI 0x08000000L
-#define IOTGP_RSPI 0x10000000L
-#define IOTGP_WSE 0x20000000L
-#define IOTGP_WE 0x40000000L
-#define IOTGP_RE 0x80000000L
-#define IOTGP_SA_SHIFT 0L
-#define IOTGP_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for Sound Blaster
-//
-//****************************************************************************
-#define IOTSB_SA_MASK 0x0000FFFFL
-#define IOTSB_MSK_MASK 0x000F0000L
-#define IOTSB_IODC_MASK 0x06000000L
-#define IOTSB_IODC_16_BIT 0x00000000L
-#define IOTSB_IODC_10_BIT 0x02000000L
-#define IOTSB_IODC_12_BIT 0x04000000L
-#define IOTSB_WSPI 0x08000000L
-#define IOTSB_RSPI 0x10000000L
-#define IOTSB_WSE 0x20000000L
-#define IOTSB_WE 0x40000000L
-#define IOTSB_RE 0x80000000L
-#define IOTSB_SA_SHIFT 0L
-#define IOTSB_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for FM.
-//
-//****************************************************************************
-#define IOTFM_SA_MASK 0x0000FFFFL
-#define IOTFM_MSK_MASK 0x000F0000L
-#define IOTFM_IODC_MASK 0x06000000L
-#define IOTFM_IODC_16_BIT 0x00000000L
-#define IOTFM_IODC_10_BIT 0x02000000L
-#define IOTFM_IODC_12_BIT 0x04000000L
-#define IOTFM_WSPI 0x08000000L
-#define IOTFM_RSPI 0x10000000L
-#define IOTFM_WSE 0x20000000L
-#define IOTFM_WE 0x40000000L
-#define IOTFM_RE 0x80000000L
-#define IOTFM_SA_SHIFT 0L
-#define IOTFM_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI request register.
-//
-//****************************************************************************
-#define PCPRR_RDC_MASK 0x00000007L
-#define PCPRR_REQ 0x00008000L
-#define PCPRR_RDC_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI grant register.
-//
-//****************************************************************************
-#define PCPGR_GDC_MASK 0x00000007L
-#define PCPGR_VL 0x00008000L
-#define PCPGR_GDC_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI Control Register.
-//
-//****************************************************************************
-#define PCPCR_EN 0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the debug index register.
-//
-//****************************************************************************
-#define DREG_REGID_MASK 0x0000007FL
-#define DREG_DEBUG 0x00000080L
-#define DREG_RGBK_MASK 0x00000700L
-#define DREG_TRAP 0x00000800L
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_TRAPX 0x00001000L
-#endif
-#endif
-#define DREG_REGID_SHIFT 0L
-#define DREG_RGBK_SHIFT 8L
-#define DREG_RGBK_REGID_MASK 0x0000077FL
-#define DREG_REGID_R0 0x00000010L
-#define DREG_REGID_R1 0x00000011L
-#define DREG_REGID_R2 0x00000012L
-#define DREG_REGID_R3 0x00000013L
-#define DREG_REGID_R4 0x00000014L
-#define DREG_REGID_R5 0x00000015L
-#define DREG_REGID_R6 0x00000016L
-#define DREG_REGID_R7 0x00000017L
-#define DREG_REGID_R8 0x00000018L
-#define DREG_REGID_R9 0x00000019L
-#define DREG_REGID_RA 0x0000001AL
-#define DREG_REGID_RB 0x0000001BL
-#define DREG_REGID_RC 0x0000001CL
-#define DREG_REGID_RD 0x0000001DL
-#define DREG_REGID_RE 0x0000001EL
-#define DREG_REGID_RF 0x0000001FL
-#define DREG_REGID_RA_BUS_LOW 0x00000020L
-#define DREG_REGID_RA_BUS_HIGH 0x00000038L
-#define DREG_REGID_YBUS_LOW 0x00000050L
-#define DREG_REGID_YBUS_HIGH 0x00000058L
-#define DREG_REGID_TRAP_0 0x00000100L
-#define DREG_REGID_TRAP_1 0x00000101L
-#define DREG_REGID_TRAP_2 0x00000102L
-#define DREG_REGID_TRAP_3 0x00000103L
-#define DREG_REGID_TRAP_4 0x00000104L
-#define DREG_REGID_TRAP_5 0x00000105L
-#define DREG_REGID_TRAP_6 0x00000106L
-#define DREG_REGID_TRAP_7 0x00000107L
-#define DREG_REGID_INDIRECT_ADDRESS 0x0000010EL
-#define DREG_REGID_TOP_OF_STACK 0x0000010FL
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_8 0x00000110L
-#define DREG_REGID_TRAP_9 0x00000111L
-#define DREG_REGID_TRAP_10 0x00000112L
-#define DREG_REGID_TRAP_11 0x00000113L
-#define DREG_REGID_TRAP_12 0x00000114L
-#define DREG_REGID_TRAP_13 0x00000115L
-#define DREG_REGID_TRAP_14 0x00000116L
-#define DREG_REGID_TRAP_15 0x00000117L
-#define DREG_REGID_TRAP_16 0x00000118L
-#define DREG_REGID_TRAP_17 0x00000119L
-#define DREG_REGID_TRAP_18 0x0000011AL
-#define DREG_REGID_TRAP_19 0x0000011BL
-#define DREG_REGID_TRAP_20 0x0000011CL
-#define DREG_REGID_TRAP_21 0x0000011DL
-#define DREG_REGID_TRAP_22 0x0000011EL
-#define DREG_REGID_TRAP_23 0x0000011FL
-#endif
-#endif
-#define DREG_REGID_RSA0_LOW 0x00000200L
-#define DREG_REGID_RSA0_HIGH 0x00000201L
-#define DREG_REGID_RSA1_LOW 0x00000202L
-#define DREG_REGID_RSA1_HIGH 0x00000203L
-#define DREG_REGID_RSA2 0x00000204L
-#define DREG_REGID_RSA3 0x00000205L
-#define DREG_REGID_RSI0_LOW 0x00000206L
-#define DREG_REGID_RSI0_HIGH 0x00000207L
-#define DREG_REGID_RSI1 0x00000208L
-#define DREG_REGID_RSI2 0x00000209L
-#define DREG_REGID_SAGUSTATUS 0x0000020AL
-#define DREG_REGID_RSCONFIG01_LOW 0x0000020BL
-#define DREG_REGID_RSCONFIG01_HIGH 0x0000020CL
-#define DREG_REGID_RSCONFIG23_LOW 0x0000020DL
-#define DREG_REGID_RSCONFIG23_HIGH 0x0000020EL
-#define DREG_REGID_RSDMA01E 0x0000020FL
-#define DREG_REGID_RSDMA23E 0x00000210L
-#define DREG_REGID_RSD0_LOW 0x00000211L
-#define DREG_REGID_RSD0_HIGH 0x00000212L
-#define DREG_REGID_RSD1_LOW 0x00000213L
-#define DREG_REGID_RSD1_HIGH 0x00000214L
-#define DREG_REGID_RSD2_LOW 0x00000215L
-#define DREG_REGID_RSD2_HIGH 0x00000216L
-#define DREG_REGID_RSD3_LOW 0x00000217L
-#define DREG_REGID_RSD3_HIGH 0x00000218L
-#define DREG_REGID_SRAR_HIGH 0x0000021AL
-#define DREG_REGID_SRAR_LOW 0x0000021BL
-#define DREG_REGID_DMA_STATE 0x0000021CL
-#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021DL
-#define DREG_REGID_NEXT_DMA_STREAM 0x0000021EL
-#define DREG_REGID_CPU_STATUS 0x00000300L
-#define DREG_REGID_MAC_MODE 0x00000301L
-#define DREG_REGID_STACK_AND_REPEAT 0x00000302L
-#define DREG_REGID_INDEX0 0x00000304L
-#define DREG_REGID_INDEX1 0x00000305L
-#define DREG_REGID_DMA_STATE_0_3 0x00000400L
-#define DREG_REGID_DMA_STATE_4_7 0x00000404L
-#define DREG_REGID_DMA_STATE_8_11 0x00000408L
-#define DREG_REGID_DMA_STATE_12_15 0x0000040CL
-#define DREG_REGID_DMA_STATE_16_19 0x00000410L
-#define DREG_REGID_DMA_STATE_20_23 0x00000414L
-#define DREG_REGID_DMA_STATE_24_27 0x00000418L
-#define DREG_REGID_DMA_STATE_28_31 0x0000041CL
-#define DREG_REGID_DMA_STATE_32_35 0x00000420L
-#define DREG_REGID_DMA_STATE_36_39 0x00000424L
-#define DREG_REGID_DMA_STATE_40_43 0x00000428L
-#define DREG_REGID_DMA_STATE_44_47 0x0000042CL
-#define DREG_REGID_DMA_STATE_48_51 0x00000430L
-#define DREG_REGID_DMA_STATE_52_55 0x00000434L
-#define DREG_REGID_DMA_STATE_56_59 0x00000438L
-#define DREG_REGID_DMA_STATE_60_63 0x0000043CL
-#define DREG_REGID_DMA_STATE_64_67 0x00000440L
-#define DREG_REGID_DMA_STATE_68_71 0x00000444L
-#define DREG_REGID_DMA_STATE_72_75 0x00000448L
-#define DREG_REGID_DMA_STATE_76_79 0x0000044CL
-#define DREG_REGID_DMA_STATE_80_83 0x00000450L
-#define DREG_REGID_DMA_STATE_84_87 0x00000454L
-#define DREG_REGID_DMA_STATE_88_91 0x00000458L
-#define DREG_REGID_DMA_STATE_92_95 0x0000045CL
-#define DREG_REGID_TRAP_SELECT 0x00000500L
-#define DREG_REGID_TRAP_WRITE_0 0x00000500L
-#define DREG_REGID_TRAP_WRITE_1 0x00000501L
-#define DREG_REGID_TRAP_WRITE_2 0x00000502L
-#define DREG_REGID_TRAP_WRITE_3 0x00000503L
-#define DREG_REGID_TRAP_WRITE_4 0x00000504L
-#define DREG_REGID_TRAP_WRITE_5 0x00000505L
-#define DREG_REGID_TRAP_WRITE_6 0x00000506L
-#define DREG_REGID_TRAP_WRITE_7 0x00000507L
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_WRITE_8 0x00000510L
-#define DREG_REGID_TRAP_WRITE_9 0x00000511L
-#define DREG_REGID_TRAP_WRITE_10 0x00000512L
-#define DREG_REGID_TRAP_WRITE_11 0x00000513L
-#define DREG_REGID_TRAP_WRITE_12 0x00000514L
-#define DREG_REGID_TRAP_WRITE_13 0x00000515L
-#define DREG_REGID_TRAP_WRITE_14 0x00000516L
-#define DREG_REGID_TRAP_WRITE_15 0x00000517L
-#define DREG_REGID_TRAP_WRITE_16 0x00000518L
-#define DREG_REGID_TRAP_WRITE_17 0x00000519L
-#define DREG_REGID_TRAP_WRITE_18 0x0000051AL
-#define DREG_REGID_TRAP_WRITE_19 0x0000051BL
-#define DREG_REGID_TRAP_WRITE_20 0x0000051CL
-#define DREG_REGID_TRAP_WRITE_21 0x0000051DL
-#define DREG_REGID_TRAP_WRITE_22 0x0000051EL
-#define DREG_REGID_TRAP_WRITE_23 0x0000051FL
-#endif
-#endif
-#define DREG_REGID_MAC0_ACC0_LOW 0x00000600L
-#define DREG_REGID_MAC0_ACC1_LOW 0x00000601L
-#define DREG_REGID_MAC0_ACC2_LOW 0x00000602L
-#define DREG_REGID_MAC0_ACC3_LOW 0x00000603L
-#define DREG_REGID_MAC1_ACC0_LOW 0x00000604L
-#define DREG_REGID_MAC1_ACC1_LOW 0x00000605L
-#define DREG_REGID_MAC1_ACC2_LOW 0x00000606L
-#define DREG_REGID_MAC1_ACC3_LOW 0x00000607L
-#define DREG_REGID_MAC0_ACC0_MID 0x00000608L
-#define DREG_REGID_MAC0_ACC1_MID 0x00000609L
-#define DREG_REGID_MAC0_ACC2_MID 0x0000060AL
-#define DREG_REGID_MAC0_ACC3_MID 0x0000060BL
-#define DREG_REGID_MAC1_ACC0_MID 0x0000060CL
-#define DREG_REGID_MAC1_ACC1_MID 0x0000060DL
-#define DREG_REGID_MAC1_ACC2_MID 0x0000060EL
-#define DREG_REGID_MAC1_ACC3_MID 0x0000060FL
-#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610L
-#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611L
-#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612L
-#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613L
-#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614L
-#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615L
-#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616L
-#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617L
-#define DREG_REGID_RSHOUT_LOW 0x00000620L
-#define DREG_REGID_RSHOUT_MID 0x00000628L
-#define DREG_REGID_RSHOUT_HIGH 0x00000630L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 S/PDIF Control register.
-//
-//****************************************************************************
-#define SPDIF_CONTROL_SPDIF_EN 0x00008000L
-#define SPDIF_CONTROL_VAL 0x00004000L
-#define SPDIF_CONTROL_COPY 0x00000004L
-#define SPDIF_CONTROL_CC0 0x00000010L
-#define SPDIF_CONTROL_CC1 0x00000020L
-#define SPDIF_CONTROL_CC2 0x00000040L
-#define SPDIF_CONTROL_CC3 0x00000080L
-#define SPDIF_CONTROL_CC4 0x00000100L
-#define SPDIF_CONTROL_CC5 0x00000200L
-#define SPDIF_CONTROL_CC6 0x00000400L
-#define SPDIF_CONTROL_L 0x00000800L
-
-#endif // _H_HWDEFS
diff --git a/sound/oss/cs4281/cs4281_wrapper-24.c b/sound/oss/cs4281/cs4281_wrapper-24.c
deleted file mode 100644
index 4559f02..0000000
--- a/sound/oss/cs4281/cs4281_wrapper-24.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
-*
-* "cs4281_wrapper.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.com).
-*
-* 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.
-*
-* 12/20/00 trw - new file.
-*
-*******************************************************************************/
-
-#include <linux/spinlock.h>
-
-static int cs4281_resume_null(struct pci_dev *pcidev) { return 0; }
-static int cs4281_suspend_null(struct pci_dev *pcidev, pm_message_t state) { return 0; }
-
-#define free_dmabuf(state, dmabuf) \
- pci_free_consistent(state->pcidev, \
- PAGE_SIZE << (dmabuf)->buforder, \
- (dmabuf)->rawbuf, (dmabuf)->dmaaddr);
-#define free_dmabuf2(state, dmabuf) \
- pci_free_consistent((state)->pcidev, \
- PAGE_SIZE << (state)->buforder_tmpbuff, \
- (state)->tmpbuff, (state)->dmaaddr_tmpbuff);
-#define cs4x_pgoff(vma) ((vma)->vm_pgoff)
-
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
deleted file mode 100644
index 0400a41..0000000
--- a/sound/oss/cs4281/cs4281m.c
+++ /dev/null
@@ -1,4487 +0,0 @@
-/*******************************************************************************
-*
-* "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- adapted from drivers by Thomas Sailer,
-* -- but don't bug him; Problems should go to:
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.com).
-*
-* 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.
-*
-* Module command line parameters:
-* none
-*
-* Supported devices:
-* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
-* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
-* /dev/midi simple MIDI UART interface, no ioctl
-*
-* Modification History
-* 08/20/00 trw - silence and no stopping DAC until release
-* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop.
-* 09/18/00 trw - added 16bit only record with conversion
-* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous
-* capture/playback rates)
-* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin
-* libOSSm.so)
-* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal)
-* 11/03/00 trw - fixed interrupt loss/stutter, added debug.
-* 11/10/00 bkz - added __devinit to cs4281_hw_init()
-* 11/10/00 trw - fixed SMP and capture spinlock hang.
-* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm.
-* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix.
-* 12/08/00 trw - added PM support.
-* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8
-* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident.
-* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup.
-* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use
-* defaultorder-100 as power of 2 for the buffer size. example:
-* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
-*
-*******************************************************************************/
-
-/* uncomment the following line to disable building PM support into the driver */
-//#define NOT_CS4281_PM 1
-
-#include <linux/list.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/bitops.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/wait.h>
-
-#include <asm/current.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-//#include "cs_dm.h"
-#include "cs4281_hwdefs.h"
-#include "cs4281pm.h"
-
-struct cs4281_state;
-
-static void stop_dac(struct cs4281_state *s);
-static void stop_adc(struct cs4281_state *s);
-static void start_dac(struct cs4281_state *s);
-static void start_adc(struct cs4281_state *s);
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-// ---------------------------------------------------------------------
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281
-#define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005
-#endif
-
-#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)
-#define CS4281_CFLR_DEFAULT 0x00000001 /* CFLR must be in AC97 link mode */
-
-// buffer order determines the size of the dma buffer for the driver.
-// under Linux, a smaller buffer allows more responsiveness from many of the
-// applications (e.g. games). A larger buffer allows some of the apps (esound)
-// to not underrun the dma buffer as easily. As default, use 32k (order=3)
-// rather than 64k as some of the games work more responsively.
-// log base 2( buff sz = 32k).
-static unsigned long defaultorder = 3;
-module_param(defaultorder, ulong, 0);
-
-//
-// Turn on/off debugging compilation by commenting out "#define CSDEBUG"
-//
-#define CSDEBUG 1
-#if CSDEBUG
-#define CSDEBUG_INTERFACE 1
-#else
-#undef CSDEBUG_INTERFACE
-#endif
-//
-// cs_debugmask areas
-//
-#define CS_INIT 0x00000001 // initialization and probe functions
-#define CS_ERROR 0x00000002 // tmp debugging bit placeholder
-#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other)
-#define CS_FUNCTION 0x00000008 // enter/leave functions
-#define CS_WAVE_WRITE 0x00000010 // write information for wave
-#define CS_WAVE_READ 0x00000020 // read information for wave
-#define CS_MIDI_WRITE 0x00000040 // write information for midi
-#define CS_MIDI_READ 0x00000080 // read information for midi
-#define CS_MPU401_WRITE 0x00000100 // write information for mpu401
-#define CS_MPU401_READ 0x00000200 // read information for mpu401
-#define CS_OPEN 0x00000400 // all open functions in the driver
-#define CS_RELEASE 0x00000800 // all release functions in the driver
-#define CS_PARMS 0x00001000 // functional and operational parameters
-#define CS_IOCTL 0x00002000 // ioctl (non-mixer)
-#define CS_PM 0x00004000 // power management
-#define CS_TMP 0x10000000 // tmp debug mask bit
-
-#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend
-#define CS_IOCTL_CMD_RESUME 0x2 // resume
-//
-// CSDEBUG is usual mode is set to 1, then use the
-// cs_debuglevel and cs_debugmask to turn on or off debugging.
-// Debug level of 1 has been defined to be kernel errors and info
-// that should be printed on any released driver.
-//
-#if CSDEBUG
-#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;}
-#else
-#define CS_DBGOUT(mask,level,x)
-#endif
-
-#if CSDEBUG
-static unsigned long cs_debuglevel = 1; // levels range from 1-9
-static unsigned long cs_debugmask = CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values
-module_param(cs_debuglevel, ulong, 0);
-module_param(cs_debugmask, ulong, 0);
-#endif
-#define CS_TRUE 1
-#define CS_FALSE 0
-
-// MIDI buffer sizes
-#define MIDIINBUF 500
-#define MIDIOUTBUF 500
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define CS4281_MAJOR_VERSION 1
-#define CS4281_MINOR_VERSION 13
-#ifdef __ia64__
-#define CS4281_ARCH 64 //architecture key
-#else
-#define CS4281_ARCH 32 //architecture key
-#endif
-
-#define CS_TYPE_ADC 0
-#define CS_TYPE_DAC 1
-
-
-static const char invalid_magic[] =
- KERN_CRIT "cs4281: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != CS4281_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-//LIST_HEAD(cs4281_devs);
-static struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs };
-
-struct cs4281_state;
-
-#include "cs4281_wrapper-24.c"
-
-struct cs4281_state {
- // magic
- unsigned int magic;
-
- // we keep the cards in a linked list
- struct cs4281_state *next;
-
- // pcidev is needed to turn off the DDMA controller at driver shutdown
- struct pci_dev *pcidev;
- struct list_head list;
-
- // soundcore stuff
- int dev_audio;
- int dev_mixer;
- int dev_midi;
-
- // hardware resources
- unsigned int pBA0phys, pBA1phys;
- char __iomem *pBA0;
- char __iomem *pBA1;
- unsigned int irq;
-
- // mixer registers
- struct {
- unsigned short vol[10];
- unsigned int recsrc;
- unsigned int modcnt;
- unsigned short micpreamp;
- } mix;
-
- // wave stuff
- struct properties {
- unsigned fmt;
- unsigned fmt_original; // original requested format
- unsigned channels;
- unsigned rate;
- unsigned char clkdiv;
- } prop_dac, prop_adc;
- unsigned conversion:1; // conversion from 16 to 8 bit in progress
- void *tmpbuff; // tmp buffer for sample conversions
- unsigned ena;
- spinlock_t lock;
- struct mutex open_sem;
- struct mutex open_sem_adc;
- struct mutex open_sem_dac;
- mode_t open_mode;
- wait_queue_head_t open_wait;
- wait_queue_head_t open_wait_adc;
- wait_queue_head_t open_wait_dac;
-
- dma_addr_t dmaaddr_tmpbuff;
- unsigned buforder_tmpbuff; // Log base 2 of 'rawbuf' size in bytes..
- struct dmabuf {
- void *rawbuf; // Physical address of
- dma_addr_t dmaaddr;
- unsigned buforder; // Log base 2 of 'rawbuf' size in bytes..
- unsigned numfrag; // # of 'fragments' in the buffer.
- unsigned fragshift; // Log base 2 of fragment size.
- unsigned hwptr, swptr;
- unsigned total_bytes; // # bytes process since open.
- unsigned blocks; // last returned blocks value GETOPTR
- unsigned wakeup; // interrupt occurred on block
- int count;
- unsigned underrun; // underrun flag
- unsigned error; // over/underrun
- wait_queue_head_t wait;
- // redundant, but makes calculations easier
- unsigned fragsize; // 2**fragshift..
- unsigned dmasize; // 2**buforder.
- unsigned fragsamples;
- // OSS stuff
- unsigned mapped:1; // Buffer mapped in cs4281_mmap()?
- unsigned ready:1; // prog_dmabuf_dac()/adc() successful?
- unsigned endcleared:1;
- unsigned type:1; // adc or dac buffer (CS_TYPE_XXX)
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-
- // midi stuff
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- struct timer_list timer;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
- struct cs4281_pm pm;
- struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES];
-};
-
-#include "cs4281pm-24.c"
-
-#if CSDEBUG
-
-// DEBUG ROUTINES
-
-#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
-#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
-#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
-#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
-
-#define SOUND_MIXER_CS_APM _SIOWR('M',124, int)
-
-
-static void cs_printioctl(unsigned int x)
-{
- unsigned int i;
- unsigned char vidx;
- // Index of mixtable1[] member is Device ID
- // and must be <= SOUND_MIXER_NRDEVICES.
- // Value of array member is index into s->mix.vol[]
- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, // voice
- [SOUND_MIXER_LINE1] = 2, // AUX
- [SOUND_MIXER_CD] = 3, // CD
- [SOUND_MIXER_LINE] = 4, // Line
- [SOUND_MIXER_SYNTH] = 5, // FM
- [SOUND_MIXER_MIC] = 6, // Mic
- [SOUND_MIXER_SPEAKER] = 7, // Speaker
- [SOUND_MIXER_RECLEV] = 8, // Recording level
- [SOUND_MIXER_VOLUME] = 9 // Master Volume
- };
-
- switch (x) {
- case SOUND_MIXER_CS_GETDBGMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_GETDBGMASK:\n"));
- break;
- case SOUND_MIXER_CS_GETDBGLEVEL:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_GETDBGLEVEL:\n"));
- break;
- case SOUND_MIXER_CS_SETDBGMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_SETDBGMASK:\n"));
- break;
- case SOUND_MIXER_CS_SETDBGLEVEL:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_SETDBGLEVEL:\n"));
- break;
- case OSS_GETVERSION:
- CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n"));
- break;
- case SNDCTL_DSP_SYNC:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n"));
- break;
- case SNDCTL_DSP_SETDUPLEX:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n"));
- break;
- case SNDCTL_DSP_GETCAPS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n"));
- break;
- case SNDCTL_DSP_RESET:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n"));
- break;
- case SNDCTL_DSP_SPEED:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n"));
- break;
- case SNDCTL_DSP_STEREO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n"));
- break;
- case SNDCTL_DSP_CHANNELS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n"));
- break;
- case SNDCTL_DSP_GETFMTS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n"));
- break;
- case SNDCTL_DSP_SETFMT:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n"));
- break;
- case SNDCTL_DSP_POST:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n"));
- break;
- case SNDCTL_DSP_GETTRIGGER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n"));
- break;
- case SNDCTL_DSP_SETTRIGGER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n"));
- break;
- case SNDCTL_DSP_GETOSPACE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n"));
- break;
- case SNDCTL_DSP_GETISPACE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n"));
- break;
- case SNDCTL_DSP_NONBLOCK:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n"));
- break;
- case SNDCTL_DSP_GETODELAY:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n"));
- break;
- case SNDCTL_DSP_GETIPTR:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n"));
- break;
- case SNDCTL_DSP_GETOPTR:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n"));
- break;
- case SNDCTL_DSP_GETBLKSIZE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n"));
- break;
- case SNDCTL_DSP_SETFRAGMENT:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SNDCTL_DSP_SETFRAGMENT:\n"));
- break;
- case SNDCTL_DSP_SUBDIVIDE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n"));
- break;
- case SOUND_PCM_READ_RATE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n"));
- break;
- case SOUND_PCM_READ_CHANNELS:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_PCM_READ_CHANNELS:\n"));
- break;
- case SOUND_PCM_READ_BITS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n"));
- break;
- case SOUND_PCM_WRITE_FILTER:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_PCM_WRITE_FILTER:\n"));
- break;
- case SNDCTL_DSP_SETSYNCRO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n"));
- break;
- case SOUND_PCM_READ_FILTER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n"));
- break;
- case SOUND_MIXER_PRIVATE1:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n"));
- break;
- case SOUND_MIXER_PRIVATE2:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n"));
- break;
- case SOUND_MIXER_PRIVATE3:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n"));
- break;
- case SOUND_MIXER_PRIVATE4:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n"));
- break;
- case SOUND_MIXER_PRIVATE5:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n"));
- break;
- case SOUND_MIXER_INFO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n"));
- break;
- case SOUND_OLD_MIXER_INFO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n"));
- break;
-
- default:
- switch (_IOC_NR(x)) {
- case SOUND_MIXER_VOLUME:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_VOLUME:\n"));
- break;
- case SOUND_MIXER_SPEAKER:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_SPEAKER:\n"));
- break;
- case SOUND_MIXER_RECLEV:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_RECLEV:\n"));
- break;
- case SOUND_MIXER_MIC:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_MIC:\n"));
- break;
- case SOUND_MIXER_SYNTH:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_SYNTH:\n"));
- break;
- case SOUND_MIXER_RECSRC:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_RECSRC:\n"));
- break;
- case SOUND_MIXER_DEVMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_DEVMASK:\n"));
- break;
- case SOUND_MIXER_RECMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_RECMASK:\n"));
- break;
- case SOUND_MIXER_STEREODEVS:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_STEREODEVS:\n"));
- break;
- case SOUND_MIXER_CAPS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n"));
- break;
- default:
- i = _IOC_NR(x);
- if (i >= SOUND_MIXER_NRDEVICES
- || !(vidx = mixtable1[i])) {
- CS_DBGOUT(CS_IOCTL, 4, printk
- ("UNKNOWN IOCTL: 0x%.8x NR=%d\n",
- x, i));
- } else {
- CS_DBGOUT(CS_IOCTL, 4, printk
- ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n",
- x, i));
- }
- break;
- }
- }
-}
-#endif
-static int prog_dmabuf_adc(struct cs4281_state *s);
-static void prog_codec(struct cs4281_state *s, unsigned type);
-
-// ---------------------------------------------------------------------
-//
-// Hardware Interfaces For the CS4281
-//
-
-
-//******************************************************************************
-// "delayus()-- Delay for the specified # of microseconds.
-//******************************************************************************
-static void delayus(struct cs4281_state *s, u32 delay)
-{
- u32 j;
- if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) {
- j = (delay * HZ) / 1000000; /* calculate delay in jiffies */
- if (j < 1)
- j = 1; /* minimum one jiffy. */
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(j);
- } else
- udelay(delay);
- return;
-}
-
-
-//******************************************************************************
-// "cs4281_read_ac97" -- Reads a word from the specified location in the
-// CS4281's address space(based on the BA0 register).
-//
-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register,
-// 0h for reads.
-// 3. Write ACCTL = Control Register = 460h for initiating the write
-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
-// 5. if DCV not cleared, break and return error
-// 6. Read ACSTS = Status Register = 464h, check VSTS bit
-//****************************************************************************
-static int cs4281_read_ac97(struct cs4281_state *card, u32 offset,
- u32 * value)
-{
- u32 count, status;
-
- // Make sure that there is not data sitting
- // around from a previous uncompleted access.
- // ACSDA = Status Data Register = 47Ch
- status = readl(card->pBA0 + BA0_ACSDA);
-
- // Setup the AC97 control registers on the CS4281 to send the
- // appropriate command to the AC97 to perform the read.
- // ACCAD = Command Address Register = 46Ch
- // ACCDA = Command Data Register = 470h
- // ACCTL = Control Register = 460h
- // bit DCV - will clear when process completed
- // bit CRW - Read command
- // bit VFRM - valid frame enabled
- // bit ESYN - ASYNC generation enabled
-
- // Get the actual AC97 register from the offset
- writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
- writel(0, card->pBA0 + BA0_ACCDA);
- writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN,
- card->pBA0 + BA0_ACCTL);
-
- // Wait for the read to occur.
- for (count = 0; count < 10; count++) {
- // First, we want to wait for a short time.
- udelay(25);
-
- // Now, check to see if the read has completed.
- // ACCTL = 460h, DCV should be reset by now and 460h = 17h
- if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV))
- break;
- }
-
- // Make sure the read completed.
- if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)
- return 1;
-
- // Wait for the valid status bit to go active.
- for (count = 0; count < 10; count++) {
- // Read the AC97 status register.
- // ACSTS = Status Register = 464h
- status = readl(card->pBA0 + BA0_ACSTS);
-
- // See if we have valid status.
- // VSTS - Valid Status
- if (status & ACSTS_VSTS)
- break;
- // Wait for a short while.
- udelay(25);
- }
-
- // Make sure we got valid status.
- if (!(status & ACSTS_VSTS))
- return 1;
-
- // Read the data returned from the AC97 register.
- // ACSDA = Status Data Register = 474h
- *value = readl(card->pBA0 + BA0_ACSDA);
-
- // Success.
- return (0);
-}
-
-
-//****************************************************************************
-//
-// "cs4281_write_ac97()"-- writes a word to the specified location in the
-// CS461x's address space (based on the part's base address zero register).
-//
-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg.
-// 3. Write ACCTL = Control Register = 460h for initiating the write
-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
-// 5. if DCV not cleared, break and return error
-//
-//****************************************************************************
-static int cs4281_write_ac97(struct cs4281_state *card, u32 offset,
- u32 value)
-{
- u32 count, status=0;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n"));
-
- // Setup the AC97 control registers on the CS4281 to send the
- // appropriate command to the AC97 to perform the read.
- // ACCAD = Command Address Register = 46Ch
- // ACCDA = Command Data Register = 470h
- // ACCTL = Control Register = 460h
- // set DCV - will clear when process completed
- // reset CRW - Write command
- // set VFRM - valid frame enabled
- // set ESYN - ASYNC generation enabled
- // set RSTN - ARST# inactive, AC97 codec not reset
-
- // Get the actual AC97 register from the offset
-
- writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
- writel(value, card->pBA0 + BA0_ACCDA);
- writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN,
- card->pBA0 + BA0_ACCTL);
-
- // Wait for the write to occur.
- for (count = 0; count < 100; count++) {
- // First, we want to wait for a short time.
- udelay(25);
- // Now, check to see if the write has completed.
- // ACCTL = 460h, DCV should be reset by now and 460h = 07h
- status = readl(card->pBA0 + BA0_ACCTL);
- if (!(status & ACCTL_DCV))
- break;
- }
-
- // Make sure the write completed.
- if (status & ACCTL_DCV) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n"));
- return 1;
- }
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n"));
- // Success.
- return 0;
-}
-
-
-//******************************************************************************
-// "Init4281()" -- Bring up the part.
-//******************************************************************************
-static __devinit int cs4281_hw_init(struct cs4281_state *card)
-{
- u32 ac97_slotid;
- u32 temp1, temp2;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n"));
-#ifndef NOT_CS4281_PM
- if(!card)
- return 1;
-#endif
- temp2 = readl(card->pBA0 + BA0_CFLR);
- CS_DBGOUT(CS_INIT | CS_ERROR | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_hw_init() CFLR 0x%x\n", temp2));
- if(temp2 != CS4281_CFLR_DEFAULT)
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
- "cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n",
- temp2,CS4281_CFLR_DEFAULT));
- writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR);
- temp2 = readl(card->pBA0 + BA0_CFLR);
- if(temp2 != CS4281_CFLR_DEFAULT)
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
- "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n"));
- return 1;
- }
- }
-
- //***************************************7
- // Set up the Sound System Configuration
- //***************************************
-
- // Set the 'Configuration Write Protect' register
- // to 4281h. Allows vendor-defined configuration
- // space between 0e4h and 0ffh to be written.
-
- writel(0x4281, card->pBA0 + BA0_CWPR); // (3e0h)
-
- // (0), Blast the clock control register to zero so that the
- // PLL starts out in a known state, and blast the master serial
- // port control register to zero so that the serial ports also
- // start out in a known state.
-
- writel(0, card->pBA0 + BA0_CLKCR1); // (400h)
- writel(0, card->pBA0 + BA0_SERMC); // (420h)
-
-
- // (1), Make ESYN go to zero to turn off
- // the Sync pulse on the AC97 link.
-
- writel(0, card->pBA0 + BA0_ACCTL);
- udelay(50);
-
-
- // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in
- // the AC97 spec) and then drive it high. This is done for non
- // AC97 modes since there might be logic external to the CS461x
- // that uses the ARST# line for a reset.
-
- writel(0, card->pBA0 + BA0_SPMC); // (3ech)
- udelay(100);
- writel(SPMC_RSTN, card->pBA0 + BA0_SPMC);
- delayus(card,50000); // Wait 50 ms for ABITCLK to become stable.
-
- // (3) Turn on the Sound System Clocks.
- writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1); // (400h)
- delayus(card,50000); // Wait for the PLL to stabilize.
- // Turn on clocking of the core (CLKCR1(400h) = 0x00000030)
- writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1);
-
- // (4) Power on everything for now..
- writel(0x7E, card->pBA0 + BA0_SSPM); // (740h)
-
- // (5) Wait for clock stabilization.
- for (temp1 = 0; temp1 < 1000; temp1++) {
- udelay(1000);
- if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)
- break;
- }
- if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: DLLRDY failed!\n"));
- return -EIO;
- }
- // (6) Enable ASYNC generation.
- writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
-
- // Now wait 'for a short while' to allow the AC97
- // part to start generating bit clock. (so we don't
- // Try to start the PLL without an input clock.)
- delayus(card,50000);
-
- // Set the serial port timing configuration, so that the
- // clock control circuit gets its clock from the right place.
- writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
-
- // (7) Wait for the codec ready signal from the AC97 codec.
-
- for (temp1 = 0; temp1 < 1000; temp1++) {
- // Delay a mil to let things settle out and
- // to prevent retrying the read too quickly.
- udelay(1000);
- if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY) // If ready, (464h)
- break; // exit the 'for' loop.
- }
- if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)) // If never came ready,
- {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
- "cs4281: ACSTS never came ready!\n"));
- return -EIO; // exit initialization.
- }
- // (8) Assert the 'valid frame' signal so we can
- // begin sending commands to the AC97 codec.
- writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
-
- // (9), Wait until CODEC calibration is finished.
- // Print an error message if it doesn't.
- for (temp1 = 0; temp1 < 1000; temp1++) {
- delayus(card,10000);
- // Read the AC97 Powerdown Control/Status Register.
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2);
- if ((temp2 & 0x0000000F) == 0x0000000F)
- break;
- }
- if ((temp2 & 0x0000000F) != 0x0000000F) {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
- "cs4281: Codec failed to calibrate. Status = %.8x.\n",
- temp2));
- return -EIO;
- }
- // (10), Set the serial port timing configuration, so that the
- // clock control circuit gets its clock from the right place.
- writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
-
-
- // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning
- // that the codec is pumping ADC data across the AC link.
- for (temp1 = 0; temp1 < 1000; temp1++) {
- // Delay a mil to let things settle out and
- // to prevent retrying the read too quickly.
- delayus(card,1000); //(test)
-
- // Read the input slot valid register; See
- // if input slots 3 and 4 are valid yet.
- if (
- (readl(card->pBA0 + BA0_ACISV) &
- (ACISV_ISV3 | ACISV_ISV4)) ==
- (ACISV_ISV3 | ACISV_ISV4)) break; // Exit the 'for' if slots are valid.
- }
- // If we never got valid data, exit initialization.
- if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4))
- != (ACISV_ISV3 | ACISV_ISV4)) {
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_ERR
- "cs4281: Never got valid data!\n"));
- return -EIO; // If no valid data, exit initialization.
- }
- // (12), Start digital data transfer of audio data to the codec.
- writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV); // (468h)
-
-
- //**************************************
- // Unmute the Master and Alternate
- // (headphone) volumes. Set to max.
- //**************************************
- cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0);
- cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0);
-
- //******************************************
- // Power on the DAC(AddDACUser()from main())
- //******************************************
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff);
-
- // Wait until we sample a DAC ready state.
- for (temp2 = 0; temp2 < 32; temp2++) {
- // Let's wait a mil to let things settle.
- delayus(card,1000);
- // Read the current state of the power control reg.
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- // If the DAC ready state bit is set, stop waiting.
- if (temp1 & 0x2)
- break;
- }
-
- //******************************************
- // Power on the ADC(AddADCUser()from main())
- //******************************************
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff);
-
- // Wait until we sample ADC ready state.
- for (temp2 = 0; temp2 < 32; temp2++) {
- // Let's wait a mil to let things settle.
- delayus(card,1000);
- // Read the current state of the power control reg.
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- // If the ADC ready state bit is set, stop waiting.
- if (temp1 & 0x1)
- break;
- }
- // Set up 4281 Register contents that
- // don't change for boot duration.
-
- // For playback, we map AC97 slot 3 and 4(Left
- // & Right PCM playback) to DMA Channel 0.
- // Set the fifo to be 15 bytes at offset zero.
-
- ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback).
- // FCR0.LS[4:0]=0(=>slot3, left PCM playback).
- // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.
- writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h)
- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable.
-
- // For capture, we map AC97 slot 10 and 11(Left
- // and Right PCM Record) to DMA Channel 1.
- // Set the fifo to be 15 bytes at offset sixteen.
- ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record).
- // FCR1.LS[4:0]=10(=>slot10, left PCM record).
- // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.
- writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h)
- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable.
-
- // Map the Playback SRC to the same AC97 slots(3 & 4--
- // --Playback left & right)as DMA channel 0.
- // Map the record SRC to the same AC97 slots(10 & 11--
- // -- Record left & right) as DMA channel 1.
-
- ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback).
- // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).
- // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)
- // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).
- writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch)
-
- // Set 'Half Terminal Count Interrupt Enable' and 'Terminal
- // Count Interrupt Enable' in DMA Control Registers 0 & 1.
- // Set 'MSK' flag to 1 to keep the DMA engines paused.
- temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h)
- writel(temp1, card->pBA0 + BA0_DCR0); // (154h
- writel(temp1, card->pBA0 + BA0_DCR1); // (15ch)
-
- // Set 'Auto-Initialize Control' to 'enabled'; For playback,
- // set 'Transfer Type Control'(TR[1:0]) to 'read transfer',
- // for record, set Transfer Type Control to 'write transfer'.
- // All other bits set to zero; Some will be changed @ transfer start.
- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h)
- writel(temp1, card->pBA0 + BA0_DMR0); // (150h)
- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h)
- writel(temp1, card->pBA0 + BA0_DMR1); // (158h)
-
- // Enable DMA interrupts generally, and
- // DMA0 & DMA1 interrupts specifically.
- temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;
- writel(temp1, card->pBA0 + BA0_HIMR);
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n"));
- return 0;
-}
-
-#ifndef NOT_CS4281_PM
-static void printpm(struct cs4281_state *s)
-{
- CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
- CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
- (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
- CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
- s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
- s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
- s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
- s->pm.u32SSCR,s->pm.u32SRCSA));
- CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
- s->pm.u32DacASR,s->pm.u32AdcASR));
- CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
- s->pm.u32DacSR,s->pm.u32AdcSR));
- CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
- s->pm.u32MIDCR_Save));
-
-}
-static void printpipe(struct cs4281_pipeline *pl)
-{
-
- CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
- CS_DBGOUT(CS_PM, 9, printk("flags:0x%x number: 0%x\n",
- (unsigned)pl->flags,pl->number));
- CS_DBGOUT(CS_PM, 9, printk("u32DBAnValue: 0%x u32DBCnValue: 0x%x\n",
- pl->u32DBAnValue,pl->u32DBCnValue));
- CS_DBGOUT(CS_PM, 9, printk("u32DMRnValue: 0x%x u32DCRnValue: 0x%x\n",
- pl->u32DMRnValue,pl->u32DCRnValue));
- CS_DBGOUT(CS_PM, 9, printk("u32DBAnAddress: 0x%x u32DBCnAddress: 0x%x\n",
- pl->u32DBAnAddress,pl->u32DBCnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32DCAnAddress: 0x%x u32DCCnAddress: 0x%x\n",
- pl->u32DCCnAddress,pl->u32DCCnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32DMRnAddress: 0x%x u32DCRnAddress: 0x%x\n",
- pl->u32DMRnAddress,pl->u32DCRnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32HDSRnAddress: 0x%x u32DBAn_Save: 0x%x\n",
- pl->u32HDSRnAddress,pl->u32DBAn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32DBCn_Save: 0x%x u32DMRn_Save: 0x%x\n",
- pl->u32DBCn_Save,pl->u32DMRn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32DCRn_Save: 0x%x u32DCCn_Save: 0x%x\n",
- pl->u32DCRn_Save,pl->u32DCCn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32DCAn_Save: 0x%x\n",
- pl->u32DCAn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32FCRn_Save: 0x%x u32FSICn_Save: 0x%x\n",
- pl->u32FCRn_Save,pl->u32FSICn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32FCRnValue: 0x%x u32FSICnValue: 0x%x\n",
- pl->u32FCRnValue,pl->u32FSICnValue));
- CS_DBGOUT(CS_PM, 9, printk("u32FCRnAddress: 0x%x u32FSICnAddress: 0x%x\n",
- pl->u32FCRnAddress,pl->u32FSICnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32FPDRnValue: 0x%x u32FPDRnAddress: 0x%x\n",
- pl->u32FPDRnValue,pl->u32FPDRnAddress));
-}
-static void printpipelines(struct cs4281_state *s)
-{
- int i;
- for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
- {
- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
- {
- printpipe(&s->pl[i]);
- }
- }
-}
-/****************************************************************************
-*
-* Suspend - save the ac97 regs, mute the outputs and power down the part.
-*
-****************************************************************************/
-static void cs4281_ac97_suspend(struct cs4281_state *s)
-{
- int Count,i;
-
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()+\n"));
-/*
-* change the state, save the current hwptr, then stop the dac/adc
-*/
- s->pm.flags &= ~CS4281_PM_IDLE;
- s->pm.flags |= CS4281_PM_SUSPENDING;
- s->pm.u32hwptr_playback = readl(s->pBA0 + BA0_DCA0);
- s->pm.u32hwptr_capture = readl(s->pBA0 + BA0_DCA1);
- stop_dac(s);
- stop_adc(s);
-
- for(Count = 0x2, i=0; (Count <= CS4281_AC97_HIGHESTREGTORESTORE)
- && (i < CS4281_AC97_NUMBER_RESTORE_REGS);
- Count += 2, i++)
- {
- cs4281_read_ac97(s, BA0_AC97_RESET + Count, &s->pm.ac97[i]);
- }
-/*
-* Save the ac97 volume registers as well as the current powerdown state.
-* Now, mute the all the outputs (master, headphone, and mono), as well
-* as the PCM volume, in preparation for powering down the entire part.
-*/
- cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME, &s->pm.u32AC97_master_volume);
- cs4281_read_ac97(s, BA0_AC97_HEADPHONE_VOLUME, &s->pm.u32AC97_headphone_volume);
- cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, &s->pm.u32AC97_master_volume_mono);
- cs4281_read_ac97(s, BA0_AC97_PCM_OUT_VOLUME, &s->pm.u32AC97_pcm_out_volume);
-
- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, 0x8000);
- cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, 0x8000);
- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
- cs4281_write_ac97(s, BA0_AC97_PCM_OUT_VOLUME, 0x8000);
-
- cs4281_read_ac97(s, BA0_AC97_POWERDOWN, &s->pm.u32AC97_powerdown);
- cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &s->pm.u32AC97_general_purpose);
-
-/*
-* And power down everything on the AC97 codec.
-*/
- cs4281_write_ac97(s, BA0_AC97_POWERDOWN, 0xff00);
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()-\n"));
-}
-
-/****************************************************************************
-*
-* Resume - power up the part and restore its registers..
-*
-****************************************************************************/
-static void cs4281_ac97_resume(struct cs4281_state *s)
-{
- int Count,i;
-
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()+\n"));
-
-/* do not save the power state registers at this time
- //
- // If we saved away the power control registers, write them into the
- // shadows so those saved values get restored instead of the current
- // shadowed value.
- //
- if( bPowerStateSaved )
- {
- PokeShadow( 0x26, ulSaveReg0x26 );
- bPowerStateSaved = FALSE;
- }
-*/
-
-//
-// First, we restore the state of the general purpose register. This
-// contains the mic select (mic1 or mic2) and if we restore this after
-// we restore the mic volume/boost state and mic2 was selected at
-// suspend time, we will end up with a brief period of time where mic1
-// is selected with the volume/boost settings for mic2, causing
-// acoustic feedback. So we restore the general purpose register
-// first, thereby getting the correct mic selected before we restore
-// the mic volume/boost.
-//
- cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE, s->pm.u32AC97_general_purpose);
-
-//
-// Now, while the outputs are still muted, restore the state of power
-// on the AC97 part.
-//
- cs4281_write_ac97(s, BA0_AC97_POWERDOWN, s->pm.u32AC97_powerdown);
-
-/*
-* Restore just the first set of registers, from register number
-* 0x02 to the register number that ulHighestRegToRestore specifies.
-*/
- for( Count = 0x2, i=0;
- (Count <= CS4281_AC97_HIGHESTREGTORESTORE)
- && (i < CS4281_AC97_NUMBER_RESTORE_REGS);
- Count += 2, i++)
- {
- cs4281_write_ac97(s, BA0_AC97_RESET + Count, s->pm.ac97[i]);
- }
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()-\n"));
-}
-
-/* do not save the power state registers at this time
-****************************************************************************
-*
-* SavePowerState - Save the power registers away.
-*
-****************************************************************************
-void
-HWAC97codec::SavePowerState(void)
-{
- ENTRY(TM_OBJECTCALLS, "HWAC97codec::SavePowerState()\r\n");
-
- ulSaveReg0x26 = PeekShadow(0x26);
-
- //
- // Note that we have saved registers that need to be restored during a
- // resume instead of ulAC97Regs[].
- //
- bPowerStateSaved = TRUE;
-
-} // SavePowerState
-*/
-
-static void cs4281_SuspendFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- /*
- * We need to save the contents of the BASIC FIFO Registers.
- */
- pl->u32FCRn_Save = readl(s->pBA0 + pl->u32FCRnAddress);
- pl->u32FSICn_Save = readl(s->pBA0 + pl->u32FSICnAddress);
-}
-static void cs4281_ResumeFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- /*
- * We need to restore the contents of the BASIC FIFO Registers.
- */
- writel(pl->u32FCRn_Save,s->pBA0 + pl->u32FCRnAddress);
- writel(pl->u32FSICn_Save,s->pBA0 + pl->u32FSICnAddress);
-}
-static void cs4281_SuspendDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- //
- // We need to save the contents of the BASIC DMA Registers.
- //
- pl->u32DBAn_Save = readl(s->pBA0 + pl->u32DBAnAddress);
- pl->u32DBCn_Save = readl(s->pBA0 + pl->u32DBCnAddress);
- pl->u32DMRn_Save = readl(s->pBA0 + pl->u32DMRnAddress);
- pl->u32DCRn_Save = readl(s->pBA0 + pl->u32DCRnAddress);
- pl->u32DCCn_Save = readl(s->pBA0 + pl->u32DCCnAddress);
- pl->u32DCAn_Save = readl(s->pBA0 + pl->u32DCAnAddress);
-}
-static void cs4281_ResumeDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- //
- // We need to save the contents of the BASIC DMA Registers.
- //
- writel( pl->u32DBAn_Save, s->pBA0 + pl->u32DBAnAddress);
- writel( pl->u32DBCn_Save, s->pBA0 + pl->u32DBCnAddress);
- writel( pl->u32DMRn_Save, s->pBA0 + pl->u32DMRnAddress);
- writel( pl->u32DCRn_Save, s->pBA0 + pl->u32DCRnAddress);
- writel( pl->u32DCCn_Save, s->pBA0 + pl->u32DCCnAddress);
- writel( pl->u32DCAn_Save, s->pBA0 + pl->u32DCAnAddress);
-}
-
-static int cs4281_suspend(struct cs4281_state *s)
-{
- int i;
- u32 u32CLKCR1;
- struct cs4281_pm *pm = &s->pm;
- CS_DBGOUT(CS_PM | CS_FUNCTION, 9,
- printk("cs4281: cs4281_suspend()+ flags=%d\n",
- (unsigned)s->pm.flags));
-/*
-* check the current state, only suspend if IDLE
-*/
- if(!(s->pm.flags & CS4281_PM_IDLE))
- {
- CS_DBGOUT(CS_PM | CS_ERROR, 2,
- printk("cs4281: cs4281_suspend() unable to suspend, not IDLE\n"));
- return 1;
- }
- s->pm.flags &= ~CS4281_PM_IDLE;
- s->pm.flags |= CS4281_PM_SUSPENDING;
-
-//
-// Gershwin CLKRUN - Set CKRA
-//
- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
-
- pm->u32CLKCR1_SAVE = u32CLKCR1;
- if(!(u32CLKCR1 & 0x00010000 ) )
- writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
-
-//
-// First, turn on the clocks (yikes) to the devices, so that they will
-// respond when we try to save their state.
-//
- if(!(u32CLKCR1 & CLKCR1_SWCE))
- {
- writel(u32CLKCR1 | CLKCR1_SWCE , s->pBA0 + BA0_CLKCR1);
- }
-
- //
- // Save the power state
- //
- pm->u32SSPMValue = readl(s->pBA0 + BA0_SSPM);
-
- //
- // Disable interrupts.
- //
- writel(HICR_CHGM, s->pBA0 + BA0_HICR);
-
- //
- // Save the PCM Playback Left and Right Volume Control.
- //
- pm->u32PPLVCvalue = readl(s->pBA0 + BA0_PPLVC);
- pm->u32PPRVCvalue = readl(s->pBA0 + BA0_PPRVC);
-
- //
- // Save the FM Synthesis Left and Right Volume Control.
- //
- pm->u32FMLVCvalue = readl(s->pBA0 + BA0_FMLVC);
- pm->u32FMRVCvalue = readl(s->pBA0 + BA0_FMRVC);
-
- //
- // Save the GPIOR value.
- //
- pm->u32GPIORvalue = readl(s->pBA0 + BA0_GPIOR);
-
- //
- // Save the JSCTL value.
- //
- pm->u32JSCTLvalue = readl(s->pBA0 + BA0_GPIOR);
-
- //
- // Save Sound System Control Register
- //
- pm->u32SSCR = readl(s->pBA0 + BA0_SSCR);
-
- //
- // Save SRC Slot Assinment register
- //
- pm->u32SRCSA = readl(s->pBA0 + BA0_SRCSA);
-
- //
- // Save sample rate
- //
- pm->u32DacASR = readl(s->pBA0 + BA0_PASR);
- pm->u32AdcASR = readl(s->pBA0 + BA0_CASR);
- pm->u32DacSR = readl(s->pBA0 + BA0_DACSR);
- pm->u32AdcSR = readl(s->pBA0 + BA0_ADCSR);
-
- //
- // Loop through all of the PipeLines
- //
- for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
- {
- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
- {
- //
- // Ask the DMAengines and FIFOs to Suspend.
- //
- cs4281_SuspendDMAengine(s,&s->pl[i]);
- cs4281_SuspendFIFO(s,&s->pl[i]);
- }
- }
- //
- // We need to save the contents of the Midi Control Register.
- //
- pm->u32MIDCR_Save = readl(s->pBA0 + BA0_MIDCR);
-/*
-* save off the AC97 part information
-*/
- cs4281_ac97_suspend(s);
-
- //
- // Turn off the serial ports.
- //
- writel(0, s->pBA0 + BA0_SERMC);
-
- //
- // Power off FM, Joystick, AC link,
- //
- writel(0, s->pBA0 + BA0_SSPM);
-
- //
- // DLL off.
- //
- writel(0, s->pBA0 + BA0_CLKCR1);
-
- //
- // AC link off.
- //
- writel(0, s->pBA0 + BA0_SPMC);
-
- //
- // Put the chip into D3(hot) state.
- //
- // PokeBA0(BA0_PMCS, 0x00000003);
-
- //
- // Gershwin CLKRUN - Clear CKRA
- //
- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
- writel(u32CLKCR1 & 0xFFFEFFFF, s->pBA0 + BA0_CLKCR1);
-
-#ifdef CSDEBUG
- printpm(s);
- printpipelines(s);
-#endif
-
- s->pm.flags &= ~CS4281_PM_SUSPENDING;
- s->pm.flags |= CS4281_PM_SUSPENDED;
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 9,
- printk("cs4281: cs4281_suspend()- flags=%d\n",
- (unsigned)s->pm.flags));
- return 0;
-}
-
-static int cs4281_resume(struct cs4281_state *s)
-{
- int i;
- unsigned temp1;
- u32 u32CLKCR1;
- struct cs4281_pm *pm = &s->pm;
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
- printk( "cs4281: cs4281_resume()+ flags=%d\n",
- (unsigned)s->pm.flags));
- if(!(s->pm.flags & CS4281_PM_SUSPENDED))
- {
- CS_DBGOUT(CS_PM | CS_ERROR, 2,
- printk("cs4281: cs4281_resume() unable to resume, not SUSPENDED\n"));
- return 1;
- }
- s->pm.flags &= ~CS4281_PM_SUSPENDED;
- s->pm.flags |= CS4281_PM_RESUMING;
-
-//
-// Gershwin CLKRUN - Set CKRA
-//
- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
- writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
-
- //
- // set the power state.
- //
- //old PokeBA0(BA0_PMCS, 0);
-
- //
- // Program the clock circuit and serial ports.
- //
- temp1 = cs4281_hw_init(s);
- if (temp1) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1,
- printk(KERN_ERR
- "cs4281: resume cs4281_hw_init() error.\n"));
- return -1;
- }
-
- //
- // restore the Power state
- //
- writel(pm->u32SSPMValue, s->pBA0 + BA0_SSPM);
-
- //
- // Set post SRC mix setting (FM or ALT48K)
- //
- writel(pm->u32SSPM_BITS, s->pBA0 + BA0_SSPM);
-
- //
- // Loop through all of the PipeLines
- //
- for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
- {
- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
- {
- //
- // Ask the DMAengines and FIFOs to Resume.
- //
- cs4281_ResumeDMAengine(s,&s->pl[i]);
- cs4281_ResumeFIFO(s,&s->pl[i]);
- }
- }
- //
- // We need to restore the contents of the Midi Control Register.
- //
- writel(pm->u32MIDCR_Save, s->pBA0 + BA0_MIDCR);
-
- cs4281_ac97_resume(s);
- //
- // Restore the PCM Playback Left and Right Volume Control.
- //
- writel(pm->u32PPLVCvalue, s->pBA0 + BA0_PPLVC);
- writel(pm->u32PPRVCvalue, s->pBA0 + BA0_PPRVC);
-
- //
- // Restore the FM Synthesis Left and Right Volume Control.
- //
- writel(pm->u32FMLVCvalue, s->pBA0 + BA0_FMLVC);
- writel(pm->u32FMRVCvalue, s->pBA0 + BA0_FMRVC);
-
- //
- // Restore the JSCTL value.
- //
- writel(pm->u32JSCTLvalue, s->pBA0 + BA0_JSCTL);
-
- //
- // Restore the GPIOR register value.
- //
- writel(pm->u32GPIORvalue, s->pBA0 + BA0_GPIOR);
-
- //
- // Restore Sound System Control Register
- //
- writel(pm->u32SSCR, s->pBA0 + BA0_SSCR);
-
- //
- // Restore SRC Slot Assignment register
- //
- writel(pm->u32SRCSA, s->pBA0 + BA0_SRCSA);
-
- //
- // Restore sample rate
- //
- writel(pm->u32DacASR, s->pBA0 + BA0_PASR);
- writel(pm->u32AdcASR, s->pBA0 + BA0_CASR);
- writel(pm->u32DacSR, s->pBA0 + BA0_DACSR);
- writel(pm->u32AdcSR, s->pBA0 + BA0_ADCSR);
-
- //
- // Restore CFL1/2 registers we saved to compensate for OEM bugs.
- //
- // PokeBA0(BA0_CFLR, ulConfig);
-
- //
- // Gershwin CLKRUN - Clear CKRA
- //
- writel(pm->u32CLKCR1_SAVE, s->pBA0 + BA0_CLKCR1);
-
- //
- // Enable interrupts on the part.
- //
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
-
-#ifdef CSDEBUG
- printpm(s);
- printpipelines(s);
-#endif
-/*
-* change the state, restore the current hwptrs, then stop the dac/adc
-*/
- s->pm.flags |= CS4281_PM_IDLE;
- s->pm.flags &= ~(CS4281_PM_SUSPENDING | CS4281_PM_SUSPENDED
- | CS4281_PM_RESUMING | CS4281_PM_RESUMED);
-
- writel(s->pm.u32hwptr_playback, s->pBA0 + BA0_DCA0);
- writel(s->pm.u32hwptr_capture, s->pBA0 + BA0_DCA1);
- start_dac(s);
- start_adc(s);
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 9, printk("cs4281: cs4281_resume()- flags=%d\n",
- (unsigned)s->pm.flags));
- return 0;
-}
-
-#endif
-
-//******************************************************************************
-// "cs4281_play_rate()" --
-//******************************************************************************
-static void cs4281_play_rate(struct cs4281_state *card, u32 playrate)
-{
- u32 DACSRvalue = 1;
-
- // Based on the sample rate, program the DACSR register.
- if (playrate == 8000)
- DACSRvalue = 5;
- if (playrate == 11025)
- DACSRvalue = 4;
- else if (playrate == 22050)
- DACSRvalue = 2;
- else if (playrate == 44100)
- DACSRvalue = 1;
- else if ((playrate <= 48000) && (playrate >= 6023))
- DACSRvalue = 24576000 / (playrate * 16);
- else if (playrate < 6023)
- // Not allowed by open.
- return;
- else if (playrate > 48000)
- // Not allowed by open.
- return;
- CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO
- "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",
- DACSRvalue, playrate));
- // Write the 'sample rate select code'
- // to the 'DAC Sample Rate' register.
- writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h)
-}
-
-//******************************************************************************
-// "cs4281_record_rate()" -- Initialize the record sample rate converter.
-//******************************************************************************
-static void cs4281_record_rate(struct cs4281_state *card, u32 outrate)
-{
- u32 ADCSRvalue = 1;
-
- //
- // Based on the sample rate, program the ADCSR register
- //
- if (outrate == 8000)
- ADCSRvalue = 5;
- if (outrate == 11025)
- ADCSRvalue = 4;
- else if (outrate == 22050)
- ADCSRvalue = 2;
- else if (outrate == 44100)
- ADCSRvalue = 1;
- else if ((outrate <= 48000) && (outrate >= 6023))
- ADCSRvalue = 24576000 / (outrate * 16);
- else if (outrate < 6023) {
- // Not allowed by open.
- return;
- } else if (outrate > 48000) {
- // Not allowed by open.
- return;
- }
- CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO
- "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",
- ADCSRvalue, outrate));
- // Write the 'sample rate select code
- // to the 'ADC Sample Rate' register.
- writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h)
-}
-
-
-
-static void stop_dac(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n"));
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_WRITE;
- temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK;
- writel(temp1, s->pBA0 + BA0_DCR0);
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void start_dac(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: start_dac()+\n"));
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped ||
- (s->dma_dac.count > 0
- && s->dma_dac.ready))
-#ifndef NOT_CS4281_PM
- && (s->pm.flags & CS4281_PM_IDLE))
-#else
-)
-#endif
- {
- s->ena |= FMODE_WRITE;
- temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask.
- writel(temp1, s->pBA0 + BA0_DCR0); // Start DMA'ing.
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
-
- writel(7, s->pBA0 + BA0_PPRVC);
- writel(7, s->pBA0 + BA0_PPLVC);
- CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO
- "cs4281: start_dac(): writel 0x%x start dma\n", temp1));
-
- }
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 3,
- printk(KERN_INFO "cs4281: start_dac()-\n"));
-}
-
-
-static void stop_adc(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_FUNCTION, 3,
- printk(KERN_INFO "cs4281: stop_adc()+\n"));
-
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_READ;
-
- if (s->conversion == 1) {
- s->conversion = 0;
- s->prop_adc.fmt = s->prop_adc.fmt_original;
- }
- temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK;
- writel(temp1, s->pBA0 + BA0_DCR1);
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 3,
- printk(KERN_INFO "cs4281: stop_adc()-\n"));
-}
-
-
-static void start_adc(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: start_adc()+\n"));
-
- if (!(s->ena & FMODE_READ) &&
- (s->dma_adc.mapped || s->dma_adc.count <=
- (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize))
- && s->dma_adc.ready
-#ifndef NOT_CS4281_PM
- && (s->pm.flags & CS4281_PM_IDLE))
-#else
-)
-#endif
- {
- 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.
- // allocate buffer and then convert from 16 bit to
- // 8 bit for the user buffer.
- //
- s->prop_adc.fmt_original = s->prop_adc.fmt;
- if (s->prop_adc.fmt & AFMT_S8) {
- s->prop_adc.fmt &= ~AFMT_S8;
- s->prop_adc.fmt |= AFMT_S16_LE;
- }
- if (s->prop_adc.fmt & AFMT_U8) {
- s->prop_adc.fmt &= ~AFMT_U8;
- s->prop_adc.fmt |= AFMT_U16_LE;
- }
- //
- // prog_dmabuf_adc performs a stop_adc() but that is
- // ok since we really haven't started the DMA yet.
- //
- prog_codec(s, CS_TYPE_ADC);
-
- if (prog_dmabuf_adc(s) != 0) {
- CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
- "cs4281: start_adc(): error in prog_dmabuf_adc\n"));
- }
- s->conversion = 1;
- }
- spin_lock_irqsave(&s->lock, flags);
- s->ena |= FMODE_READ;
- temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK; // Clear DMA1 channel mask bit.
- writel(temp1, s->pBA0 + BA0_DCR1); // Start recording
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
- spin_unlock_irqrestore(&s->lock, flags);
-
- CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO
- "cs4281: start_adc(): writel 0x%x \n", temp1));
- }
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: start_adc()-\n"));
-
-}
-
-
-// ---------------------------------------------------------------------
-
-#define DMABUF_MINORDER 1 // ==> min buffer size = 8K.
-
-
-static void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db)
-{
- struct page *map, *mapend;
-
- if (db->rawbuf) {
- // Undo prog_dmabuf()'s marking the pages as reserved
- mapend =
- virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -
- 1);
- for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
- ClearPageReserved(map);
- free_dmabuf(s, db);
- }
- if (s->tmpbuff && (db->type == CS_TYPE_ADC)) {
- // Undo prog_dmabuf()'s marking the pages as reserved
- mapend =
- virt_to_page(s->tmpbuff +
- (PAGE_SIZE << s->buforder_tmpbuff) - 1);
- for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
- ClearPageReserved(map);
- free_dmabuf2(s, db);
- }
- s->tmpbuff = NULL;
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
-{
- int order;
- unsigned bytespersec, temp1;
- unsigned bufs, sample_shift = 0;
- struct page *map, *mapend;
- unsigned long df;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_dmabuf()+\n"));
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error =
- db->endcleared = db->blocks = db->wakeup = db->underrun = 0;
-/*
-* check for order within limits, but do not overwrite value, check
-* later for a fractional defaultorder (i.e. 100+).
-*/
- if((defaultorder > 0) && (defaultorder < 12))
- df = defaultorder;
- else
- df = 1;
-
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = df; order >= DMABUF_MINORDER; order--)
- if ( (db->rawbuf = (void *) pci_alloc_consistent(
- s->pcidev, PAGE_SIZE << order, &db-> dmaaddr)))
- break;
- if (!db->rawbuf) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: prog_dmabuf(): unable to allocate rawbuf\n"));
- return -ENOMEM;
- }
- db->buforder = order;
- // Now mark the pages as reserved; otherwise the
- // remap_pfn_range() in cs4281_mmap doesn't work.
- // 1. get index to last page in mem_map array for rawbuf.
- mapend = virt_to_page(db->rawbuf +
- (PAGE_SIZE << db->buforder) - 1);
-
- // 2. mark each physical page in range as 'reserved'.
- for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
- SetPageReserved(map);
- }
- if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) {
- for (order = df; order >= DMABUF_MINORDER;
- order--)
- if ( (s->tmpbuff = (void *) pci_alloc_consistent(
- s->pcidev, PAGE_SIZE << order,
- &s->dmaaddr_tmpbuff)))
- break;
- if (!s->tmpbuff) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: prog_dmabuf(): unable to allocate tmpbuff\n"));
- return -ENOMEM;
- }
- s->buforder_tmpbuff = order;
- // Now mark the pages as reserved; otherwise the
- // remap_pfn_range() in cs4281_mmap doesn't work.
- // 1. get index to last page in mem_map array for rawbuf.
- mapend = virt_to_page(s->tmpbuff +
- (PAGE_SIZE << s->buforder_tmpbuff) - 1);
-
- // 2. mark each physical page in range as 'reserved'.
- for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
- SetPageReserved(map);
- }
- if (db->type == CS_TYPE_DAC) {
- if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- sample_shift++;
- if (s->prop_dac.channels > 1)
- sample_shift++;
- bytespersec = s->prop_dac.rate << sample_shift;
- } else // CS_TYPE_ADC
- {
- if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- sample_shift++;
- if (s->prop_adc.channels > 1)
- sample_shift++;
- bytespersec = s->prop_adc.rate << sample_shift;
- }
- bufs = PAGE_SIZE << db->buforder;
-
-/*
-* added fractional "defaultorder" inputs. if >100 then use
-* defaultorder-100 as power of 2 for the buffer size. example:
-* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
-*/
- if(defaultorder >= 100)
- {
- bufs = 1 << (defaultorder-100);
- }
-
-#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds.
- db->numfrag = 2;
-/*
-* Nominal frag size(bytes/interrupt)
-*/
- temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS);
- db->fragshift = 8; // Min 256 bytes.
- while (1 << db->fragshift < temp1) // Calc power of 2 frag size.
- db->fragshift += 1;
- db->fragsize = 1 << db->fragshift;
- db->dmasize = db->fragsize * 2;
- db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
-
-// If the calculated size is larger than the allocated
-// buffer, divide the allocated buffer into 2 fragments.
- if (db->dmasize > bufs) {
-
- db->numfrag = 2; // Two fragments.
- db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer.
- db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
- db->dmasize = bufs; // Use all the alloc'ed buffer.
-
- db->fragshift = 0; // Calculate 'fragshift'.
- temp1 = db->fragsize; // update_ptr() uses it
- while ((temp1 >>= 1) > 1) // to calc 'total-bytes'
- db->fragshift += 1; // returned in DSP_GETI/OPTR.
- }
- CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n",
- db->numfrag, db->fragsize, db->fragsamples,
- db->fragshift, bufs,
- (db->type == CS_TYPE_DAC) ? s->prop_dac.fmt :
- s->prop_adc.fmt,
- (db->type == CS_TYPE_DAC) ? s->prop_dac.channels :
- s->prop_adc.channels));
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_dmabuf()-\n"));
- return 0;
-}
-
-
-static int prog_dmabuf_adc(struct cs4281_state *s)
-{
- unsigned long va;
- unsigned count;
- int c;
- stop_adc(s);
- s->dma_adc.type = CS_TYPE_ADC;
- if ((c = prog_dmabuf(s, &s->dma_adc)))
- return c;
-
- if (s->dma_adc.rawbuf) {
- memset(s->dma_adc.rawbuf,
- (s->prop_adc.
- fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- s->dma_adc.dmasize);
- }
- if (s->tmpbuff) {
- memset(s->tmpbuff,
- (s->prop_adc.
- fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- PAGE_SIZE << s->buforder_tmpbuff);
- }
-
- va = virt_to_bus(s->dma_adc.rawbuf);
-
- count = s->dma_adc.dmasize;
-
- if (s->prop_adc.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
- count /= 2; // 16-bit.
-
- if (s->prop_adc.channels > 1)
- count /= 2; // Assume stereo.
-
- CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n",
- count, (unsigned) va));
-
- writel(va, s->pBA0 + BA0_DBA1); // Set buffer start address.
- writel(count - 1, s->pBA0 + BA0_DBC1); // Set count.
- s->dma_adc.ready = 1;
- return 0;
-}
-
-
-static int prog_dmabuf_dac(struct cs4281_state *s)
-{
- unsigned long va;
- unsigned count;
- int c;
- stop_dac(s);
- s->dma_dac.type = CS_TYPE_DAC;
- if ((c = prog_dmabuf(s, &s->dma_dac)))
- return c;
- memset(s->dma_dac.rawbuf,
- (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- s->dma_dac.dmasize);
-
- va = virt_to_bus(s->dma_dac.rawbuf);
-
- count = s->dma_dac.dmasize;
- if (s->prop_dac.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
- count /= 2; // 16-bit.
-
- if (s->prop_dac.channels > 1)
- count /= 2; // Assume stereo.
-
- writel(va, s->pBA0 + BA0_DBA0); // Set buffer start address.
- writel(count - 1, s->pBA0 + BA0_DBC0); // Set count.
-
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n",
- count, (unsigned) va));
-
- s->dma_dac.ready = 1;
- return 0;
-}
-
-
-static 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;
- }
- CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
- "cs4281: clear_advance(): memset %d at %p for %d size \n",
- (unsigned)c, ((char *) buf) + bptr, len));
- memset(((char *) buf) + bptr, c, len);
-}
-
-
-
-// call with spinlock held!
-static void cs4281_update_ptr(struct cs4281_state *s, int intflag)
-{
- int diff;
- unsigned hwptr, va;
-
- // update ADC pointer
- if (s->ena & FMODE_READ) {
- hwptr = readl(s->pBA0 + BA0_DCA1); // Read capture DMA address.
- va = virt_to_bus(s->dma_adc.rawbuf);
- hwptr -= (unsigned) va;
- diff =
- (s->dma_adc.dmasize + hwptr -
- s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count > s->dma_adc.dmasize)
- s->dma_adc.count = s->dma_adc.dmasize;
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >=
- (signed) s->dma_adc.fragsize) wake_up(&s->
- dma_adc.
- wait);
- } else {
- if (s->dma_adc.count > 0)
- wake_up(&s->dma_adc.wait);
- }
- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
- s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count));
- }
- // update DAC pointer
- //
- // check for end of buffer, means that we are going to wait for another interrupt
- // to allow silence to fill the fifos on the part, to keep pops down to a minimum.
- //
- if (s->ena & FMODE_WRITE) {
- hwptr = readl(s->pBA0 + BA0_DCA0); // Read play DMA address.
- va = virt_to_bus(s->dma_dac.rawbuf);
- hwptr -= (unsigned) va;
- diff = (s->dma_dac.dmasize + hwptr -
- s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= s->dma_dac.fragsize) {
- s->dma_dac.wakeup = 1;
- wake_up(&s->dma_dac.wait);
- if (s->dma_dac.count > s->dma_dac.dmasize)
- s->dma_dac.count &=
- s->dma_dac.dmasize - 1;
- }
- } else {
- s->dma_dac.count -= diff;
- if (s->dma_dac.count <= 0) {
- //
- // fill with silence, and do not shut down the DAC.
- // Continue to play silence until the _release.
- //
- CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): memset %d at %p for %d size \n",
- (unsigned)(s->prop_dac.fmt &
- (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- s->dma_dac.rawbuf, s->dma_dac.dmasize));
- memset(s->dma_dac.rawbuf,
- (s->prop_dac.
- fmt & (AFMT_U8 | AFMT_U16_LE)) ?
- 0x80 : 0, s->dma_dac.dmasize);
- if (s->dma_dac.count < 0) {
- s->dma_dac.underrun = 1;
- s->dma_dac.count = 0;
- CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): underrun\n"));
- }
- } else if (s->dma_dac.count <=
- (signed) s->dma_dac.fragsize
- && !s->dma_dac.endcleared) {
- clear_advance(s->dma_dac.rawbuf,
- s->dma_dac.dmasize,
- s->dma_dac.swptr,
- s->dma_dac.fragsize,
- (s->prop_dac.
- fmt & (AFMT_U8 |
- AFMT_U16_LE)) ? 0x80
- : 0);
- s->dma_dac.endcleared = 1;
- }
- if ( (s->dma_dac.count <= (signed) s->dma_dac.dmasize/2) ||
- intflag)
- {
- wake_up(&s->dma_dac.wait);
- }
- }
- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
- s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count));
- }
-}
-
-
-// ---------------------------------------------------------------------
-
-static void prog_codec(struct cs4281_state *s, unsigned type)
-{
- unsigned long flags;
- unsigned temp1, format;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_codec()+ \n"));
-
- spin_lock_irqsave(&s->lock, flags);
- if (type == CS_TYPE_ADC) {
- temp1 = readl(s->pBA0 + BA0_DCR1);
- writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1); // Stop capture DMA, if active.
-
- // program sampling rates
- // Note, for CS4281, capture & play rates can be set independently.
- cs4281_record_rate(s, s->prop_adc.rate);
-
- // program ADC parameters
- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;
- if (s->prop_adc.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
- if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian?
- format |= DMRn_BEND;
- if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE))
- format |= DMRn_USIGN; // Unsigned.
- } else
- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
- if (s->prop_adc.channels < 2)
- format |= DMRn_MONO;
-
- writel(format, s->pBA0 + BA0_DMR1);
-
- CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
- "cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n",
- (format & DMRn_SIZE8) ? "8" : "16",
- (format & DMRn_USIGN) ? "Unsigned" : "Signed",
- (format & DMRn_MONO) ? "Mono" : "Stereo",
- s->prop_adc.rate, format));
-
- s->ena &= ~FMODE_READ; // not capturing data yet
- }
-
-
- if (type == CS_TYPE_DAC) {
- temp1 = readl(s->pBA0 + BA0_DCR0);
- writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0); // Stop play DMA, if active.
-
- // program sampling rates
- // Note, for CS4281, capture & play rates can be set independently.
- cs4281_play_rate(s, s->prop_dac.rate);
-
- // program DAC parameters
- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;
- if (s->prop_dac.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
- if (s->prop_dac.fmt & (AFMT_S16_BE | AFMT_U16_BE))
- format |= DMRn_BEND; // Big Endian.
- if (s->prop_dac.fmt & (AFMT_U16_LE | AFMT_U16_BE))
- format |= DMRn_USIGN; // Unsigned.
- } else
- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
-
- if (s->prop_dac.channels < 2)
- format |= DMRn_MONO;
-
- writel(format, s->pBA0 + BA0_DMR0);
-
-
- CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
- "cs4281: prog_codec(): dac %s %s %s rate=%d DMR0 format=0x%.8x\n",
- (format & DMRn_SIZE8) ? "8" : "16",
- (format & DMRn_USIGN) ? "Unsigned" : "Signed",
- (format & DMRn_MONO) ? "Mono" : "Stereo",
- s->prop_dac.rate, format));
-
- s->ena &= ~FMODE_WRITE; // not capturing data yet
-
- }
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_codec()- \n"));
-}
-
-
-static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,
- unsigned long arg)
-{
- // Index to mixer_src[] is value of AC97 Input Mux Select Reg.
- // Value of array member is recording source Device ID Mask.
- static const unsigned int mixer_src[8] = {
- SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1,
- SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0
- };
- void __user *argp = (void __user *)arg;
-
- // Index of mixtable1[] member is Device ID
- // and must be <= SOUND_MIXER_NRDEVICES.
- // Value of array member is index into s->mix.vol[]
- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, // voice
- [SOUND_MIXER_LINE1] = 2, // AUX
- [SOUND_MIXER_CD] = 3, // CD
- [SOUND_MIXER_LINE] = 4, // Line
- [SOUND_MIXER_SYNTH] = 5, // FM
- [SOUND_MIXER_MIC] = 6, // Mic
- [SOUND_MIXER_SPEAKER] = 7, // Speaker
- [SOUND_MIXER_RECLEV] = 8, // Recording level
- [SOUND_MIXER_VOLUME] = 9 // Master Volume
- };
-
-
- static const unsigned mixreg[] = {
- BA0_AC97_PCM_OUT_VOLUME,
- BA0_AC97_AUX_VOLUME,
- BA0_AC97_CD_VOLUME,
- BA0_AC97_LINE_IN_VOLUME
- };
- unsigned char l, r, rl, rr, vidx;
- unsigned char attentbl[11] =
- { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 };
- unsigned temp1;
- int i, val;
-
- VALIDATE_STATE(s);
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
- "cs4281: mixer_ioctl(): s=%p cmd=0x%.8x\n", s, cmd));
-#if CSDEBUG
- cs_printioctl(cmd);
-#endif
-#if CSDEBUG_INTERFACE
-
- if ((cmd == SOUND_MIXER_CS_GETDBGMASK) ||
- (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
- (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
- (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
- (cmd == SOUND_MIXER_CS_APM))
- {
- switch (cmd) {
-
- case SOUND_MIXER_CS_GETDBGMASK:
- return put_user(cs_debugmask,
- (unsigned long __user *) argp);
-
- case SOUND_MIXER_CS_GETDBGLEVEL:
- return put_user(cs_debuglevel,
- (unsigned long __user *) argp);
-
- case SOUND_MIXER_CS_SETDBGMASK:
- if (get_user(val, (unsigned long __user *) argp))
- return -EFAULT;
- cs_debugmask = val;
- return 0;
-
- case SOUND_MIXER_CS_SETDBGLEVEL:
- if (get_user(val, (unsigned long __user *) argp))
- return -EFAULT;
- cs_debuglevel = val;
- return 0;
-#ifndef NOT_CS4281_PM
- case SOUND_MIXER_CS_APM:
- if (get_user(val, (unsigned long __user *) argp))
- return -EFAULT;
- if(val == CS_IOCTL_CMD_SUSPEND)
- cs4281_suspend(s);
- else if(val == CS_IOCTL_CMD_RESUME)
- cs4281_resume(s);
- else
- {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n",
- val));
- }
- return 0;
-#endif
- default:
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n"));
- return 0;
- }
- }
-#endif
-
- if (cmd == SOUND_MIXER_PRIVATE1) {
- // enable/disable/query mixer preamp
- if (get_user(val, (int __user *) argp))
- return -EFAULT;
- if (val != -1) {
- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
- temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf);
- cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
- }
- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
- val = (temp1 & 0x40) ? 1 : 0;
- return put_user(val, (int __user *) argp);
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- // enable/disable/query spatializer
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- if (val != -1) {
- temp1 = (val & 0x3f) >> 2;
- cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1);
- cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE,
- &temp1);
- cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,
- temp1 | 0x2000);
- }
- cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1);
- return put_user((temp1 << 2) | 3, (int __user *)argp);
- }
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strlcpy(info.id, "CS4281", sizeof(info.id));
- strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strlcpy(info.id, "CS4281", sizeof(info.id));
- strlcpy(info.name, "Crystal CS4281", 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);
-
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- // If ioctl has only the SIOC_READ bit(bit 31)
- // on, process the only-read commands.
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
- cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1);
- return put_user(mixer_src[temp1&7], (int __user *)argp);
-
- case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
- SOUND_MASK_CD | SOUND_MASK_LINE |
- SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME |
- SOUND_MASK_RECLEV |
- SOUND_MASK_SPEAKER, (int __user *)argp);
-
- case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source
- return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC |
- SOUND_MASK_CD | SOUND_MASK_VOLUME |
- SOUND_MASK_LINE1, (int __user *) argp);
-
- case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
- SOUND_MASK_CD | SOUND_MASK_LINE |
- SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME |
- SOUND_MASK_RECLEV, (int __user *)argp);
-
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, (int __user *)argp);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES
- || !(vidx = mixtable1[i]))
- return -EINVAL;
- return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
- }
- }
- // If ioctl doesn't have both the SIOC_READ and
- // the SIOC_WRITE bit set, return invalid.
- if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE))
- return -EINVAL;
-
- // Increment the count of volume writes.
- s->mix.modcnt++;
-
- // Isolate the command; it must be a write.
- switch (_IOC_NR(cmd)) {
-
- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- i = hweight32(val); // i = # bits on in val.
- if (i != 1) // One & only 1 bit must be on.
- return 0;
- for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) {
- if (val == mixer_src[i]) {
- temp1 = (i << 8) | i;
- cs4281_write_ac97(s,
- BA0_AC97_RECORD_SELECT,
- temp1);
- return 0;
- }
- }
- return 0;
-
- case SOUND_MIXER_VOLUME:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100; // Max soundcard.h vol is 100.
- if (l < 6) {
- rl = 63;
- l = 0;
- } else
- rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten.
-
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100; // Max right volume is 100, too
- if (r < 6) {
- rr = 63;
- r = 0;
- } else
- rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation.
-
- if ((rl > 60) && (rr > 60)) // If both l & r are 'low',
- temp1 = 0x8000; // turn on the mute bit.
- else
- temp1 = 0;
-
- temp1 |= (rl << 8) | rr;
-
- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1);
- cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[8] = ((unsigned int) r << 8) | l;
-#else
- s->mix.vol[8] = val;
-#endif
- return put_user(s->mix.vol[8], (int __user *)argp);
-
- case SOUND_MIXER_SPEAKER:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (l < 3) {
- rl = 0;
- l = 0;
- } else {
- rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15.
- l = (rl * 13 + 5) / 2;
- }
-
- if (rl < 3) {
- temp1 = 0x8000;
- rl = 0;
- } else
- temp1 = 0;
- rl = 15 - rl; // Convert volume to attenuation.
- temp1 |= rl << 1;
- cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[6] = l << 8;
-#else
- s->mix.vol[6] = val;
-#endif
- return put_user(s->mix.vol[6], (int __user *)argp);
-
- case SOUND_MIXER_RECLEV:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15.
- rr = (r * 2 - 5) / 13;
- if (rl < 3 && rr < 3)
- temp1 = 0x8000;
- else
- temp1 = 0;
-
- temp1 = temp1 | (rl << 8) | rr;
- cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[7] = ((unsigned int) r << 8) | l;
-#else
- s->mix.vol[7] = val;
-#endif
- return put_user(s->mix.vol[7], (int __user *)argp);
-
- case SOUND_MIXER_MIC:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (l < 1) {
- l = 0;
- rl = 0;
- } else {
- rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31.
- l = (rl * 16 + 4) / 5;
- }
- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
- temp1 &= 0x40; // Isolate 20db gain bit.
- if (rl < 3) {
- temp1 |= 0x8000;
- rl = 0;
- }
- rl = 31 - rl; // Convert volume to attenuation.
- temp1 |= rl;
- cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[5] = val << 8;
-#else
- s->mix.vol[5] = val;
-#endif
- return put_user(s->mix.vol[5], (int __user *)argp);
-
-
- case SOUND_MIXER_SYNTH:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63.
- rr = (r * 2 - 11) / 3;
- if (rl < 3) // If l is low, turn on
- temp1 = 0x0080; // the mute bit.
- else
- temp1 = 0;
-
- rl = 63 - rl; // Convert vol to attenuation.
- writel(temp1 | rl, s->pBA0 + BA0_FMLVC);
- if (rr < 3) // If rr is low, turn on
- temp1 = 0x0080; // the mute bit.
- else
- temp1 = 0;
- rr = 63 - rr; // Convert vol to attenuation.
- writel(temp1 | rr, s->pBA0 + BA0_FMRVC);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[4] = (r << 8) | l;
-#else
- s->mix.vol[4] = val;
-#endif
- return put_user(s->mix.vol[4], (int __user *)argp);
-
-
- default:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: mixer_ioctl(): default\n"));
-
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
- return -EINVAL;
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (l < 1) {
- l = 0;
- rl = 31;
- } else
- rl = (attentbl[(l * 10) / 100]) >> 1;
-
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- if (r < 1) {
- r = 0;
- rr = 31;
- } else
- rr = (attentbl[(r * 10) / 100]) >> 1;
- if ((rl > 30) && (rr > 30))
- temp1 = 0x8000;
- else
- temp1 = 0;
- temp1 = temp1 | (rl << 8) | rr;
- cs4281_write_ac97(s, mixreg[vidx - 1], temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l;
-#else
- s->mix.vol[vidx - 1] = val;
-#endif
-#ifndef NOT_CS4281_PM
- CS_DBGOUT(CS_PM, 9, printk(KERN_INFO
- "write ac97 mixreg[%d]=0x%x mix.vol[]=0x%x\n",
- vidx-1,temp1,s->mix.vol[vidx-1]));
-#endif
- return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
- }
-}
-
-
-// ---------------------------------------------------------------------
-
-static int cs4281_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct cs4281_state *s=NULL;
- struct list_head *entry;
-
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_open_mixdev()+\n"));
-
- list_for_each(entry, &cs4281_devs)
- {
- s = list_entry(entry, struct cs4281_state, list);
- if(s->dev_mixer == minor)
- break;
- }
- if (!s)
- {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
- printk(KERN_INFO "cs4281: cs4281_open_mixdev()- -ENODEV\n"));
- return -ENODEV;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
-
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_open_mixdev()- 0\n"));
-
- return nonseekable_open(inode, file);
-}
-
-
-static int cs4281_release_mixdev(struct inode *inode, struct file *file)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-
-static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct cs4281_state *) file->private_data, cmd,
- arg);
-}
-
-
-// ******************************************************************************************
-// Mixer file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = cs4281_ioctl_mixdev,
- .open = cs4281_open_mixdev,
- .release = cs4281_release_mixdev,
-};
-
-// ---------------------------------------------------------------------
-
-
-static int drain_adc(struct cs4281_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
- unsigned tmo;
-
- if (s->dma_adc.mapped)
- return 0;
- add_wait_queue(&s->dma_adc.wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_adc.count;
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: drain_adc() %d\n", count));
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0) {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: drain_adc() count<0\n"));
- break;
- }
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_adc.wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo =
- 3 * HZ * (count +
- s->dma_adc.fragsize) / 2 / s->prop_adc.rate;
- if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- tmo >>= 1;
- if (s->prop_adc.channels > 1)
- tmo >>= 1;
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "cs4281: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_adc.wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static int drain_dac(struct cs4281_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
- unsigned tmo;
-
- if (s->dma_dac.mapped)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo =
- 3 * HZ * (count +
- s->dma_dac.fragsize) / 2 / s->prop_dac.rate;
- if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- tmo >>= 1;
- if (s->prop_dac.channels > 1)
- tmo >>= 1;
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "cs4281: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-//****************************************************************************
-//
-// CopySamples copies 16-bit stereo samples from the source to the
-// destination, possibly converting down to either 8-bit or mono or both.
-// count specifies the number of output bytes to write.
-//
-// Arguments:
-//
-// dst - Pointer to a destination buffer.
-// src - Pointer to a source buffer
-// count - The number of bytes to copy into the destination buffer.
-// iChannels - Stereo - 2
-// Mono - 1
-// fmt - AFMT_xxx (soundcard.h formats)
-//
-// NOTES: only call this routine for conversion to 8bit from 16bit
-//
-//****************************************************************************
-static void CopySamples(char *dst, char *src, int count, int iChannels,
- unsigned fmt)
-{
-
- unsigned short *psSrc;
- long lAudioSample;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: CopySamples()+ "));
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- " dst=%p src=%p count=%d iChannels=%d fmt=0x%x\n",
- dst, src, (unsigned) count, (unsigned) iChannels, (unsigned) fmt));
-
- // Gershwin does format conversion in hardware so normally
- // we don't do any host based coversion. The data formatter
- // truncates 16 bit data to 8 bit and that causes some hiss.
- // We have already forced the HW to do 16 bit sampling and
- // 2 channel so that we can use software to round instead
- // of truncate
-
- //
- // See if the data should be output as 8-bit unsigned stereo.
- // or if the data should be output at 8-bit unsigned mono.
- //
- if ( ((iChannels == 2) && (fmt & AFMT_U8)) ||
- ((iChannels == 1) && (fmt & AFMT_U8)) ) {
- //
- // Convert each 16-bit unsigned stereo sample to 8-bit unsigned
- // stereo using rounding.
- //
- psSrc = (unsigned short *) src;
- count = count / 2;
- while (count--) {
- lAudioSample = (long) psSrc[count] + (long) 0x80;
- if (lAudioSample > 0xffff) {
- lAudioSample = 0xffff;
- }
- dst[count] = (char) (lAudioSample >> 8);
- }
- }
- //
- // check for 8-bit signed stereo.
- //
- else if ((iChannels == 2) && (fmt & AFMT_S8)) {
- //
- // Convert each 16-bit stereo sample to 8-bit stereo using rounding.
- //
- psSrc = (short *) src;
- while (count--) {
- lAudioSample =
- (((long) psSrc[0] + (long) psSrc[1]) / 2);
- psSrc += 2;
- *dst++ = (char) ((short) lAudioSample >> 8);
- }
- }
- //
- // Otherwise, the data should be output as 8-bit signed mono.
- //
- else if ((iChannels == 1) && (fmt & AFMT_S8)) {
- //
- // Convert each 16-bit signed mono sample to 8-bit signed mono
- // using rounding.
- //
- psSrc = (short *) src;
- count = count / 2;
- while (count--) {
- lAudioSample =
- (((long) psSrc[0] + (long) psSrc[1]) / 2);
- if (lAudioSample > 0x7fff) {
- lAudioSample = 0x7fff;
- }
- psSrc += 2;
- *dst++ = (char) ((short) lAudioSample >> 8);
- }
- }
-}
-
-//
-// cs_copy_to_user()
-// replacement for the standard copy_to_user, to allow for a conversion from
-// 16 bit to 8 bit if the record conversion is active. the cs4281 has some
-// issues with 8 bit capture, so the driver always captures data in 16 bit
-// and then if the user requested 8 bit, converts from 16 to 8 bit.
-//
-static unsigned cs_copy_to_user(struct cs4281_state *s, void __user *dest,
- unsigned *hwsrc, unsigned cnt,
- unsigned *copied)
-{
- void *src = hwsrc; //default to the standard destination buffer addr
-
- CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
- "cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=%p\n",
- s->prop_adc.fmt, s->prop_adc.fmt_original,
- (unsigned) cnt, dest));
-
- if (cnt > s->dma_adc.dmasize) {
- cnt = s->dma_adc.dmasize;
- }
- if (!cnt) {
- *copied = 0;
- return 0;
- }
- if (s->conversion) {
- if (!s->tmpbuff) {
- *copied = cnt / 2;
- return 0;
- }
- CopySamples(s->tmpbuff, (void *) hwsrc, cnt,
- (unsigned) s->prop_adc.channels,
- s->prop_adc.fmt_original);
- src = s->tmpbuff;
- cnt = cnt / 2;
- }
-
- if (copy_to_user(dest, src, cnt)) {
- *copied = 0;
- return -EFAULT;
- }
- *copied = cnt;
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: cs_copy_to_user()- copied bytes is %d \n", cnt));
- return 0;
-}
-
-// ---------------------------------------------------------------------
-
-static ssize_t cs4281_read(struct file *file, char __user *buffer, size_t count,
- loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
- unsigned copied = 0;
-
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
- printk(KERN_INFO "cs4281: cs4281_read()+ %Zu \n", count));
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-//
-// "count" is the amount of bytes to read (from app), is decremented each loop
-// by the amount of bytes that have been returned to the user buffer.
-// "cnt" is the running total of each read from the buffer (changes each loop)
-// "buffer" points to the app's buffer
-// "ret" keeps a running total of the amount of bytes that have been copied
-// to the user buffer.
-// "copied" is the total bytes copied into the user buffer for each loop.
-//
- while (count > 0) {
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- "_read() count>0 count=%Zu .count=%d .swptr=%d .hwptr=%d \n",
- count, s->dma_adc.count,
- s->dma_adc.swptr, s->dma_adc.hwptr));
- spin_lock_irqsave(&s->lock, flags);
-
- // get the current copy point of the sw buffer
- swptr = s->dma_adc.swptr;
-
- // cnt is the amount of unread bytes from the end of the
- // hw buffer to the current sw pointer
- cnt = s->dma_adc.dmasize - swptr;
-
- // dma_adc.count is the current total bytes that have not been read.
- // if the amount of unread bytes from the current sw pointer to the
- // end of the buffer is greater than the current total bytes that
- // have not been read, then set the "cnt" (unread bytes) to the
- // amount of unread bytes.
-
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- spin_unlock_irqrestore(&s->lock, flags);
- //
- // if we are converting from 8/16 then we need to copy
- // twice the number of 16 bit bytes then 8 bit bytes.
- //
- if (s->conversion) {
- if (cnt > (count * 2))
- cnt = (count * 2);
- } else {
- if (cnt > count)
- cnt = count;
- }
- //
- // "cnt" NOW is the smaller of the amount that will be read,
- // and the amount that is requested in this read (or partial).
- // if there are no bytes in the buffer to read, then start the
- // ADC and wait for the interrupt handler to wake us up.
- //
- if (cnt <= 0) {
-
- // start up the dma engine and then continue back to the top of
- // the loop when wake up occurs.
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- // there are bytes in the buffer to read.
- // copy from the hw buffer over to the user buffer.
- // user buffer is designated by "buffer"
- // virtual address to copy from is rawbuf+swptr
- // the "cnt" is the number of bytes to read.
-
- CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
- "_read() copy_to cnt=%d count=%Zu ", cnt, count));
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- " .dmasize=%d .count=%d buffer=%p ret=%Zd\n",
- s->dma_adc.dmasize, s->dma_adc.count, buffer, ret));
-
- if (cs_copy_to_user
- (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied))
- return ret ? ret : -EFAULT;
- 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 -= copied;
- buffer += copied;
- ret += copied;
- start_adc(s);
- }
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
- printk(KERN_INFO "cs4281: cs4281_read()- %Zd\n", ret));
- return ret;
-}
-
-
-static ssize_t cs4281_write(struct file *file, const char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr, hwptr, busaddr;
- int cnt;
-
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
- printk(KERN_INFO "cs4281: cs4281_write()+ count=%Zu\n",
- count));
- VALIDATE_STATE(s);
-
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- if (s->dma_dac.underrun) {
- s->dma_dac.underrun = 0;
- hwptr = readl(s->pBA0 + BA0_DCA0);
- busaddr = virt_to_bus(s->dma_dac.rawbuf);
- hwptr -= (unsigned) busaddr;
- s->dma_dac.swptr = s->dma_dac.hwptr = hwptr;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize - swptr;
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- start_dac(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(s);
- }
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
- printk(KERN_INFO "cs4281: cs4281_write()- %Zd\n", ret));
- return ret;
-}
-
-
-static unsigned int cs4281_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO "cs4281: cs4281_poll()+\n"));
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO
- "cs4281: cs4281_poll() wait on FMODE_WRITE\n"));
- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO
- "cs4281: cs4281_poll() wait on FMODE_READ\n"));
- if(!s->dma_dac.ready && prog_dmabuf_adc(s))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >=
- (signed) s->dma_dac.fragsize) {
- if (s->dma_dac.wakeup)
- mask |= POLLOUT | POLLWRNORM;
- else
- mask = 0;
- s->dma_dac.wakeup = 0;
- }
- } else {
- if ((signed) (s->dma_dac.dmasize/2) >= s->dma_dac.count)
- mask |= POLLOUT | POLLWRNORM;
- }
- } else if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed) s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- } else {
- if (s->dma_adc.count > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",
- mask));
- return mask;
-}
-
-
-static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- struct dmabuf *db;
- int ret;
- unsigned long size;
-
- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_mmap()+\n"));
-
- VALIDATE_STATE(s);
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf_dac(s)) != 0)
- return ret;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf_adc(s)) != 0)
- return ret;
- db = &s->dma_adc;
- } else
- return -EINVAL;
-//
-// only support PLAYBACK for now
-//
- db = &s->dma_dac;
-
- if (cs4x_pgoff(vma) != 0)
- return -EINVAL;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- return -EINVAL;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
- db->mapped = 1;
-
- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n",
- (unsigned) size));
-
- return 0;
-}
-
-
-static int cs4281_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- int __user *p = (int __user *)arg;
-
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): file=%p cmd=0x%.8x\n", file, cmd));
-#if CSDEBUG
- cs_printioctl(cmd);
-#endif
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n",
- SOUND_VERSION));
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SYNC\n"));
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(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:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_RESET\n"));
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr =
- s->dma_dac.count = s->dma_dac.total_bytes =
- s->dma_dac.blocks = s->dma_dac.wakeup = 0;
- prog_codec(s, CS_TYPE_DAC);
- }
- 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 =
- s->dma_adc.blocks = s->dma_dac.wakeup = 0;
- prog_codec(s, CS_TYPE_ADC);
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SPEED val=%d\n", val));
- //
- // support independent capture and playback channels
- // assume that the file mode bit determines the
- // direction of the data flow.
- //
- if (file->f_mode & FMODE_READ) {
- if (val >= 0) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- // program sampling rates
- if (val > 48000)
- val = 48000;
- if (val < 6300)
- val = 6300;
- s->prop_adc.rate = val;
- prog_codec(s, CS_TYPE_ADC);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val >= 0) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- // program sampling rates
- if (val > 48000)
- val = 48000;
- if (val < 6300)
- val = 6300;
- s->prop_dac.rate = val;
- prog_codec(s, CS_TYPE_DAC);
- }
- }
-
- if (file->f_mode & FMODE_WRITE)
- val = s->prop_dac.rate;
- else if (file->f_mode & FMODE_READ)
- val = s->prop_adc.rate;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_STEREO val=%d\n", val));
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- s->prop_adc.channels = val ? 2 : 1;
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- s->prop_dac.channels = val ? 2 : 1;
- prog_codec(s, CS_TYPE_DAC);
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_CHANNELS val=%d\n",
- val));
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- s->prop_adc.channels = 2;
- else
- s->prop_adc.channels = 1;
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- s->prop_dac.channels = 2;
- else
- s->prop_dac.channels = 1;
- prog_codec(s, CS_TYPE_DAC);
- }
- }
-
- if (file->f_mode & FMODE_WRITE)
- val = s->prop_dac.channels;
- else if (file->f_mode & FMODE_READ)
- val = s->prop_adc.channels;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_GETFMTS: // Returns a mask
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_GETFMT val=0x%.8x\n",
- AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
- AFMT_U8));
- return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
- AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SETFMT val=0x%.8x\n",
- val));
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val != AFMT_S16_LE
- && val != AFMT_U16_LE && val != AFMT_S8
- && val != AFMT_U8)
- val = AFMT_U8;
- s->prop_adc.fmt = val;
- s->prop_adc.fmt_original = s->prop_adc.fmt;
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val != AFMT_S16_LE
- && val != AFMT_U16_LE && val != AFMT_S8
- && val != AFMT_U8)
- val = AFMT_U8;
- s->prop_dac.fmt = val;
- s->prop_dac.fmt_original = s->prop_dac.fmt;
- prog_codec(s, CS_TYPE_DAC);
- }
- } else {
- if (file->f_mode & FMODE_WRITE)
- val = s->prop_dac.fmt_original;
- else if (file->f_mode & FMODE_READ)
- val = s->prop_adc.fmt_original;
- }
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SETFMT return val=0x%.8x\n",
- val));
- return put_user(val, p);
-
- case SNDCTL_DSP_POST:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_POST\n"));
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & s->ena & FMODE_READ)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & s->ena & FMODE_WRITE)
- 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;
- start_adc(s);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready
- && (ret = prog_dmabuf_dac(s)))
- return ret;
- start_dac(s);
- } else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)))
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- abinfo.fragsize = s->dma_dac.fragsize;
- if (s->dma_dac.mapped)
- abinfo.bytes = s->dma_dac.dmasize;
- else
- abinfo.bytes =
- s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n",
- abinfo.fragsize,abinfo.bytes,abinfo.fragstotal,
- abinfo.fragments));
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(p, &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)))
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- if (s->conversion) {
- abinfo.fragsize = s->dma_adc.fragsize / 2;
- abinfo.bytes = s->dma_adc.count / 2;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments =
- abinfo.bytes >> (s->dma_adc.fragshift - 1);
- } else {
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.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(p, &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_dac.ready && prog_dmabuf_dac(s))
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if(!s->dma_adc.ready && prog_dmabuf_adc(s))
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- cinfo.bytes = s->dma_adc.total_bytes;
- if (s->dma_adc.mapped) {
- cinfo.blocks =
- (cinfo.bytes >> s->dma_adc.fragshift) -
- s->dma_adc.blocks;
- s->dma_adc.blocks =
- cinfo.bytes >> s->dma_adc.fragshift;
- } else {
- if (s->conversion) {
- cinfo.blocks =
- s->dma_adc.count /
- 2 >> (s->dma_adc.fragshift - 1);
- } else
- cinfo.blocks =
- s->dma_adc.count >> s->dma_adc.
- fragshift;
- }
- if (s->conversion)
- cinfo.ptr = s->dma_adc.hwptr / 2;
- else
- 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(p, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- cinfo.bytes = s->dma_dac.total_bytes;
- if (s->dma_dac.mapped) {
- cinfo.blocks =
- (cinfo.bytes >> s->dma_dac.fragshift) -
- s->dma_dac.blocks;
- s->dma_dac.blocks =
- cinfo.bytes >> s->dma_dac.fragshift;
- } else {
- cinfo.blocks =
- s->dma_dac.count >> s->dma_dac.fragshift;
- }
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize - 1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(p, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf_dac(s)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf_adc(s)))
- return val;
- if (s->conversion)
- return put_user(s->dma_adc.fragsize / 2, p);
- else
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- return 0; // Say OK, but do nothing.
-
- 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, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- else if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- if (file->f_mode & FMODE_READ)
- return put_user(s->prop_adc.rate, p);
- else if (file->f_mode & FMODE_WRITE)
- return put_user(s->prop_dac.rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- if (file->f_mode & FMODE_READ)
- return put_user(s->prop_adc.channels, p);
- else if (file->f_mode & FMODE_WRITE)
- return put_user(s->prop_dac.channels, p);
-
- case SOUND_PCM_READ_BITS:
- if (file->f_mode & FMODE_READ)
- return
- put_user(
- (s->prop_adc.
- fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
- p);
- else if (file->f_mode & FMODE_WRITE)
- return
- put_user(
- (s->prop_dac.
- fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
- p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-
-static int cs4281_release(struct inode *inode, struct file *file)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
-
- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO
- "cs4281: cs4281_release(): inode=%p file=%p f_mode=%d\n",
- inode, file, file->f_mode));
-
- VALIDATE_STATE(s);
-
- if (file->f_mode & FMODE_WRITE) {
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_sem_dac);
- stop_dac(s);
- dealloc_dmabuf(s, &s->dma_dac);
- s->open_mode &= ~FMODE_WRITE;
- mutex_unlock(&s->open_sem_dac);
- wake_up(&s->open_wait_dac);
- }
- if (file->f_mode & FMODE_READ) {
- drain_adc(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_sem_adc);
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- s->open_mode &= ~FMODE_READ;
- mutex_unlock(&s->open_sem_adc);
- wake_up(&s->open_wait_adc);
- }
- return 0;
-}
-
-static int cs4281_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct cs4281_state *s=NULL;
- struct list_head *entry;
-
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): inode=%p file=%p f_mode=0x%x\n",
- inode, file, file->f_mode));
-
- list_for_each(entry, &cs4281_devs)
- {
- s = list_entry(entry, struct cs4281_state, list);
-
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- if (entry == &cs4281_devs)
- return -ENODEV;
- if (!s) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
- return -ENODEV;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
-
- // wait for device to become free
- if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): Error - must open READ and/or WRITE\n"));
- return -ENODEV;
- }
- if (file->f_mode & FMODE_WRITE) {
- mutex_lock(&s->open_sem_dac);
- while (s->open_mode & FMODE_WRITE) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_sem_dac);
- return -EBUSY;
- }
- mutex_unlock(&s->open_sem_dac);
- interruptible_sleep_on(&s->open_wait_dac);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_sem_dac);
- }
- }
- if (file->f_mode & FMODE_READ) {
- mutex_lock(&s->open_sem_adc);
- while (s->open_mode & FMODE_READ) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_sem_adc);
- return -EBUSY;
- }
- mutex_unlock(&s->open_sem_adc);
- interruptible_sleep_on(&s->open_wait_adc);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_sem_adc);
- }
- }
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- if (file->f_mode & FMODE_READ) {
- s->prop_adc.fmt = AFMT_U8;
- s->prop_adc.fmt_original = s->prop_adc.fmt;
- s->prop_adc.channels = 1;
- s->prop_adc.rate = 8000;
- s->prop_adc.clkdiv = 96 | 0x80;
- s->conversion = 0;
- s->ena &= ~FMODE_READ;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
- s->dma_adc.subdivision = 0;
- mutex_unlock(&s->open_sem_adc);
-
- if (prog_dmabuf_adc(s)) {
- CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
- "cs4281: adc Program dmabufs failed.\n"));
- cs4281_release(inode, file);
- return -ENOMEM;
- }
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- s->prop_dac.fmt = AFMT_U8;
- s->prop_dac.fmt_original = s->prop_dac.fmt;
- s->prop_dac.channels = 1;
- s->prop_dac.rate = 8000;
- s->prop_dac.clkdiv = 96 | 0x80;
- s->conversion = 0;
- s->ena &= ~FMODE_WRITE;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
- s->dma_dac.subdivision = 0;
- mutex_unlock(&s->open_sem_dac);
-
- if (prog_dmabuf_dac(s)) {
- CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
- "cs4281: dac Program dmabufs failed.\n"));
- cs4281_release(inode, file);
- return -ENOMEM;
- }
- prog_codec(s, CS_TYPE_DAC);
- }
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
- printk(KERN_INFO "cs4281: cs4281_open()- 0\n"));
- return nonseekable_open(inode, file);
-}
-
-
-// ******************************************************************************************
-// Wave (audio) file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = cs4281_read,
- .write = cs4281_write,
- .poll = cs4281_poll,
- .ioctl = cs4281_ioctl,
- .mmap = cs4281_mmap,
- .open = cs4281_open,
- .release = cs4281_release,
-};
-
-// ---------------------------------------------------------------------
-
-// hold spinlock for the following!
-static void cs4281_handle_midi(struct cs4281_state *s)
-{
- unsigned char ch;
- int wake;
- unsigned temp1;
-
- wake = 0;
- while (!(readl(s->pBA0 + BA0_MIDSR) & 0x80)) {
- ch = readl(s->pBA0 + BA0_MIDRP);
- 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 (!(readl(s->pBA0 + BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) {
- temp1 = (s->midi.obuf[s->midi.ord]) & 0x000000ff;
- writel(temp1, s->pBA0 + BA0_MIDWP);
- 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);
-}
-
-
-
-static irqreturn_t cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct cs4281_state *s = (struct cs4281_state *) dev_id;
- unsigned int temp1;
-
- // fastpath out, to ease interrupt sharing
- temp1 = readl(s->pBA0 + BA0_HISR); // Get Int Status reg.
-
- CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO
- "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n", temp1));
-/*
-* If not DMA or MIDI interrupt, then just return.
-*/
- if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) {
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
- CS_DBGOUT(CS_INTERRUPT, 9, printk(KERN_INFO
- "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n"));
- return IRQ_NONE;
- }
-
- if (temp1 & HISR_DMA0) // If play interrupt,
- readl(s->pBA0 + BA0_HDSR0); // clear the source.
-
- if (temp1 & HISR_DMA1) // Same for play.
- readl(s->pBA0 + BA0_HDSR1);
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Local EOI
-
- spin_lock(&s->lock);
- cs4281_update_ptr(s,CS_TRUE);
- cs4281_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-// **************************************************************************
-
-static void cs4281_midi_timer(unsigned long data)
-{
- struct cs4281_state *s = (struct cs4281_state *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- cs4281_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->midi.timer.expires = jiffies + 1;
- add_timer(&s->midi.timer);
-}
-
-
-// ---------------------------------------------------------------------
-
-static ssize_t cs4281_midi_read(struct file *file, char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- 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;
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->midi.iwait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
- return ret ? ret : -EFAULT;
- 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;
- }
- return ret;
-}
-
-
-static ssize_t cs4281_midi_write(struct file *file, const char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- 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)
- cs4281_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->midi.owait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
- return ret ? ret : -EFAULT;
- 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);
- cs4281_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return ret;
-}
-
-
-static unsigned int cs4281_midi_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_flags & FMODE_WRITE)
- poll_wait(file, &s->midi.owait, wait);
- if (file->f_flags & FMODE_READ)
- poll_wait(file, &s->midi.iwait, wait);
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_flags & FMODE_READ) {
- if (s->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_flags & FMODE_WRITE) {
- if (s->midi.ocnt < MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-
-static int cs4281_midi_open(struct inode *inode, struct file *file)
-{
- unsigned long flags, temp1;
- unsigned int minor = iminor(inode);
- struct cs4281_state *s=NULL;
- struct list_head *entry;
- list_for_each(entry, &cs4281_devs)
- {
- s = list_entry(entry, struct cs4281_state, list);
-
- if (s->dev_midi == minor)
- break;
- }
-
- if (entry == &cs4281_devs)
- return -ENODEV;
- if (!s)
- {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
- return -ENODEV;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- // wait for device to become free
- mutex_lock(&s->open_sem);
- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_sem);
- return -EBUSY;
- }
- mutex_unlock(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_sem);
- }
- 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;
- writel(1, s->pBA0 + BA0_MIDCR); // Reset the interface.
- writel(0, s->pBA0 + BA0_MIDCR); // Return to normal mode.
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- writel(0x0000000f, s->pBA0 + BA0_MIDCR); // Enable transmit, record, ints.
- temp1 = readl(s->pBA0 + BA0_HIMR);
- writel(temp1 & 0xffbfffff, s->pBA0 + BA0_HIMR); // Enable midi int. recognition.
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts
- init_timer(&s->midi.timer);
- s->midi.timer.expires = jiffies + 1;
- s->midi.timer.data = (unsigned long) s;
- s->midi.timer.function = cs4281_midi_timer;
- add_timer(&s->midi.timer);
- }
- 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;
- }
- 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_sem);
- return nonseekable_open(inode, file);
-}
-
-
-static int cs4281_midi_release(struct inode *inode, struct file *file)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- unsigned count, tmo;
-
- VALIDATE_STATE(s);
-
- 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) {
- remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG
- "cs4281: midi timed out??\n");
- }
- remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
- }
- mutex_lock(&s->open_sem);
- 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))) {
- writel(0, s->pBA0 + BA0_MIDCR); // Disable Midi interrupts.
- del_timer(&s->midi.timer);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- mutex_unlock(&s->open_sem);
- wake_up(&s->open_wait);
- return 0;
-}
-
-// ******************************************************************************************
-// Midi file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = cs4281_midi_read,
- .write = cs4281_midi_write,
- .poll = cs4281_midi_poll,
- .open = cs4281_midi_open,
- .release = cs4281_midi_release,
-};
-
-
-// ---------------------------------------------------------------------
-
-// maximum number of devices
-#define NR_DEVICE 8 // Only eight devices supported currently.
-
-// ---------------------------------------------------------------------
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
-
- {
- SOUND_MIXER_WRITE_VOLUME, 0x4040}, {
- SOUND_MIXER_WRITE_PCM, 0x4040}, {
- SOUND_MIXER_WRITE_SYNTH, 0x4040}, {
- SOUND_MIXER_WRITE_CD, 0x4040}, {
- SOUND_MIXER_WRITE_LINE, 0x4040}, {
- SOUND_MIXER_WRITE_LINE1, 0x4040}, {
- SOUND_MIXER_WRITE_RECLEV, 0x0000}, {
- SOUND_MIXER_WRITE_SPEAKER, 0x4040}, {
- SOUND_MIXER_WRITE_MIC, 0x0000}
-};
-
-
-#ifndef NOT_CS4281_PM
-static void __devinit cs4281_BuildFIFO(
- struct cs4281_pipeline *p,
- struct cs4281_state *s)
-{
- switch(p->number)
- {
- case 0: /* playback */
- {
- p->u32FCRnAddress = BA0_FCR0;
- p->u32FSICnAddress = BA0_FSIC0;
- p->u32FPDRnAddress = BA0_FPDR0;
- break;
- }
- case 1: /* capture */
- {
- p->u32FCRnAddress = BA0_FCR1;
- p->u32FSICnAddress = BA0_FSIC1;
- p->u32FPDRnAddress = BA0_FPDR1;
- break;
- }
-
- case 2:
- {
- p->u32FCRnAddress = BA0_FCR2;
- p->u32FSICnAddress = BA0_FSIC2;
- p->u32FPDRnAddress = BA0_FPDR2;
- break;
- }
- case 3:
- {
- p->u32FCRnAddress = BA0_FCR3;
- p->u32FSICnAddress = BA0_FSIC3;
- p->u32FPDRnAddress = BA0_FPDR3;
- break;
- }
- default:
- break;
- }
- //
- // first read the hardware to initialize the member variables
- //
- p->u32FCRnValue = readl(s->pBA0 + p->u32FCRnAddress);
- p->u32FSICnValue = readl(s->pBA0 + p->u32FSICnAddress);
- p->u32FPDRnValue = readl(s->pBA0 + p->u32FPDRnAddress);
-
-}
-
-static void __devinit cs4281_BuildDMAengine(
- struct cs4281_pipeline *p,
- struct cs4281_state *s)
-{
-/*
-* initialize all the addresses of this pipeline dma info.
-*/
- switch(p->number)
- {
- case 0: /* playback */
- {
- p->u32DBAnAddress = BA0_DBA0;
- p->u32DCAnAddress = BA0_DCA0;
- p->u32DBCnAddress = BA0_DBC0;
- p->u32DCCnAddress = BA0_DCC0;
- p->u32DMRnAddress = BA0_DMR0;
- p->u32DCRnAddress = BA0_DCR0;
- p->u32HDSRnAddress = BA0_HDSR0;
- break;
- }
-
- case 1: /* capture */
- {
- p->u32DBAnAddress = BA0_DBA1;
- p->u32DCAnAddress = BA0_DCA1;
- p->u32DBCnAddress = BA0_DBC1;
- p->u32DCCnAddress = BA0_DCC1;
- p->u32DMRnAddress = BA0_DMR1;
- p->u32DCRnAddress = BA0_DCR1;
- p->u32HDSRnAddress = BA0_HDSR1;
- break;
- }
-
- case 2:
- {
- p->u32DBAnAddress = BA0_DBA2;
- p->u32DCAnAddress = BA0_DCA2;
- p->u32DBCnAddress = BA0_DBC2;
- p->u32DCCnAddress = BA0_DCC2;
- p->u32DMRnAddress = BA0_DMR2;
- p->u32DCRnAddress = BA0_DCR2;
- p->u32HDSRnAddress = BA0_HDSR2;
- break;
- }
-
- case 3:
- {
- p->u32DBAnAddress = BA0_DBA3;
- p->u32DCAnAddress = BA0_DCA3;
- p->u32DBCnAddress = BA0_DBC3;
- p->u32DCCnAddress = BA0_DCC3;
- p->u32DMRnAddress = BA0_DMR3;
- p->u32DCRnAddress = BA0_DCR3;
- p->u32HDSRnAddress = BA0_HDSR3;
- break;
- }
- default:
- break;
- }
-
-//
-// Initialize the dma values for this pipeline
-//
- p->u32DBAnValue = readl(s->pBA0 + p->u32DBAnAddress);
- p->u32DBCnValue = readl(s->pBA0 + p->u32DBCnAddress);
- p->u32DMRnValue = readl(s->pBA0 + p->u32DMRnAddress);
- p->u32DCRnValue = readl(s->pBA0 + p->u32DCRnAddress);
-
-}
-
-static void __devinit cs4281_InitPM(struct cs4281_state *s)
-{
- int i;
- struct cs4281_pipeline *p;
-
- for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
- {
- p = &s->pl[i];
- p->number = i;
- cs4281_BuildDMAengine(p,s);
- cs4281_BuildFIFO(p,s);
- /*
- * currently only 2 pipelines are used
- * so, only set the valid bit on the playback and capture.
- */
- if( (i == CS4281_PLAYBACK_PIPELINE_NUMBER) ||
- (i == CS4281_CAPTURE_PIPELINE_NUMBER))
- p->flags |= CS4281_PIPELINE_VALID;
- }
- s->pm.u32SSPM_BITS = 0x7e; /* rev c, use 0x7c for rev a or b */
-}
-#endif
-
-static int __devinit cs4281_probe(struct pci_dev *pcidev,
- const struct pci_device_id *pciid)
-{
- struct cs4281_state *s;
- dma_addr_t dma_mask;
- mm_segment_t fs;
- int i, val;
- unsigned int temp1, temp2;
-
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
- printk(KERN_INFO "cs4281: probe()+\n"));
-
- if (pci_enable_device(pcidev)) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: pci_enable_device() failed\n"));
- return -1;
- }
- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM) ||
- !(pci_resource_flags(pcidev, 1) & IORESOURCE_MEM)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe()- Memory region not assigned\n"));
- return -ENODEV;
- }
- if (pcidev->irq == 0) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() IRQ not assigned\n"));
- return -ENODEV;
- }
- dma_mask = 0xffffffff; /* this enables playback and recording */
- i = pci_set_dma_mask(pcidev, dma_mask);
- if (i) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n"));
- return i;
- }
- if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() no memory for state struct.\n"));
- return -1;
- }
- memset(s, 0, sizeof(struct cs4281_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->open_wait_adc);
- init_waitqueue_head(&s->open_wait_dac);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- mutex_init(&s->open_sem);
- mutex_init(&s->open_sem_adc);
- mutex_init(&s->open_sem_dac);
- spin_lock_init(&s->lock);
- s->pBA0phys = pci_resource_start(pcidev, 0);
- s->pBA1phys = pci_resource_start(pcidev, 1);
-
- /* Convert phys to linear. */
- s->pBA0 = ioremap_nocache(s->pBA0phys, 4096);
- if (!s->pBA0) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
- "cs4281: BA0 I/O mapping failed. Skipping part.\n"));
- goto err_free;
- }
- s->pBA1 = ioremap_nocache(s->pBA1phys, 65536);
- if (!s->pBA1) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
- "cs4281: BA1 I/O mapping failed. Skipping part.\n"));
- goto err_unmap;
- }
-
- temp1 = readl(s->pBA0 + BA0_PCICFG00);
- temp2 = readl(s->pBA0 + BA0_PCICFG04);
-
- CS_DBGOUT(CS_INIT, 2,
- printk(KERN_INFO
- "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=%p pBA1=%p \n",
- (unsigned) temp1, (unsigned) temp2, s->pBA0, s->pBA1));
- CS_DBGOUT(CS_INIT, 2,
- printk(KERN_INFO
- "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
- (unsigned) s->pBA0phys, (unsigned) s->pBA1phys));
-
-#ifndef NOT_CS4281_PM
- s->pm.flags = CS4281_PM_IDLE;
-#endif
- temp1 = cs4281_hw_init(s);
- if (temp1) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
- "cs4281: cs4281_hw_init() failed. Skipping part.\n"));
- goto err_irq;
- }
- s->magic = CS4281_MAGIC;
- s->pcidev = pcidev;
- s->irq = pcidev->irq;
- if (request_irq
- (s->irq, cs4281_interrupt, IRQF_SHARED, "Crystal CS4281", s)) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_ERR "cs4281: irq %u in use\n", s->irq));
- goto err_irq;
- }
- if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) <
- 0) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() register_sound_dsp() failed.\n"));
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) <
- 0) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() register_sound_mixer() failed.\n"));
- goto err_dev2;
- }
- if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() register_sound_midi() failed.\n"));
- goto err_dev3;
- }
-#ifndef NOT_CS4281_PM
- cs4281_InitPM(s);
- s->pm.flags |= CS4281_PM_NOT_REGISTERED;
-#endif
-
- pci_set_master(pcidev); // enable bus mastering
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val);
- for (i = 0; i < sizeof(initvol) / sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val);
- }
- val = 1; // enable mic preamp
- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val);
- set_fs(fs);
-
- pci_set_drvdata(pcidev, s);
- list_add(&s->list, &cs4281_devs);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: probe()- device allocated successfully\n"));
- return 0;
-
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- free_irq(s->irq, s);
- err_irq:
- iounmap(s->pBA1);
- err_unmap:
- iounmap(s->pBA0);
- err_free:
- kfree(s);
-
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
- "cs4281: probe()- no device allocated\n"));
- return -ENODEV;
-} // probe_cs4281
-
-
-// ---------------------------------------------------------------------
-
-static void __devexit cs4281_remove(struct pci_dev *pci_dev)
-{
- struct cs4281_state *s = pci_get_drvdata(pci_dev);
- // stop DMA controller
- synchronize_irq(s->irq);
- free_irq(s->irq, s);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_midi(s->dev_midi);
- iounmap(s->pBA1);
- iounmap(s->pBA0);
- pci_set_drvdata(pci_dev,NULL);
- list_del(&s->list);
- kfree(s);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: cs4281_remove()-: remove successful\n"));
-}
-
-static struct pci_device_id cs4281_pci_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_CIRRUS,
- .device = PCI_DEVICE_ID_CRYSTAL_CS4281,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, cs4281_pci_tbl);
-
-static struct pci_driver cs4281_pci_driver = {
- .name = "cs4281",
- .id_table = cs4281_pci_tbl,
- .probe = cs4281_probe,
- .remove = __devexit_p(cs4281_remove),
- .suspend = CS4281_SUSPEND_TBL,
- .resume = CS4281_RESUME_TBL,
-};
-
-static int __init cs4281_init_module(void)
-{
- int rtn = 0;
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: cs4281_init_module()+ \n"));
- printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " "
- __DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION,
- CS4281_ARCH);
- rtn = pci_register_driver(&cs4281_pci_driver);
-
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn));
- return rtn;
-}
-
-static void __exit cs4281_cleanup_module(void)
-{
- pci_unregister_driver(&cs4281_pci_driver);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n"));
-}
-// ---------------------------------------------------------------------
-
-MODULE_AUTHOR("gw boynton, audio@crystal.cirrus.com");
-MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver");
-MODULE_LICENSE("GPL");
-
-// ---------------------------------------------------------------------
-
-module_init(cs4281_init_module);
-module_exit(cs4281_cleanup_module);
-
diff --git a/sound/oss/cs4281/cs4281pm-24.c b/sound/oss/cs4281/cs4281pm-24.c
deleted file mode 100644
index 90cbd76..0000000
--- a/sound/oss/cs4281/cs4281pm-24.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
-*
-* "cs4281pm.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.com).
-*
-* 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.
-*
-* 12/22/00 trw - new file.
-*
-*******************************************************************************/
-
-#ifndef NOT_CS4281_PM
-#include <linux/pm.h>
-
-static int cs4281_suspend(struct cs4281_state *s);
-static int cs4281_resume(struct cs4281_state *s);
-/*
-* for now (12/22/00) only enable the pm_register PM support.
-* allow these table entries to be null.
-#define CS4281_SUSPEND_TBL cs4281_suspend_tbl
-#define CS4281_RESUME_TBL cs4281_resume_tbl
-*/
-#define CS4281_SUSPEND_TBL cs4281_suspend_null
-#define CS4281_RESUME_TBL cs4281_resume_null
-
-#else /* CS4281_PM */
-#define CS4281_SUSPEND_TBL cs4281_suspend_null
-#define CS4281_RESUME_TBL cs4281_resume_null
-#endif /* CS4281_PM */
-
diff --git a/sound/oss/cs4281/cs4281pm.h b/sound/oss/cs4281/cs4281pm.h
deleted file mode 100644
index b44fdc9..0000000
--- a/sound/oss/cs4281/cs4281pm.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef NOT_CS4281_PM
-/*******************************************************************************
-*
-* "cs4281pm.h" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.com).
-*
-* 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.
-*
-* 12/22/00 trw - new file.
-*
-*******************************************************************************/
-/* general pm definitions */
-#define CS4281_AC97_HIGHESTREGTORESTORE 0x26
-#define CS4281_AC97_NUMBER_RESTORE_REGS (CS4281_AC97_HIGHESTREGTORESTORE/2-1)
-
-/* pipeline definitions */
-#define CS4281_NUMBER_OF_PIPELINES 4
-#define CS4281_PIPELINE_VALID 0x0001
-#define CS4281_PLAYBACK_PIPELINE_NUMBER 0x0000
-#define CS4281_CAPTURE_PIPELINE_NUMBER 0x0001
-
-/* PM state defintions */
-#define CS4281_PM_NOT_REGISTERED 0x1000
-#define CS4281_PM_IDLE 0x0001
-#define CS4281_PM_SUSPENDING 0x0002
-#define CS4281_PM_SUSPENDED 0x0004
-#define CS4281_PM_RESUMING 0x0008
-#define CS4281_PM_RESUMED 0x0010
-
-struct cs4281_pm {
- unsigned long flags;
- u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue;
- u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR;
- u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save;
- u32 u32SSPM_BITS;
- u32 ac97[CS4281_AC97_NUMBER_RESTORE_REGS];
- u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono;
- u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose;
- u32 u32hwptr_playback,u32hwptr_capture;
-};
-
-struct cs4281_pipeline {
- unsigned flags;
- unsigned number;
- u32 u32DBAnValue,u32DBCnValue,u32DMRnValue,u32DCRnValue;
- u32 u32DBAnAddress,u32DCAnAddress,u32DBCnAddress,u32DCCnAddress;
- u32 u32DMRnAddress,u32DCRnAddress,u32HDSRnAddress;
- u32 u32DBAn_Save,u32DBCn_Save,u32DMRn_Save,u32DCRn_Save;
- u32 u32DCCn_Save,u32DCAn_Save;
-/*
-* technically, these are fifo variables, but just map the
-* first fifo with the first pipeline and then use the fifo
-* variables inside of the pipeline struct.
-*/
- u32 u32FCRn_Save,u32FSICn_Save;
- u32 u32FCRnValue,u32FCRnAddress,u32FSICnValue,u32FSICnAddress;
- u32 u32FPDRnValue,u32FPDRnAddress;
-};
-#endif
diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c
index fb64279..08274c9 100644
--- a/sound/oss/dev_table.c
+++ b/sound/oss/dev_table.c
@@ -13,9 +13,39 @@
#include <linux/init.h>
-#define _DEV_TABLE_C_
#include "sound_config.h"
+struct audio_operations *audio_devs[MAX_AUDIO_DEV];
+EXPORT_SYMBOL(audio_devs);
+
+int num_audiodevs;
+EXPORT_SYMBOL(num_audiodevs);
+
+struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
+EXPORT_SYMBOL(mixer_devs);
+
+int num_mixers;
+EXPORT_SYMBOL(num_mixers);
+
+struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
+EXPORT_SYMBOL(synth_devs);
+
+int num_synths;
+
+struct midi_operations *midi_devs[MAX_MIDI_DEV];
+EXPORT_SYMBOL(midi_devs);
+
+int num_midis;
+EXPORT_SYMBOL(num_midis);
+
+struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
+ &default_sound_timer, NULL
+};
+EXPORT_SYMBOL(sound_timer_devs);
+
+int num_sound_timers = 1;
+
+
static int sound_alloc_audiodev(void);
int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
@@ -75,6 +105,7 @@
audio_init_devices();
return num;
}
+EXPORT_SYMBOL(sound_install_audiodrv);
int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
int driver_size, void *devc)
@@ -113,6 +144,7 @@
mixer_devs[n] = op;
return n;
}
+EXPORT_SYMBOL(sound_install_mixer);
void sound_unload_audiodev(int dev)
{
@@ -122,6 +154,7 @@
unregister_sound_dsp((dev<<4)+3);
}
}
+EXPORT_SYMBOL(sound_unload_audiodev);
static int sound_alloc_audiodev(void)
{
@@ -144,6 +177,7 @@
num_midis = i + 1;
return i;
}
+EXPORT_SYMBOL(sound_alloc_mididev);
int sound_alloc_synthdev(void)
{
@@ -158,6 +192,7 @@
}
return -1;
}
+EXPORT_SYMBOL(sound_alloc_synthdev);
int sound_alloc_mixerdev(void)
{
@@ -169,6 +204,7 @@
num_mixers = i + 1;
return i;
}
+EXPORT_SYMBOL(sound_alloc_mixerdev);
int sound_alloc_timerdev(void)
{
@@ -183,6 +219,7 @@
}
return -1;
}
+EXPORT_SYMBOL(sound_alloc_timerdev);
void sound_unload_mixerdev(int dev)
{
@@ -192,6 +229,7 @@
num_mixers--;
}
}
+EXPORT_SYMBOL(sound_unload_mixerdev);
void sound_unload_mididev(int dev)
{
@@ -200,15 +238,19 @@
unregister_sound_midi((dev<<4)+2);
}
}
+EXPORT_SYMBOL(sound_unload_mididev);
void sound_unload_synthdev(int dev)
{
if (dev != -1)
synth_devs[dev] = NULL;
}
+EXPORT_SYMBOL(sound_unload_synthdev);
void sound_unload_timerdev(int dev)
{
if (dev != -1)
sound_timer_devs[dev] = NULL;
}
+EXPORT_SYMBOL(sound_unload_timerdev);
+
diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h
index adf1d62..b7617be 100644
--- a/sound/oss/dev_table.h
+++ b/sound/oss/dev_table.h
@@ -352,22 +352,8 @@
void (*arm_timer)(int dev, long time);
};
-#ifdef _DEV_TABLE_C_
-struct audio_operations *audio_devs[MAX_AUDIO_DEV];
-int num_audiodevs;
-struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
-int num_mixers;
-struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
-int num_synths;
-struct midi_operations *midi_devs[MAX_MIDI_DEV];
-int num_midis;
-
extern struct sound_timer_operations default_sound_timer;
-struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
- &default_sound_timer, NULL
-};
-int num_sound_timers = 1;
-#else
+
extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
extern int num_audiodevs;
extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
@@ -378,7 +364,6 @@
extern int num_midis;
extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV];
extern int num_sound_timers;
-#endif /* _DEV_TABLE_C_ */
extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
void sound_timer_init (struct sound_lowlev_timer *t, char *name);
diff --git a/sound/oss/dm.h b/sound/oss/dm.h
deleted file mode 100644
index 14a9059..0000000
--- a/sound/oss/dm.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef _DRIVERS_SOUND_DM_H
-#define _DRIVERS_SOUND_DM_H
-
-/*
- * Definitions of the 'direct midi sound' interface used
- * by the newer commercial OSS package. We should export
- * this to userland somewhere in glibc later.
- */
-
-/*
- * Data structure composing an FM "note" or sound event.
- */
-
-struct dm_fm_voice
-{
- u8 op;
- u8 voice;
- u8 am;
- u8 vibrato;
- u8 do_sustain;
- u8 kbd_scale;
- u8 harmonic;
- u8 scale_level;
- u8 volume;
- u8 attack;
- u8 decay;
- u8 sustain;
- u8 release;
- u8 feedback;
- u8 connection;
- u8 left;
- u8 right;
- u8 waveform;
-};
-
-/*
- * This describes an FM note by its voice, octave, frequency number (10bit)
- * and key on/off.
- */
-
-struct dm_fm_note
-{
- u8 voice;
- u8 octave;
- u32 fnum;
- u8 key_on;
-};
-
-/*
- * FM parameters that apply globally to all voices, and thus are not "notes"
- */
-
-struct dm_fm_params
-{
- u8 am_depth;
- u8 vib_depth;
- u8 kbd_split;
- u8 rhythm;
-
- /* This block is the percussion instrument data */
- u8 bass;
- u8 snare;
- u8 tomtom;
- u8 cymbal;
- u8 hihat;
-};
-
-/*
- * FM mode ioctl settings
- */
-
-#define FM_IOCTL_RESET 0x20
-#define FM_IOCTL_PLAY_NOTE 0x21
-#define FM_IOCTL_SET_VOICE 0x22
-#define FM_IOCTL_SET_PARAMS 0x23
-#define FM_IOCTL_SET_MODE 0x24
-#define FM_IOCTL_SET_OPL 0x25
-
-#endif
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index 6c1cf74..b256c04 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -926,6 +926,7 @@
sound_start_dma(dmap, physaddr, count, dma_mode);
return count;
}
+EXPORT_SYMBOL(DMAbuf_start_dma);
static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode)
{
@@ -1055,6 +1056,8 @@
do_outputintr(dev, notify_only);
spin_unlock_irqrestore(&dmap->lock,flags);
}
+EXPORT_SYMBOL(DMAbuf_outputintr);
+
/* called with dmap->lock held in irq context */
static void do_inputintr(int dev)
{
@@ -1154,36 +1157,7 @@
do_inputintr(dev);
spin_unlock_irqrestore(&dmap->lock,flags);
}
-
-int DMAbuf_open_dma(int dev)
-{
- /*
- * NOTE! This routine opens only the primary DMA channel (output).
- */
- struct audio_operations *adev = audio_devs[dev];
- int err;
-
- if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0)
- return -EBUSY;
- dma_init_buffers(adev->dmap_out);
- adev->dmap_out->flags |= DMA_ALLOC_DONE;
- adev->dmap_out->fragment_size = adev->dmap_out->buffsize;
-
- if (adev->dmap_out->dma >= 0) {
- unsigned long flags;
-
- flags=claim_dma_lock();
- clear_dma_ff(adev->dmap_out->dma);
- disable_dma(adev->dmap_out->dma);
- release_dma_lock(flags);
- }
- return 0;
-}
-
-void DMAbuf_close_dma(int dev)
-{
- close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out);
-}
+EXPORT_SYMBOL(DMAbuf_inputintr);
void DMAbuf_init(int dev, int dma1, int dma2)
{
@@ -1192,12 +1166,6 @@
* NOTE! This routine could be called several times.
*/
- /* drag in audio_syms.o */
- {
- extern char audio_syms_symbol;
- audio_syms_symbol = 0;
- }
-
if (adev && adev->dmap_out == NULL) {
if (adev->d == NULL)
panic("OSS: audio_devs[%d]->d == NULL\n", dev);
diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
deleted file mode 100644
index 13f4831..0000000
--- a/sound/oss/es1370.c
+++ /dev/null
@@ -1,2819 +0,0 @@
-/*****************************************************************************/
-
-/*
- * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
- *
- * 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 David C. Niemi
- *
- *
- * Module command line parameters:
- * lineout if 1 the LINE jack is used as an output instead of an input.
- * LINE then contains the unmixed dsp output. This can be used
- * to make the card a four channel one: use dsp to output two
- * channels to LINE and dac to output the other two channels to
- * SPKR. Set the mixer to only output synth to SPKR.
- * micbias sets the +5V bias to the mic if using an electretmic.
- *
- *
- * Note: sync mode is not yet supported (i.e. running dsp and dac from the same
- * clock source)
- *
- * 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 output only,
- * only 5512, 11025, 22050 and 44100 samples/s,
- * 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
- * 26.03.1998 0.1 Initial release
- * 31.03.1998 0.2 Fix bug in GETOSPACE
- * 04.04.1998 0.3 Make it work (again) under 2.0.33
- * Fix mixer write operation not returning the actual
- * settings
- * 05.04.1998 0.4 First attempt at using the new PCI stuff
- * 29.04.1998 0.5 Fix hang when ^C is pressed on amp
- * 07.05.1998 0.6 Don't double lock around stop_*() in *_release()
- * 10.05.1998 0.7 First stab at a simple midi interface (no bells&whistles)
- * 14.05.1998 0.8 Don't allow excessive interrupt rates
- * 08.06.1998 0.9 First release using Alan Cox' soundcore instead of
- * miscdevice
- * 05.07.1998 0.10 Fixed the driver to correctly maintin OSS style volume
- * settings (not sure if this should be standard)
- * Fixed many references: f_flags should be f_mode
- * -- Gerald Britton <gbritton@mit.edu>
- * 03.08.1998 0.11 Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se
- * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
- * as it produces an annoying ssssh in the lower sampling rate
- * Do not include modversions.h
- * 22.08.1998 0.12 Mixer registers actually have 5 instead of 4 bits
- * pointed out by Itai Nahshon
- * 31.08.1998 0.13 Fix realplayer problems - dac.count issues
- * 08.10.1998 0.14 Joystick support fixed
- * -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
- * 10.12.1998 0.15 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.1998 0.16 Don't wake up app until there are fragsize bytes to read/write
- * 06.01.1999 0.17 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.1999 0.18 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.1999 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.1999 0.20 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>
- * Note: joystick address handling might still be wrong on archs
- * other than i386
- * 10.05.1999 0.21 Added support for an electret mic for SB PCI64
- * to the Linux kernel sound driver. This mod also straighten
- * out the question marks around the mic impedance setting
- * (micz). From Kim.Berts@fisub.mail.abb.com
- * 11.05.1999 0.22 Implemented the IMIX call to mute recording monitor.
- * Guenter Geiger <geiger@epy.co.at>
- * 15.06.1999 0.23 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.1999 0.24 Add pci_set_master
- * 02.08.1999 0.25 Added workaround for the "phantom write" bug first
- * documented by Dave Sharpless from Anchor Games
- * 03.08.1999 0.26 adapt to Linus' new __setup/__initcall
- * added kernel command line option "es1370=joystick[,lineout[,micbias]]"
- * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
- * 12.08.1999 0.27 module_init/__setup fixes
- * 19.08.1999 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
- * 31.08.1999 0.29 add spin_lock_init
- * replaced current->state = x with set_current_state(x)
- * 03.09.1999 0.30 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 28.10.1999 0.31 More waitqueue races fixed
- * 08.01.2000 0.32 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.33 Use pci_alloc_consistent and pci_register_driver
- * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask
- * 12.12.2000 0.35 More dma buffer initializations, patch from
- * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- * 07.01.2001 0.36 Timeout change in wrcodec as requested by Frank Klemm <pfk@fuchs.offl.uni-jena.de>
- * 31.01.2001 0.37 Register/Unregister gameport
- * Fix SETTRIGGER non OSS API conformity
- * 03.01.2003 0.38 open_mode fixes from Georg Acher <acher@in.tum.de>
- *
- * some important things missing in Ensoniq documentation:
- *
- * Experimental PCLKDIV results: play the same waveforms on both DAC1 and DAC2
- * and vary PCLKDIV to obtain zero beat.
- * 5512sps: 254
- * 44100sps: 30
- * seems to be fs = 1411200/(PCLKDIV+2)
- *
- * should find out when curr_sample_ct is cleared and
- * where exactly the CCB fetches data
- *
- * The card uses a 22.5792 MHz crystal.
- * The LINEIN jack may be converted to an AOUT jack by
- * setting pin 47 (XCTL0) of the ES1370 to high.
- * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic
- *
- *
- */
-
-/*****************************************************************************/
-
-#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/smp_lock.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/gameport.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.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 DBG(x) {}
-/*#define DBG(x) {x}*/
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_ENSONIQ
-#define PCI_VENDOR_ID_ENSONIQ 0x1274
-#endif
-
-#ifndef PCI_DEVICE_ID_ENSONIQ_ES1370
-#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
-#endif
-
-#define ES1370_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1370)
-
-#define ES1370_EXTENT 0x40
-#define JOY_EXTENT 8
-
-#define ES1370_REG_CONTROL 0x00
-#define ES1370_REG_STATUS 0x04
-#define ES1370_REG_UART_DATA 0x08
-#define ES1370_REG_UART_STATUS 0x09
-#define ES1370_REG_UART_CONTROL 0x09
-#define ES1370_REG_UART_TEST 0x0a
-#define ES1370_REG_MEMPAGE 0x0c
-#define ES1370_REG_CODEC 0x10
-#define ES1370_REG_SERIAL_CONTROL 0x20
-#define ES1370_REG_DAC1_SCOUNT 0x24
-#define ES1370_REG_DAC2_SCOUNT 0x28
-#define ES1370_REG_ADC_SCOUNT 0x2c
-
-#define ES1370_REG_DAC1_FRAMEADR 0xc30
-#define ES1370_REG_DAC1_FRAMECNT 0xc34
-#define ES1370_REG_DAC2_FRAMEADR 0xc38
-#define ES1370_REG_DAC2_FRAMECNT 0xc3c
-#define ES1370_REG_ADC_FRAMEADR 0xd30
-#define ES1370_REG_ADC_FRAMECNT 0xd34
-#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
-#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
-
-#define ES1370_FMT_U8_MONO 0
-#define ES1370_FMT_U8_STEREO 1
-#define ES1370_FMT_S16_MONO 2
-#define ES1370_FMT_S16_STEREO 3
-#define ES1370_FMT_STEREO 1
-#define ES1370_FMT_S16 2
-#define ES1370_FMT_MASK 3
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
-
-#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
-#define DAC2_DIVTOSR(x) (1411200/((x)+2))
-
-#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */
-#define CTRL_XCTL1 0x40000000 /* electret mic bias */
-#define CTRL_OPEN 0x20000000 /* no function, can be read and written */
-#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */
-#define CTRL_SH_PCLKDIV 16
-#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
-#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
-#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
-#define CTRL_SH_WTSRSEL 12
-#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */
-#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
-#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */
-#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */
-#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 (presumably at address 0x200) */
-#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */
-#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */
-
-#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
-#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */
-#define STAT_CBUSY 0x00000200 /* 1 = codec busy */
-#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */
-#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
-#define STAT_SH_VC 5
-#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 */
-
-#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 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)
-
-/* --------------------------------------------------------------------- */
-
-struct es1370_state {
- /* magic */
- unsigned int magic;
-
- /* list of es1370 devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
- int dev_mixer;
- int dev_dac;
- int dev_midi;
-
- /* hardware resources */
- unsigned long io; /* long for SPARC */
- unsigned int irq;
-
- /* mixer registers; there is no HW readback */
- struct {
- unsigned short vol[10];
- unsigned int recsrc;
- unsigned int modcnt;
- unsigned short micpreamp;
- unsigned int imix;
- } mix;
-
- /* wave stuff */
- unsigned ctrl;
- unsigned sctrl;
-
- 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;
-
- /* The following buffer is used to point the phantom write channel to. */
- unsigned char *bugbuf_cpu;
- dma_addr_t bugbuf_dma;
-
- /* 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 mutex;
-};
-
-/* --------------------------------------------------------------------- */
-
-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 void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data)
-{
- unsigned long tmo = jiffies + HZ/10, j;
-
- do {
- j = jiffies;
- if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) {
- outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC);
- return;
- }
- schedule();
- } while ((signed)(tmo-j) > 0);
- printk(KERN_ERR "es1370: write to codec register timeout\n");
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct es1370_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_ADC_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac1(struct es1370_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_DAC1_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac2(struct es1370_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_DAC2_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac1(struct es1370_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+ES1370_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+ES1370_REG_DAC1_SCOUNT);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac2(struct es1370_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+ES1370_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+ES1370_REG_DAC2_SCOUNT);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct es1370_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+ES1370_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+ES1370_REG_ADC_SCOUNT);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1370_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 es1370_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 es1370_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 &= ES1370_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 & ES1370_FMT_S16) ? 0 : 0x80, db->dmasize);
- outl((reg >> 8) & 15, s->io+ES1370_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 es1370_state *s)
-{
- stop_adc(s);
- return prog_dmabuf(s, &s->dma_adc, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
- (s->sctrl >> SCTRL_SH_R1FMT) & ES1370_FMT_MASK, ES1370_REG_ADC_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac2(struct es1370_state *s)
-{
- stop_dac2(s);
- return prog_dmabuf(s, &s->dma_dac2, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
- (s->sctrl >> SCTRL_SH_P2FMT) & ES1370_FMT_MASK, ES1370_REG_DAC2_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac1(struct es1370_state *s)
-{
- stop_dac1(s);
- return prog_dmabuf(s, &s->dma_dac1, dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
- (s->sctrl >> SCTRL_SH_P1FMT) & ES1370_FMT_MASK, ES1370_REG_DAC1_FRAMEADR);
-}
-
-static inline unsigned get_hwptr(struct es1370_state *s, struct dmabuf *db, unsigned reg)
-{
- unsigned hwptr, diff;
-
- outl((reg >> 8) & 15, s->io+ES1370_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 es1370_update_ptr(struct es1370_state *s)
-{
- int diff;
-
- /* update ADC pointer */
- if (s->ctrl & CTRL_ADC_EN) {
- diff = get_hwptr(s, &s->dma_adc, ES1370_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+ES1370_REG_CONTROL);
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC1 pointer */
- if (s->ctrl & CTRL_DAC1_EN) {
- diff = get_hwptr(s, &s->dma_dac1, ES1370_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+ES1370_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, ES1370_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+ES1370_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 es1370_handle_midi(struct es1370_state *s)
-{
- unsigned char ch;
- int wake;
-
- if (!(s->ctrl & CTRL_UART_EN))
- return;
- wake = 0;
- while (inb(s->io+ES1370_REG_UART_STATUS) & USTAT_RXRDY) {
- ch = inb(s->io+ES1370_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+ES1370_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) {
- outb(s->midi.obuf[s->midi.ord], s->io+ES1370_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+ES1370_REG_UART_CONTROL);
-}
-
-static irqreturn_t es1370_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct es1370_state *s = (struct es1370_state *)dev_id;
- unsigned int intsrc, sctl;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inl(s->io+ES1370_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+ES1370_REG_SERIAL_CONTROL);
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- es1370_update_ptr(s);
- es1370_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "es1370: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != ES1370_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-static const struct {
- unsigned volidx:4;
- unsigned left:4;
- unsigned right:4;
- unsigned stereo:1;
- unsigned recmask:13;
- unsigned avail:1;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x0000, 1 }, /* master */
- [SOUND_MIXER_PCM] = { 1, 0x2, 0x3, 1, 0x0400, 1 }, /* voice */
- [SOUND_MIXER_SYNTH] = { 2, 0x4, 0x5, 1, 0x0060, 1 }, /* FM */
- [SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 }, /* CD */
- [SOUND_MIXER_LINE] = { 4, 0x8, 0x9, 1, 0x0018, 1 }, /* Line */
- [SOUND_MIXER_LINE1] = { 5, 0xa, 0xb, 1, 0x1800, 1 }, /* AUX */
- [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 0, 0x0100, 1 }, /* Mono1 */
- [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 0, 0x0200, 1 }, /* Mono2 */
- [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 0, 0x0001, 1 }, /* Mic */
- [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } /* mono out */
-};
-
-static void set_recsrc(struct es1370_state *s, unsigned int val)
-{
- unsigned int i, j;
-
- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (!mixtable[i].recmask) {
- val &= ~(1 << i);
- continue;
- }
- j |= mixtable[i].recmask;
- }
- s->mix.recsrc = val;
- wrcodec(s, 0x12, j & 0xd5);
- wrcodec(s, 0x13, j & 0xaa);
- wrcodec(s, 0x14, (j >> 8) & 0x17);
- wrcodec(s, 0x15, (j >> 8) & 0x0f);
- i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
- if (!s->mix.imix) {
- i &= 0xff60; /* mute record and line monitor */
- }
- wrcodec(s, 0x10, i);
- wrcodec(s, 0x11, i >> 8);
-}
-
-static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg)
-{
- unsigned long flags;
- int i, val;
- unsigned char l, r, rl, rr;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_PRIVATE1) {
- /* enable/disable/query mixer preamp */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- s->mix.micpreamp = !!val;
- wrcodec(s, 0x19, s->mix.micpreamp);
- }
- return put_user(s->mix.micpreamp, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- /* enable/disable/query use of linein as second lineout */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->ctrl |= CTRL_XCTL0;
- else
- s->ctrl &= ~CTRL_XCTL0;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->ctrl & CTRL_XCTL0) ? 1 : 0, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE3) {
- /* enable/disable/query microphone impedance setting */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->ctrl |= CTRL_XCTL1;
- else
- s->ctrl &= ~CTRL_XCTL1;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->ctrl & CTRL_XCTL1) ? 1 : 0, p);
- }
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strncpy(info.id, "ES1370", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
- info.modify_counter = s->mix.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;
- strncpy(info.id, "ES1370", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(s->mix.recsrc, p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- val = SOUND_MASK_IMIX;
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].avail)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].recmask)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].stereo)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(0, p);
-
- case SOUND_MIXER_IMIX:
- return put_user(s->mix.imix, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
- return -EINVAL;
- return put_user(s->mix.vol[mixtable[i].volidx], p);
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
-
- case SOUND_MIXER_IMIX:
- if (get_user(s->mix.imix, p))
- return -EFAULT;
- set_recsrc(s, s->mix.recsrc);
- return 0;
-
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- set_recsrc(s, val);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (mixtable[i].stereo) {
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- if (l < 7) {
- rl = 0x80;
- l = 0;
- } else {
- rl = 31 - ((l - 7) / 3);
- l = (31 - rl) * 3 + 7;
- }
- if (r < 7) {
- rr = 0x80;
- r = 0;
- } else {
- rr = 31 - ((r - 7) / 3);
- r = (31 - rr) * 3 + 7;
- }
- wrcodec(s, mixtable[i].right, rr);
- } else {
- if (mixtable[i].left == 15) {
- if (l < 2) {
- rr = rl = 0x80;
- r = l = 0;
- } else {
- rl = 7 - ((l - 2) / 14);
- r = l = (7 - rl) * 14 + 2;
- }
- } else {
- if (l < 7) {
- rl = 0x80;
- r = l = 0;
- } else {
- rl = 31 - ((l - 7) / 3);
- r = l = (31 - rl) * 3 + 7;
- }
- }
- }
- wrcodec(s, mixtable[i].left, rl);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[mixtable[i].volidx] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[mixtable[i].volidx] = val;
-#endif
- return put_user(s->mix.vol[mixtable[i].volidx], p);
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int es1370_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_state, devs);
- if (s->dev_mixer == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int es1370_release_mixdev(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int es1370_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct es1370_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations es1370_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = es1370_ioctl_mixdev,
- .open = es1370_open_mixdev,
- .release = es1370_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac1(struct es1370_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
- / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
- tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "es1370: 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 es1370_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_INTERRUPTIBLE);
- 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
- / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
- tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "es1370: 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 es1370_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_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->mutex);
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- goto out;
-
- 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->mutex);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- mutex_lock(&s->mutex);
- 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->mutex);
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t es1370_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_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_dac2.mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- mutex_lock(&s->mutex);
- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
- goto out;
- 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->mutex);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- mutex_lock(&s->mutex);
- 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->mutex);
- remove_wait_queue(&s->dma_dac2.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct es1370_state *s = (struct es1370_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);
- es1370_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 es1370_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- struct dmabuf *db;
- int ret = 0;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- mutex_lock(&s->mutex);
- 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->mutex);
- unlock_kernel();
- return ret;
-}
-
-static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct es1370_state *s = (struct es1370_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 (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
- return -EINVAL;
- if (val < 4000)
- val = 4000;
- if (val > 50000)
- val = 50000;
- stop_adc(s);
- stop_dac2(s);
- s->dma_adc.ready = s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), 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+ES1370_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+ES1370_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+ES1370_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+ES1370_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+ES1370_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+ES1370_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);
- es1370_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);
- es1370_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);
- es1370_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);
- es1370_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);
- es1370_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(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), 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 mixer_ioctl(s, cmd, arg);
-}
-
-static int es1370_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_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);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_READ|FMODE_WRITE)))
- s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV);
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- s->sctrl &= ~SCTRL_R1FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT;
- else
- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_R1FMT;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0;
- s->dma_dac2.enabled = 1;
- s->sctrl &= ~SCTRL_P2FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT;
- else
- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P2FMT;
- }
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- outl(s->ctrl, s->io+ES1370_REG_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->mutex);
- return nonseekable_open(inode, file);
-}
-
-static int es1370_release(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_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);
- synchronize_irq(s->irq);
- 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));
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1370_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = es1370_read,
- .write = es1370_write,
- .poll = es1370_poll,
- .ioctl = es1370_ioctl,
- .mmap = es1370_mmap,
- .open = es1370_open,
- .release = es1370_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_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 es1370_poll_dac(struct file *file, struct poll_table_struct *wait)
-{
- struct es1370_state *s = (struct es1370_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);
- es1370_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 es1370_mmap_dac(struct file *file, struct vm_area_struct *vma)
-{
- struct es1370_state *s = (struct es1370_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 es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- unsigned ctrl;
- 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;
- for (ctrl = 0; ctrl <= 2; ctrl++)
- if (val < (dac1_samplerate[ctrl] + dac1_samplerate[ctrl+1]) / 2)
- break;
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (ctrl << CTRL_SH_WTSRSEL);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], 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+ES1370_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 (s->dma_dac1.mapped)
- return -EINVAL;
- 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+ES1370_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+ES1370_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);
- es1370_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);
- es1370_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);
- es1370_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(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], 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 mixer_ioctl(s, cmd, arg);
-}
-
-static int es1370_open_dac(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_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;
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL);
- s->sctrl &= ~SCTRL_P1FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P1FMT;
- else
- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P1FMT;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= FMODE_DAC;
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int es1370_release_dac(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_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;
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1370_dac_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = es1370_write_dac,
- .poll = es1370_poll_dac,
- .ioctl = es1370_ioctl_dac,
- .mmap = es1370_mmap_dac,
- .open = es1370_open_dac,
- .release = es1370_release_dac,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_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 es1370_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_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);
- es1370_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);
- es1370_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 es1370_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct es1370_state *s = (struct es1370_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 es1370_midi_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_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+ES1370_REG_UART_CONTROL);
- outb(0, s->io+ES1370_REG_UART_CONTROL);
- outb(0, s->io+ES1370_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+ES1370_REG_CONTROL);
- es1370_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 es1370_midi_release(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_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)
- DBG(printk(KERN_DEBUG "es1370: 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+ES1370_REG_CONTROL);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1370_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = es1370_midi_read,
- .write = es1370_midi_write,
- .poll = es1370_midi_poll,
- .open = es1370_midi_open,
- .release = es1370_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int lineout[NR_DEVICE];
-static int micbias[NR_DEVICE];
-
-static unsigned int devindex;
-
-module_param_array(lineout, bool, NULL, 0);
-MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
-module_param_array(micbias, bool, NULL, 0);
-MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("ES1370 AudioPCI Driver");
-MODULE_LICENSE("GPL");
-
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
- { SOUND_MIXER_WRITE_LINE3, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 },
- { SOUND_MIXER_WRITE_OGAIN, 0x4040 }
-};
-
-#ifdef SUPPORT_JOYSTICK
-
-static int __devinit es1370_register_gameport(struct es1370_state *s)
-{
- struct gameport *gp;
-
- if (!request_region(0x200, JOY_EXTENT, "es1370")) {
- printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
- return -EBUSY;
- }
-
- s->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
- release_region(0x200, JOY_EXTENT);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "ESS1370");
- gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
- gp->dev.parent = &s->dev->dev;
- gp->io = 0x200;
-
- s->ctrl |= CTRL_JYSTK_EN;
- outl(s->ctrl, s->io + ES1370_REG_CONTROL);
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void es1370_unregister_gameport(struct es1370_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, JOY_EXTENT);
-
- }
-}
-
-#else
-static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; }
-static inline void es1370_unregister_gameport(struct es1370_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- struct es1370_state *s;
- mm_segment_t fs;
- int i, val, ret;
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
-
- if ( !(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
- !pci_resource_start(pcidev, 0)
- )
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
- i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
- if (i) {
- printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
- return i;
- }
- if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) {
- printk(KERN_WARNING "es1370: out of memory\n");
- return -ENOMEM;
- }
- memset(s, 0, sizeof(struct es1370_state));
- 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 = ES1370_MAGIC;
- s->dev = pcidev;
- s->io = pci_resource_start(pcidev, 0);
- s->irq = pcidev->irq;
- if (!request_region(s->io, ES1370_EXTENT, "es1370")) {
- printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
- ret = -EBUSY;
- goto err_region;
- }
- if ((ret=request_irq(s->irq, es1370_interrupt, IRQF_SHARED, "es1370",s))) {
- printk(KERN_ERR "es1370: irq %u in use\n", s->irq);
- goto err_irq;
- }
-
- /* initialize codec registers */
- /* note: setting CTRL_SERR_DIS is reported to break
- * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
- s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
- if (lineout[devindex])
- s->ctrl |= CTRL_XCTL0;
- if (micbias[devindex])
- s->ctrl |= CTRL_XCTL1;
- s->sctrl = 0;
- printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n",
- s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in",
- (s->ctrl & CTRL_XCTL1) ? "1" : "0");
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) {
- ret = s->dev_dac;
- goto err_dev3;
- }
- if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) {
- ret = s->dev_midi;
- goto err_dev4;
- }
- /* initialize the chips */
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- /* point phantom write channel to "bugbuf" */
- s->bugbuf_cpu = pci_alloc_consistent(pcidev,16,&s->bugbuf_dma);
- if (!s->bugbuf_cpu) {
- ret = -ENOMEM;
- goto err_dev5;
- }
- outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
- outl(s->bugbuf_dma, s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
- outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
- pci_set_master(pcidev); /* enable bus mastering */
- wrcodec(s, 0x16, 3); /* no RST, PD */
- wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */
- wrcodec(s, 0x18, 0); /* recording source is mixer */
- wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */
- s->mix.imix = 1;
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- set_fs(fs);
-
- es1370_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_dev5:
- unregister_sound_midi(s->dev_midi);
- err_dev4:
- unregister_sound_dsp(s->dev_dac);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "es1370: cannot register misc device\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->io, ES1370_EXTENT);
- err_region:
- kfree(s);
- return ret;
-}
-
-static void __devexit es1370_remove(struct pci_dev *dev)
-{
- struct es1370_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- list_del(&s->devs);
- outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */
- outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
- synchronize_irq(s->irq);
- free_irq(s->irq, s);
- es1370_unregister_gameport(s);
- release_region(s->io, ES1370_EXTENT);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_dsp(s->dev_dac);
- unregister_sound_midi(s->dev_midi);
- pci_free_consistent(dev, 16, s->bugbuf_cpu, s->bugbuf_dma);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver es1370_driver = {
- .name = "es1370",
- .id_table = id_table,
- .probe = es1370_probe,
- .remove = __devexit_p(es1370_remove),
-};
-
-static int __init init_es1370(void)
-{
- printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n");
- return pci_register_driver(&es1370_driver);
-}
-
-static void __exit cleanup_es1370(void)
-{
- printk(KERN_INFO "es1370: unloading\n");
- pci_unregister_driver(&es1370_driver);
-}
-
-module_init(init_es1370);
-module_exit(cleanup_es1370);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: es1370=lineout[,micbias]] */
-
-static int __init es1370_setup(char *str)
-{
- static unsigned __initdata nr_dev = 0;
-
- if (nr_dev >= NR_DEVICE)
- return 0;
-
- (void)
- ((get_option(&str,&lineout [nr_dev]) == 2)
- && get_option(&str,&micbias [nr_dev])
- );
-
- nr_dev++;
- return 1;
-}
-
-__setup("es1370=", es1370_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
deleted file mode 100644
index 82f40a0..0000000
--- a/sound/oss/esssolo1.c
+++ /dev/null
@@ -1,2516 +0,0 @@
-/****************************************************************************/
-
-/*
- * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver.
- *
- * 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.
- *
- * Module command line parameters:
- * none so far
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * Revision history
- * 10.11.1998 0.1 Initial release (without any hardware)
- * 22.03.1999 0.2 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.1999 0.3 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>
- * 15.06.1999 0.4 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.1999 0.5 Add pci_set_master
- * 12.08.1999 0.6 Fix MIDI UART crashing the driver
- * Changed mixer semantics from OSS documented
- * behaviour to OSS "code behaviour".
- * Recording might actually work now.
- * The real DDMA controller address register is at PCI config
- * 0x60, while the register at 0x18 is used as a placeholder
- * register for BIOS address allocation. This register
- * is supposed to be copied into 0x60, according
- * to the Solo1 datasheet. When I do that, I can access
- * the DDMA registers except the mask bit, which
- * is stuck at 1. When I copy the contents of 0x18 +0x10
- * to the DDMA base register, everything seems to work.
- * The fun part is that the Windows Solo1 driver doesn't
- * seem to do these tricks.
- * Bugs remaining: plops and clicks when starting/stopping playback
- * 31.08.1999 0.7 add spin_lock_init
- * replaced current->state = x with set_current_state(x)
- * 03.09.1999 0.8 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 07.10.1999 0.9 Fix initialization; complain if sequencer writes time out
- * Revised resource grabbing for the FM synthesizer
- * 28.10.1999 0.10 More waitqueue races fixed
- * 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
- * Disabling recording on Alpha
- * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun;
- * Tim Janik's BSE (Bedevilled Sound Engine) found this
- * Integrated (aka redid 8-)) APM support patch by Zach Brown
- * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver
- * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled
- * 13.03.2000 0.15 Reintroduce initialization of a couple of PCI config space registers
- * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask
- * 12.12.2000 0.17 More dma buffer initializations, patch from
- * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- * 31.01.2001 0.18 Register/Unregister gameport, original patch from
- * Nathaniel Daw <daw@cs.cmu.edu>
- * Fix SETTRIGGER non OSS API conformity
- * 10.03.2001 provide abs function, prevent picking up a bogus kernel macro
- * for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
- * 15.05.2001 pci_enable_device moved, return values in probe cleaned
- * up. Marcus Meissner <mm@caldera.de>
- * 22.05.2001 0.19 more cleanups, changed PM to PCI 2.4 style, got rid
- * of global list of devices, using pci device data.
- * Marcus Meissner <mm@caldera.de>
- * 03.01.2003 0.20 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/bitops.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/gameport.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "dm.h"
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_ESS
-#define PCI_VENDOR_ID_ESS 0x125d
-#endif
-#ifndef PCI_DEVICE_ID_ESS_SOLO1
-#define PCI_DEVICE_ID_ESS_SOLO1 0x1969
-#endif
-
-#define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
-
-#define DDMABASE_OFFSET 0 /* chip bug workaround kludge */
-#define DDMABASE_EXTENT 16
-
-#define IOBASE_EXTENT 16
-#define SBBASE_EXTENT 16
-#define VCBASE_EXTENT (DDMABASE_EXTENT+DDMABASE_OFFSET)
-#define MPUBASE_EXTENT 4
-#define GPBASE_EXTENT 4
-#define GAMEPORT_EXTENT 4
-
-#define FMSYNTH_EXTENT 4
-
-/* 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 FMODE_DMFM 0x10
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-static struct pci_driver solo1_driver;
-
-/* --------------------------------------------------------------------- */
-
-struct solo1_state {
- /* magic */
- unsigned int magic;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
- int dev_mixer;
- int dev_midi;
- int dev_dmfm;
-
- /* hardware resources */
- unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */
- unsigned int irq;
-
- /* mixer registers */
- struct {
- unsigned short vol[10];
- unsigned int recsrc;
- unsigned int modcnt;
- unsigned short micpreamp;
- } mix;
-
- /* wave stuff */
- unsigned fmt;
- unsigned channels;
- unsigned rate;
- unsigned char clkdiv;
- unsigned ena;
-
- 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_dac, dma_adc;
-
- /* midi stuff */
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- struct timer_list timer;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
-#if SUPPORT_JOYSTICK
- struct gameport *gameport;
-#endif
-};
-
-/* --------------------------------------------------------------------- */
-
-static inline void write_seq(struct solo1_state *s, unsigned char data)
-{
- int i;
- unsigned long flags;
-
- /* the local_irq_save stunt is to send the data within the command window */
- for (i = 0; i < 0xffff; i++) {
- local_irq_save(flags);
- if (!(inb(s->sbbase+0xc) & 0x80)) {
- outb(data, s->sbbase+0xc);
- local_irq_restore(flags);
- return;
- }
- local_irq_restore(flags);
- }
- printk(KERN_ERR "esssolo1: write_seq timeout\n");
- outb(data, s->sbbase+0xc);
-}
-
-static inline int read_seq(struct solo1_state *s, unsigned char *data)
-{
- int i;
-
- if (!data)
- return 0;
- for (i = 0; i < 0xffff; i++)
- if (inb(s->sbbase+0xe) & 0x80) {
- *data = inb(s->sbbase+0xa);
- return 1;
- }
- printk(KERN_ERR "esssolo1: read_seq timeout\n");
- return 0;
-}
-
-static inline int reset_ctrl(struct solo1_state *s)
-{
- int i;
-
- outb(3, s->sbbase+6); /* clear sequencer and FIFO */
- udelay(10);
- outb(0, s->sbbase+6);
- for (i = 0; i < 0xffff; i++)
- if (inb(s->sbbase+0xe) & 0x80)
- if (inb(s->sbbase+0xa) == 0xaa) {
- write_seq(s, 0xc6); /* enter enhanced mode */
- return 1;
- }
- return 0;
-}
-
-static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char data)
-{
- write_seq(s, reg);
- write_seq(s, data);
-}
-
-#if 0 /* unused */
-static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
-{
- unsigned char r;
-
- write_seq(s, 0xc0);
- write_seq(s, reg);
- read_seq(s, &r);
- return r;
-}
-#endif /* unused */
-
-static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data)
-{
- outb(reg, s->sbbase+4);
- outb(data, s->sbbase+5);
-}
-
-static unsigned char read_mixer(struct solo1_state *s, unsigned char reg)
-{
- outb(reg, s->sbbase+4);
- return inb(s->sbbase+5);
-}
-
-/* --------------------------------------------------------------------- */
-
-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 inline void stop_dac(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_WRITE;
- write_mixer(s, 0x78, 0x10);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
- s->ena |= FMODE_WRITE;
- write_mixer(s, 0x78, 0x12);
- udelay(10);
- write_mixer(s, 0x78, 0x13);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_adc(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_READ;
- write_ctrl(s, 0xb8, 0xe);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- s->ena |= FMODE_READ;
- write_ctrl(s, 0xb8, 0xf);
-#if 0
- printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf);
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
- inb(s->ddmabase+0xf), inw(s->ddmabase+4), inl(s->ddmabase), inb(s->ddmabase+8));
-#endif
- outb(0, s->ddmabase+0xd); /* master reset */
- outb(1, s->ddmabase+0xf); /* mask */
- outb(0x54/*0x14*/, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
- outl(virt_to_bus(s->dma_adc.rawbuf), s->ddmabase);
- outw(s->dma_adc.dmasize-1, s->ddmabase+4);
- outb(0, s->ddmabase+0xf);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-#if 0
- printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x SBstat: 0x%02x\n"
- KERN_DEBUG "solo1: DMA: stat: 0x%02x cnt: 0x%04x mask: 0x%02x\n",
- read_ctrl(s, 0xb8), inb(s->sbbase+0xc),
- inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->ddmabase+0xf));
- printk(KERN_DEBUG "solo1: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
- KERN_DEBUG "solo1: B1: 0x%02x B2: 0x%02x B4: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n",
- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb4), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8),
- read_ctrl(s, 0xb9));
-#endif
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct solo1_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 solo1_state *s, struct dmabuf *db)
-{
- int order;
- unsigned bytespersec;
- unsigned bufs, sample_shift = 0;
- 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);
- }
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- sample_shift++;
- if (s->channels > 1)
- sample_shift++;
- bytespersec = s->rate << sample_shift;
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytespersec)
- db->fragshift = ld2(bytespersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytespersec/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;
- db->dmasize = db->numfrag << db->fragshift;
- db->enabled = 1;
- return 0;
-}
-
-static inline int prog_dmabuf_adc(struct solo1_state *s)
-{
- unsigned long va;
- int c;
-
- stop_adc(s);
- /* check if PCI implementation supports 24bit busmaster DMA */
- if (s->dev->dma_mask > 0xffffff)
- return -EIO;
- if ((c = prog_dmabuf(s, &s->dma_adc)))
- return c;
- va = s->dma_adc.dmaaddr;
- if ((va & ~((1<<24)-1)))
- panic("solo1: buffer above 16M boundary");
- outb(0, s->ddmabase+0xd); /* clear */
- outb(1, s->ddmabase+0xf); /* mask */
- /*outb(0, s->ddmabase+8);*/ /* enable (enable is active low!) */
- outb(0x54, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
- outl(va, s->ddmabase);
- outw(s->dma_adc.dmasize-1, s->ddmabase+4);
- c = - s->dma_adc.fragsamples;
- write_ctrl(s, 0xa4, c);
- write_ctrl(s, 0xa5, c >> 8);
- outb(0, s->ddmabase+0xf);
- s->dma_adc.ready = 1;
- return 0;
-}
-
-static int prog_dmabuf_dac(struct solo1_state *s)
-{
- unsigned long va;
- int c;
-
- stop_dac(s);
- if ((c = prog_dmabuf(s, &s->dma_dac)))
- return c;
- memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
- va = s->dma_dac.dmaaddr;
- if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))
- panic("solo1: buffer crosses 1M boundary");
- outl(va, s->iobase);
- /* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */
- outw(s->dma_dac.dmasize, s->iobase+4);
- c = - s->dma_dac.fragsamples;
- write_mixer(s, 0x74, c);
- write_mixer(s, 0x76, c >> 8);
- outb(0xa, s->iobase+6);
- s->dma_dac.ready = 1;
- return 0;
-}
-
-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 solo1_update_ptr(struct solo1_state *s)
-{
- int diff;
- unsigned hwptr;
-
- /* update ADC pointer */
- if (s->ena & FMODE_READ) {
- hwptr = (s->dma_adc.dmasize - 1 - inw(s->ddmabase+4)) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
-#if 0
- printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",
- s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);
-#endif
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- } else {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- s->ena &= ~FMODE_READ;
- write_ctrl(s, 0xb8, 0xe);
- s->dma_adc.error++;
- }
- if (s->dma_adc.count > 0)
- wake_up(&s->dma_adc.wait);
- }
- }
- /* update DAC pointer */
- if (s->ena & FMODE_WRITE) {
- hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
-#if 0
- printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n",
- s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count);
-#endif
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- wake_up(&s->dma_dac.wait);
- } else {
- s->dma_dac.count -= diff;
- if (s->dma_dac.count <= 0) {
- s->ena &= ~FMODE_WRITE;
- write_mixer(s, 0x78, 0x12);
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr,
- s->dma_dac.fragsize, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
- wake_up(&s->dma_dac.wait);
- }
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void prog_codec(struct solo1_state *s)
-{
- unsigned long flags;
- int fdiv, filter;
- unsigned char c;
-
- reset_ctrl(s);
- write_seq(s, 0xd3);
- /* program sampling rates */
- filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */
- fdiv = 256 - 7160000 / (filter * 82);
- spin_lock_irqsave(&s->lock, flags);
- write_ctrl(s, 0xa1, s->clkdiv);
- write_ctrl(s, 0xa2, fdiv);
- write_mixer(s, 0x70, s->clkdiv);
- write_mixer(s, 0x72, fdiv);
- /* program ADC parameters */
- write_ctrl(s, 0xb8, 0xe);
- write_ctrl(s, 0xb9, /*0x1*/0);
- write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12);
- c = 0xd0;
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- c |= 0x04;
- if (s->fmt & (AFMT_S16_LE | AFMT_S8))
- c |= 0x20;
- if (s->channels > 1)
- c ^= 0x48;
- write_ctrl(s, 0xb7, (c & 0x70) | 1);
- write_ctrl(s, 0xb7, c);
- write_ctrl(s, 0xb1, 0x50);
- write_ctrl(s, 0xb2, 0x50);
- /* program DAC parameters */
- c = 0x40;
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- c |= 1;
- if (s->fmt & (AFMT_S16_LE | AFMT_S8))
- c |= 4;
- if (s->channels > 1)
- c |= 2;
- write_mixer(s, 0x7a, c);
- write_mixer(s, 0x78, 0x10);
- s->ena = 0;
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != SOLO1_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg)
-{
- static const unsigned int mixer_src[8] = {
- SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,
- SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0
- };
- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, /* voice */
- [SOUND_MIXER_SYNTH] = 2, /* FM */
- [SOUND_MIXER_CD] = 3, /* CD */
- [SOUND_MIXER_LINE] = 4, /* Line */
- [SOUND_MIXER_LINE1] = 5, /* AUX */
- [SOUND_MIXER_MIC] = 6, /* Mic */
- [SOUND_MIXER_LINE2] = 7, /* Mono in */
- [SOUND_MIXER_SPEAKER] = 8, /* Speaker */
- [SOUND_MIXER_RECLEV] = 9, /* Recording level */
- [SOUND_MIXER_VOLUME] = 10 /* Master Volume */
- };
- static const unsigned char mixreg[] = {
- 0x7c, /* voice */
- 0x36, /* FM */
- 0x38, /* CD */
- 0x3e, /* Line */
- 0x3a, /* AUX */
- 0x1a, /* Mic */
- 0x6d /* Mono in */
- };
- unsigned char l, r, rl, rr, vidx;
- int i, val;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
-
- if (cmd == SOUND_MIXER_PRIVATE1) {
- /* enable/disable/query mixer preamp */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- val = val ? 0xff : 0xf7;
- write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
- }
- val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
- return put_user(val, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- /* enable/disable/query spatializer */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- val &= 0x3f;
- write_mixer(s, 0x52, val);
- write_mixer(s, 0x50, val ? 0x08 : 0);
- }
- return put_user(read_mixer(s, 0x52), p);
- }
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strncpy(info.id, "Solo1", sizeof(info.id));
- strncpy(info.name, "ESS Solo1", sizeof(info.name));
- info.modify_counter = s->mix.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;
- strncpy(info.id, "Solo1", sizeof(info.id));
- strncpy(info.name, "ESS Solo1", sizeof(info.name));
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(mixer_src[read_mixer(s, 0x1c) & 7], p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV |
- SOUND_MASK_SPEAKER, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
- return -EINVAL;
- return put_user(s->mix.vol[vidx-1], p);
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-#if 0
- {
- static const unsigned char regs[] = {
- 0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
- };
- int i;
-
- for (i = 0; i < sizeof(regs); i++)
- printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
- regs[i], read_mixer(s, regs[i]));
- printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
- 0xb4, read_ctrl(s, 0xb4));
- }
-#endif
- if (get_user(val, p))
- return -EFAULT;
- i = hweight32(val);
- if (i == 0)
- return 0;
- else if (i > 1)
- val &= ~mixer_src[read_mixer(s, 0x1c) & 7];
- for (i = 0; i < 8; i++) {
- if (mixer_src[i] & val)
- break;
- }
- if (i > 7)
- return 0;
- write_mixer(s, 0x1c, i);
- return 0;
-
- case SOUND_MIXER_VOLUME:
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- if (l < 6) {
- rl = 0x40;
- l = 0;
- } else {
- rl = (l * 2 - 11) / 3;
- l = (rl * 3 + 11) / 2;
- }
- if (r < 6) {
- rr = 0x40;
- r = 0;
- } else {
- rr = (r * 2 - 11) / 3;
- r = (rr * 3 + 11) / 2;
- }
- write_mixer(s, 0x60, rl);
- write_mixer(s, 0x62, rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[9] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[9] = val;
-#endif
- return put_user(s->mix.vol[9], p);
-
- case SOUND_MIXER_SPEAKER:
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- else if (l < 2)
- l = 2;
- rl = (l - 2) / 14;
- l = rl * 14 + 2;
- write_mixer(s, 0x3c, rl);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[7] = l * 0x101;
-#else
- s->mix.vol[7] = val;
-#endif
- return put_user(s->mix.vol[7], p);
-
- case SOUND_MIXER_RECLEV:
- if (get_user(val, p))
- return -EFAULT;
- l = (val << 1) & 0x1fe;
- if (l > 200)
- l = 200;
- else if (l < 5)
- l = 5;
- r = (val >> 7) & 0x1fe;
- if (r > 200)
- r = 200;
- else if (r < 5)
- r = 5;
- rl = (l - 5) / 13;
- rr = (r - 5) / 13;
- r = (rl * 13 + 5) / 2;
- l = (rr * 13 + 5) / 2;
- write_ctrl(s, 0xb4, (rl << 4) | rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[8] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[8] = val;
-#endif
- return put_user(s->mix.vol[8], p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = (val << 1) & 0x1fe;
- if (l > 200)
- l = 200;
- else if (l < 5)
- l = 5;
- r = (val >> 7) & 0x1fe;
- if (r > 200)
- r = 200;
- else if (r < 5)
- r = 5;
- rl = (l - 5) / 13;
- rr = (r - 5) / 13;
- r = (rl * 13 + 5) / 2;
- l = (rr * 13 + 5) / 2;
- write_mixer(s, mixreg[vidx-1], (rl << 4) | rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[vidx-1] = val;
-#endif
- return put_user(s->mix.vol[vidx-1], p);
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int solo1_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
- drvr = pci_dev_driver (pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (s->dev_mixer == minor)
- break;
- }
- if (!s)
- return -ENODEV;
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int solo1_release_mixdev(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations solo1_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = solo1_ioctl_mixdev,
- .open = solo1_open_mixdev,
- .release = solo1_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct solo1_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
- unsigned tmo;
-
- if (s->dma_dac.mapped)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- tmo >>= 1;
- if (s->channels > 1)
- tmo >>= 1;
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "solo1: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t solo1_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- 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;
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x cnt: %u\n",
- read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);
-#endif
- if (cnt <= 0) {
- if (s->dma_adc.enabled)
- start_adc(s);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
- KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
- KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
- KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
- inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
-#endif
- if (inb(s->ddmabase+15) & 1)
- printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
- KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
- KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
- KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
- inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
-#endif
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- 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);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n",
- read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));
-#endif
- }
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t solo1_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-#if 0
- printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x 71: 0x%02x 72: 0x%02x 74: 0x%02x 76: 0x%02x 78: 0x%02x 7A: 0x%02x\n"
- KERN_DEBUG "solo1_write: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x SBstat: 0x%02x\n",
- read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76),
- read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
- printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x reg 7A: 0x%02x DMAcnt: 0x%04x DMAstat: 0x%02x SBstat: 0x%02x\n",
- read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
-#endif
- ret = 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize-swptr;
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.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_dac.enabled)
- start_dac(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_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac.enabled)
- start_dac(s);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf_dac(s))
- return 0;
- poll_wait(file, &s->dma_dac.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);
- solo1_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- } else {
- if (s->dma_adc.count > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-
-static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf_dac(s)) != 0)
- goto out;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf_adc(s)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret, count;
- int div1, div2;
- unsigned rate1, rate2;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.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_dac(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_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.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;
- }
- prog_codec(s);
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program sampling rates */
- if (val > 48000)
- val = 48000;
- if (val < 6300)
- val = 6300;
- div1 = (768000 + val / 2) / val;
- rate1 = (768000 + div1 / 2) / div1;
- div1 = -div1;
- div2 = (793800 + val / 2) / val;
- rate2 = (793800 + div2 / 2) / div2;
- div2 = (-div2) & 0x7f;
- if (abs(val - rate2) < abs(val - rate1)) {
- rate1 = rate2;
- div1 = div2;
- }
- s->rate = rate1;
- s->clkdiv = div1;
- prog_codec(s);
- }
- return put_user(s->rate, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program channels */
- s->channels = val ? 2 : 1;
- prog_codec(s);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program channels */
- s->channels = (val >= 2) ? 2 : 1;
- prog_codec(s);
- }
- return put_user(s->channels, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program format */
- if (val != AFMT_S16_LE && val != AFMT_U16_LE &&
- val != AFMT_S8 && val != AFMT_U8)
- val = AFMT_U8;
- s->fmt = val;
- prog_codec(s);
- }
- return put_user(s->fmt, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & s->ena & FMODE_READ)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & s->ena & FMODE_WRITE)
- 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_dac.enabled = 1;
- start_adc(s);
- if (inb(s->ddmabase+15) & 1)
- printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
- } else {
- s->dma_dac.enabled = 0;
- stop_adc(s);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
- return ret;
- s->dma_dac.enabled = 1;
- start_dac(s);
- } else {
- s->dma_dac.enabled = 0;
- stop_dac(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac.dmasize - count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.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);
- solo1_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.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_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- count = s->dma_dac.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);
- solo1_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.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_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
-#if 0
- printk(KERN_DEBUG "esssolo1: GETOPTR: bytes %u blocks %u ptr %u, buforder %u numfrag %u fragshift %u\n"
- KERN_DEBUG "esssolo1: swptr %u count %u fragsize %u dmasize %u fragsamples %u\n",
- cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift,
- s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples);
-#endif
- 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_dac(s)))
- return val;
- return put_user(s->dma_dac.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_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;
- }
- 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, 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_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user(s->rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user(s->channels, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int solo1_release(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- outb(0, s->iobase+6); /* disable DMA */
- dealloc_dmabuf(s, &s->dma_dac);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- outb(1, s->ddmabase+0xf); /* mask DMA channel */
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- dealloc_dmabuf(s, &s->dma_adc);
- }
- s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static int solo1_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver(pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- if (!s)
- return -ENODEV;
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
- 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->fmt = AFMT_U8;
- s->channels = 1;
- s->rate = 8000;
- s->clkdiv = 96 | 0x80;
- s->ena = 0;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- s->dma_dac.enabled = 1;
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- prog_codec(s);
- return nonseekable_open(inode, file);
-}
-
-static /*const*/ struct file_operations solo1_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = solo1_read,
- .write = solo1_write,
- .poll = solo1_poll,
- .ioctl = solo1_ioctl,
- .mmap = solo1_mmap,
- .open = solo1_open,
- .release = solo1_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* hold spinlock for the following! */
-static void solo1_handle_midi(struct solo1_state *s)
-{
- unsigned char ch;
- int wake;
-
- if (!(s->mpubase))
- return;
- wake = 0;
- while (!(inb(s->mpubase+1) & 0x80)) {
- ch = inb(s->mpubase);
- 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->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
- outb(s->midi.obuf[s->midi.ord], s->mpubase);
- 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);
-}
-
-static irqreturn_t solo1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct solo1_state *s = (struct solo1_state *)dev_id;
- unsigned int intsrc;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inb(s->iobase+7); /* get interrupt source(s) */
- if (!intsrc)
- return IRQ_NONE;
- (void)inb(s->sbbase+0xe); /* clear interrupt */
- spin_lock(&s->lock);
- /* clear audio interrupts first */
- if (intsrc & 0x20)
- write_mixer(s, 0x7a, read_mixer(s, 0x7a) & 0x7f);
- solo1_update_ptr(s);
- solo1_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-static void solo1_midi_timer(unsigned long data)
-{
- struct solo1_state *s = (struct solo1_state *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- solo1_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->midi.timer.expires = jiffies+1;
- add_timer(&s->midi.timer);
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t solo1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_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 solo1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_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);
- solo1_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);
- solo1_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 solo1_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_flags & FMODE_WRITE)
- poll_wait(file, &s->midi.owait, wait);
- if (file->f_flags & FMODE_READ)
- poll_wait(file, &s->midi.iwait, wait);
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_flags & FMODE_READ) {
- if (s->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_flags & FMODE_WRITE) {
- if (s->midi.ocnt < MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int solo1_midi_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver(pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (s->dev_midi == minor)
- break;
- }
- if (!s)
- return -ENODEV;
- 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(0xff, s->mpubase+1); /* reset command */
- outb(0x3f, s->mpubase+1); /* uart command */
- if (!(inb(s->mpubase+1) & 0x80))
- inb(s->mpubase);
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */
- init_timer(&s->midi.timer);
- s->midi.timer.expires = jiffies+1;
- s->midi.timer.data = (unsigned long)s;
- s->midi.timer.function = solo1_midi_timer;
- add_timer(&s->midi.timer);
- }
- 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;
- }
- 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 solo1_midi_release(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_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 "solo1: 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))) {
- outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */
- del_timer(&s->midi.timer);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations solo1_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = solo1_midi_read,
- .write = solo1_midi_write,
- .poll = solo1_midi_poll,
- .open = solo1_midi_open,
- .release = solo1_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- static const unsigned char op_offset[18] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
- };
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- struct dm_fm_voice v;
- struct dm_fm_note n;
- struct dm_fm_params p;
- unsigned int io;
- unsigned int regb;
-
- switch (cmd) {
- case FM_IOCTL_RESET:
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->sbbase);
- outb(0, s->sbbase+1);
- outb(regb, s->sbbase+2);
- outb(0, s->sbbase+3);
- }
- return 0;
-
- case FM_IOCTL_PLAY_NOTE:
- if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
- return -EFAULT;
- if (n.voice >= 18)
- return -EINVAL;
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->sbbase+2;
- } else {
- regb = n.voice;
- io = s->sbbase;
- }
- outb(0xa0 + regb, io);
- outb(n.fnum & 0xff, io+1);
- outb(0xb0 + regb, io);
- outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
- return 0;
-
- case FM_IOCTL_SET_VOICE:
- if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
- return -EFAULT;
- if (v.voice >= 18)
- return -EINVAL;
- regb = op_offset[v.voice];
- io = s->sbbase + ((v.op & 1) << 1);
- outb(0x20 + regb, io);
- outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) |
- ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
- outb(0x40 + regb, io);
- outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
- outb(0x60 + regb, io);
- outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
- outb(0x80 + regb, io);
- outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
- outb(0xe0 + regb, io);
- outb(v.waveform & 0x7, io+1);
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->sbbase+2;
- } else {
- regb = n.voice;
- io = s->sbbase;
- }
- outb(0xc0 + regb, io);
- outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
- (v.connection & 1), io+1);
- return 0;
-
- case FM_IOCTL_SET_PARAMS:
- if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
- return -EFAULT;
- outb(0x08, s->sbbase);
- outb((p.kbd_split & 1) << 6, s->sbbase+1);
- outb(0xbd, s->sbbase);
- outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
- ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1);
- return 0;
-
- case FM_IOCTL_SET_OPL:
- outb(4, s->sbbase+2);
- outb(arg, s->sbbase+3);
- return 0;
-
- case FM_IOCTL_SET_MODE:
- outb(5, s->sbbase+2);
- outb(arg & 1, s->sbbase+3);
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-static int solo1_dmfm_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver(pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (s->dev_dmfm == minor)
- break;
- }
- if (!s)
- return -ENODEV;
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & FMODE_DMFM) {
- 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 (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) {
- mutex_unlock(&s->open_mutex);
- printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
- return -EBUSY;
- }
- /* init the stuff */
- outb(1, s->sbbase);
- outb(0x20, s->sbbase+1); /* enable waveforms */
- outb(4, s->sbbase+2);
- outb(0, s->sbbase+3); /* no 4op enabled */
- outb(5, s->sbbase+2);
- outb(1, s->sbbase+3); /* enable OPL3 */
- s->open_mode |= FMODE_DMFM;
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int solo1_dmfm_release(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned int regb;
-
- VALIDATE_STATE(s);
- lock_kernel();
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~FMODE_DMFM;
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->sbbase);
- outb(0, s->sbbase+1);
- outb(regb, s->sbbase+2);
- outb(0, s->sbbase+3);
- }
- release_region(s->sbbase, FMSYNTH_EXTENT);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations solo1_dmfm_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = solo1_dmfm_ioctl,
- .open = solo1_dmfm_open,
- .release = solo1_dmfm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
- { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
- { SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 }
-};
-
-static int setup_solo1(struct solo1_state *s)
-{
- struct pci_dev *pcidev = s->dev;
- mm_segment_t fs;
- int i, val;
-
- /* initialize DDMA base address */
- printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
- pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1);
- /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
- pci_write_config_dword(pcidev, 0x50, 0);
- /* disable legacy audio address decode */
- pci_write_config_word(pcidev, 0x40, 0x907f);
-
- /* initialize the chips */
- if (!reset_ctrl(s)) {
- printk(KERN_ERR "esssolo1: cannot reset controller\n");
- return -1;
- }
- outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
-
- /* initialize mixer regs */
- write_mixer(s, 0x7f, 0); /* disable music digital recording */
- write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
- write_mixer(s, 0x64, 0x45); /* volume control */
- write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
- write_mixer(s, 0x50, 0); /* disable spatializer */
- write_mixer(s, 0x52, 0);
- write_mixer(s, 0x14, 0); /* DAC1 minimum volume */
- write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- outb(1, s->ddmabase+0xf); /* mask channel */
- /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */
-
- pci_set_master(pcidev); /* enable bus mastering */
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- val = 1; /* enable mic preamp */
- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
- set_fs(fs);
- return 0;
-}
-
-static int
-solo1_suspend(struct pci_dev *pci_dev, pm_message_t state) {
- struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- return 1;
- outb(0, s->iobase+6);
- /* DMA master clear */
- outb(0, s->ddmabase+0xd);
- /* reset sequencer and FIFO */
- outb(3, s->sbbase+6);
- /* turn off DDMA controller address space */
- pci_write_config_word(s->dev, 0x60, 0);
- return 0;
-}
-
-static int
-solo1_resume(struct pci_dev *pci_dev) {
- struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- return 1;
- setup_solo1(s);
- return 0;
-}
-
-#ifdef SUPPORT_JOYSTICK
-static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
-{
- struct gameport *gp;
-
- if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: gameport io ports are in use\n");
- return -EBUSY;
- }
-
- s->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR "solo1: can not allocate memory for gameport\n");
- release_region(io_port, GAMEPORT_EXTENT);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "ESS Solo1 Gameport");
- gameport_set_phys(gp, "isa%04x/gameport0", io_port);
- gp->dev.parent = &s->dev->dev;
- gp->io = io_port;
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void solo1_unregister_gameport(struct solo1_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, GAMEPORT_EXTENT);
- }
-}
-#else
-static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
-static inline void solo1_unregister_gameport(struct solo1_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- struct solo1_state *s;
- int gpio;
- int ret;
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
- !(pci_resource_flags(pcidev, 1) & IORESOURCE_IO) ||
- !(pci_resource_flags(pcidev, 2) & IORESOURCE_IO) ||
- !(pci_resource_flags(pcidev, 3) & IORESOURCE_IO))
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
-
- /* Recording requires 24-bit DMA, so attempt to set dma mask
- * to 24 bits first, then 32 bits (playback only) if that fails.
- */
- if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK) &&
- pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
- printk(KERN_WARNING "solo1: out of memory\n");
- return -ENOMEM;
- }
- memset(s, 0, sizeof(struct solo1_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.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 = SOLO1_MAGIC;
- s->dev = pcidev;
- s->iobase = pci_resource_start(pcidev, 0);
- s->sbbase = pci_resource_start(pcidev, 1);
- s->vcbase = pci_resource_start(pcidev, 2);
- s->ddmabase = s->vcbase + DDMABASE_OFFSET;
- s->mpubase = pci_resource_start(pcidev, 3);
- gpio = pci_resource_start(pcidev, 4);
- s->irq = pcidev->irq;
- ret = -EBUSY;
- if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region1;
- }
- if (!request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region2;
- }
- if (!request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region3;
- }
- if (!request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region4;
- }
- if ((ret=request_irq(s->irq,solo1_interrupt,IRQF_SHARED,"ESS Solo1",s))) {
- printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
- goto err_irq;
- }
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) {
- ret = s->dev_midi;
- goto err_dev3;
- }
- if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) {
- ret = s->dev_dmfm;
- goto err_dev4;
- }
- if (setup_solo1(s)) {
- ret = -EIO;
- goto err;
- }
- /* register gameport */
- solo1_register_gameport(s, gpio);
- /* store it in the driver field */
- pci_set_drvdata(pcidev, s);
- return 0;
-
- err:
- unregister_sound_special(s->dev_dmfm);
- err_dev4:
- unregister_sound_midi(s->dev_midi);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "solo1: initialisation error\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->mpubase, MPUBASE_EXTENT);
- err_region4:
- release_region(s->ddmabase, DDMABASE_EXTENT);
- err_region3:
- release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- err_region2:
- release_region(s->iobase, IOBASE_EXTENT);
- err_region1:
- kfree(s);
- return ret;
-}
-
-static void __devexit solo1_remove(struct pci_dev *dev)
-{
- struct solo1_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- /* stop DMA controller */
- outb(0, s->iobase+6);
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- outb(3, s->sbbase+6); /* reset sequencer and FIFO */
- synchronize_irq(s->irq);
- pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
- free_irq(s->irq, s);
- solo1_unregister_gameport(s);
- release_region(s->iobase, IOBASE_EXTENT);
- release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- release_region(s->ddmabase, DDMABASE_EXTENT);
- release_region(s->mpubase, MPUBASE_EXTENT);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_midi(s->dev_midi);
- unregister_sound_special(s->dev_dmfm);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver solo1_driver = {
- .name = "ESS Solo1",
- .id_table = id_table,
- .probe = solo1_probe,
- .remove = __devexit_p(solo1_remove),
- .suspend = solo1_suspend,
- .resume = solo1_resume,
-};
-
-
-static int __init init_solo1(void)
-{
- printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n");
- return pci_register_driver(&solo1_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("ESS Solo1 Driver");
-MODULE_LICENSE("GPL");
-
-
-static void __exit cleanup_solo1(void)
-{
- printk(KERN_INFO "solo1: unloading\n");
- pci_unregister_driver(&solo1_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-module_init(init_solo1);
-module_exit(cleanup_solo1);
-
diff --git a/sound/oss/forte.c b/sound/oss/forte.c
deleted file mode 100644
index ea1c020..0000000
--- a/sound/oss/forte.c
+++ /dev/null
@@ -1,2139 +0,0 @@
-/*
- * forte.c - ForteMedia FM801 OSS Driver
- *
- * Written by Martin K. Petersen <mkp@mkp.net>
- * Copyright (C) 2002 Hewlett-Packard Company
- * Portions Copyright (C) 2003 Martin K. Petersen
- *
- * Latest version: http://mkp.net/forte/
- *
- * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers
- * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik. Thanks
- * guys!
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/pci.h>
-
-#include <linux/delay.h>
-#include <linux/poll.h>
-
-#include <linux/sound.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#define DRIVER_NAME "forte"
-#define DRIVER_VERSION "$Id: forte.c,v 1.63 2003/03/01 05:32:42 mkp Exp $"
-#define PFX DRIVER_NAME ": "
-
-#undef M_DEBUG
-
-#ifdef M_DEBUG
-#define DPRINTK(args...) printk(KERN_WARNING args)
-#else
-#define DPRINTK(args...)
-#endif
-
-/* Card capabilities */
-#define FORTE_CAPS (DSP_CAP_MMAP | DSP_CAP_TRIGGER)
-
-/* Supported audio formats */
-#define FORTE_FMTS (AFMT_U8 | AFMT_S16_LE)
-
-/* Buffers */
-#define FORTE_MIN_FRAG_SIZE 256
-#define FORTE_MAX_FRAG_SIZE PAGE_SIZE
-#define FORTE_DEF_FRAG_SIZE 256
-#define FORTE_MIN_FRAGMENTS 2
-#define FORTE_MAX_FRAGMENTS 256
-#define FORTE_DEF_FRAGMENTS 2
-#define FORTE_MIN_BUF_MSECS 500
-#define FORTE_MAX_BUF_MSECS 1000
-
-/* PCI BARs */
-#define FORTE_PCM_VOL 0x00 /* PCM Output Volume */
-#define FORTE_FM_VOL 0x02 /* FM Output Volume */
-#define FORTE_I2S_VOL 0x04 /* I2S Volume */
-#define FORTE_REC_SRC 0x06 /* Record Source */
-#define FORTE_PLY_CTRL 0x08 /* Playback Control */
-#define FORTE_PLY_COUNT 0x0a /* Playback Count */
-#define FORTE_PLY_BUF1 0x0c /* Playback Buffer I */
-#define FORTE_PLY_BUF2 0x10 /* Playback Buffer II */
-#define FORTE_CAP_CTRL 0x14 /* Capture Control */
-#define FORTE_CAP_COUNT 0x16 /* Capture Count */
-#define FORTE_CAP_BUF1 0x18 /* Capture Buffer I */
-#define FORTE_CAP_BUF2 0x1c /* Capture Buffer II */
-#define FORTE_CODEC_CTRL 0x22 /* Codec Control */
-#define FORTE_I2S_MODE 0x24 /* I2S Mode Control */
-#define FORTE_VOLUME 0x26 /* Volume Up/Down/Mute Status */
-#define FORTE_I2C_CTRL 0x29 /* I2C Control */
-#define FORTE_AC97_CMD 0x2a /* AC'97 Command */
-#define FORTE_AC97_DATA 0x2c /* AC'97 Data */
-#define FORTE_MPU401_DATA 0x30 /* MPU401 Data */
-#define FORTE_MPU401_CMD 0x31 /* MPU401 Command */
-#define FORTE_GPIO_CTRL 0x52 /* General Purpose I/O Control */
-#define FORTE_GEN_CTRL 0x54 /* General Control */
-#define FORTE_IRQ_MASK 0x56 /* Interrupt Mask */
-#define FORTE_IRQ_STATUS 0x5a /* Interrupt Status */
-#define FORTE_OPL3_BANK0 0x68 /* OPL3 Status Read / Bank 0 Write */
-#define FORTE_OPL3_DATA0 0x69 /* OPL3 Data 0 Write */
-#define FORTE_OPL3_BANK1 0x6a /* OPL3 Bank 1 Write */
-#define FORTE_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */
-#define FORTE_POWERDOWN 0x70 /* Blocks Power Down Control */
-
-#define FORTE_CAP_OFFSET FORTE_CAP_CTRL - FORTE_PLY_CTRL
-
-#define FORTE_AC97_ADDR_SHIFT 10
-
-/* Playback and record control register bits */
-#define FORTE_BUF1_LAST (1<<1)
-#define FORTE_BUF2_LAST (1<<2)
-#define FORTE_START (1<<5)
-#define FORTE_PAUSE (1<<6)
-#define FORTE_IMMED_STOP (1<<7)
-#define FORTE_RATE_SHIFT 8
-#define FORTE_RATE_MASK (15 << FORTE_RATE_SHIFT)
-#define FORTE_CHANNELS_4 (1<<12) /* Playback only */
-#define FORTE_CHANNELS_6 (2<<12) /* Playback only */
-#define FORTE_CHANNELS_6MS (3<<12) /* Playback only */
-#define FORTE_CHANNELS_MASK (3<<12)
-#define FORTE_16BIT (1<<14)
-#define FORTE_STEREO (1<<15)
-
-/* IRQ status bits */
-#define FORTE_IRQ_PLAYBACK (1<<8)
-#define FORTE_IRQ_CAPTURE (1<<9)
-#define FORTE_IRQ_VOLUME (1<<14)
-#define FORTE_IRQ_MPU (1<<15)
-
-/* CODEC control */
-#define FORTE_CC_CODEC_RESET (1<<5)
-#define FORTE_CC_AC97_RESET (1<<6)
-
-/* AC97 cmd */
-#define FORTE_AC97_WRITE (0<<7)
-#define FORTE_AC97_READ (1<<7)
-#define FORTE_AC97_DP_INVALID (0<<8)
-#define FORTE_AC97_DP_VALID (1<<8)
-#define FORTE_AC97_PORT_RDY (0<<9)
-#define FORTE_AC97_PORT_BSY (1<<9)
-
-
-struct forte_channel {
- const char *name;
-
- unsigned short ctrl; /* Ctrl BAR contents */
- unsigned long iobase; /* Ctrl BAR address */
-
- wait_queue_head_t wait;
-
- void *buf; /* Buffer */
- dma_addr_t buf_handle; /* Buffer handle */
-
- unsigned int record;
- unsigned int format;
- unsigned int rate;
- unsigned int stereo;
-
- unsigned int frag_sz; /* Current fragment size */
- unsigned int frag_num; /* Current # of fragments */
- unsigned int frag_msecs; /* Milliseconds per frag */
- unsigned int buf_sz; /* Current buffer size */
-
- unsigned int hwptr; /* Tail */
- unsigned int swptr; /* Head */
- unsigned int filled_frags; /* Fragments currently full */
- unsigned int next_buf; /* Index of next buffer */
-
- unsigned int active; /* Channel currently in use */
- unsigned int mapped; /* mmap */
-
- unsigned int buf_pages; /* Real size of buffer */
- unsigned int nr_irqs; /* Number of interrupts */
- unsigned int bytes; /* Total bytes */
- unsigned int residue; /* Partial fragment */
-};
-
-
-struct forte_chip {
- struct pci_dev *pci_dev;
- unsigned long iobase;
- int irq;
-
- struct mutex open_mutex; /* Device access */
- spinlock_t lock; /* State */
-
- spinlock_t ac97_lock;
- struct ac97_codec *ac97;
-
- int multichannel;
- int dsp; /* OSS handle */
- int trigger; /* mmap I/O trigger */
-
- struct forte_channel play;
- struct forte_channel rec;
-};
-
-
-static int channels[] = { 2, 4, 6, };
-static int rates[] = { 5500, 8000, 9600, 11025, 16000, 19200,
- 22050, 32000, 38400, 44100, 48000, };
-
-static struct forte_chip *forte;
-static int found;
-
-
-/* AC97 Codec -------------------------------------------------------------- */
-
-
-/**
- * forte_ac97_wait:
- * @chip: fm801 instance whose AC97 codec to wait on
- *
- * FIXME:
- * Stop busy-waiting
- */
-
-static inline int
-forte_ac97_wait (struct forte_chip *chip)
-{
- int i = 10000;
-
- while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY)
- && i-- )
- cpu_relax();
-
- return i == 0;
-}
-
-
-/**
- * forte_ac97_read:
- * @codec: AC97 codec to read from
- * @reg: register to read
- */
-
-static u16
-forte_ac97_read (struct ac97_codec *codec, u8 reg)
-{
- u16 ret = 0;
- struct forte_chip *chip = codec->private_data;
-
- spin_lock (&chip->ac97_lock);
-
- /* Knock, knock */
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_read: Serial bus busy\n");
- goto out;
- }
-
- /* Send read command */
- outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD);
-
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n",
- reg);
- goto out;
- }
-
- /* Sanity checking */
- if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) {
- printk (KERN_ERR PFX "ac97_read: Invalid data port");
- goto out;
- }
-
- /* Fetch result */
- ret = inw (chip->iobase + FORTE_AC97_DATA);
-
- out:
- spin_unlock (&chip->ac97_lock);
- return ret;
-}
-
-
-/**
- * forte_ac97_write:
- * @codec: AC97 codec to send command to
- * @reg: register to write
- * @val: value to write
- */
-
-static void
-forte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val)
-{
- struct forte_chip *chip = codec->private_data;
-
- spin_lock (&chip->ac97_lock);
-
- /* Knock, knock */
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_write: Serial bus busy\n");
- goto out;
- }
-
- outw (val, chip->iobase + FORTE_AC97_DATA);
- outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD);
-
- /* Wait for completion */
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_write: Bus busy after write\n");
- goto out;
- }
-
- out:
- spin_unlock (&chip->ac97_lock);
-}
-
-
-/* Mixer ------------------------------------------------------------------- */
-
-
-/**
- * forte_mixer_open:
- * @inode:
- * @file:
- */
-
-static int
-forte_mixer_open (struct inode *inode, struct file *file)
-{
- struct forte_chip *chip = forte;
- file->private_data = chip->ac97;
- return 0;
-}
-
-
-/**
- * forte_mixer_release:
- * @inode:
- * @file:
- */
-
-static int
-forte_mixer_release (struct inode *inode, struct file *file)
-{
- /* We will welease Wodewick */
- return 0;
-}
-
-
-/**
- * forte_mixer_ioctl:
- * @inode:
- * @file:
- */
-
-static int
-forte_mixer_ioctl (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 struct file_operations forte_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = forte_mixer_ioctl,
- .open = forte_mixer_open,
- .release = forte_mixer_release,
-};
-
-
-/* Channel ----------------------------------------------------------------- */
-
-/**
- * forte_channel_reset:
- * @channel: Channel to reset
- *
- * Locking: Must be called with lock held.
- */
-
-static void
-forte_channel_reset (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase)
- return;
-
- DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);
-
- channel->ctrl &= ~FORTE_START;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-
- /* We always play at least two fragments, hence these defaults */
- channel->hwptr = channel->frag_sz;
- channel->next_buf = 1;
- channel->swptr = 0;
- channel->filled_frags = 0;
- channel->active = 0;
- channel->bytes = 0;
- channel->nr_irqs = 0;
- channel->mapped = 0;
- channel->residue = 0;
-}
-
-
-/**
- * forte_channel_start:
- * @channel: Channel to start (record/playback)
- *
- * Locking: Must be called with lock held.
- */
-
-static void inline
-forte_channel_start (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase || channel->active)
- return;
-
- channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST
- | FORTE_IMMED_STOP);
- channel->ctrl |= FORTE_START;
- channel->active = 1;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/**
- * forte_channel_stop:
- * @channel: Channel to stop
- *
- * Locking: Must be called with lock held.
- */
-
-static void inline
-forte_channel_stop (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase)
- return;
-
- channel->ctrl &= ~(FORTE_START | FORTE_PAUSE);
- channel->ctrl |= FORTE_IMMED_STOP;
-
- channel->active = 0;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/**
- * forte_channel_pause:
- * @channel: Channel to pause
- *
- * Locking: Must be called with lock held.
- */
-
-static void inline
-forte_channel_pause (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase)
- return;
-
- channel->ctrl |= FORTE_PAUSE;
-
- channel->active = 0;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/**
- * forte_channel_rate:
- * @channel: Channel whose rate to set. Playback and record are
- * independent.
- * @rate: Channel rate in Hz
- *
- * Locking: Must be called with lock held.
- */
-
-static int
-forte_channel_rate (struct forte_channel *channel, unsigned int rate)
-{
- int new_rate;
-
- if (!channel || !channel->iobase)
- return -EINVAL;
-
- /* The FM801 only supports a handful of fixed frequencies.
- * We find the value closest to what userland requested.
- */
- if (rate <= 6250) { rate = 5500; new_rate = 0; }
- else if (rate <= 8800) { rate = 8000; new_rate = 1; }
- else if (rate <= 10312) { rate = 9600; new_rate = 2; }
- else if (rate <= 13512) { rate = 11025; new_rate = 3; }
- else if (rate <= 17600) { rate = 16000; new_rate = 4; }
- else if (rate <= 20625) { rate = 19200; new_rate = 5; }
- else if (rate <= 27025) { rate = 22050; new_rate = 6; }
- else if (rate <= 35200) { rate = 32000; new_rate = 7; }
- else if (rate <= 41250) { rate = 38400; new_rate = 8; }
- else if (rate <= 46050) { rate = 44100; new_rate = 9; }
- else { rate = 48000; new_rate = 10; }
-
- channel->ctrl &= ~FORTE_RATE_MASK;
- channel->ctrl |= new_rate << FORTE_RATE_SHIFT;
- channel->rate = rate;
-
- DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate);
-
- return rate;
-}
-
-
-/**
- * forte_channel_format:
- * @channel: Channel whose audio format to set
- * @format: OSS format ID
- *
- * Locking: Must be called with lock held.
- */
-
-static int
-forte_channel_format (struct forte_channel *channel, int format)
-{
- if (!channel || !channel->iobase)
- return -EINVAL;
-
- switch (format) {
-
- case AFMT_QUERY:
- break;
-
- case AFMT_U8:
- channel->ctrl &= ~FORTE_16BIT;
- channel->format = AFMT_U8;
- break;
-
- case AFMT_S16_LE:
- default:
- channel->ctrl |= FORTE_16BIT;
- channel->format = AFMT_S16_LE;
- break;
- }
-
- DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name,
- format, channel->format);
-
- return channel->format;
-}
-
-
-/**
- * forte_channel_stereo:
- * @channel: Channel to toggle
- * @stereo: 0 for Mono, 1 for Stereo
- *
- * Locking: Must be called with lock held.
- */
-
-static int
-forte_channel_stereo (struct forte_channel *channel, unsigned int stereo)
-{
- int ret;
-
- if (!channel || !channel->iobase)
- return -EINVAL;
-
- DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo);
-
- switch (stereo) {
-
- case 0:
- channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK);
- channel-> stereo = stereo;
- ret = stereo;
- break;
-
- case 1:
- channel->ctrl &= ~FORTE_CHANNELS_MASK;
- channel->ctrl |= FORTE_STEREO;
- channel-> stereo = stereo;
- ret = stereo;
- break;
-
- default:
- DPRINTK ("Unsupported channel format");
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-
-/**
- * forte_channel_buffer:
- * @channel: Channel whose buffer to set up
- *
- * Locking: Must be called with lock held.
- */
-
-static void
-forte_channel_buffer (struct forte_channel *channel, int sz, int num)
-{
- unsigned int msecs, shift;
-
- /* Go away, I'm busy */
- if (channel->filled_frags || channel->bytes)
- return;
-
- /* Fragment size must be a power of 2 */
- shift = 0; sz++;
- while (sz >>= 1)
- shift++;
- channel->frag_sz = 1 << shift;
-
- /* Round fragment size to something reasonable */
- if (channel->frag_sz < FORTE_MIN_FRAG_SIZE)
- channel->frag_sz = FORTE_MIN_FRAG_SIZE;
-
- if (channel->frag_sz > FORTE_MAX_FRAG_SIZE)
- channel->frag_sz = FORTE_MAX_FRAG_SIZE;
-
- /* Find fragment length in milliseconds */
- msecs = channel->frag_sz /
- (channel->format == AFMT_S16_LE ? 2 : 1) /
- (channel->stereo ? 2 : 1) /
- (channel->rate / 1000);
-
- channel->frag_msecs = msecs;
-
- /* Pick a suitable number of fragments */
- if (msecs * num < FORTE_MIN_BUF_MSECS)
- num = FORTE_MIN_BUF_MSECS / msecs;
-
- if (msecs * num > FORTE_MAX_BUF_MSECS)
- num = FORTE_MAX_BUF_MSECS / msecs;
-
- /* Fragment number must be a power of 2 */
- shift = 0;
- while (num >>= 1)
- shift++;
- channel->frag_num = 1 << (shift + 1);
-
- /* Round fragment number to something reasonable */
- if (channel->frag_num < FORTE_MIN_FRAGMENTS)
- channel->frag_num = FORTE_MIN_FRAGMENTS;
-
- if (channel->frag_num > FORTE_MAX_FRAGMENTS)
- channel->frag_num = FORTE_MAX_FRAGMENTS;
-
- channel->buf_sz = channel->frag_sz * channel->frag_num;
-
- DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n",
- __FUNCTION__, channel->name, channel->frag_sz,
- channel->frag_num, channel->buf_sz);
-}
-
-
-/**
- * forte_channel_prep:
- * @channel: Channel whose buffer to prepare
- *
- * Locking: Lock held.
- */
-
-static void
-forte_channel_prep (struct forte_channel *channel)
-{
- struct page *page;
- int i;
-
- if (channel->buf)
- return;
-
- forte_channel_buffer (channel, channel->frag_sz, channel->frag_num);
- channel->buf_pages = channel->buf_sz >> PAGE_SHIFT;
-
- if (channel->buf_sz % PAGE_SIZE)
- channel->buf_pages++;
-
- DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n",
- __FUNCTION__, channel->name, channel->frag_sz,
- channel->frag_num, channel->buf_sz, channel->buf_pages);
-
- /* DMA buffer */
- channel->buf = pci_alloc_consistent (forte->pci_dev,
- channel->buf_pages * PAGE_SIZE,
- &channel->buf_handle);
-
- if (!channel->buf || !channel->buf_handle)
- BUG();
-
- page = virt_to_page (channel->buf);
-
- /* FIXME: can this go away ? */
- for (i = 0 ; i < channel->buf_pages ; i++)
- SetPageReserved(page++);
-
- /* Prep buffer registers */
- outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT);
- outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1);
- outl (channel->buf_handle + channel->frag_sz,
- channel->iobase + FORTE_PLY_BUF2);
-
- /* Reset hwptr */
- channel->hwptr = channel->frag_sz;
- channel->next_buf = 1;
-
- DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name,
- channel->buf, channel->buf_handle);
-}
-
-
-/**
- * forte_channel_drain:
- * @chip:
- * @channel:
- *
- * Locking: Don't hold the lock.
- */
-
-static inline int
-forte_channel_drain (struct forte_channel *channel)
-{
- DECLARE_WAITQUEUE (wait, current);
- unsigned long flags;
-
- DPRINTK ("%s\n", __FUNCTION__);
-
- if (channel->mapped) {
- spin_lock_irqsave (&forte->lock, flags);
- forte_channel_stop (channel);
- spin_unlock_irqrestore (&forte->lock, flags);
- return 0;
- }
-
- spin_lock_irqsave (&forte->lock, flags);
- add_wait_queue (&channel->wait, &wait);
-
- for (;;) {
- if (channel->active == 0 || channel->filled_frags == 1)
- break;
-
- spin_unlock_irqrestore (&forte->lock, flags);
-
- __set_current_state (TASK_INTERRUPTIBLE);
- schedule();
-
- spin_lock_irqsave (&forte->lock, flags);
- }
-
- forte_channel_stop (channel);
- forte_channel_reset (channel);
- set_current_state (TASK_RUNNING);
- remove_wait_queue (&channel->wait, &wait);
- spin_unlock_irqrestore (&forte->lock, flags);
-
- return 0;
-}
-
-
-/**
- * forte_channel_init:
- * @chip: Forte chip instance the channel hangs off
- * @channel: Channel to initialize
- *
- * Description:
- * Initializes a channel, sets defaults, and allocates
- * buffers.
- *
- * Locking: No lock held.
- */
-
-static int
-forte_channel_init (struct forte_chip *chip, struct forte_channel *channel)
-{
- DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase);
-
- spin_lock_irq (&chip->lock);
- memset (channel, 0x0, sizeof (*channel));
-
- if (channel == &chip->play) {
- channel->name = "PCM_OUT";
- channel->iobase = chip->iobase;
- DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__,
- (void *) channel->iobase);
- }
- else if (channel == &chip->rec) {
- channel->name = "PCM_IN";
- channel->iobase = chip->iobase + FORTE_CAP_OFFSET;
- channel->record = 1;
- DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__,
- (void *) channel->iobase);
- }
- else
- BUG();
-
- init_waitqueue_head (&channel->wait);
-
- /* Defaults: 48kHz, 16-bit, stereo */
- channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL);
- forte_channel_reset (channel);
- forte_channel_stereo (channel, 1);
- forte_channel_format (channel, AFMT_S16_LE);
- forte_channel_rate (channel, 48000);
- channel->frag_sz = FORTE_DEF_FRAG_SIZE;
- channel->frag_num = FORTE_DEF_FRAGMENTS;
-
- chip->trigger = 0;
- spin_unlock_irq (&chip->lock);
-
- return 0;
-}
-
-
-/**
- * forte_channel_free:
- * @chip: Chip this channel hangs off
- * @channel: Channel to nuke
- *
- * Description:
- * Resets channel and frees buffers.
- *
- * Locking: Hold your horses.
- */
-
-static void
-forte_channel_free (struct forte_chip *chip, struct forte_channel *channel)
-{
- DPRINTK ("%s: %s\n", __FUNCTION__, channel->name);
-
- if (!channel->buf_handle)
- return;
-
- pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE,
- channel->buf, channel->buf_handle);
-
- memset (channel, 0x0, sizeof (*channel));
-}
-
-
-/* DSP --------------------------------------------------------------------- */
-
-
-/**
- * forte_dsp_ioctl:
- */
-
-static int
-forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ival=0, ret, rval=0, rd, wr, count;
- struct forte_chip *chip;
- struct audio_buf_info abi;
- struct count_info cinfo;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- chip = file->private_data;
-
- if (file->f_mode & FMODE_WRITE)
- wr = 1;
- else
- wr = 0;
-
- if (file->f_mode & FMODE_READ)
- rd = 1;
- else
- rd = 0;
-
- switch (cmd) {
-
- case OSS_GETVERSION:
- return put_user (SOUND_VERSION, p);
-
- case SNDCTL_DSP_GETCAPS:
- DPRINTK ("%s: GETCAPS\n", __FUNCTION__);
-
- ival = FORTE_CAPS; /* DUPLEX */
- return put_user (ival, p);
-
- case SNDCTL_DSP_GETFMTS:
- DPRINTK ("%s: GETFMTS\n", __FUNCTION__);
-
- ival = FORTE_FMTS; /* U8, 16LE */
- return put_user (ival, p);
-
- case SNDCTL_DSP_SETFMT: /* U8, 16LE */
- DPRINTK ("%s: SETFMT\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_format (&chip->rec, ival);
- }
-
- if (wr) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_format (&chip->play, ival);
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (rval, p);
-
- case SNDCTL_DSP_STEREO: /* 0 - mono, 1 - stereo */
- DPRINTK ("%s: STEREO\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_stereo (&chip->rec, ival);
- }
-
- if (wr) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_stereo (&chip->play, ival);
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (rval, p);
-
- case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */
- DPRINTK ("%s: CHANNELS\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_stereo (&chip->rec, ival-1) + 1;
- }
-
- if (wr) {
- forte_channel_stop (&chip->play);
- rval = forte_channel_stereo (&chip->play, ival-1) + 1;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (rval, p);
-
- case SNDCTL_DSP_SPEED:
- DPRINTK ("%s: SPEED\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_rate (&chip->rec, ival);
- }
-
- if (wr) {
- forte_channel_stop (&chip->play);
- rval = forte_channel_rate (&chip->play, ival);
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user(rval, p);
-
- case SNDCTL_DSP_GETBLKSIZE:
- DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__);
-
- spin_lock_irq (&chip->lock);
-
- if (rd)
- ival = chip->rec.frag_sz;
-
- if (wr)
- ival = chip->play.frag_sz;
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (ival, p);
-
- case SNDCTL_DSP_RESET:
- DPRINTK ("%s: RESET\n", __FUNCTION__);
-
- spin_lock_irq (&chip->lock);
-
- if (rd)
- forte_channel_reset (&chip->rec);
-
- if (wr)
- forte_channel_reset (&chip->play);
-
- spin_unlock_irq (&chip->lock);
-
- return 0;
-
- case SNDCTL_DSP_SYNC:
- DPRINTK ("%s: SYNC\n", __FUNCTION__);
-
- if (wr)
- ret = forte_channel_drain (&chip->play);
-
- return 0;
-
- case SNDCTL_DSP_POST:
- DPRINTK ("%s: POST\n", __FUNCTION__);
-
- if (wr) {
- spin_lock_irq (&chip->lock);
-
- if (chip->play.filled_frags)
- forte_channel_start (&chip->play);
-
- spin_unlock_irq (&chip->lock);
- }
-
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_buffer (&chip->rec, ival & 0xffff,
- (ival >> 16) & 0xffff);
- ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz;
- }
-
- if (wr) {
- forte_channel_buffer (&chip->play, ival & 0xffff,
- (ival >> 16) & 0xffff);
- ival = (chip->play.frag_num << 16) +chip->play.frag_sz;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (ival, p);
-
- case SNDCTL_DSP_GETISPACE:
- DPRINTK ("%s: GETISPACE\n", __FUNCTION__);
-
- if (!rd)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- abi.fragstotal = chip->rec.frag_num;
- abi.fragsize = chip->rec.frag_sz;
-
- if (chip->rec.mapped) {
- abi.fragments = chip->rec.frag_num - 2;
- abi.bytes = abi.fragments * abi.fragsize;
- }
- else {
- abi.fragments = chip->rec.filled_frags;
- abi.bytes = abi.fragments * abi.fragsize;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETIPTR:
- DPRINTK ("%s: GETIPTR\n", __FUNCTION__);
-
- if (!rd)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- if (chip->rec.active)
- cinfo.ptr = chip->rec.hwptr;
- else
- cinfo.ptr = 0;
-
- cinfo.bytes = chip->rec.bytes;
- cinfo.blocks = chip->rec.nr_irqs;
- chip->rec.nr_irqs = 0;
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!wr)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- abi.fragstotal = chip->play.frag_num;
- abi.fragsize = chip->play.frag_sz;
-
- if (chip->play.mapped) {
- abi.fragments = chip->play.frag_num - 2;
- abi.bytes = chip->play.buf_sz;
- }
- else {
- abi.fragments = chip->play.frag_num -
- chip->play.filled_frags;
-
- if (chip->play.residue)
- abi.fragments--;
-
- abi.bytes = abi.fragments * abi.fragsize +
- chip->play.residue;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!wr)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- if (chip->play.active)
- cinfo.ptr = chip->play.hwptr;
- else
- cinfo.ptr = 0;
-
- cinfo.bytes = chip->play.bytes;
- cinfo.blocks = chip->play.nr_irqs;
- chip->play.nr_irqs = 0;
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!wr)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- if (!chip->play.active) {
- ival = 0;
- }
- else if (chip->play.mapped) {
- count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1;
- ival = chip->play.frag_sz - count;
- }
- else {
- ival = chip->play.filled_frags * chip->play.frag_sz;
-
- if (chip->play.residue)
- ival += chip->play.frag_sz - chip->play.residue;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (ival, p);
-
- case SNDCTL_DSP_SETDUPLEX:
- DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__);
-
- return -EINVAL;
-
- case SNDCTL_DSP_GETTRIGGER:
- DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__);
-
- return put_user (chip->trigger, p);
-
- case SNDCTL_DSP_SETTRIGGER:
-
- if (get_user (ival, p))
- return -EFAULT;
-
- DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival);
-
- if (wr) {
- spin_lock_irq (&chip->lock);
-
- if (ival & PCM_ENABLE_OUTPUT)
- forte_channel_start (&chip->play);
- else {
- chip->trigger = 1;
- forte_channel_prep (&chip->play);
- forte_channel_stop (&chip->play);
- }
-
- spin_unlock_irq (&chip->lock);
- }
- else if (rd) {
- spin_lock_irq (&chip->lock);
-
- if (ival & PCM_ENABLE_INPUT)
- forte_channel_start (&chip->rec);
- else {
- chip->trigger = 1;
- forte_channel_prep (&chip->rec);
- forte_channel_stop (&chip->rec);
- }
-
- spin_unlock_irq (&chip->lock);
- }
-
- return 0;
-
- case SOUND_PCM_READ_RATE:
- DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__);
- return put_user (chip->play.rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__);
- return put_user (chip->play.stereo, p);
-
- case SOUND_PCM_READ_BITS:
- DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__);
- return put_user (chip->play.format, p);
-
- case SNDCTL_DSP_NONBLOCK:
- DPRINTK ("%s: DSP_NONBLOCK\n", __FUNCTION__);
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- default:
- DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, argp);
- break;
- }
-
- return -EINVAL;
-}
-
-
-/**
- * forte_dsp_open:
- */
-
-static int
-forte_dsp_open (struct inode *inode, struct file *file)
-{
- struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */
-
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&chip->open_mutex)) {
- DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__);
- return -EAGAIN;
- }
- }
- else {
- if (mutex_lock_interruptible(&chip->open_mutex)) {
- DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
- return -ERESTARTSYS;
- }
- }
-
- file->private_data = forte;
-
- DPRINTK ("%s: dsp opened by %d\n", __FUNCTION__, current->pid);
-
- if (file->f_mode & FMODE_WRITE)
- forte_channel_init (forte, &forte->play);
-
- if (file->f_mode & FMODE_READ)
- forte_channel_init (forte, &forte->rec);
-
- return nonseekable_open(inode, file);
-}
-
-
-/**
- * forte_dsp_release:
- */
-
-static int
-forte_dsp_release (struct inode *inode, struct file *file)
-{
- struct forte_chip *chip = file->private_data;
- int ret = 0;
-
- DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip);
-
- if (file->f_mode & FMODE_WRITE) {
- forte_channel_drain (&chip->play);
-
- spin_lock_irq (&chip->lock);
-
- forte_channel_free (chip, &chip->play);
-
- spin_unlock_irq (&chip->lock);
- }
-
- if (file->f_mode & FMODE_READ) {
- while (chip->rec.filled_frags > 0)
- interruptible_sleep_on (&chip->rec.wait);
-
- spin_lock_irq (&chip->lock);
-
- forte_channel_stop (&chip->rec);
- forte_channel_free (chip, &chip->rec);
-
- spin_unlock_irq (&chip->lock);
- }
-
- mutex_unlock(&chip->open_mutex);
-
- return ret;
-}
-
-
-/**
- * forte_dsp_poll:
- *
- */
-
-static unsigned int
-forte_dsp_poll (struct file *file, struct poll_table_struct *wait)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned int mask = 0;
-
- chip = file->private_data;
-
- if (file->f_mode & FMODE_WRITE) {
- channel = &chip->play;
-
- if (channel->active)
- poll_wait (file, &channel->wait, wait);
-
- spin_lock_irq (&chip->lock);
-
- if (channel->frag_num - channel->filled_frags > 0)
- mask |= POLLOUT | POLLWRNORM;
-
- spin_unlock_irq (&chip->lock);
- }
-
- if (file->f_mode & FMODE_READ) {
- channel = &chip->rec;
-
- if (channel->active)
- poll_wait (file, &channel->wait, wait);
-
- spin_lock_irq (&chip->lock);
-
- if (channel->filled_frags > 0)
- mask |= POLLIN | POLLRDNORM;
-
- spin_unlock_irq (&chip->lock);
- }
-
- return mask;
-}
-
-
-/**
- * forte_dsp_mmap:
- */
-
-static int
-forte_dsp_mmap (struct file *file, struct vm_area_struct *vma)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned long size;
- int ret;
-
- chip = file->private_data;
-
- DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__,
- vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff);
-
- spin_lock_irq (&chip->lock);
-
- if (vma->vm_flags & VM_WRITE && chip->play.active) {
- ret = -EBUSY;
- goto out;
- }
-
- if (vma->vm_flags & VM_READ && chip->rec.active) {
- ret = -EBUSY;
- goto out;
- }
-
- if (file->f_mode & FMODE_WRITE)
- channel = &chip->play;
- else if (file->f_mode & FMODE_READ)
- channel = &chip->rec;
- else {
- ret = -EINVAL;
- goto out;
- }
-
- forte_channel_prep (channel);
- channel->mapped = 1;
-
- if (vma->vm_pgoff != 0) {
- ret = -EINVAL;
- goto out;
- }
-
- size = vma->vm_end - vma->vm_start;
-
- if (size > channel->buf_pages * PAGE_SIZE) {
- DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__,
- size, channel->buf_sz);
- ret = -EINVAL;
- goto out;
- }
-
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(channel->buf) >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
- DPRINTK ("%s: remap el a no worko\n", __FUNCTION__);
- ret = -EAGAIN;
- goto out;
- }
-
- ret = 0;
-
- out:
- spin_unlock_irq (&chip->lock);
- return ret;
-}
-
-
-/**
- * forte_dsp_write:
- */
-
-static ssize_t
-forte_dsp_write (struct file *file, const char __user *buffer, size_t bytes,
- loff_t *ppos)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned int i = bytes, sz = 0;
- unsigned long flags;
-
- if (!access_ok (VERIFY_READ, buffer, bytes))
- return -EFAULT;
-
- chip = (struct forte_chip *) file->private_data;
-
- if (!chip)
- BUG();
-
- channel = &chip->play;
-
- if (!channel)
- BUG();
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Set up buffers with the right fragment size */
- forte_channel_prep (channel);
-
- while (i) {
- /* All fragment buffers in use -> wait */
- if (channel->frag_num - channel->filled_frags == 0) {
- DECLARE_WAITQUEUE (wait, current);
-
- /* For trigger or non-blocking operation, get out */
- if (chip->trigger || file->f_flags & O_NONBLOCK) {
- spin_unlock_irqrestore (&chip->lock, flags);
- return -EAGAIN;
- }
-
- /* Otherwise wait for buffers */
- add_wait_queue (&channel->wait, &wait);
-
- for (;;) {
- spin_unlock_irqrestore (&chip->lock, flags);
-
- set_current_state (TASK_INTERRUPTIBLE);
- schedule();
-
- spin_lock_irqsave (&chip->lock, flags);
-
- if (channel->frag_num - channel->filled_frags)
- break;
- }
-
- remove_wait_queue (&channel->wait, &wait);
- set_current_state (TASK_RUNNING);
-
- if (signal_pending (current)) {
- spin_unlock_irqrestore (&chip->lock, flags);
- return -ERESTARTSYS;
- }
- }
-
- if (channel->residue)
- sz = channel->residue;
- else if (i > channel->frag_sz)
- sz = channel->frag_sz;
- else
- sz = i;
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- if (copy_from_user ((void *) channel->buf + channel->swptr, buffer, sz))
- return -EFAULT;
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Advance software pointer */
- buffer += sz;
- channel->swptr += sz;
- channel->swptr %= channel->buf_sz;
- i -= sz;
-
- /* Only bump filled_frags if a full fragment has been written */
- if (channel->swptr % channel->frag_sz == 0) {
- channel->filled_frags++;
- channel->residue = 0;
- }
- else
- channel->residue = channel->frag_sz - sz;
-
- /* If playback isn't active, start it */
- if (channel->active == 0 && chip->trigger == 0)
- forte_channel_start (channel);
- }
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- return bytes - i;
-}
-
-
-/**
- * forte_dsp_read:
- */
-
-static ssize_t
-forte_dsp_read (struct file *file, char __user *buffer, size_t bytes,
- loff_t *ppos)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned int i = bytes, sz;
- unsigned long flags;
-
- if (!access_ok (VERIFY_WRITE, buffer, bytes))
- return -EFAULT;
-
- chip = (struct forte_chip *) file->private_data;
-
- if (!chip)
- BUG();
-
- channel = &chip->rec;
-
- if (!channel)
- BUG();
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Set up buffers with the right fragment size */
- forte_channel_prep (channel);
-
- /* Start recording */
- if (!chip->trigger)
- forte_channel_start (channel);
-
- while (i) {
- /* No fragment buffers in use -> wait */
- if (channel->filled_frags == 0) {
- DECLARE_WAITQUEUE (wait, current);
-
- /* For trigger mode operation, get out */
- if (chip->trigger) {
- spin_unlock_irqrestore (&chip->lock, flags);
- return -EAGAIN;
- }
-
- add_wait_queue (&channel->wait, &wait);
-
- for (;;) {
- if (channel->active == 0)
- break;
-
- if (channel->filled_frags)
- break;
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- set_current_state (TASK_INTERRUPTIBLE);
- schedule();
-
- spin_lock_irqsave (&chip->lock, flags);
- }
-
- set_current_state (TASK_RUNNING);
- remove_wait_queue (&channel->wait, &wait);
- }
-
- if (i > channel->frag_sz)
- sz = channel->frag_sz;
- else
- sz = i;
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) {
- DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__);
- return -EFAULT;
- }
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Advance software pointer */
- buffer += sz;
- if (channel->filled_frags > 0)
- channel->filled_frags--;
- channel->swptr += channel->frag_sz;
- channel->swptr %= channel->buf_sz;
- i -= sz;
- }
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- return bytes - i;
-}
-
-
-static struct file_operations forte_dsp_fops = {
- .owner = THIS_MODULE,
- .llseek = &no_llseek,
- .read = &forte_dsp_read,
- .write = &forte_dsp_write,
- .poll = &forte_dsp_poll,
- .ioctl = &forte_dsp_ioctl,
- .open = &forte_dsp_open,
- .release = &forte_dsp_release,
- .mmap = &forte_dsp_mmap,
-};
-
-
-/* Common ------------------------------------------------------------------ */
-
-
-/**
- * forte_interrupt:
- */
-
-static irqreturn_t
-forte_interrupt (int irq, void *dev_id, struct pt_regs *regs)
-{
- struct forte_chip *chip = dev_id;
- struct forte_channel *channel = NULL;
- u16 status, count;
-
- status = inw (chip->iobase + FORTE_IRQ_STATUS);
-
- /* If this is not for us, get outta here ASAP */
- if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0)
- return IRQ_NONE;
-
- if (status & FORTE_IRQ_PLAYBACK) {
- channel = &chip->play;
-
- spin_lock (&chip->lock);
-
- if (channel->frag_sz == 0)
- goto pack;
-
- /* Declare a fragment done */
- if (channel->filled_frags > 0)
- channel->filled_frags--;
- channel->bytes += channel->frag_sz;
- channel->nr_irqs++;
-
- /* Flip-flop between buffer I and II */
- channel->next_buf ^= 1;
-
- /* Advance hardware pointer by fragment size and wrap around */
- channel->hwptr += channel->frag_sz;
- channel->hwptr %= channel->buf_sz;
-
- /* Buffer I or buffer II BAR */
- outl (channel->buf_handle + channel->hwptr,
- channel->next_buf == 0 ?
- channel->iobase + FORTE_PLY_BUF1 :
- channel->iobase + FORTE_PLY_BUF2);
-
- /* If the currently playing fragment is last, schedule pause */
- if (channel->filled_frags == 1)
- forte_channel_pause (channel);
-
- pack:
- /* Acknowledge interrupt */
- outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS);
-
- if (waitqueue_active (&channel->wait))
- wake_up_all (&channel->wait);
-
- spin_unlock (&chip->lock);
- }
-
- if (status & FORTE_IRQ_CAPTURE) {
- channel = &chip->rec;
- spin_lock (&chip->lock);
-
- /* One fragment filled */
- channel->filled_frags++;
-
- /* Get # of completed bytes */
- count = inw (channel->iobase + FORTE_PLY_COUNT) + 1;
-
- if (count == 0) {
- DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__,
- channel->filled_frags);
- channel->filled_frags = 0;
- goto rack;
- }
-
- /* Buffer I or buffer II BAR */
- outl (channel->buf_handle + channel->hwptr,
- channel->next_buf == 0 ?
- channel->iobase + FORTE_PLY_BUF1 :
- channel->iobase + FORTE_PLY_BUF2);
-
- /* Flip-flop between buffer I and II */
- channel->next_buf ^= 1;
-
- /* Advance hardware pointer by fragment size and wrap around */
- channel->hwptr += channel->frag_sz;
- channel->hwptr %= channel->buf_sz;
-
- /* Out of buffers */
- if (channel->filled_frags == channel->frag_num - 1)
- forte_channel_stop (channel);
- rack:
- /* Acknowledge interrupt */
- outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS);
-
- spin_unlock (&chip->lock);
-
- if (waitqueue_active (&channel->wait))
- wake_up_all (&channel->wait);
- }
-
- return IRQ_HANDLED;
-}
-
-
-/**
- * forte_proc_read:
- */
-
-static int
-forte_proc_read (char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int i = 0, p_rate, p_chan, r_rate;
- unsigned short p_reg, r_reg;
-
- i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n \n",
- DRIVER_VERSION);
-
- if (!forte->iobase)
- return i;
-
- p_rate = p_chan = -1;
- p_reg = inw (forte->iobase + FORTE_PLY_CTRL);
- p_rate = (p_reg >> 8) & 15;
- p_chan = (p_reg >> 12) & 3;
-
- if (p_rate >= 0 || p_rate <= 10)
- p_rate = rates[p_rate];
-
- if (p_chan >= 0 || p_chan <= 2)
- p_chan = channels[p_chan];
-
- r_rate = -1;
- r_reg = inw (forte->iobase + FORTE_CAP_CTRL);
- r_rate = (r_reg >> 8) & 15;
-
- if (r_rate >= 0 || r_rate <= 10)
- r_rate = rates[r_rate];
-
- i += sprintf (page + i,
- " Playback Capture\n"
- "FIFO empty : %-3s %-3s\n"
- "Buf1 Last : %-3s %-3s\n"
- "Buf2 Last : %-3s %-3s\n"
- "Started : %-3s %-3s\n"
- "Paused : %-3s %-3s\n"
- "Immed Stop : %-3s %-3s\n"
- "Rate : %-5d %-5d\n"
- "Channels : %-5d -\n"
- "16-bit : %-3s %-3s\n"
- "Stereo : %-3s %-3s\n"
- " \n"
- "Buffer Sz : %-6d %-6d\n"
- "Frag Sz : %-6d %-6d\n"
- "Frag Num : %-6d %-6d\n"
- "Frag msecs : %-6d %-6d\n"
- "Used Frags : %-6d %-6d\n"
- "Mapped : %-3s %-3s\n",
- p_reg & 1<<0 ? "yes" : "no",
- r_reg & 1<<0 ? "yes" : "no",
- p_reg & 1<<1 ? "yes" : "no",
- r_reg & 1<<1 ? "yes" : "no",
- p_reg & 1<<2 ? "yes" : "no",
- r_reg & 1<<2 ? "yes" : "no",
- p_reg & 1<<5 ? "yes" : "no",
- r_reg & 1<<5 ? "yes" : "no",
- p_reg & 1<<6 ? "yes" : "no",
- r_reg & 1<<6 ? "yes" : "no",
- p_reg & 1<<7 ? "yes" : "no",
- r_reg & 1<<7 ? "yes" : "no",
- p_rate, r_rate,
- p_chan,
- p_reg & 1<<14 ? "yes" : "no",
- r_reg & 1<<14 ? "yes" : "no",
- p_reg & 1<<15 ? "yes" : "no",
- r_reg & 1<<15 ? "yes" : "no",
- forte->play.buf_sz, forte->rec.buf_sz,
- forte->play.frag_sz, forte->rec.frag_sz,
- forte->play.frag_num, forte->rec.frag_num,
- forte->play.frag_msecs, forte->rec.frag_msecs,
- forte->play.filled_frags, forte->rec.filled_frags,
- forte->play.mapped ? "yes" : "no",
- forte->rec.mapped ? "yes" : "no"
- );
-
- return i;
-}
-
-
-/**
- * forte_proc_init:
- *
- * Creates driver info entries in /proc
- */
-
-static int __init
-forte_proc_init (void)
-{
- if (!proc_mkdir ("driver/forte", NULL))
- return -EIO;
-
- if (!create_proc_read_entry ("driver/forte/chip", 0, NULL, forte_proc_read, forte)) {
- remove_proc_entry ("driver/forte", NULL);
- return -EIO;
- }
-
- if (!create_proc_read_entry("driver/forte/ac97", 0, NULL, ac97_read_proc, forte->ac97)) {
- remove_proc_entry ("driver/forte/chip", NULL);
- remove_proc_entry ("driver/forte", NULL);
- return -EIO;
- }
-
- return 0;
-}
-
-
-/**
- * forte_proc_remove:
- *
- * Removes driver info entries in /proc
- */
-
-static void
-forte_proc_remove (void)
-{
- remove_proc_entry ("driver/forte/ac97", NULL);
- remove_proc_entry ("driver/forte/chip", NULL);
- remove_proc_entry ("driver/forte", NULL);
-}
-
-
-/**
- * forte_chip_init:
- * @chip: Chip instance to initialize
- *
- * Description:
- * Resets chip, configures codec and registers the driver with
- * the sound subsystem.
- *
- * Press and hold Start for 8 secs, then switch on Run
- * and hold for 4 seconds. Let go of Start. Numbers
- * assume a properly oiled TWG.
- */
-
-static int __devinit
-forte_chip_init (struct forte_chip *chip)
-{
- u8 revision;
- u16 cmdw;
- struct ac97_codec *codec;
-
- pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision);
-
- if (revision >= 0xB1) {
- chip->multichannel = 1;
- printk (KERN_INFO PFX "Multi-channel device detected.\n");
- }
-
- /* Reset chip */
- outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET,
- chip->iobase + FORTE_CODEC_CTRL);
- udelay(100);
- outw (0, chip->iobase + FORTE_CODEC_CTRL);
-
- /* Request read from AC97 */
- outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT),
- chip->iobase + FORTE_AC97_CMD);
- mdelay(750);
-
- if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) {
- printk (KERN_INFO PFX "AC97 codec not responding");
- return -EIO;
- }
-
- /* Init volume */
- outw (0x0808, chip->iobase + FORTE_PCM_VOL);
- outw (0x9f1f, chip->iobase + FORTE_FM_VOL);
- outw (0x8808, chip->iobase + FORTE_I2S_VOL);
-
- /* I2S control - I2S mode */
- outw (0x0003, chip->iobase + FORTE_I2S_MODE);
-
- /* Interrupt setup - unmask PLAYBACK & CAPTURE */
- cmdw = inw (chip->iobase + FORTE_IRQ_MASK);
- cmdw &= ~0x0003;
- outw (cmdw, chip->iobase + FORTE_IRQ_MASK);
-
- /* Interrupt clear */
- outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE,
- chip->iobase + FORTE_IRQ_STATUS);
-
- /* Set up the AC97 codec */
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
- codec->private_data = chip;
- codec->codec_read = forte_ac97_read;
- codec->codec_write = forte_ac97_write;
- codec->id = 0;
-
- if (ac97_probe_codec (codec) == 0) {
- printk (KERN_ERR PFX "codec probe failed\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- /* Register mixer */
- if ((codec->dev_mixer =
- register_sound_mixer (&forte_mixer_fops, -1)) < 0) {
- printk (KERN_ERR PFX "couldn't register mixer!\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- chip->ac97 = codec;
-
- /* Register DSP */
- if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) {
- printk (KERN_ERR PFX "couldn't register dsp!\n");
- return -1;
- }
-
- /* Register with /proc */
- if (forte_proc_init()) {
- printk (KERN_ERR PFX "couldn't add entries to /proc!\n");
- return -1;
- }
-
- return 0;
-}
-
-
-/**
- * forte_probe:
- * @pci_dev: PCI struct for probed device
- * @pci_id:
- *
- * Description:
- * Allocates chip instance, I/O region, and IRQ
- */
-static int __init
-forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- struct forte_chip *chip;
- int ret = 0;
-
- /* FIXME: Support more than one chip */
- if (found++)
- return -EIO;
-
- /* Ignition */
- if (pci_enable_device (pci_dev))
- return -EIO;
-
- pci_set_master (pci_dev);
-
- /* Allocate chip instance and configure */
- forte = (struct forte_chip *)
- kmalloc (sizeof (struct forte_chip), GFP_KERNEL);
- chip = forte;
-
- if (chip == NULL) {
- printk (KERN_WARNING PFX "Out of memory");
- return -ENOMEM;
- }
-
- memset (chip, 0, sizeof (struct forte_chip));
- chip->pci_dev = pci_dev;
-
- mutex_init(&chip->open_mutex);
- spin_lock_init (&chip->lock);
- spin_lock_init (&chip->ac97_lock);
-
- if (! request_region (pci_resource_start (pci_dev, 0),
- pci_resource_len (pci_dev, 0), DRIVER_NAME)) {
- printk (KERN_WARNING PFX "Unable to reserve I/O space");
- ret = -ENOMEM;
- goto error;
- }
-
- chip->iobase = pci_resource_start (pci_dev, 0);
- chip->irq = pci_dev->irq;
-
- if (request_irq (chip->irq, forte_interrupt, IRQF_SHARED, DRIVER_NAME,
- chip)) {
- printk (KERN_WARNING PFX "Unable to reserve IRQ");
- ret = -EIO;
- goto error;
- }
-
- pci_set_drvdata (pci_dev, chip);
-
- printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%16llX IRQ %u\n",
- chip->iobase, (unsigned long long)pci_resource_end (pci_dev, 0),
- chip->irq);
-
- /* Power it up */
- if ((ret = forte_chip_init (chip)) == 0)
- return 0;
-
- error:
- if (chip->irq)
- free_irq (chip->irq, chip);
-
- if (chip->iobase)
- release_region (pci_resource_start (pci_dev, 0),
- pci_resource_len (pci_dev, 0));
-
- kfree (chip);
-
- return ret;
-}
-
-
-/**
- * forte_remove:
- * @pci_dev: PCI device to unclaim
- *
- */
-
-static void
-forte_remove (struct pci_dev *pci_dev)
-{
- struct forte_chip *chip = pci_get_drvdata (pci_dev);
-
- if (chip == NULL)
- return;
-
- /* Turn volume down to avoid popping */
- outw (0x1f1f, chip->iobase + FORTE_PCM_VOL);
- outw (0x1f1f, chip->iobase + FORTE_FM_VOL);
- outw (0x1f1f, chip->iobase + FORTE_I2S_VOL);
-
- forte_proc_remove();
- free_irq (chip->irq, chip);
- release_region (chip->iobase, pci_resource_len (pci_dev, 0));
-
- unregister_sound_dsp (chip->dsp);
- unregister_sound_mixer (chip->ac97->dev_mixer);
- ac97_release_codec(chip->ac97);
- kfree (chip);
-
- printk (KERN_INFO PFX "driver released\n");
-}
-
-
-static struct pci_device_id forte_pci_ids[] = {
- { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0, }
-};
-
-
-static struct pci_driver forte_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = forte_pci_ids,
- .probe = forte_probe,
- .remove = forte_remove,
-
-};
-
-
-/**
- * forte_init_module:
- *
- */
-
-static int __init
-forte_init_module (void)
-{
- printk (KERN_INFO PFX DRIVER_VERSION "\n");
-
- return pci_register_driver (&forte_pci_driver);
-}
-
-
-/**
- * forte_cleanup_module:
- *
- */
-
-static void __exit
-forte_cleanup_module (void)
-{
- pci_unregister_driver (&forte_pci_driver);
-}
-
-
-module_init(forte_init_module);
-module_exit(forte_cleanup_module);
-
-MODULE_AUTHOR("Martin K. Petersen <mkp@mkp.net>");
-MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE (pci, forte_pci_ids);
diff --git a/sound/oss/gus.h b/sound/oss/gus.h
deleted file mode 100644
index 3d5271b..0000000
--- a/sound/oss/gus.h
+++ /dev/null
@@ -1,24 +0,0 @@
-
-#include "ad1848.h"
-
-/* From gus_card.c */
-int gus_set_midi_irq(int num);
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs * dummy);
-
-/* From gus_wave.c */
-int gus_wave_detect(int baseaddr);
-void gus_wave_init(struct address_info *hw_config);
-void gus_wave_unload (struct address_info *hw_config);
-void gus_voice_irq(void);
-void gus_write8(int reg, unsigned int data);
-void guswave_dma_irq(void);
-void gus_delay(void);
-int gus_default_mixer_ioctl (int dev, unsigned int cmd, void __user *arg);
-void gus_timer_command (unsigned int addr, unsigned int val);
-
-/* From gus_midi.c */
-void gus_midi_init(struct address_info *hw_config);
-void gus_midi_interrupt(int dummy);
-
-/* From ics2101.c */
-int ics2101_mixer_init(void);
diff --git a/sound/oss/gus_card.c b/sound/oss/gus_card.c
deleted file mode 100644
index a3d6ae3..0000000
--- a/sound/oss/gus_card.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * sound/oss/gus_card.c
- *
- * Detection routine for the Gravis Ultrasound.
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- *
- * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious
- * usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
- * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups.
- *
- * Status:
- * Tested...
- */
-
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_hw.h"
-
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy);
-
-int gus_base = 0, gus_irq = 0, gus_dma = 0;
-int gus_no_wave_dma = 0;
-extern int gus_wave_volume;
-extern int gus_pcm_volume;
-extern int have_gus_max;
-int gus_pnp_flag = 0;
-#ifdef CONFIG_SOUND_GUS16
-static int db16; /* Has a Gus16 AD1848 on it */
-#endif
-
-static void __init attach_gus(struct address_info *hw_config)
-{
- gus_wave_init(hw_config);
-
- if (sound_alloc_dma(hw_config->dma, "GUS"))
- printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma);
- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
- if (sound_alloc_dma(hw_config->dma2, "GUS(2)"))
- printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2);
- gus_midi_init(hw_config);
- if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0)
- printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq);
-
- return;
-}
-
-static int __init probe_gus(struct address_info *hw_config)
-{
- int irq;
- int io_addr;
-
- if (hw_config->card_subtype == 1)
- gus_pnp_flag = 1;
-
- irq = hw_config->irq;
-
- if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */
- if (irq != 3 && irq != 5 && irq != 7 && irq != 9 &&
- irq != 11 && irq != 12 && irq != 15)
- {
- printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq);
- return 0;
- }
- if (gus_wave_detect(hw_config->io_base))
- return 1;
-
-#ifndef EXCLUDE_GUS_IODETECT
-
- /*
- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
- */
-
- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) {
- if (io_addr == hw_config->io_base) /* Already tested */
- continue;
- if (gus_wave_detect(io_addr)) {
- hw_config->io_base = io_addr;
- return 1;
- }
- }
-#endif
-
- printk("NO GUS card found !\n");
- return 0;
-}
-
-static void __exit unload_gus(struct address_info *hw_config)
-{
- DDB(printk("unload_gus(%x)\n", hw_config->io_base));
-
- gus_wave_unload(hw_config);
-
- release_region(hw_config->io_base, 16);
- release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */
- free_irq(hw_config->irq, hw_config);
-
- sound_free_dma(hw_config->dma);
-
- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
- sound_free_dma(hw_config->dma2);
-}
-
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
- unsigned char src;
- extern int gus_timer_enabled;
- int handled = 0;
-
-#ifdef CONFIG_SOUND_GUSMAX
- if (have_gus_max) {
- struct address_info *hw_config = dev_id;
- adintr(irq, (void *)hw_config->slots[1], NULL);
- }
-#endif
-#ifdef CONFIG_SOUND_GUS16
- if (db16) {
- struct address_info *hw_config = dev_id;
- adintr(irq, (void *)hw_config->slots[3], NULL);
- }
-#endif
-
- while (1)
- {
- if (!(src = inb(u_IrqStatus)))
- break;
- handled = 1;
- if (src & DMA_TC_IRQ)
- {
- guswave_dma_irq();
- }
- if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
- {
- gus_midi_interrupt(0);
- }
- if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
- {
- if (gus_timer_enabled)
- sound_timer_interrupt();
- gus_write8(0x45, 0); /* Ack IRQ */
- gus_timer_command(4, 0x80); /* Reset IRQ flags */
- }
- if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
- gus_voice_irq();
- }
- return IRQ_RETVAL(handled);
-}
-
-/*
- * Some extra code for the 16 bit sampling option
- */
-
-#ifdef CONFIG_SOUND_GUS16
-
-static int __init init_gus_db16(struct address_info *hw_config)
-{
- struct resource *ports;
-
- ports = request_region(hw_config->io_base, 4, "ad1848");
- if (!ports)
- return 0;
-
- if (!ad1848_detect(ports, NULL, hw_config->osp)) {
- release_region(hw_config->io_base, 4);
- return 0;
- }
-
- gus_pcm_volume = 100;
- gus_wave_volume = 90;
-
- hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", ports,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma, 0,
- hw_config->osp,
- THIS_MODULE);
- return 1;
-}
-
-static void __exit unload_gus_db16(struct address_info *hw_config)
-{
-
- ad1848_unload(hw_config->io_base,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma, 0);
- sound_unload_audiodev(hw_config->slots[3]);
-}
-#endif
-
-#ifdef CONFIG_SOUND_GUS16
-static int gus16;
-#endif
-#ifdef CONFIG_SOUND_GUSMAX
-static int no_wave_dma; /* Set if no dma is to be used for the
- wave table (GF1 chip) */
-#endif
-
-
-/*
- * Note DMA2 of -1 has the right meaning in the GUS driver as well
- * as here.
- */
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1; /* Set this for modules that need it */
-static int __initdata type = 0; /* 1 for PnP */
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma16, int, 0);
-module_param(type, int, 0);
-#ifdef CONFIG_SOUND_GUSMAX
-module_param(no_wave_dma, int, 0);
-#endif
-#ifdef CONFIG_SOUND_GUS16
-module_param(db16, int, 0);
-module_param(gus16, int, 0);
-#endif
-MODULE_LICENSE("GPL");
-
-static int __init init_gus(void)
-{
- printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma16;
- cfg.card_subtype = type;
-#ifdef CONFIG_SOUND_GUSMAX
- gus_no_wave_dma = no_wave_dma;
-#endif
-
- if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
- printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n");
- return -EINVAL;
- }
-
-#ifdef CONFIG_SOUND_GUS16
- if (gus16 && init_gus_db16(&cfg))
- db16 = 1;
-#endif
- if (!probe_gus(&cfg))
- return -ENODEV;
- attach_gus(&cfg);
-
- return 0;
-}
-
-static void __exit cleanup_gus(void)
-{
-#ifdef CONFIG_SOUND_GUS16
- if (db16)
- unload_gus_db16(&cfg);
-#endif
- unload_gus(&cfg);
-}
-
-module_init(init_gus);
-module_exit(cleanup_gus);
-
-#ifndef MODULE
-static int __init setup_gus(char *str)
-{
- /* io, irq, dma, dma2 */
- int ints[5];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma16 = ints[4];
-
- return 1;
-}
-
-__setup("gus=", setup_gus);
-#endif
diff --git a/sound/oss/gus_hw.h b/sound/oss/gus_hw.h
deleted file mode 100644
index f97a0b8..0000000
--- a/sound/oss/gus_hw.h
+++ /dev/null
@@ -1,50 +0,0 @@
-
-/*
- * I/O addresses
- */
-
-#define u_Base (gus_base + 0x000)
-#define u_Mixer u_Base
-#define u_Status (gus_base + 0x006)
-#define u_TimerControl (gus_base + 0x008)
-#define u_TimerData (gus_base + 0x009)
-#define u_IRQDMAControl (gus_base + 0x00b)
-#define u_MidiControl (gus_base + 0x100)
-#define MIDI_RESET 0x03
-#define MIDI_ENABLE_XMIT 0x20
-#define MIDI_ENABLE_RCV 0x80
-#define u_MidiStatus u_MidiControl
-#define MIDI_RCV_FULL 0x01
-#define MIDI_XMIT_EMPTY 0x02
-#define MIDI_FRAME_ERR 0x10
-#define MIDI_OVERRUN 0x20
-#define MIDI_IRQ_PEND 0x80
-#define u_MidiData (gus_base + 0x101)
-#define u_Voice (gus_base + 0x102)
-#define u_Command (gus_base + 0x103)
-#define u_DataLo (gus_base + 0x104)
-#define u_DataHi (gus_base + 0x105)
-#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */
-#define u_MixSelect (gus_base + 0x506) /* registers. */
-#define u_IrqStatus u_Status
-# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */
-# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */
-# define GF1_TIMER1_IRQ 0x04 /* general purpose timer */
-# define GF1_TIMER2_IRQ 0x08 /* general purpose timer */
-# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */
-# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */
-# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */
-
-#define ICS2101 1
-# define ICS_MIXDEVS 6
-# define DEV_MIC 0
-# define DEV_LINE 1
-# define DEV_CD 2
-# define DEV_GF1 3
-# define DEV_UNUSED 4
-# define DEV_VOL 5
-
-# define CHN_LEFT 0
-# define CHN_RIGHT 1
-#define CS4231 2
-#define u_DRAMIO (gus_base + 0x107)
diff --git a/sound/oss/gus_linearvol.h b/sound/oss/gus_linearvol.h
deleted file mode 100644
index 7ad0c30..0000000
--- a/sound/oss/gus_linearvol.h
+++ /dev/null
@@ -1,18 +0,0 @@
-static unsigned short gus_linearvol[128] = {
- 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
- 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
- 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
- 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
- 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
- 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
- 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
- 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
- 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
- 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
- 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
- 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
- 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
- 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
- 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
- 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
-};
diff --git a/sound/oss/gus_midi.c b/sound/oss/gus_midi.c
deleted file mode 100644
index d1997a4..0000000
--- a/sound/oss/gus_midi.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * sound/oss/gus_midi.c
- *
- * The low level driver for the GUS Midi Interface.
- *
- *
- * 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.
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added __init to gus_midi_init()
- */
-
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_hw.h"
-
-static int midi_busy, input_opened;
-static int my_dev;
-static int output_used;
-static volatile unsigned char gus_midi_control;
-static void (*midi_input_intr) (int dev, unsigned char data);
-
-static unsigned char tmp_queue[256];
-extern int gus_pnp_flag;
-static volatile int qlen;
-static volatile unsigned char qhead, qtail;
-extern int gus_base, gus_irq, gus_dma;
-extern int *gus_osp;
-extern spinlock_t gus_lock;
-
-static int GUS_MIDI_STATUS(void)
-{
- return inb(u_MidiStatus);
-}
-
-static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev))
-{
- if (midi_busy)
- {
-/* printk("GUS: Midi busy\n");*/
- return -EBUSY;
- }
- outb((MIDI_RESET), u_MidiControl);
- gus_delay();
-
- gus_midi_control = 0;
- input_opened = 0;
-
- if (mode == OPEN_READ || mode == OPEN_READWRITE)
- if (!gus_pnp_flag)
- {
- gus_midi_control |= MIDI_ENABLE_RCV;
- input_opened = 1;
- }
- outb((gus_midi_control), u_MidiControl); /* Enable */
-
- midi_busy = 1;
- qlen = qhead = qtail = output_used = 0;
- midi_input_intr = input;
-
- return 0;
-}
-
-static int dump_to_midi(unsigned char midi_byte)
-{
- unsigned long flags;
- int ok = 0;
-
- output_used = 1;
-
- spin_lock_irqsave(&gus_lock, flags);
-
- if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY)
- {
- ok = 1;
- outb((midi_byte), u_MidiData);
- }
- else
- {
- /*
- * Enable Midi xmit interrupts (again)
- */
- gus_midi_control |= MIDI_ENABLE_XMIT;
- outb((gus_midi_control), u_MidiControl);
- }
-
- spin_unlock_irqrestore(&gus_lock,flags);
- return ok;
-}
-
-static void gus_midi_close(int dev)
-{
- /*
- * Reset FIFO pointers, disable intrs
- */
-
- outb((MIDI_RESET), u_MidiControl);
- midi_busy = 0;
-}
-
-static int gus_midi_out(int dev, unsigned char midi_byte)
-{
- unsigned long flags;
-
- /*
- * Drain the local queue first
- */
- spin_lock_irqsave(&gus_lock, flags);
-
- while (qlen && dump_to_midi(tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
- spin_unlock_irqrestore(&gus_lock,flags);
-
- /*
- * Output the byte if the local queue is empty.
- */
-
- if (!qlen)
- if (dump_to_midi(midi_byte))
- return 1; /*
- * OK
- */
-
- /*
- * Put to the local queue
- */
-
- if (qlen >= 256)
- return 0; /*
- * Local queue full
- */
- spin_lock_irqsave(&gus_lock, flags);
-
- tmp_queue[qtail] = midi_byte;
- qlen++;
- qtail++;
-
- spin_unlock_irqrestore(&gus_lock,flags);
- return 1;
-}
-
-static int gus_midi_start_read(int dev)
-{
- return 0;
-}
-
-static int gus_midi_end_read(int dev)
-{
- return 0;
-}
-
-static void gus_midi_kick(int dev)
-{
-}
-
-static int gus_midi_buffer_status(int dev)
-{
- unsigned long flags;
-
- if (!output_used)
- return 0;
-
- spin_lock_irqsave(&gus_lock, flags);
-
- if (qlen && dump_to_midi(tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
- spin_unlock_irqrestore(&gus_lock,flags);
- return (qlen > 0) || !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
-}
-
-#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-static struct midi_operations gus_midi_operations =
-{
- .owner = THIS_MODULE,
- .info = {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
- .converter = &std_midi_synth,
- .in_info = {0},
- .open = gus_midi_open,
- .close = gus_midi_close,
- .outputc = gus_midi_out,
- .start_read = gus_midi_start_read,
- .end_read = gus_midi_end_read,
- .kick = gus_midi_kick,
- .buffer_status = gus_midi_buffer_status,
-};
-
-void __init gus_midi_init(struct address_info *hw_config)
-{
- int dev = sound_alloc_mididev();
-
- if (dev == -1)
- {
- printk(KERN_INFO "gus_midi: Too many midi devices detected\n");
- return;
- }
- outb((MIDI_RESET), u_MidiControl);
-
- std_midi_synth.midi_dev = my_dev = dev;
- hw_config->slots[2] = dev;
- midi_devs[dev] = &gus_midi_operations;
- sequencer_init();
- return;
-}
-
-void gus_midi_interrupt(int dummy)
-{
- volatile unsigned char stat, data;
- int timeout = 10;
-
- spin_lock(&gus_lock);
-
- while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY))
- {
- if (stat & MIDI_RCV_FULL)
- {
- data = inb(u_MidiData);
- if (input_opened)
- midi_input_intr(my_dev, data);
- }
- if (stat & MIDI_XMIT_EMPTY)
- {
- while (qlen && dump_to_midi(tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
- if (!qlen)
- {
- /*
- * Disable Midi output interrupts, since no data in the buffer
- */
- gus_midi_control &= ~MIDI_ENABLE_XMIT;
- outb((gus_midi_control), u_MidiControl);
- outb((gus_midi_control), u_MidiControl);
- }
- }
- }
- spin_unlock(&gus_lock);
-}
diff --git a/sound/oss/gus_vol.c b/sound/oss/gus_vol.c
deleted file mode 100644
index 6ae6924..0000000
--- a/sound/oss/gus_vol.c
+++ /dev/null
@@ -1,153 +0,0 @@
-
-/*
- * gus_vol.c - Compute volume for GUS.
- *
- *
- * 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.
- */
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_linearvol.h"
-
-#define GUS_VOLUME gus_wave_volume
-
-
-extern int gus_wave_volume;
-
-/*
- * Calculate gus volume from note velocity, main volume, expression, and
- * intrinsic patch volume given in patch library. Expression is multiplied
- * in, so it emphasizes differences in note velocity, while main volume is
- * added in -- I don't know whether this is right, but it seems reasonable to
- * me. (In the previous stage, main volume controller messages were changed
- * to expression controller messages, if they were found to be used for
- * dynamic volume adjustments, so here, main volume can be assumed to be
- * constant throughout a song.)
- *
- * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
- * we can give a big boost to very weak voices like nylon guitar and the
- * basses. The normal value is 64. Strings are assigned lower values.
- */
-
-unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev)
-{
- int i, m, n, x;
-
-
- /*
- * A voice volume of 64 is considered neutral, so adjust the main volume if
- * something other than this neutral value was assigned in the patch
- * library.
- */
- x = 256 + 6 * (voicev - 64);
-
- /*
- * Boost expression by voice volume above neutral.
- */
-
- if (voicev > 65)
- xpn += voicev - 64;
- xpn += (voicev - 64) / 2;
-
- /*
- * Combine multiplicative and level components.
- */
- x = vel * xpn * 6 + (voicev / 4) * x;
-
-#ifdef GUS_VOLUME
- /*
- * Further adjustment by installation-specific master volume control
- * (default 60).
- */
- x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
-#endif
-
-#ifdef GUS_USE_CHN_MAIN_VOLUME
- /*
- * Experimental support for the channel main volume
- */
-
- mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
- x = (x * mainv * mainv) / 16384;
-#endif
-
- if (x < 2)
- return (0);
- else if (x >= 65535)
- return ((15 << 8) | 255);
-
- /*
- * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit
- * mantissa m.
- */
-
- n = x;
- i = 7;
- if (n < 128)
- {
- while (i > 0 && n < (1 << i))
- i--;
- }
- else
- {
- while (n > 255)
- {
- n >>= 1;
- i++;
- }
- }
- /*
- * Mantissa is part of linear volume not expressed in exponent. (This is
- * not quite like real logs -- I wonder if it's right.)
- */
- m = x - (1 << i);
-
- /*
- * Adjust mantissa to 8 bits.
- */
- if (m > 0)
- {
- if (i > 8)
- m >>= i - 8;
- else if (i < 8)
- m <<= 8 - i;
- }
- return ((i << 8) + m);
-}
-
-/*
- * Volume-values are interpreted as linear values. Volume is based on the
- * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
- * and the volume set by the mixer-device (default 60%).
- */
-
-unsigned short gus_linear_vol(int vol, int mainvol)
-{
- int mixer_mainvol;
-
- if (vol <= 0)
- vol = 0;
- else if (vol >= 127)
- vol = 127;
-
-#ifdef GUS_VOLUME
- mixer_mainvol = GUS_VOLUME;
-#else
- mixer_mainvol = 100;
-#endif
-
-#ifdef GUS_USE_CHN_MAIN_VOLUME
- if (mainvol <= 0)
- mainvol = 0;
- else if (mainvol >= 127)
- mainvol = 127;
-#else
- mainvol = 127;
-#endif
- return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
-}
diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c
deleted file mode 100644
index 597db7a..0000000
--- a/sound/oss/gus_wave.c
+++ /dev/null
@@ -1,3464 +0,0 @@
-/*
- * sound/oss/gus_wave.c
- *
- * Driver for the Gravis UltraSound wave table synth.
- *
- *
- * 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)
- * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
- * usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
- * Bartlomiej Zolnierkiewicz : added some __init/__exit
- */
-
-#include <linux/init.h>
-#include <linux/config.h>
-#include <linux/spinlock.h>
-
-#define GUSPNP_AUTODETECT
-
-#include "sound_config.h"
-#include <linux/ultrasound.h>
-
-#include "gus.h"
-#include "gus_hw.h"
-
-#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
-
-#define MAX_SAMPLE 150
-#define MAX_PATCH 256
-
-#define NOT_SAMPLE 0xffff
-
-struct voice_info
-{
- unsigned long orig_freq;
- unsigned long current_freq;
- unsigned long mode;
- int fixed_pitch;
- int bender;
- int bender_range;
- int panning;
- int midi_volume;
- unsigned int initial_volume;
- unsigned int current_volume;
- int loop_irq_mode, loop_irq_parm;
-#define LMODE_FINISH 1
-#define LMODE_PCM 2
-#define LMODE_PCM_STOP 3
- int volume_irq_mode, volume_irq_parm;
-#define VMODE_HALT 1
-#define VMODE_ENVELOPE 2
-#define VMODE_START_NOTE 3
-
- int env_phase;
- unsigned char env_rate[6];
- unsigned char env_offset[6];
-
- /*
- * Volume computation parameters for gus_adagio_vol()
- */
- int main_vol, expression_vol, patch_vol;
-
- /* Variables for "Ultraclick" removal */
- int dev_pending, note_pending, volume_pending,
- sample_pending;
- char kill_pending;
- long offset_pending;
-
-};
-
-static struct voice_alloc_info *voice_alloc;
-static struct address_info *gus_hw_config;
-extern int gus_base;
-extern int gus_irq, gus_dma;
-extern int gus_pnp_flag;
-extern int gus_no_wave_dma;
-static int gus_dma2 = -1;
-static int dual_dma_mode;
-static long gus_mem_size;
-static long free_mem_ptr;
-static int gus_busy;
-static int gus_no_dma;
-static int nr_voices;
-static int gus_devnum;
-static int volume_base, volume_scale, volume_method;
-static int gus_recmask = SOUND_MASK_MIC;
-static int recording_active;
-static int only_read_access;
-static int only_8_bits;
-
-static int iw_mode = 0;
-int gus_wave_volume = 60;
-int gus_pcm_volume = 80;
-int have_gus_max = 0;
-static int gus_line_vol = 100, gus_mic_vol;
-static unsigned char mix_image = 0x00;
-
-int gus_timer_enabled = 0;
-
-/*
- * Current version of this driver doesn't allow synth and PCM functions
- * at the same time. The active_device specifies the active driver
- */
-
-static int active_device;
-
-#define GUS_DEV_WAVE 1 /* Wave table synth */
-#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */
-#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer done ch. 1/2 */
-
-static int gus_audio_speed;
-static int gus_audio_channels;
-static int gus_audio_bits;
-static int gus_audio_bsize;
-static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */
-
-static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper);
-
-/*
- * Variables and buffers for PCM output
- */
-
-#define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */
-
-static int pcm_bsize, pcm_nblk, pcm_banksize;
-static int pcm_datasize[MAX_PCM_BUFFERS];
-static volatile int pcm_head, pcm_tail, pcm_qlen;
-static volatile int pcm_active;
-static volatile int dma_active;
-static int pcm_opened;
-static int pcm_current_dev;
-static int pcm_current_block;
-static unsigned long pcm_current_buf;
-static int pcm_current_count;
-static int pcm_current_intrflag;
-DEFINE_SPINLOCK(gus_lock);
-
-extern int *gus_osp;
-
-static struct voice_info voices[32];
-
-static int freq_div_table[] =
-{
- 44100, /* 14 */
- 41160, /* 15 */
- 38587, /* 16 */
- 36317, /* 17 */
- 34300, /* 18 */
- 32494, /* 19 */
- 30870, /* 20 */
- 29400, /* 21 */
- 28063, /* 22 */
- 26843, /* 23 */
- 25725, /* 24 */
- 24696, /* 25 */
- 23746, /* 26 */
- 22866, /* 27 */
- 22050, /* 28 */
- 21289, /* 29 */
- 20580, /* 30 */
- 19916, /* 31 */
- 19293 /* 32 */
-};
-
-static struct patch_info *samples;
-static long sample_ptrs[MAX_SAMPLE + 1];
-static int sample_map[32];
-static int free_sample;
-static int mixer_type;
-
-
-static int patch_table[MAX_PATCH];
-static int patch_map[32];
-
-static struct synth_info gus_info = {
- "Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS,
- 0, 16, 0, MAX_PATCH
-};
-
-static void gus_poke(long addr, unsigned char data);
-static void compute_and_set_volume(int voice, int volume, int ramp_time);
-extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
-extern unsigned short gus_linear_vol(int vol, int mainvol);
-static void compute_volume(int voice, int volume);
-static void do_volume_irq(int voice);
-static void set_input_volumes(void);
-static void gus_tmr_install(int io_base);
-
-#define INSTANT_RAMP -1 /* Instant change. No ramping */
-#define FAST_RAMP 0 /* Fastest possible ramp */
-
-static void reset_sample_memory(void)
-{
- int i;
-
- for (i = 0; i <= MAX_SAMPLE; i++)
- sample_ptrs[i] = -1;
- for (i = 0; i < 32; i++)
- sample_map[i] = -1;
- for (i = 0; i < 32; i++)
- patch_map[i] = -1;
-
- gus_poke(0, 0); /* Put a silent sample to the beginning */
- gus_poke(1, 0);
- free_mem_ptr = 2;
-
- free_sample = 0;
-
- for (i = 0; i < MAX_PATCH; i++)
- patch_table[i] = NOT_SAMPLE;
-}
-
-void gus_delay(void)
-{
- int i;
-
- for (i = 0; i < 7; i++)
- inb(u_DRAMIO);
-}
-
-static void gus_poke(long addr, unsigned char data)
-{ /* Writes a byte to the DRAM */
- outb((0x43), u_Command);
- outb((addr & 0xff), u_DataLo);
- outb(((addr >> 8) & 0xff), u_DataHi);
-
- outb((0x44), u_Command);
- outb(((addr >> 16) & 0xff), u_DataHi);
- outb((data), u_DRAMIO);
-}
-
-static unsigned char gus_peek(long addr)
-{ /* Reads a byte from the DRAM */
- unsigned char tmp;
-
- outb((0x43), u_Command);
- outb((addr & 0xff), u_DataLo);
- outb(((addr >> 8) & 0xff), u_DataHi);
-
- outb((0x44), u_Command);
- outb(((addr >> 16) & 0xff), u_DataHi);
- tmp = inb(u_DRAMIO);
-
- return tmp;
-}
-
-void gus_write8(int reg, unsigned int data)
-{ /* Writes to an indirect register (8 bit) */
- outb((reg), u_Command);
- outb(((unsigned char) (data & 0xff)), u_DataHi);
-}
-
-static unsigned char gus_read8(int reg)
-{
- /* Reads from an indirect register (8 bit). Offset 0x80. */
- unsigned char val;
-
- outb((reg | 0x80), u_Command);
- val = inb(u_DataHi);
-
- return val;
-}
-
-static unsigned char gus_look8(int reg)
-{
- /* Reads from an indirect register (8 bit). No additional offset. */
- unsigned char val;
-
- outb((reg), u_Command);
- val = inb(u_DataHi);
-
- return val;
-}
-
-static void gus_write16(int reg, unsigned int data)
-{
- /* Writes to an indirect register (16 bit) */
- outb((reg), u_Command);
-
- outb(((unsigned char) (data & 0xff)), u_DataLo);
- outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi);
-}
-
-static unsigned short gus_read16(int reg)
-{
- /* Reads from an indirect register (16 bit). Offset 0x80. */
- unsigned char hi, lo;
-
- outb((reg | 0x80), u_Command);
-
- lo = inb(u_DataLo);
- hi = inb(u_DataHi);
-
- return ((hi << 8) & 0xff00) | lo;
-}
-
-static unsigned short gus_look16(int reg)
-{
- /* Reads from an indirect register (16 bit). No additional offset. */
- unsigned char hi, lo;
-
- outb((reg), u_Command);
-
- lo = inb(u_DataLo);
- hi = inb(u_DataHi);
-
- return ((hi << 8) & 0xff00) | lo;
-}
-
-static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit)
-{
- /* Writes an 24 bit memory address */
- unsigned long hold_address;
-
- if (is16bit)
- {
- if (iw_mode)
- {
- /* Interwave spesific address translations */
- address >>= 1;
- }
- else
- {
- /*
- * Special processing required for 16 bit patches
- */
-
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
- }
- gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
- gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
- + (frac << 5));
- /* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */
- gus_delay();
- gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
- gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
- + (frac << 5));
-}
-
-static void gus_select_voice(int voice)
-{
- if (voice < 0 || voice > 31)
- return;
- outb((voice), u_Voice);
-}
-
-static void gus_select_max_voices(int nvoices)
-{
- if (iw_mode)
- nvoices = 32;
- if (nvoices < 14)
- nvoices = 14;
- if (nvoices > 32)
- nvoices = 32;
-
- voice_alloc->max_voice = nr_voices = nvoices;
- gus_write8(0x0e, (nvoices - 1) | 0xc0);
-}
-
-static void gus_voice_on(unsigned int mode)
-{
- gus_write8(0x00, (unsigned char) (mode & 0xfc));
- gus_delay();
- gus_write8(0x00, (unsigned char) (mode & 0xfc));
-}
-
-static void gus_voice_off(void)
-{
- gus_write8(0x00, gus_read8(0x00) | 0x03);
-}
-
-static void gus_voice_mode(unsigned int m)
-{
- unsigned char mode = (unsigned char) (m & 0xff);
-
- gus_write8(0x00, (gus_read8(0x00) & 0x03) |
- (mode & 0xfc)); /* Don't touch last two bits */
- gus_delay();
- gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc));
-}
-
-static void gus_voice_freq(unsigned long freq)
-{
- unsigned long divisor = freq_div_table[nr_voices - 14];
- unsigned short fc;
-
- /* Interwave plays at 44100 Hz with any number of voices */
- if (iw_mode)
- fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100);
- else
- fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
- fc = fc << 1;
-
- gus_write16(0x01, fc);
-}
-
-static void gus_voice_volume(unsigned int vol)
-{
- gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */
- gus_write16(0x09, (unsigned short) (vol << 4));
-}
-
-static void gus_voice_balance(unsigned int balance)
-{
- gus_write8(0x0c, (unsigned char) (balance & 0xff));
-}
-
-static void gus_ramp_range(unsigned int low, unsigned int high)
-{
- gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff));
- gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff));
-}
-
-static void gus_ramp_rate(unsigned int scale, unsigned int rate)
-{
- gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
-}
-
-static void gus_rampon(unsigned int m)
-{
- unsigned char mode = (unsigned char) (m & 0xff);
-
- gus_write8(0x0d, mode & 0xfc);
- gus_delay();
- gus_write8(0x0d, mode & 0xfc);
-}
-
-static void gus_ramp_mode(unsigned int m)
-{
- unsigned char mode = (unsigned char) (m & 0xff);
-
- gus_write8(0x0d, (gus_read8(0x0d) & 0x03) |
- (mode & 0xfc)); /* Leave the last 2 bits alone */
- gus_delay();
- gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc));
-}
-
-static void gus_rampoff(void)
-{
- gus_write8(0x0d, 0x03);
-}
-
-static void gus_set_voice_pos(int voice, long position)
-{
- int sample_no;
-
- if ((sample_no = sample_map[voice]) != -1) {
- if (position < samples[sample_no].len) {
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- voices[voice].offset_pending = position;
- else
- gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0,
- samples[sample_no].mode & WAVE_16_BITS);
- }
- }
-}
-
-static void gus_voice_init(int voice)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_volume(0);
- gus_voice_off();
- gus_write_addr(0x0a, 0, 0, 0); /* Set current position to 0 */
- gus_write8(0x00, 0x03); /* Voice off */
- gus_write8(0x0d, 0x03); /* Ramping off */
- voice_alloc->map[voice] = 0;
- voice_alloc->alloc_times[voice] = 0;
- spin_unlock_irqrestore(&gus_lock,flags);
-
-}
-
-static void gus_voice_init2(int voice)
-{
- voices[voice].panning = 0;
- voices[voice].mode = 0;
- voices[voice].orig_freq = 20000;
- voices[voice].current_freq = 20000;
- voices[voice].bender = 0;
- voices[voice].bender_range = 200;
- voices[voice].initial_volume = 0;
- voices[voice].current_volume = 0;
- voices[voice].loop_irq_mode = 0;
- voices[voice].loop_irq_parm = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].volume_irq_parm = 0;
- voices[voice].env_phase = 0;
- voices[voice].main_vol = 127;
- voices[voice].patch_vol = 127;
- voices[voice].expression_vol = 127;
- voices[voice].sample_pending = -1;
- voices[voice].fixed_pitch = 0;
-}
-
-static void step_envelope(int voice)
-{
- unsigned vol, prev_vol, phase;
- unsigned char rate;
- unsigned long flags;
-
- if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
- {
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_rampoff();
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- /*
- * Sustain phase begins. Continue envelope after receiving note off.
- */
- }
- if (voices[voice].env_phase >= 5)
- {
- /* Envelope finished. Shoot the voice down */
- gus_voice_init(voice);
- return;
- }
- prev_vol = voices[voice].current_volume;
- phase = ++voices[voice].env_phase;
- compute_volume(voice, voices[voice].midi_volume);
- vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
- rate = voices[voice].env_rate[phase];
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
-
- gus_voice_volume(prev_vol);
-
-
- gus_write8(0x06, rate); /* Ramping rate */
-
- voices[voice].volume_irq_mode = VMODE_ENVELOPE;
-
- if (((vol - prev_vol) / 64) == 0) /* No significant volume change */
- {
- spin_unlock_irqrestore(&gus_lock,flags);
- step_envelope(voice); /* Continue the envelope on the next step */
- return;
- }
- if (vol > prev_vol)
- {
- if (vol >= (4096 - 64))
- vol = 4096 - 65;
- gus_ramp_range(0, vol);
- gus_rampon(0x20); /* Increasing volume, with IRQ */
- }
- else
- {
- if (vol <= 64)
- vol = 65;
- gus_ramp_range(vol, 4030);
- gus_rampon(0x60); /* Decreasing volume, with IRQ */
- }
- voices[voice].current_volume = vol;
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void init_envelope(int voice)
-{
- voices[voice].env_phase = -1;
- voices[voice].current_volume = 64;
-
- step_envelope(voice);
-}
-
-static void start_release(int voice)
-{
- if (gus_read8(0x00) & 0x03)
- return; /* Voice already stopped */
-
- voices[voice].env_phase = 2; /* Will be incremented by step_envelope */
-
- voices[voice].current_volume = voices[voice].initial_volume =
- gus_read16(0x09) >> 4; /* Get current volume */
-
- voices[voice].mode &= ~WAVE_SUSTAIN_ON;
- gus_rampoff();
- step_envelope(voice);
-}
-
-static void gus_voice_fade(int voice)
-{
- int instr_no = sample_map[voice], is16bits;
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
-
- if (instr_no < 0 || instr_no > MAX_SAMPLE)
- {
- gus_write8(0x00, 0x03); /* Hard stop */
- voice_alloc->map[voice] = 0;
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- start_release(voice);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- /*
- * Ramp the volume down but not too quickly.
- */
- if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */
- {
- gus_voice_off();
- gus_rampoff();
- gus_voice_init(voice);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- gus_ramp_range(65, 4030);
- gus_ramp_rate(2, 4);
- gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */
- voices[voice].volume_irq_mode = VMODE_HALT;
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void gus_reset(void)
-{
- int i;
-
- gus_select_max_voices(24);
- volume_base = 3071;
- volume_scale = 4;
- volume_method = VOL_METHOD_ADAGIO;
-
- for (i = 0; i < 32; i++)
- {
- gus_voice_init(i); /* Turn voice off */
- gus_voice_init2(i);
- }
-}
-
-static void gus_initialize(void)
-{
- unsigned long flags;
- unsigned char dma_image, irq_image, tmp;
-
- static unsigned char gus_irq_map[16] = {
- 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7
- };
-
- static unsigned char gus_dma_map[8] = {
- 0, 1, 0, 2, 0, 3, 4, 5
- };
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_write8(0x4c, 0); /* Reset GF1 */
- gus_delay();
- gus_delay();
-
- gus_write8(0x4c, 1); /* Release Reset */
- gus_delay();
- gus_delay();
-
- /*
- * Clear all interrupts
- */
-
- gus_write8(0x41, 0); /* DMA control */
- gus_write8(0x45, 0); /* Timer control */
- gus_write8(0x49, 0); /* Sample control */
-
- gus_select_max_voices(24);
-
- inb(u_Status); /* Touch the status register */
-
- gus_look8(0x41); /* Clear any pending DMA IRQs */
- gus_look8(0x49); /* Clear any pending sample IRQs */
- gus_read8(0x0f); /* Clear pending IRQs */
-
- gus_reset(); /* Resets all voices */
-
- gus_look8(0x41); /* Clear any pending DMA IRQs */
- gus_look8(0x49); /* Clear any pending sample IRQs */
- gus_read8(0x0f); /* Clear pending IRQs */
-
- gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */
-
- /*
- * Set up for Digital ASIC
- */
-
- outb((0x05), gus_base + 0x0f);
-
- mix_image |= 0x02; /* Disable line out (for a moment) */
- outb((mix_image), u_Mixer);
-
- outb((0x00), u_IRQDMAControl);
-
- outb((0x00), gus_base + 0x0f);
-
- /*
- * Now set up the DMA and IRQ interface
- *
- * The GUS supports two IRQs and two DMAs.
- *
- * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
- * Adding this support requires significant changes to the dmabuf.c, dsp.c
- * and audio.c also.
- */
-
- irq_image = 0;
- tmp = gus_irq_map[gus_irq];
- if (!gus_pnp_flag && !tmp)
- printk(KERN_WARNING "Warning! GUS IRQ not selected\n");
- irq_image |= tmp;
- irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
-
- dual_dma_mode = 1;
- if (gus_dma2 == gus_dma || gus_dma2 == -1)
- {
- dual_dma_mode = 0;
- dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
-
- tmp = gus_dma_map[gus_dma];
- if (!tmp)
- printk(KERN_WARNING "Warning! GUS DMA not selected\n");
-
- dma_image |= tmp;
- }
- else
- {
- /* Setup dual DMA channel mode for GUS MAX */
-
- dma_image = gus_dma_map[gus_dma];
- if (!dma_image)
- printk(KERN_WARNING "Warning! GUS DMA not selected\n");
-
- tmp = gus_dma_map[gus_dma2] << 3;
- if (!tmp)
- {
- printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n");
- tmp = 0x40; /* Combine DMA channels */
- dual_dma_mode = 0;
- }
- dma_image |= tmp;
- }
-
- /*
- * For some reason the IRQ and DMA addresses must be written twice
- */
-
- /*
- * Doing it first time
- */
-
- outb((mix_image), u_Mixer); /* Select DMA control */
- outb((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */
-
- outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */
- outb((irq_image), u_IRQDMAControl); /* Set IRQ address */
-
- /*
- * Doing it second time
- */
-
- outb((mix_image), u_Mixer); /* Select DMA control */
- outb((dma_image), u_IRQDMAControl); /* Set DMA address */
-
- outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */
- outb((irq_image), u_IRQDMAControl); /* Set IRQ address */
-
- gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
-
- mix_image &= ~0x02; /* Enable line out */
- mix_image |= 0x08; /* Enable IRQ */
- outb((mix_image), u_Mixer); /*
- * Turn mixer channels on
- * Note! Mic in is left off.
- */
-
- gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
-
- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
-
- inb(u_Status); /* Touch the status register */
-
- gus_look8(0x41); /* Clear any pending DMA IRQs */
- gus_look8(0x49); /* Clear any pending sample IRQs */
-
- gus_read8(0x0f); /* Clear pending IRQs */
-
- if (iw_mode)
- gus_write8(0x19, gus_read8(0x19) | 0x01);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-
-static void __init pnp_mem_init(void)
-{
-#include "iwmem.h"
-#define CHUNK_SIZE (256*1024)
-#define BANK_SIZE (4*1024*1024)
-#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE)
-
- int bank, chunk, addr, total = 0;
- int bank_sizes[4];
- int i, j, bits = -1, testbits = -1, nbanks = 0;
-
- /*
- * This routine determines what kind of RAM is installed in each of the four
- * SIMM banks and configures the DRAM address decode logic accordingly.
- */
-
- /*
- * Place the chip into enhanced mode
- */
- gus_write8(0x19, gus_read8(0x19) | 0x01);
- gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */
-
- /*
- * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
- */
-
- gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c);
-
- /*
- * Perform the DRAM size detection for each bank individually.
- */
- for (bank = 0; bank < 4; bank++)
- {
- int size = 0;
-
- addr = bank * BANK_SIZE;
-
- /* Clean check points of each chunk */
- for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
- {
- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
- }
-
- /* Write a value to each chunk point and verify the result */
- for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
- {
- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55);
- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA);
-
- if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 &&
- gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA)
- {
- /* OK. There is RAM. Now check for possible shadows */
- int ok = 1, chunk2;
-
- for (chunk2 = 0; ok && chunk2 < chunk; chunk2++)
- if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) ||
- gus_peek(addr + chunk2 * CHUNK_SIZE + 1L))
- ok = 0; /* Addressing wraps */
-
- if (ok)
- size = (chunk + 1) * CHUNK_SIZE;
- }
- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
- }
- bank_sizes[bank] = size;
- if (size)
- nbanks = bank + 1;
- DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024));
- }
-
- if (nbanks == 0) /* No RAM - Give up */
- {
- printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n");
- printk(KERN_ERR "Sound: Unable to work with this card.\n");
- gus_write8(0x19, gus_read8(0x19) & ~0x01);
- gus_mem_size = 0;
- return;
- }
-
- /*
- * Now we know how much DRAM there is in each bank. The next step is
- * to find a DRAM size encoding (0 to 12) which is best for the combination
- * we have.
- *
- * First try if any of the possible alternatives matches exactly the amount
- * of memory we have.
- */
-
- for (i = 0; bits == -1 && i < 13; i++)
- {
- bits = i;
-
- for (j = 0; bits != -1 && j < 4; j++)
- if (mem_decode[i][j] != bank_sizes[j])
- bits = -1; /* No hit */
- }
-
- /*
- * If necessary, try to find a combination where other than the last
- * bank matches our configuration and the last bank is left oversized.
- * In this way we don't leave holes in the middle of memory.
- */
-
- if (bits == -1) /* No luck yet */
- {
- for (i = 0; bits == -1 && i < 13; i++)
- {
- bits = i;
-
- for (j = 0; bits != -1 && j < nbanks - 1; j++)
- if (mem_decode[i][j] != bank_sizes[j])
- bits = -1; /* No hit */
- if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1])
- bits = -1; /* The last bank is too small */
- }
- }
- /*
- * The last resort is to search for a combination where the banks are
- * smaller than the actual SIMMs. This leaves some memory in the banks
- * unused but doesn't leave holes in the DRAM address space.
- */
- if (bits == -1) /* No luck yet */
- {
- for (i = 0; i < 13; i++)
- {
- testbits = i;
- for (j = 0; testbits != -1 && j < nbanks - 1; j++)
- if (mem_decode[i][j] > bank_sizes[j]) {
- testbits = -1;
- }
- if(testbits > bits) bits = testbits;
- }
- if (bits != -1)
- {
- printk(KERN_INFO "Interwave: Can't use all installed RAM.\n");
- printk(KERN_INFO "Interwave: Try reordering SIMMS.\n");
- }
- printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n");
- printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n");
- bits = 0;
- }
- DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits));
-
- for (bank = 0; bank < 4; bank++)
- {
- DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024));
-
- if (bank_sizes[bank] > mem_decode[bits][bank])
- total += mem_decode[bits][bank];
- else
- total += bank_sizes[bank];
- }
-
- DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024));
-
- /*
- * Set the memory addressing mode.
- */
- gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits);
-
-/* Leave the chip into enhanced mode. Disable LFO */
- gus_mem_size = total;
- iw_mode = 1;
- gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02);
-}
-
-int __init gus_wave_detect(int baseaddr)
-{
- unsigned long i, max_mem = 1024L;
- unsigned long loc;
- unsigned char val;
-
- if (!request_region(baseaddr, 16, "GUS"))
- return 0;
- if (!request_region(baseaddr + 0x100, 12, "GUS")) { /* 0x10c-> is MAX */
- release_region(baseaddr, 16);
- return 0;
- }
-
- gus_base = baseaddr;
-
- gus_write8(0x4c, 0); /* Reset GF1 */
- gus_delay();
- gus_delay();
-
- gus_write8(0x4c, 1); /* Release Reset */
- gus_delay();
- gus_delay();
-
-#ifdef GUSPNP_AUTODETECT
- val = gus_look8(0x5b); /* Version number register */
- gus_write8(0x5b, ~val); /* Invert all bits */
-
- if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */
- {
- if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */
- {
- DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
- gus_pnp_flag = 1;
- }
- else
- {
- DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b)));
- gus_pnp_flag = 0;
- }
- }
- gus_write8(0x5b, val); /* Restore all bits */
-#endif
-
- if (gus_pnp_flag)
- pnp_mem_init();
- if (iw_mode)
- return 1;
-
- /* See if there is first block there.... */
- gus_poke(0L, 0xaa);
- if (gus_peek(0L) != 0xaa) {
- release_region(baseaddr + 0x100, 12);
- release_region(baseaddr, 16);
- return 0;
- }
-
- /* Now zero it out so that I can check for mirroring .. */
- gus_poke(0L, 0x00);
- for (i = 1L; i < max_mem; i++)
- {
- int n, failed;
-
- /* check for mirroring ... */
- if (gus_peek(0L) != 0)
- break;
- loc = i << 10;
-
- for (n = loc - 1, failed = 0; n <= loc; n++)
- {
- gus_poke(loc, 0xaa);
- if (gus_peek(loc) != 0xaa)
- failed = 1;
- gus_poke(loc, 0x55);
- if (gus_peek(loc) != 0x55)
- failed = 1;
- }
- if (failed)
- break;
- }
- gus_mem_size = i << 10;
- return 1;
-}
-
-static int guswave_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
-
- switch (cmd)
- {
- case SNDCTL_SYNTH_INFO:
- gus_info.nr_voices = nr_voices;
- if (copy_to_user(arg, &gus_info, sizeof(gus_info)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_SEQ_RESETSAMPLES:
- reset_sample_memory();
- return 0;
-
- case SNDCTL_SEQ_PERCMODE:
- return 0;
-
- case SNDCTL_SYNTH_MEMAVL:
- return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
-
- default:
- return -EINVAL;
- }
-}
-
-static int guswave_set_instr(int dev, int voice, int instr_no)
-{
- int sample_no;
-
- if (instr_no < 0 || instr_no > MAX_PATCH)
- instr_no = 0; /* Default to acoustic piano */
-
- if (voice < 0 || voice > 31)
- return -EINVAL;
-
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].sample_pending = instr_no;
- return 0;
- }
- sample_no = patch_table[instr_no];
- patch_map[voice] = -1;
-
- if (sample_no == NOT_SAMPLE)
- {
-/* printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/
- return -EINVAL; /* Patch not defined */
- }
- if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
- {
-/* printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/
- return -EINVAL;
- }
- sample_map[voice] = sample_no;
- patch_map[voice] = instr_no;
- return 0;
-}
-
-static int guswave_kill_note(int dev, int voice, int note, int velocity)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- /* voice_alloc->map[voice] = 0xffff; */
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].kill_pending = 1;
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- else
- {
- spin_unlock_irqrestore(&gus_lock,flags);
- gus_voice_fade(voice);
- }
-
- return 0;
-}
-
-static void guswave_aftertouch(int dev, int voice, int pressure)
-{
-}
-
-static void guswave_panning(int dev, int voice, int value)
-{
- if (voice >= 0 || voice < 32)
- voices[voice].panning = value;
-}
-
-static void guswave_volume_method(int dev, int mode)
-{
- if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
- volume_method = mode;
-}
-
-static void compute_volume(int voice, int volume)
-{
- if (volume < 128)
- voices[voice].midi_volume = volume;
-
- switch (volume_method)
- {
- case VOL_METHOD_ADAGIO:
- voices[voice].initial_volume =
- gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol,
- voices[voice].expression_vol,
- voices[voice].patch_vol);
- break;
-
- case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */
- voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol);
- break;
-
- default:
- voices[voice].initial_volume = volume_base +
- (voices[voice].midi_volume * volume_scale);
- }
-
- if (voices[voice].initial_volume > 4030)
- voices[voice].initial_volume = 4030;
-}
-
-static void compute_and_set_volume(int voice, int volume, int ramp_time)
-{
- int curr, target, rate;
- unsigned long flags;
-
- compute_volume(voice, volume);
- voices[voice].current_volume = voices[voice].initial_volume;
-
- spin_lock_irqsave(&gus_lock,flags);
- /*
- * CAUTION! Interrupts disabled. Enable them before returning
- */
-
- gus_select_voice(voice);
-
- curr = gus_read16(0x09) >> 4;
- target = voices[voice].initial_volume;
-
- if (ramp_time == INSTANT_RAMP)
- {
- gus_rampoff();
- gus_voice_volume(target);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- if (ramp_time == FAST_RAMP)
- rate = 63;
- else
- rate = 16;
- gus_ramp_rate(0, rate);
-
- if ((target - curr) / 64 == 0) /* Close enough to target. */
- {
- gus_rampoff();
- gus_voice_volume(target);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- if (target > curr)
- {
- if (target > (4095 - 65))
- target = 4095 - 65;
- gus_ramp_range(curr, target);
- gus_rampon(0x00); /* Ramp up, once, no IRQ */
- }
- else
- {
- if (target < 65)
- target = 65;
-
- gus_ramp_range(target, curr);
- gus_rampon(0x40); /* Ramp down, once, no irq */
- }
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void dynamic_volume_change(int voice)
-{
- unsigned char status;
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- status = gus_read8(0x00); /* Get voice status */
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (status & 0x03)
- return; /* Voice was not running */
-
- if (!(voices[voice].mode & WAVE_ENVELOPES))
- {
- compute_and_set_volume(voice, voices[voice].midi_volume, 1);
- return;
- }
-
- /*
- * Voice is running and has envelopes.
- */
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- status = gus_read8(0x0d); /* Ramping status */
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (status & 0x03) /* Sustain phase? */
- {
- compute_and_set_volume(voice, voices[voice].midi_volume, 1);
- return;
- }
- if (voices[voice].env_phase < 0)
- return;
-
- compute_volume(voice, voices[voice].midi_volume);
-
-}
-
-static void guswave_controller(int dev, int voice, int ctrl_num, int value)
-{
- unsigned long flags;
- unsigned long freq;
-
- if (voice < 0 || voice > 31)
- return;
-
- switch (ctrl_num)
- {
- case CTRL_PITCH_BENDER:
- voices[voice].bender = value;
-
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- {
- freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0);
- voices[voice].current_freq = freq;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_freq(freq);
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- break;
-
- case CTRL_PITCH_BENDER_RANGE:
- voices[voice].bender_range = value;
- break;
- case CTL_EXPRESSION:
- value /= 128;
- case CTRL_EXPRESSION:
- if (volume_method == VOL_METHOD_ADAGIO)
- {
- voices[voice].expression_vol = value;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change(voice);
- }
- break;
-
- case CTL_PAN:
- voices[voice].panning = (value * 2) - 128;
- break;
-
- case CTL_MAIN_VOLUME:
- value = (value * 100) / 16383;
-
- case CTRL_MAIN_VOLUME:
- voices[voice].main_vol = value;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change(voice);
- break;
-
- default:
- break;
- }
-}
-
-static int guswave_start_note2(int dev, int voice, int note_num, int volume)
-{
- int sample, best_sample, best_delta, delta_freq;
- int is16bits, samplep, patch, pan;
- unsigned long note_freq, base_note, freq, flags;
- unsigned char mode = 0;
-
- if (voice < 0 || voice > 31)
- {
-/* printk("GUS: Invalid voice\n");*/
- return -EINVAL;
- }
- if (note_num == 255)
- {
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- voices[voice].midi_volume = volume;
- dynamic_volume_change(voice);
- return 0;
- }
- compute_and_set_volume(voice, volume, 1);
- return 0;
- }
- if ((patch = patch_map[voice]) == -1)
- return -EINVAL;
- if ((samplep = patch_table[patch]) == NOT_SAMPLE)
- {
- return -EINVAL;
- }
- note_freq = note_to_freq(note_num);
-
- /*
- * Find a sample within a patch so that the note_freq is between low_note
- * and high_note.
- */
- sample = -1;
-
- best_sample = samplep;
- best_delta = 1000000;
- while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1)
- {
- delta_freq = note_freq - samples[samplep].base_note;
- if (delta_freq < 0)
- delta_freq = -delta_freq;
- if (delta_freq < best_delta)
- {
- best_sample = samplep;
- best_delta = delta_freq;
- }
- if (samples[samplep].low_note <= note_freq &&
- note_freq <= samples[samplep].high_note)
- {
- sample = samplep;
- }
- else
- samplep = samples[samplep].key; /* Link to next sample */
- }
- if (sample == -1)
- sample = best_sample;
-
- if (sample == -1)
- {
-/* printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/
- return 0; /* Should play default patch ??? */
- }
- is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
- voices[voice].mode = samples[sample].mode;
- voices[voice].patch_vol = samples[sample].volume;
-
- if (iw_mode)
- gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- int i;
-
- for (i = 0; i < 6; i++)
- {
- voices[voice].env_rate[i] = samples[sample].env_rate[i];
- voices[voice].env_offset[i] = samples[sample].env_offset[i];
- }
- }
- sample_map[voice] = sample;
-
- if (voices[voice].fixed_pitch) /* Fixed pitch */
- {
- freq = samples[sample].base_freq;
- }
- else
- {
- base_note = samples[sample].base_note / 100;
- note_freq /= 100;
-
- freq = samples[sample].base_freq * note_freq / base_note;
- }
-
- voices[voice].orig_freq = freq;
-
- /*
- * Since the pitch bender may have been set before playing the note, we
- * have to calculate the bending now.
- */
-
- freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender,
- voices[voice].bender_range, 0);
- voices[voice].current_freq = freq;
-
- pan = (samples[sample].panning + voices[voice].panning) / 32;
- pan += 7;
- if (pan < 0)
- pan = 0;
- if (pan > 15)
- pan = 15;
-
- if (samples[sample].mode & WAVE_16_BITS)
- {
- mode |= 0x04; /* 16 bits */
- if ((sample_ptrs[sample] / GUS_BANK_SIZE) !=
- ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))
- printk(KERN_ERR "GUS: Sample address error\n");
- }
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_off();
- gus_rampoff();
-
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- compute_volume(voice, volume);
- init_envelope(voice);
- }
- else
- {
- compute_and_set_volume(voice, volume, 0);
- }
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
-
- if (samples[sample].mode & WAVE_LOOP_BACK)
- gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -
- voices[voice].offset_pending, 0, is16bits); /* start=end */
- else
- gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits); /* Sample start=begin */
-
- if (samples[sample].mode & WAVE_LOOPING)
- {
- mode |= 0x08;
-
- if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10;
-
- if (samples[sample].mode & WAVE_LOOP_BACK)
- {
- gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end -
- voices[voice].offset_pending,
- (samples[sample].fractions >> 4) & 0x0f, is16bits);
- mode |= 0x40;
- }
- gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start,
- samples[sample].fractions & 0x0f, is16bits); /* Loop start location */
- gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end,
- (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */
- }
- else
- {
- mode |= 0x20; /* Loop IRQ at the end */
- voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */
- voices[voice].loop_irq_parm = 1;
- gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits); /* Loop start location */
- gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1,
- (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */
- }
- gus_voice_freq(freq);
- gus_voice_balance(pan);
- gus_voice_on(mode);
- spin_unlock_irqrestore(&gus_lock,flags);
-
- return 0;
-}
-
-/*
- * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
- * when the note playing on the voice is changed. It uses volume
- * ramping.
- */
-
-static int guswave_start_note(int dev, int voice, int note_num, int volume)
-{
- unsigned long flags;
- int mode;
- int ret_val = 0;
-
- spin_lock_irqsave(&gus_lock,flags);
- if (note_num == 255)
- {
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].volume_pending = volume;
- }
- else
- {
- ret_val = guswave_start_note2(dev, voice, note_num, volume);
- }
- }
- else
- {
- gus_select_voice(voice);
- mode = gus_read8(0x00);
- if (mode & 0x20)
- gus_write8(0x00, mode & 0xdf); /* No interrupt! */
-
- voices[voice].offset_pending = 0;
- voices[voice].kill_pending = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].loop_irq_mode = 0;
-
- if (voices[voice].sample_pending >= 0)
- {
- spin_unlock_irqrestore(&gus_lock,flags); /* Run temporarily with interrupts enabled */
- guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice); /* Reselect the voice (just to be sure) */
- }
- if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065))
- {
- ret_val = guswave_start_note2(dev, voice, note_num, volume);
- }
- else
- {
- voices[voice].dev_pending = dev;
- voices[voice].note_pending = note_num;
- voices[voice].volume_pending = volume;
- voices[voice].volume_irq_mode = VMODE_START_NOTE;
-
- gus_rampoff();
- gus_ramp_range(2000, 4065);
- gus_ramp_rate(0, 63); /* Fastest possible rate */
- gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */
- }
- }
- spin_unlock_irqrestore(&gus_lock,flags);
- return ret_val;
-}
-
-static void guswave_reset(int dev)
-{
- int i;
-
- for (i = 0; i < 32; i++)
- {
- gus_voice_init(i);
- gus_voice_init2(i);
- }
-}
-
-static int guswave_open(int dev, int mode)
-{
- int err;
-
- if (gus_busy)
- return -EBUSY;
-
- voice_alloc->timestamp = 0;
-
- if (gus_no_wave_dma) {
- gus_no_dma = 1;
- } else {
- if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
- {
- /* printk( "GUS: Loading samples without DMA\n"); */
- gus_no_dma = 1; /* Upload samples using PIO */
- }
- else
- gus_no_dma = 0;
- }
-
- init_waitqueue_head(&dram_sleeper);
- gus_busy = 1;
- active_device = GUS_DEV_WAVE;
-
- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
- gus_initialize();
- gus_reset();
- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
-
- return 0;
-}
-
-static void guswave_close(int dev)
-{
- gus_busy = 0;
- active_device = 0;
- gus_reset();
-
- if (!gus_no_dma)
- DMAbuf_close_dma(gus_devnum);
-}
-
-static int guswave_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
- struct patch_info patch;
- int instr;
- long sizeof_patch;
-
- unsigned long blk_sz, blk_end, left, src_offs, target;
-
- sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
-
- if (format != GUS_PATCH)
- {
-/* printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/
- return -EINVAL;
- }
- if (count < sizeof_patch)
- {
-/* printk("GUS Error: Patch header too short\n");*/
- return -EINVAL;
- }
- count -= sizeof_patch;
-
- if (free_sample >= MAX_SAMPLE)
- {
-/* printk("GUS: Sample table full\n");*/
- return -ENOSPC;
- }
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
-
- if (copy_from_user(&((char *) &patch)[offs], &(addr)[offs],
- sizeof_patch - offs))
- return -EFAULT;
-
- if (patch.mode & WAVE_ROM)
- return -EINVAL;
- if (gus_mem_size == 0)
- return -ENOSPC;
-
- instr = patch.instr_no;
-
- if (instr < 0 || instr > MAX_PATCH)
- {
-/* printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/
- return -EINVAL;
- }
- if (count < patch.len)
- {
-/* printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/
- patch.len = count;
- }
- if (patch.len <= 0 || patch.len > gus_mem_size)
- {
-/* printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/
- return -EINVAL;
- }
- if (patch.mode & WAVE_LOOPING)
- {
- if (patch.loop_start < 0 || patch.loop_start >= patch.len)
- {
-/* printk(KERN_ERR "GUS: Invalid loop start\n");*/
- return -EINVAL;
- }
- if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
- {
-/* printk(KERN_ERR "GUS: Invalid loop end\n");*/
- return -EINVAL;
- }
- }
- free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
-
- if (patch.mode & WAVE_16_BITS)
- {
- /*
- * 16 bit samples must fit one 256k bank.
- */
- if (patch.len >= GUS_BANK_SIZE)
- {
-/* printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/
- return -ENOSPC;
- }
- if ((free_mem_ptr / GUS_BANK_SIZE) !=
- ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
- {
- unsigned long tmp_mem =
- /* Align to 256K */
- ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
-
- if ((tmp_mem + patch.len) > gus_mem_size)
- return -ENOSPC;
-
- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
- }
- }
- if ((free_mem_ptr + patch.len) > gus_mem_size)
- return -ENOSPC;
-
- sample_ptrs[free_sample] = free_mem_ptr;
-
- /*
- * Tremolo is not possible with envelopes
- */
-
- if (patch.mode & WAVE_ENVELOPES)
- patch.mode &= ~WAVE_TREMOLO;
-
- if (!(patch.mode & WAVE_FRACTIONS))
- {
- patch.fractions = 0;
- }
- memcpy((char *) &samples[free_sample], &patch, sizeof_patch);
-
- /*
- * Link this_one sample to the list of samples for patch 'instr'.
- */
-
- samples[free_sample].key = patch_table[instr];
- patch_table[instr] = free_sample;
-
- /*
- * Use DMA to transfer the wave data to the DRAM
- */
-
- left = patch.len;
- src_offs = 0;
- target = free_mem_ptr;
-
- while (left) /* Not completely transferred yet */
- {
- blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
- if (blk_sz > left)
- blk_sz = left;
-
- /*
- * DMA cannot cross bank (256k) boundaries. Check for that.
- */
-
- blk_end = target + blk_sz;
-
- if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE))
- {
- /* Split the block */
- blk_end &= ~(GUS_BANK_SIZE - 1);
- blk_sz = blk_end - target;
- }
- if (gus_no_dma)
- {
- /*
- * For some reason the DMA is not possible. We have to use PIO.
- */
- long i;
- unsigned char data;
-
- for (i = 0; i < blk_sz; i++)
- {
- get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[sizeof_patch + i]));
- if (patch.mode & WAVE_UNSIGNED)
- if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
- data ^= 0x80; /* Convert to signed */
- gus_poke(target + i, data);
- }
- }
- else
- {
- unsigned long address, hold_address;
- unsigned char dma_command;
- unsigned long flags;
-
- if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)
- {
- printk(KERN_ERR "GUS: DMA buffer == NULL\n");
- return -ENOSPC;
- }
- /*
- * OK, move now. First in and then out.
- */
-
- if (copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf,
- &(addr)[sizeof_patch + src_offs],
- blk_sz))
- return -EFAULT;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
- blk_sz, DMA_MODE_WRITE);
-
- /*
- * Set the DRAM address for the wave data
- */
-
- if (iw_mode)
- {
- /* Different address translation in enhanced mode */
-
- unsigned char hi;
-
- if (gus_dma > 4)
- address = target >> 1; /* Convert to 16 bit word address */
- else
- address = target;
-
- hi = (unsigned char) ((address >> 16) & 0xf0);
- hi += (unsigned char) (address & 0x0f);
-
- gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */
- gus_write8(0x50, hi);
- }
- else
- {
- address = target;
- if (audio_devs[gus_devnum]->dmap_out->dma > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
- gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- }
-
- /*
- * Start the DMA transfer
- */
-
- dma_command = 0x21; /* IRQ enable, DMA start */
- if (patch.mode & WAVE_UNSIGNED)
- dma_command |= 0x80; /* Invert MSB */
- if (patch.mode & WAVE_16_BITS)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- if (audio_devs[gus_devnum]->dmap_out->dma > 3)
- dma_command |= 0x04; /* 16 bit DMA _channel_ */
-
- /*
- * Sleep here until the DRAM DMA done interrupt is served
- */
- active_device = GUS_DEV_WAVE;
- gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */
-
- spin_unlock_irqrestore(&gus_lock,flags); /* opens a race */
- if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
- printk("GUS: DMA Transfer timed out\n");
- }
-
- /*
- * Now the next part
- */
-
- left -= blk_sz;
- src_offs += blk_sz;
- target += blk_sz;
-
- gus_write8(0x41, 0); /* Stop DMA */
- }
-
- free_mem_ptr += patch.len;
- free_sample++;
- return 0;
-}
-
-static void guswave_hw_control(int dev, unsigned char *event_rec)
-{
- int voice, cmd;
- unsigned short p1, p2;
- unsigned int plong;
- unsigned long flags;
-
- cmd = event_rec[2];
- voice = event_rec[3];
- p1 = *(unsigned short *) &event_rec[4];
- p2 = *(unsigned short *) &event_rec[6];
- plong = *(unsigned int *) &event_rec[4];
-
- if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
- (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
- do_volume_irq(voice);
-
- switch (cmd)
- {
- case _GUS_NUMVOICES:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_select_max_voices(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICESAMPLE:
- guswave_set_instr(dev, voice, p1);
- break;
-
- case _GUS_VOICEON:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_on(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEOFF:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_off();
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEFADE:
- gus_voice_fade(voice);
- break;
-
- case _GUS_VOICEMODE:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_mode(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEBALA:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_balance(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEFREQ:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_freq(plong);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEVOL:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_volume(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEVOL2: /* Just update the software voice level */
- voices[voice].initial_volume = voices[voice].current_volume = p1;
- break;
-
- case _GUS_RAMPRANGE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_ramp_range(p1, p2);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPRATE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NJET-NJET */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_ramp_rate(p1, p2);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPMODE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_ramp_mode(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPON:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* EI-EI */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_rampon(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPOFF:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NEJ-NEJ */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_rampoff();
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOLUME_SCALE:
- volume_base = p1;
- volume_scale = p2;
- break;
-
- case _GUS_VOICE_POS:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_set_voice_pos(voice, plong);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- default:
- break;
- }
-}
-
-static int gus_audio_set_speed(int speed)
-{
- if (speed <= 0)
- speed = gus_audio_speed;
-
- if (speed < 4000)
- speed = 4000;
-
- if (speed > 44100)
- speed = 44100;
-
- gus_audio_speed = speed;
-
- if (only_read_access)
- {
- /* Compute nearest valid recording speed and return it */
-
- /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */
- speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
- speed = (9878400 / (speed * 16)) - 2;
- }
- return speed;
-}
-
-static int gus_audio_set_channels(int channels)
-{
- if (!channels)
- return gus_audio_channels;
- if (channels > 2)
- channels = 2;
- if (channels < 1)
- channels = 1;
- gus_audio_channels = channels;
- return channels;
-}
-
-static int gus_audio_set_bits(int bits)
-{
- if (!bits)
- return gus_audio_bits;
-
- if (bits != 8 && bits != 16)
- bits = 8;
-
- if (only_8_bits)
- bits = 8;
-
- gus_audio_bits = bits;
- return bits;
-}
-
-static int gus_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int val;
-
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (get_user(val, (int __user*)arg))
- return -EFAULT;
- val = gus_audio_set_speed(val);
- break;
-
- case SOUND_PCM_READ_RATE:
- val = gus_audio_speed;
- break;
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- val = gus_audio_set_channels(val + 1) - 1;
- break;
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- val = gus_audio_set_channels(val);
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- val = gus_audio_channels;
- break;
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- val = gus_audio_set_bits(val);
- break;
-
- case SOUND_PCM_READ_BITS:
- val = gus_audio_bits;
- break;
-
- case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
- case SOUND_PCM_READ_FILTER:
- val = -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *)arg);
-}
-
-static void gus_audio_reset(int dev)
-{
- if (recording_active)
- {
- gus_write8(0x49, 0x00); /* Halt recording */
- set_input_volumes();
- }
-}
-
-static int saved_iw_mode; /* A hack hack hack */
-
-static int gus_audio_open(int dev, int mode)
-{
- if (gus_busy)
- return -EBUSY;
-
- if (gus_pnp_flag && mode & OPEN_READ)
- {
-/* printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/
- return -EIO;
- }
- gus_initialize();
-
- gus_busy = 1;
- active_device = 0;
-
- saved_iw_mode = iw_mode;
- if (iw_mode)
- {
- /* There are some problems with audio in enhanced mode so disable it */
- gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */
- iw_mode = 0;
- }
-
- gus_reset();
- reset_sample_memory();
- gus_select_max_voices(14);
-
- pcm_active = 0;
- dma_active = 0;
- pcm_opened = 1;
- if (mode & OPEN_READ)
- {
- recording_active = 1;
- set_input_volumes();
- }
- only_read_access = !(mode & OPEN_WRITE);
- only_8_bits = mode & OPEN_READ;
- if (only_8_bits)
- audio_devs[dev]->format_mask = AFMT_U8;
- else
- audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;
-
- return 0;
-}
-
-static void gus_audio_close(int dev)
-{
- iw_mode = saved_iw_mode;
- gus_reset();
- gus_busy = 0;
- pcm_opened = 0;
- active_device = 0;
-
- if (recording_active)
- {
- gus_write8(0x49, 0x00); /* Halt recording */
- set_input_volumes();
- }
- recording_active = 0;
-}
-
-static void gus_audio_update_volume(void)
-{
- unsigned long flags;
- int voice;
-
- if (pcm_active && pcm_opened)
- for (voice = 0; voice < gus_audio_channels; voice++)
- {
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_rampoff();
- gus_voice_volume(1530 + (25 * gus_pcm_volume));
- gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
- spin_unlock_irqrestore(&gus_lock,flags);
- }
-}
-
-static void play_next_pcm_block(void)
-{
- unsigned long flags;
- int speed = gus_audio_speed;
- int this_one, is16bits, chn;
- unsigned long dram_loc;
- unsigned char mode[2], ramp_mode[2];
-
- if (!pcm_qlen)
- return;
-
- this_one = pcm_head;
-
- for (chn = 0; chn < gus_audio_channels; chn++)
- {
- mode[chn] = 0x00;
- ramp_mode[chn] = 0x03; /* Ramping and rollover off */
-
- if (chn == 0)
- {
- mode[chn] |= 0x20; /* Loop IRQ */
- voices[chn].loop_irq_mode = LMODE_PCM;
- }
- if (gus_audio_bits != 8)
- {
- is16bits = 1;
- mode[chn] |= 0x04; /* 16 bit data */
- }
- else
- is16bits = 0;
-
- dram_loc = this_one * pcm_bsize;
- dram_loc += chn * pcm_banksize;
-
- if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */
- {
- mode[chn] |= 0x08; /* Enable loop */
- ramp_mode[chn] = 0x03; /* Disable rollover bit */
- }
- else
- {
- if (chn == 0)
- ramp_mode[chn] = 0x04; /* Enable rollover bit */
- }
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(chn);
- gus_voice_freq(speed);
-
- if (gus_audio_channels == 1)
- gus_voice_balance(7); /* mono */
- else if (chn == 0)
- gus_voice_balance(0); /* left */
- else
- gus_voice_balance(15); /* right */
-
- if (!pcm_active) /* Playback not already active */
- {
- /*
- * The playback was not started yet (or there has been a pause).
- * Start the voice (again) and ask for a rollover irq at the end of
- * this_one block. If this_one one is last of the buffers, use just
- * the normal loop with irq.
- */
-
- gus_voice_off();
- gus_rampoff();
- gus_voice_volume(1530 + (25 * gus_pcm_volume));
- gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
-
- gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */
- gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */
-
- if (chn != 0)
- gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
- 0, is16bits); /* Loop end location */
- }
- if (chn == 0)
- gus_write_addr(0x04, dram_loc + pcm_bsize - 1,
- 0, is16bits); /* Loop end location */
- else
- mode[chn] |= 0x08; /* Enable looping */
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- for (chn = 0; chn < gus_audio_channels; chn++)
- {
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(chn);
- gus_write8(0x0d, ramp_mode[chn]);
- if (iw_mode)
- gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */
- gus_voice_on(mode[chn]);
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- pcm_active = 1;
-}
-
-static void gus_transfer_output_block(int dev, unsigned long buf,
- int total_count, int intrflag, int chn)
-{
- /*
- * This routine transfers one block of audio data to the DRAM. In mono mode
- * it's called just once. When in stereo mode, this_one routine is called
- * once for both channels.
- *
- * The left/mono channel data is transferred to the beginning of dram and the
- * right data to the area pointed by gus_page_size.
- */
-
- int this_one, count;
- unsigned long flags;
- unsigned char dma_command;
- unsigned long address, hold_address;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- count = total_count / gus_audio_channels;
-
- if (chn == 0)
- {
- if (pcm_qlen >= pcm_nblk)
- printk(KERN_WARNING "GUS Warning: PCM buffers out of sync\n");
-
- this_one = pcm_current_block = pcm_tail;
- pcm_qlen++;
- pcm_tail = (pcm_tail + 1) % pcm_nblk;
- pcm_datasize[this_one] = count;
- }
- else
- this_one = pcm_current_block;
-
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE);
-
- address = this_one * pcm_bsize;
- address += chn * pcm_banksize;
-
- if (audio_devs[dev]->dmap_out->dma > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
- gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
-
- dma_command = 0x21; /* IRQ enable, DMA start */
-
- if (gus_audio_bits != 8)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- else
- dma_command |= 0x80; /* Invert MSB */
-
- if (audio_devs[dev]->dmap_out->dma > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
-
- gus_write8(0x41, dma_command); /* Kick start */
-
- if (chn == (gus_audio_channels - 1)) /* Last channel */
- {
- /*
- * Last (right or mono) channel data
- */
- dma_active = 1; /* DMA started. There is a unacknowledged buffer */
- active_device = GUS_DEV_PCM_DONE;
- if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize))
- {
- play_next_pcm_block();
- }
- }
- else
- {
- /*
- * Left channel data. The right channel
- * is transferred after DMA interrupt
- */
- active_device = GUS_DEV_PCM_CONTINUE;
- }
-
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void gus_uninterleave8(char *buf, int l)
-{
-/* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */
- int i, p = 0, halfsize = l / 2;
- char *buf2 = buf + halfsize, *src = bounce_buf;
-
- memcpy(bounce_buf, buf, l);
-
- for (i = 0; i < halfsize; i++)
- {
- buf[i] = src[p++]; /* Left channel */
- buf2[i] = src[p++]; /* Right channel */
- }
-}
-
-static void gus_uninterleave16(short *buf, int l)
-{
-/* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */
- int i, p = 0, halfsize = l / 2;
- short *buf2 = buf + halfsize, *src = (short *) bounce_buf;
-
- memcpy(bounce_buf, (char *) buf, l * 2);
-
- for (i = 0; i < halfsize; i++)
- {
- buf[i] = src[p++]; /* Left channel */
- buf2[i] = src[p++]; /* Right channel */
- }
-}
-
-static void gus_audio_output_block(int dev, unsigned long buf, int total_count,
- int intrflag)
-{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
- dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT;
-
- pcm_current_buf = buf;
- pcm_current_count = total_count;
- pcm_current_intrflag = intrflag;
- pcm_current_dev = dev;
- if (gus_audio_channels == 2)
- {
- char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys);
-
- if (gus_audio_bits == 8)
- gus_uninterleave8(b, total_count);
- else
- gus_uninterleave16((short *) b, total_count / 2);
- }
- gus_transfer_output_block(dev, buf, total_count, intrflag, 0);
-}
-
-static void gus_audio_start_input(int dev, unsigned long buf, int count,
- int intrflag)
-{
- unsigned long flags;
- unsigned char mode;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ);
- mode = 0xa0; /* DMA IRQ enabled, invert MSB */
-
- if (audio_devs[dev]->dmap_in->dma > 3)
- mode |= 0x04; /* 16 bit DMA channel */
- if (gus_audio_channels > 1)
- mode |= 0x02; /* Stereo */
- mode |= 0x01; /* DMA enable */
-
- gus_write8(0x49, mode);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int gus_audio_prepare_for_input(int dev, int bsize, int bcount)
-{
- unsigned int rate;
-
- gus_audio_bsize = bsize;
- audio_devs[dev]->dmap_in->flags |= DMA_NODMA;
- rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
-
- gus_write8(0x48, rate & 0xff); /* Set sampling rate */
-
- if (gus_audio_bits != 8)
- {
-/* printk("GUS Error: 16 bit recording not supported\n");*/
- return -EINVAL;
- }
- return 0;
-}
-
-static int gus_audio_prepare_for_output(int dev, int bsize, int bcount)
-{
- int i;
-
- long mem_ptr, mem_size;
-
- audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT;
- mem_ptr = 0;
- mem_size = gus_mem_size / gus_audio_channels;
-
- if (mem_size > (256 * 1024))
- mem_size = 256 * 1024;
-
- pcm_bsize = bsize / gus_audio_channels;
- pcm_head = pcm_tail = pcm_qlen = 0;
-
- pcm_nblk = 2; /* MAX_PCM_BUFFERS; */
- if ((pcm_bsize * pcm_nblk) > mem_size)
- pcm_nblk = mem_size / pcm_bsize;
-
- for (i = 0; i < pcm_nblk; i++)
- pcm_datasize[i] = 0;
-
- pcm_banksize = pcm_nblk * pcm_bsize;
-
- if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024))
- pcm_nblk--;
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- return 0;
-}
-
-static int gus_local_qlen(int dev)
-{
- return pcm_qlen;
-}
-
-
-static struct audio_driver gus_audio_driver =
-{
- .owner = THIS_MODULE,
- .open = gus_audio_open,
- .close = gus_audio_close,
- .output_block = gus_audio_output_block,
- .start_input = gus_audio_start_input,
- .ioctl = gus_audio_ioctl,
- .prepare_for_input = gus_audio_prepare_for_input,
- .prepare_for_output = gus_audio_prepare_for_output,
- .halt_io = gus_audio_reset,
- .local_qlen = gus_local_qlen,
-};
-
-static void guswave_setup_voice(int dev, int voice, int chn)
-{
- struct channel_info *info = &synth_devs[dev]->chn_info[chn];
-
- guswave_set_instr(dev, voice, info->pgm_num);
- voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */
- voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
- voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128;
- voices[voice].bender = 0;
- voices[voice].bender_range = info->bender_range;
-
- if (chn == 9)
- voices[voice].fixed_pitch = 1;
-}
-
-static void guswave_bender(int dev, int voice, int value)
-{
- int freq;
- unsigned long flags;
-
- voices[voice].bender = value - 8192;
- freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0);
- voices[voice].current_freq = freq;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_freq(freq);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
- int i, p, best = -1, best_time = 0x7fffffff;
-
- p = alloc->ptr;
- /*
- * First look for a completely stopped voice
- */
-
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0)
- {
- alloc->ptr = p;
- return p;
- }
- if (alloc->alloc_times[p] < best_time)
- {
- best = p;
- best_time = alloc->alloc_times[p];
- }
- p = (p + 1) % alloc->max_voice;
- }
-
- /*
- * Then look for a releasing voice
- */
-
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0xffff)
- {
- alloc->ptr = p;
- return p;
- }
- p = (p + 1) % alloc->max_voice;
- }
- if (best >= 0)
- p = best;
-
- alloc->ptr = p;
- return p;
-}
-
-static struct synth_operations guswave_operations =
-{
- .owner = THIS_MODULE,
- .id = "GUS",
- .info = &gus_info,
- .midi_dev = 0,
- .synth_type = SYNTH_TYPE_SAMPLE,
- .synth_subtype = SAMPLE_TYPE_GUS,
- .open = guswave_open,
- .close = guswave_close,
- .ioctl = guswave_ioctl,
- .kill_note = guswave_kill_note,
- .start_note = guswave_start_note,
- .set_instr = guswave_set_instr,
- .reset = guswave_reset,
- .hw_control = guswave_hw_control,
- .load_patch = guswave_load_patch,
- .aftertouch = guswave_aftertouch,
- .controller = guswave_controller,
- .panning = guswave_panning,
- .volume_method = guswave_volume_method,
- .bender = guswave_bender,
- .alloc_voice = guswave_alloc,
- .setup_voice = guswave_setup_voice
-};
-
-static void set_input_volumes(void)
-{
- unsigned long flags;
- unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
-
- if (have_gus_max) /* Don't disturb GUS MAX */
- return;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- /*
- * Enable channels having vol > 10%
- * Note! bit 0x01 means the line in DISABLED while 0x04 means
- * the mic in ENABLED.
- */
- if (gus_line_vol > 10)
- mask &= ~0x01;
- if (gus_mic_vol > 10)
- mask |= 0x04;
-
- if (recording_active)
- {
- /*
- * Disable channel, if not selected for recording
- */
- if (!(gus_recmask & SOUND_MASK_LINE))
- mask |= 0x01;
- if (!(gus_recmask & SOUND_MASK_MIC))
- mask &= ~0x04;
- }
- mix_image &= ~0x07;
- mix_image |= mask & 0x07;
- outb((mix_image), u_Mixer);
-
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
- SOUND_MASK_SYNTH|SOUND_MASK_PCM)
-
-int gus_default_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int vol, val;
-
- if (((cmd >> 8) & 0xff) != 'M')
- return -EINVAL;
-
- if (!access_ok(VERIFY_WRITE, arg, sizeof(int)))
- return -EFAULT;
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- {
- if (__get_user(val, (int __user *) arg))
- return -EFAULT;
-
- switch (cmd & 0xff)
- {
- case SOUND_MIXER_RECSRC:
- gus_recmask = val & MIX_DEVS;
- if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
- gus_recmask = SOUND_MASK_MIC;
- /* Note! Input volumes are updated during next open for recording */
- val = gus_recmask;
- break;
-
- case SOUND_MIXER_MIC:
- vol = val & 0xff;
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- gus_mic_vol = vol;
- set_input_volumes();
- val = vol | (vol << 8);
- break;
-
- case SOUND_MIXER_LINE:
- vol = val & 0xff;
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- gus_line_vol = vol;
- set_input_volumes();
- val = vol | (vol << 8);
- break;
-
- case SOUND_MIXER_PCM:
- gus_pcm_volume = val & 0xff;
- if (gus_pcm_volume < 0)
- gus_pcm_volume = 0;
- if (gus_pcm_volume > 100)
- gus_pcm_volume = 100;
- gus_audio_update_volume();
- val = gus_pcm_volume | (gus_pcm_volume << 8);
- break;
-
- case SOUND_MIXER_SYNTH:
- gus_wave_volume = val & 0xff;
- if (gus_wave_volume < 0)
- gus_wave_volume = 0;
- if (gus_wave_volume > 100)
- gus_wave_volume = 100;
- if (active_device == GUS_DEV_WAVE)
- {
- int voice;
- for (voice = 0; voice < nr_voices; voice++)
- dynamic_volume_change(voice); /* Apply the new vol */
- }
- val = gus_wave_volume | (gus_wave_volume << 8);
- break;
-
- default:
- return -EINVAL;
- }
- }
- else
- {
- switch (cmd & 0xff)
- {
- /*
- * Return parameters
- */
- case SOUND_MIXER_RECSRC:
- val = gus_recmask;
- break;
-
- case SOUND_MIXER_DEVMASK:
- val = MIX_DEVS;
- break;
-
- case SOUND_MIXER_STEREODEVS:
- val = 0;
- break;
-
- case SOUND_MIXER_RECMASK:
- val = SOUND_MASK_MIC | SOUND_MASK_LINE;
- break;
-
- case SOUND_MIXER_CAPS:
- val = 0;
- break;
-
- case SOUND_MIXER_MIC:
- val = gus_mic_vol | (gus_mic_vol << 8);
- break;
-
- case SOUND_MIXER_LINE:
- val = gus_line_vol | (gus_line_vol << 8);
- break;
-
- case SOUND_MIXER_PCM:
- val = gus_pcm_volume | (gus_pcm_volume << 8);
- break;
-
- case SOUND_MIXER_SYNTH:
- val = gus_wave_volume | (gus_wave_volume << 8);
- break;
-
- default:
- return -EINVAL;
- }
- }
- return __put_user(val, (int __user *)arg);
-}
-
-static struct mixer_operations gus_mixer_operations =
-{
- .owner = THIS_MODULE,
- .id = "GUS",
- .name = "Gravis Ultrasound",
- .ioctl = gus_default_mixer_ioctl
-};
-
-static int __init gus_default_mixer_init(void)
-{
- int n;
-
- if ((n = sound_alloc_mixerdev()) != -1)
- {
- /*
- * Don't install if there is another
- * mixer
- */
- mixer_devs[n] = &gus_mixer_operations;
- }
- if (have_gus_max)
- {
- /*
- * Enable all mixer channels on the GF1 side. Otherwise recording will
- * not be possible using GUS MAX.
- */
- mix_image &= ~0x07;
- mix_image |= 0x04; /* All channels enabled */
- outb((mix_image), u_Mixer);
- }
- return n;
-}
-
-void __init gus_wave_init(struct address_info *hw_config)
-{
- unsigned long flags;
- unsigned char val;
- char *model_num = "2.4";
- char tmp[64];
- int gus_type = 0x24; /* 2.4 */
-
- int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
- int sdev;
-
- hw_config->slots[0] = -1; /* No wave */
- hw_config->slots[1] = -1; /* No ad1848 */
- hw_config->slots[4] = -1; /* No audio */
- hw_config->slots[5] = -1; /* No mixer */
-
- if (!gus_pnp_flag)
- {
- if (irq < 0 || irq > 15)
- {
- printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq);
- return;
- }
- }
-
- if (dma < 0 || dma > 7 || dma == 4)
- {
- printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma);
- return;
- }
- gus_irq = irq;
- gus_dma = dma;
- gus_dma2 = dma2;
- gus_hw_config = hw_config;
-
- if (gus_dma2 == -1)
- gus_dma2 = dma;
-
- /*
- * Try to identify the GUS model.
- *
- * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
- */
-
- spin_lock_irqsave(&gus_lock,flags);
- outb((0x20), gus_base + 0x0f);
- val = inb(gus_base + 0x0f);
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */
- {
- int ad_flags = 0;
-
- if (gus_pnp_flag)
- ad_flags = 0x12345678; /* Interwave "magic" */
- /*
- * It has the digital ASIC so the card is at least v3.4.
- * Next try to detect the true model.
- */
-
- if (gus_pnp_flag) /* Hack hack hack */
- val = 10;
- else
- val = inb(u_MixSelect);
-
- /*
- * Value 255 means pre-3.7 which don't have mixer.
- * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
- * 10 and above is GUS MAX which has the CS4231 codec/mixer.
- *
- */
-
- if (val == 255 || val < 5)
- {
- model_num = "3.4";
- gus_type = 0x34;
- }
- else if (val < 10)
- {
- model_num = "3.7";
- gus_type = 0x37;
- mixer_type = ICS2101;
- request_region(u_MixSelect, 1, "GUS mixer");
- }
- else
- {
- struct resource *ports;
- ports = request_region(gus_base + 0x10c, 4, "ad1848");
- model_num = "MAX";
- gus_type = 0x40;
- mixer_type = CS4231;
-#ifdef CONFIG_SOUND_GUSMAX
- {
- unsigned char max_config = 0x40; /* Codec enable */
-
- if (gus_dma2 == -1)
- gus_dma2 = gus_dma;
-
- if (gus_dma > 3)
- max_config |= 0x10; /* 16 bit capture DMA */
-
- if (gus_dma2 > 3)
- max_config |= 0x20; /* 16 bit playback DMA */
-
- max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
-
- outb((max_config), gus_base + 0x106); /* UltraMax control */
- }
-
- if (!ports)
- goto no_cs4231;
-
- if (ad1848_detect(ports, &ad_flags, hw_config->osp))
- {
- char *name = "GUS MAX";
- int old_num_mixers = num_mixers;
-
- if (gus_pnp_flag)
- name = "GUS PnP";
-
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- have_gus_max = 1;
- if (hw_config->name)
- name = hw_config->name;
-
- hw_config->slots[1] = ad1848_init(name, ports,
- -irq, gus_dma2, /* Playback DMA */
- gus_dma, /* Capture DMA */
- 1, /* Share DMA channels with GF1 */
- hw_config->osp,
- THIS_MODULE);
-
- if (num_mixers > old_num_mixers)
- {
- /* GUS has it's own mixer map */
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
- }
- }
- else {
- release_region(gus_base + 0x10c, 4);
- no_cs4231:
- printk(KERN_WARNING "GUS: No CS4231 ??");
- }
-#else
- printk(KERN_ERR "GUS MAX found, but not compiled in\n");
-#endif
- }
- }
- else
- {
- /*
- * ASIC not detected so the card must be 2.2 or 2.4.
- * There could still be the 16-bit/mixer daughter card.
- */
- }
-
- if (hw_config->name)
- snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name,
- (int) gus_mem_size / 1024);
- else if (gus_pnp_flag)
- snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)",
- (int) gus_mem_size / 1024);
- else
- snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num,
- (int) gus_mem_size / 1024);
-
-
- samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples));
- if (samples == NULL)
- {
- printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
- return;
- }
- conf_printf(tmp, hw_config);
- strlcpy(gus_info.name, tmp, sizeof(gus_info.name));
-
- if ((sdev = sound_alloc_synthdev()) == -1)
- printk(KERN_WARNING "gus_init: Too many synthesizers\n");
- else
- {
- voice_alloc = &guswave_operations.alloc;
- if (iw_mode)
- guswave_operations.id = "IWAVE";
- hw_config->slots[0] = sdev;
- synth_devs[sdev] = &guswave_operations;
- sequencer_init();
- gus_tmr_install(gus_base + 8);
- }
-
- reset_sample_memory();
-
- gus_initialize();
-
- if ((gus_mem_size > 0) && !gus_no_wave_dma)
- {
- hw_config->slots[4] = -1;
- if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
- "Ultrasound",
- &gus_audio_driver,
- sizeof(struct audio_driver),
- NEEDS_RESTART |
- ((!iw_mode && dma2 != dma && dma2 != -1) ?
- DMA_DUPLEX : 0),
- AFMT_U8 | AFMT_S16_LE,
- NULL, dma, dma2)) < 0)
- {
- return;
- }
-
- hw_config->slots[4] = gus_devnum;
- audio_devs[gus_devnum]->min_fragment = 9; /* 512k */
- audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */
- audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
- audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
- }
-
- /*
- * Mixer dependent initialization.
- */
-
- switch (mixer_type)
- {
- case ICS2101:
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- request_region(u_MixSelect, 1, "GUS mixer");
- hw_config->slots[5] = ics2101_mixer_init();
- audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */
- return;
-
- case CS4231:
- /* Initialized elsewhere (ad1848.c) */
- default:
- hw_config->slots[5] = gus_default_mixer_init();
- audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */
- return;
- }
-}
-
-void __exit gus_wave_unload(struct address_info *hw_config)
-{
-#ifdef CONFIG_SOUND_GUSMAX
- if (have_gus_max)
- {
- ad1848_unload(gus_base + 0x10c,
- -gus_irq,
- gus_dma2, /* Playback DMA */
- gus_dma, /* Capture DMA */
- 1); /* Share DMA channels with GF1 */
- }
-#endif
-
- if (mixer_type == ICS2101)
- {
- release_region(u_MixSelect, 1);
- }
- if (hw_config->slots[0] != -1)
- sound_unload_synthdev(hw_config->slots[0]);
- if (hw_config->slots[1] != -1)
- sound_unload_audiodev(hw_config->slots[1]);
- if (hw_config->slots[2] != -1)
- sound_unload_mididev(hw_config->slots[2]);
- if (hw_config->slots[4] != -1)
- sound_unload_audiodev(hw_config->slots[4]);
- if (hw_config->slots[5] != -1)
- sound_unload_mixerdev(hw_config->slots[5]);
-
- vfree(samples);
- samples=NULL;
-}
-/* called in interrupt context */
-static void do_loop_irq(int voice)
-{
- unsigned char tmp;
- int mode, parm;
-
- spin_lock(&gus_lock);
- gus_select_voice(voice);
-
- tmp = gus_read8(0x00);
- tmp &= ~0x20; /*
- * Disable wave IRQ for this_one voice
- */
- gus_write8(0x00, tmp);
-
- if (tmp & 0x03) /* Voice stopped */
- voice_alloc->map[voice] = 0;
-
- mode = voices[voice].loop_irq_mode;
- voices[voice].loop_irq_mode = 0;
- parm = voices[voice].loop_irq_parm;
-
- switch (mode)
- {
- case LMODE_FINISH: /*
- * Final loop finished, shoot volume down
- */
-
- if ((int) (gus_read16(0x09) >> 4) < 100) /*
- * Get current volume
- */
- {
- gus_voice_off();
- gus_rampoff();
- gus_voice_init(voice);
- break;
- }
- gus_ramp_range(65, 4065);
- gus_ramp_rate(0, 63); /*
- * Fastest possible rate
- */
- gus_rampon(0x20 | 0x40); /*
- * Ramp down, once, irq
- */
- voices[voice].volume_irq_mode = VMODE_HALT;
- break;
-
- case LMODE_PCM_STOP:
- pcm_active = 0; /* Signal to the play_next_pcm_block routine */
- case LMODE_PCM:
- {
- pcm_qlen--;
- pcm_head = (pcm_head + 1) % pcm_nblk;
- if (pcm_qlen && pcm_active)
- {
- play_next_pcm_block();
- }
- else
- {
- /* Underrun. Just stop the voice */
- gus_select_voice(0); /* Left channel */
- gus_voice_off();
- gus_rampoff();
- gus_select_voice(1); /* Right channel */
- gus_voice_off();
- gus_rampoff();
- pcm_active = 0;
- }
-
- /*
- * If the queue was full before this interrupt, the DMA transfer was
- * suspended. Let it continue now.
- */
-
- if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
- DMAbuf_outputintr(gus_devnum, 0);
- }
- break;
-
- default:
- break;
- }
- spin_unlock(&gus_lock);
-}
-
-static void do_volume_irq(int voice)
-{
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- gus_select_voice(voice);
- tmp = gus_read8(0x0d);
- tmp &= ~0x20; /*
- * Disable volume ramp IRQ
- */
- gus_write8(0x0d, tmp);
-
- mode = voices[voice].volume_irq_mode;
- voices[voice].volume_irq_mode = 0;
- parm = voices[voice].volume_irq_parm;
-
- switch (mode)
- {
- case VMODE_HALT: /* Decay phase finished */
- if (iw_mode)
- gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */
- spin_unlock_irqrestore(&gus_lock,flags);
- gus_voice_init(voice);
- break;
-
- case VMODE_ENVELOPE:
- gus_rampoff();
- spin_unlock_irqrestore(&gus_lock,flags);
- step_envelope(voice);
- break;
-
- case VMODE_START_NOTE:
- spin_unlock_irqrestore(&gus_lock,flags);
- guswave_start_note2(voices[voice].dev_pending, voice,
- voices[voice].note_pending, voices[voice].volume_pending);
- if (voices[voice].kill_pending)
- guswave_kill_note(voices[voice].dev_pending, voice,
- voices[voice].note_pending, 0);
-
- if (voices[voice].sample_pending >= 0)
- {
- guswave_set_instr(voices[voice].dev_pending, voice,
- voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
- }
- break;
-
- default:
- spin_unlock_irqrestore(&gus_lock,flags);
- }
-}
-/* called in irq context */
-void gus_voice_irq(void)
-{
- unsigned long wave_ignore = 0, volume_ignore = 0;
- unsigned long voice_bit;
-
- unsigned char src, voice;
-
- while (1)
- {
- src = gus_read8(0x0f); /*
- * Get source info
- */
- voice = src & 0x1f;
- src &= 0xc0;
-
- if (src == (0x80 | 0x40))
- return; /*
- * No interrupt
- */
-
- voice_bit = 1 << voice;
-
- if (!(src & 0x80)) /*
- * Wave IRQ pending
- */
- if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /*
- * Not done
- * yet
- */
- {
- wave_ignore |= voice_bit;
- do_loop_irq(voice);
- }
- if (!(src & 0x40)) /*
- * Volume IRQ pending
- */
- if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /*
- * Not done
- * yet
- */
- {
- volume_ignore |= voice_bit;
- do_volume_irq(voice);
- }
- }
-}
-
-void guswave_dma_irq(void)
-{
- unsigned char status;
-
- status = gus_look8(0x41); /* Get DMA IRQ Status */
- if (status & 0x40) /* DMA interrupt pending */
- switch (active_device)
- {
- case GUS_DEV_WAVE:
- wake_up(&dram_sleeper);
- break;
-
- case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- gus_transfer_output_block(pcm_current_dev, pcm_current_buf,
- pcm_current_count,
- pcm_current_intrflag, 1);
- break;
-
- case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- if (pcm_qlen < pcm_nblk)
- {
- dma_active = 0;
- if (gus_busy)
- {
- if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
- DMAbuf_outputintr(gus_devnum, 0);
- }
- }
- break;
-
- default:
- break;
- }
- status = gus_look8(0x49); /*
- * Get Sampling IRQ Status
- */
- if (status & 0x40) /*
- * Sampling Irq pending
- */
- {
- DMAbuf_inputintr(gus_devnum);
- }
-}
-
-/*
- * Timer stuff
- */
-
-static volatile int select_addr, data_addr;
-static volatile int curr_timer;
-
-void gus_timer_command(unsigned int addr, unsigned int val)
-{
- int i;
-
- outb(((unsigned char) (addr & 0xff)), select_addr);
-
- for (i = 0; i < 2; i++)
- inb(select_addr);
-
- outb(((unsigned char) (val & 0xff)), data_addr);
-
- for (i = 0; i < 2; i++)
- inb(select_addr);
-}
-
-static void arm_timer(int timer, unsigned int interval)
-{
- curr_timer = timer;
-
- if (timer == 1)
- {
- gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */
- gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */
- gus_timer_command(0x04, 0x01); /* Start timer 1 */
- }
- else
- {
- gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */
- gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */
- gus_timer_command(0x04, 0x02); /* Start timer 2 */
- }
-
- gus_timer_enabled = 1;
-}
-
-static unsigned int gus_tmr_start(int dev, unsigned int usecs_per_tick)
-{
- int timer_no, resolution;
- int divisor;
-
- if (usecs_per_tick > (256 * 80))
- {
- timer_no = 2;
- resolution = 320; /* usec */
- }
- else
- {
- timer_no = 1;
- resolution = 80; /* usec */
- }
- divisor = (usecs_per_tick + (resolution / 2)) / resolution;
- arm_timer(timer_no, divisor);
-
- return divisor * resolution;
-}
-
-static void gus_tmr_disable(int dev)
-{
- gus_write8(0x45, 0); /* Disable both timers */
- gus_timer_enabled = 0;
-}
-
-static void gus_tmr_restart(int dev)
-{
- if (curr_timer == 1)
- gus_write8(0x45, 0x04); /* Start timer 1 again */
- else
- gus_write8(0x45, 0x08); /* Start timer 2 again */
- gus_timer_enabled = 1;
-}
-
-static struct sound_lowlev_timer gus_tmr =
-{
- 0,
- 1,
- gus_tmr_start,
- gus_tmr_disable,
- gus_tmr_restart
-};
-
-static void gus_tmr_install(int io_base)
-{
- struct sound_lowlev_timer *tmr;
-
- select_addr = io_base;
- data_addr = io_base + 1;
-
- tmr = &gus_tmr;
-
-#ifdef THIS_GETS_FIXED
- sound_timer_init(&gus_tmr, "GUS");
-#endif
-}
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
deleted file mode 100644
index 6601b28..0000000
--- a/sound/oss/harmony.c
+++ /dev/null
@@ -1,1330 +0,0 @@
-/*
- sound/oss/harmony.c
-
- This is a sound driver for ASP's and Lasi's Harmony sound chip
- and is unlikely to be used for anything other than on a HP PA-RISC.
-
- Harmony is found in HP 712s, 715/new and many other GSC based machines.
- On older 715 machines you'll find the technically identical chip
- called 'Vivace'. Both Harmony and Vicace are supported by this driver.
-
- Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@onefishtwo.ca>
- Copyright 2000-2003 (c) Helge Deller <deller@gmx.de>
- Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr>
- Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr>
- Copyright 2004 (c) Stuart Brady <sdbrady@ntlworld.com>
-
-
-TODO:
- - fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to
- return the real values
- - add private ioctl for selecting line- or microphone input
- (only one of them is available at the same time)
- - add module parameters
- - implement mmap functionality
- - implement gain meter ?
- - ...
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-
-#include <asm/parisc-device.h>
-#include <asm/io.h>
-
-#include "sound_config.h"
-
-
-#define PFX "harmony: "
-#define HARMONY_VERSION "V0.9a"
-
-#undef DEBUG
-#ifdef DEBUG
-# define DPRINTK printk
-#else
-# define DPRINTK(x,...)
-#endif
-
-
-#define MAX_BUFS 10 /* maximum number of rotating buffers */
-#define HARMONY_BUF_SIZE 4096 /* needs to be a multiple of PAGE_SIZE (4096)! */
-
-#define CNTL_C 0x80000000
-#define CNTL_ST 0x00000020
-#define CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */
-#define CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */
-
-#define GAINCTL_HE 0x08000000
-#define GAINCTL_LE 0x04000000
-#define GAINCTL_SE 0x02000000
-
-#define DSTATUS_PN 0x00000200
-#define DSTATUS_RN 0x00000002
-
-#define DSTATUS_IE 0x80000000
-
-#define HARMONY_DF_16BIT_LINEAR 0
-#define HARMONY_DF_8BIT_ULAW 1
-#define HARMONY_DF_8BIT_ALAW 2
-
-#define HARMONY_SS_MONO 0
-#define HARMONY_SS_STEREO 1
-
-#define HARMONY_SR_8KHZ 0x08
-#define HARMONY_SR_16KHZ 0x09
-#define HARMONY_SR_27KHZ 0x0A
-#define HARMONY_SR_32KHZ 0x0B
-#define HARMONY_SR_48KHZ 0x0E
-#define HARMONY_SR_9KHZ 0x0F
-#define HARMONY_SR_5KHZ 0x10
-#define HARMONY_SR_11KHZ 0x11
-#define HARMONY_SR_18KHZ 0x12
-#define HARMONY_SR_22KHZ 0x13
-#define HARMONY_SR_37KHZ 0x14
-#define HARMONY_SR_44KHZ 0x15
-#define HARMONY_SR_33KHZ 0x16
-#define HARMONY_SR_6KHZ 0x17
-
-/*
- * Some magics numbers used to auto-detect file formats
- */
-
-#define HARMONY_MAGIC_8B_ULAW 1
-#define HARMONY_MAGIC_8B_ALAW 27
-#define HARMONY_MAGIC_16B_LINEAR 3
-#define HARMONY_MAGIC_MONO 1
-#define HARMONY_MAGIC_STEREO 2
-
-/*
- * Channels Positions in mixer register
- */
-
-#define GAIN_HE_SHIFT 27
-#define GAIN_HE_MASK ( 1 << GAIN_HE_SHIFT)
-#define GAIN_LE_SHIFT 26
-#define GAIN_LE_MASK ( 1 << GAIN_LE_SHIFT)
-#define GAIN_SE_SHIFT 25
-#define GAIN_SE_MASK ( 1 << GAIN_SE_SHIFT)
-#define GAIN_IS_SHIFT 24
-#define GAIN_IS_MASK ( 1 << GAIN_IS_SHIFT)
-#define GAIN_MA_SHIFT 20
-#define GAIN_MA_MASK ( 0x0f << GAIN_MA_SHIFT)
-#define GAIN_LI_SHIFT 16
-#define GAIN_LI_MASK ( 0x0f << GAIN_LI_SHIFT)
-#define GAIN_RI_SHIFT 12
-#define GAIN_RI_MASK ( 0x0f << GAIN_RI_SHIFT)
-#define GAIN_LO_SHIFT 6
-#define GAIN_LO_MASK ( 0x3f << GAIN_LO_SHIFT)
-#define GAIN_RO_SHIFT 0
-#define GAIN_RO_MASK ( 0x3f << GAIN_RO_SHIFT)
-
-
-#define MAX_OUTPUT_LEVEL (GAIN_RO_MASK >> GAIN_RO_SHIFT)
-#define MAX_INPUT_LEVEL (GAIN_RI_MASK >> GAIN_RI_SHIFT)
-#define MAX_MONITOR_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT)
-
-#define MIXER_INTERNAL SOUND_MIXER_LINE1
-#define MIXER_LINEOUT SOUND_MIXER_LINE2
-#define MIXER_HEADPHONES SOUND_MIXER_LINE3
-
-#define MASK_INTERNAL SOUND_MASK_LINE1
-#define MASK_LINEOUT SOUND_MASK_LINE2
-#define MASK_HEADPHONES SOUND_MASK_LINE3
-
-/*
- * Channels Mask in mixer register
- */
-
-#define GAIN_TOTAL_SILENCE 0x00F00FFF
-#define GAIN_DEFAULT 0x0FF00000
-
-
-struct harmony_hpa {
- u8 unused000;
- u8 id;
- u8 teleshare_id;
- u8 unused003;
- u32 reset;
- u32 cntl;
- u32 gainctl;
- u32 pnxtadd;
- u32 pcuradd;
- u32 rnxtadd;
- u32 rcuradd;
- u32 dstatus;
- u32 ov;
- u32 pio;
- u32 unused02c;
- u32 unused030[3];
- u32 diag;
-};
-
-struct harmony_dev {
- struct harmony_hpa *hpa;
- struct parisc_device *dev;
- u32 current_gain;
- u32 dac_rate; /* 8000 ... 48000 (Hz) */
- u8 data_format; /* HARMONY_DF_xx_BIT_xxx */
- u8 sample_rate; /* HARMONY_SR_xx_KHZ */
- u8 stereo_select; /* HARMONY_SS_MONO or HARMONY_SS_STEREO */
- int format_initialized :1;
- int suspended_playing :1;
- int suspended_recording :1;
-
- int blocked_playing :1;
- int blocked_recording :1;
- int audio_open :1;
- int mixer_open :1;
-
- wait_queue_head_t wq_play, wq_record;
- int first_filled_play; /* first buffer containing data (next to play) */
- int nb_filled_play;
- int play_offset;
- int first_filled_record;
- int nb_filled_record;
-
- int dsp_unit, mixer_unit;
-};
-
-
-static struct harmony_dev harmony;
-
-
-/*
- * Dynamic sound buffer allocation and DMA memory
- */
-
-struct harmony_buffer {
- unsigned char *addr;
- dma_addr_t dma_handle;
- int dma_coherent; /* Zero if dma_alloc_coherent() fails */
- unsigned int len;
-};
-
-/*
- * Harmony memory buffers
- */
-
-static struct harmony_buffer played_buf, recorded_buf, silent, graveyard;
-
-
-#define CHECK_WBACK_INV_OFFSET(b,offset,len) \
- do { if (!b.dma_coherent) \
- dma_cache_wback_inv((unsigned long)b.addr+offset,len); \
- } while (0)
-
-
-static int __init harmony_alloc_buffer(struct harmony_buffer *b,
- unsigned int buffer_count)
-{
- b->len = buffer_count * HARMONY_BUF_SIZE;
- b->addr = dma_alloc_coherent(&harmony.dev->dev,
- b->len, &b->dma_handle, GFP_KERNEL|GFP_DMA);
- if (b->addr && b->dma_handle) {
- b->dma_coherent = 1;
- DPRINTK(KERN_INFO PFX "coherent memory: 0x%lx, played_buf: 0x%lx\n",
- (unsigned long)b->dma_handle, (unsigned long)b->addr);
- } else {
- b->dma_coherent = 0;
- /* kmalloc()ed memory will HPMC on ccio machines ! */
- b->addr = kmalloc(b->len, GFP_KERNEL);
- if (!b->addr) {
- printk(KERN_ERR PFX "couldn't allocate memory\n");
- return -EBUSY;
- }
- b->dma_handle = __pa(b->addr);
- }
- return 0;
-}
-
-static void __exit harmony_free_buffer(struct harmony_buffer *b)
-{
- if (!b->addr)
- return;
-
- if (b->dma_coherent)
- dma_free_coherent(&harmony.dev->dev,
- b->len, b->addr, b->dma_handle);
- else
- kfree(b->addr);
-
- memset(b, 0, sizeof(*b));
-}
-
-
-
-/*
- * Low-Level sound-chip programming
- */
-
-static void __inline__ harmony_wait_CNTL(void)
-{
- /* Wait until we're out of control mode */
- while (gsc_readl(&harmony.hpa->cntl) & CNTL_C)
- /* wait */ ;
-}
-
-
-static void harmony_update_control(void)
-{
- u32 default_cntl;
-
- /* Set CNTL */
- default_cntl = (CNTL_C | /* The C bit */
- (harmony.data_format << 6) | /* Set the data format */
- (harmony.stereo_select << 5) | /* Stereo select */
- (harmony.sample_rate)); /* Set sample rate */
- harmony.format_initialized = 1;
-
- /* initialize CNTL */
- gsc_writel(default_cntl, &harmony.hpa->cntl);
-}
-
-static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select)
-{
- harmony.sample_rate = sample_rate;
- harmony.data_format = data_format;
- harmony.stereo_select = stereo_select;
- harmony_update_control();
-}
-
-static void harmony_set_rate(u8 data_rate)
-{
- harmony.sample_rate = data_rate;
- harmony_update_control();
-}
-
-static int harmony_detect_rate(int *freq)
-{
- int newrate;
- switch (*freq) {
- case 8000: newrate = HARMONY_SR_8KHZ; break;
- case 16000: newrate = HARMONY_SR_16KHZ; break;
- case 27428: newrate = HARMONY_SR_27KHZ; break;
- case 32000: newrate = HARMONY_SR_32KHZ; break;
- case 48000: newrate = HARMONY_SR_48KHZ; break;
- case 9600: newrate = HARMONY_SR_9KHZ; break;
- case 5512: newrate = HARMONY_SR_5KHZ; break;
- case 11025: newrate = HARMONY_SR_11KHZ; break;
- case 18900: newrate = HARMONY_SR_18KHZ; break;
- case 22050: newrate = HARMONY_SR_22KHZ; break;
- case 37800: newrate = HARMONY_SR_37KHZ; break;
- case 44100: newrate = HARMONY_SR_44KHZ; break;
- case 33075: newrate = HARMONY_SR_33KHZ; break;
- case 6615: newrate = HARMONY_SR_6KHZ; break;
- default: newrate = HARMONY_SR_8KHZ;
- *freq = 8000; break;
- }
- return newrate;
-}
-
-static void harmony_set_format(u8 data_format)
-{
- harmony.data_format = data_format;
- harmony_update_control();
-}
-
-static void harmony_set_stereo(u8 stereo_select)
-{
- harmony.stereo_select = stereo_select;
- harmony_update_control();
-}
-
-static void harmony_disable_interrupts(void)
-{
- harmony_wait_CNTL();
- gsc_writel(0, &harmony.hpa->dstatus);
-}
-
-static void harmony_enable_interrupts(void)
-{
- harmony_wait_CNTL();
- gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus);
-}
-
-/*
- * harmony_silence()
- *
- * This subroutine fills in a buffer starting at location start and
- * silences for length bytes. This references the current
- * configuration of the audio format.
- *
- */
-
-static void harmony_silence(struct harmony_buffer *buffer, int start, int length)
-{
- u8 silence_char;
-
- /* Despite what you hear, silence is different in
- different audio formats. */
- switch (harmony.data_format) {
- case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break;
- case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break;
- case HARMONY_DF_16BIT_LINEAR: /* fall through */
- default: silence_char = 0;
- }
-
- memset(buffer->addr+start, silence_char, length);
-}
-
-
-static int harmony_audio_open(struct inode *inode, struct file *file)
-{
- if (harmony.audio_open)
- return -EBUSY;
-
- harmony.audio_open = 1;
- harmony.suspended_playing = harmony.suspended_recording = 1;
- harmony.blocked_playing = harmony.blocked_recording = 0;
- harmony.first_filled_play = harmony.first_filled_record = 0;
- harmony.nb_filled_play = harmony.nb_filled_record = 0;
- harmony.play_offset = 0;
- init_waitqueue_head(&harmony.wq_play);
- init_waitqueue_head(&harmony.wq_record);
-
- /* Start off in a balanced mode. */
- harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
- harmony_update_control();
- harmony.format_initialized = 0;
-
- /* Clear out all the buffers and flush to cache */
- harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
- CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
- return 0;
-}
-
-/*
- * Release (close) the audio device.
- */
-
-static int harmony_audio_release(struct inode *inode, struct file *file)
-{
- if (!harmony.audio_open)
- return -EBUSY;
-
- harmony.audio_open = 0;
-
- return 0;
-}
-
-/*
- * Read recorded data off the audio device.
- */
-
-static ssize_t harmony_audio_read(struct file *file,
- char *buffer,
- size_t size_count,
- loff_t *ppos)
-{
- int total_count = (int) size_count;
- int count = 0;
- int buf_to_read;
-
- while (count<total_count) {
- /* Wait until we're out of control mode */
- harmony_wait_CNTL();
-
- /* Figure out which buffer to fill in */
- if (harmony.nb_filled_record <= 2) {
- harmony.blocked_recording = 1;
- if (harmony.suspended_recording) {
- harmony.suspended_recording = 0;
- harmony_enable_interrupts();
- }
-
- interruptible_sleep_on(&harmony.wq_record);
- harmony.blocked_recording = 0;
- }
-
- if (harmony.nb_filled_record < 2)
- return -EBUSY;
-
- buf_to_read = harmony.first_filled_record;
-
- /* Copy the page to an aligned buffer */
- if (copy_to_user(buffer+count, recorded_buf.addr +
- (HARMONY_BUF_SIZE*buf_to_read),
- HARMONY_BUF_SIZE)) {
- count = -EFAULT;
- break;
- }
-
- harmony.nb_filled_record--;
- harmony.first_filled_record++;
- harmony.first_filled_record %= MAX_BUFS;
-
- count += HARMONY_BUF_SIZE;
- }
- return count;
-}
-
-
-
-
-/*
- * Here is the place where we try to recognize file format.
- * Sun/NeXT .au files begin with the string .snd
- * At offset 12 is specified the encoding.
- * At offset 16 is specified speed rate
- * At Offset 20 is specified the numbers of voices
- */
-
-#define four_bytes_to_u32(start) (file_header[start] << 24)|\
- (file_header[start+1] << 16)|\
- (file_header[start+2] << 8)|\
- (file_header[start+3]);
-
-#define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\
-
-
-static int harmony_format_auto_detect(const char *buffer, int block_size)
-{
- u8 file_header[24];
- u32 start_string;
- int ret = 0;
-
- if (block_size>24) {
- if (copy_from_user(file_header, buffer, sizeof(file_header)))
- ret = -EFAULT;
-
- start_string = four_bytes_to_u32(0);
-
- if ((file_header[4]==0) && (start_string==0x2E736E64)) {
- u32 format;
- u32 nb_voices;
- u32 speed;
-
- format = four_bytes_to_u32(12);
- nb_voices = four_bytes_to_u32(20);
- speed = four_bytes_to_u32(16);
-
- switch (format) {
- case HARMONY_MAGIC_8B_ULAW:
- harmony.data_format = HARMONY_DF_8BIT_ULAW;
- break;
- case HARMONY_MAGIC_8B_ALAW:
- harmony.data_format = HARMONY_DF_8BIT_ALAW;
- break;
- case HARMONY_MAGIC_16B_LINEAR:
- harmony.data_format = HARMONY_DF_16BIT_LINEAR;
- break;
- default:
- harmony_set_control(HARMONY_DF_16BIT_LINEAR,
- HARMONY_SR_44KHZ, HARMONY_SS_STEREO);
- goto out;
- }
- switch (nb_voices) {
- case HARMONY_MAGIC_MONO:
- harmony.stereo_select = HARMONY_SS_MONO;
- break;
- case HARMONY_MAGIC_STEREO:
- harmony.stereo_select = HARMONY_SS_STEREO;
- break;
- default:
- harmony.stereo_select = HARMONY_SS_MONO;
- break;
- }
- harmony_set_rate(harmony_detect_rate(&speed));
- harmony.dac_rate = speed;
- goto out;
- }
- }
- harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
-out:
- return ret;
-}
-#undef four_bytes_to_u32
-
-
-static ssize_t harmony_audio_write(struct file *file,
- const char *buffer,
- size_t size_count,
- loff_t *ppos)
-{
- int total_count = (int) size_count;
- int count = 0;
- int frame_size;
- int buf_to_fill;
- int fresh_buffer;
-
- if (!harmony.format_initialized) {
- if (harmony_format_auto_detect(buffer, total_count))
- return -EFAULT;
- }
-
- while (count<total_count) {
- /* Wait until we're out of control mode */
- harmony_wait_CNTL();
-
- /* Figure out which buffer to fill in */
- if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) {
- harmony.blocked_playing = 1;
- interruptible_sleep_on(&harmony.wq_play);
- harmony.blocked_playing = 0;
- }
- if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset)
- return -EBUSY;
-
-
- buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play);
- if (harmony.play_offset) {
- buf_to_fill--;
- buf_to_fill += MAX_BUFS;
- }
- buf_to_fill %= MAX_BUFS;
-
- fresh_buffer = (harmony.play_offset == 0);
-
- /* Figure out the size of the frame */
- if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) {
- frame_size = HARMONY_BUF_SIZE - harmony.play_offset;
- } else {
- frame_size = total_count - count;
- /* Clear out the buffer, since there we'll only be
- overlaying part of the old buffer with the new one */
- harmony_silence(&played_buf,
- HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset,
- HARMONY_BUF_SIZE-frame_size-harmony.play_offset);
- }
-
- /* Copy the page to an aligned buffer */
- if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset,
- buffer+count, frame_size))
- return -EFAULT;
- CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset),
- frame_size);
-
- if (fresh_buffer)
- harmony.nb_filled_play++;
-
- count += frame_size;
- harmony.play_offset += frame_size;
- harmony.play_offset %= HARMONY_BUF_SIZE;
- if (harmony.suspended_playing && (harmony.nb_filled_play>=4))
- harmony_enable_interrupts();
- }
-
- return count;
-}
-
-static unsigned int harmony_audio_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- unsigned int mask = 0;
-
- if (file->f_mode & FMODE_READ) {
- if (!harmony.suspended_recording)
- poll_wait(file, &harmony.wq_record, wait);
- if (harmony.nb_filled_record)
- mask |= POLLIN | POLLRDNORM;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- if (!harmony.suspended_playing)
- poll_wait(file, &harmony.wq_play, wait);
- if (harmony.nb_filled_play)
- mask |= POLLOUT | POLLWRNORM;
- }
-
- return mask;
-}
-
-static int harmony_audio_ioctl(struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- int ival, new_format;
- int frag_size, frag_buf;
- struct audio_buf_info info;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *) arg);
-
- case SNDCTL_DSP_GETCAPS:
- ival = DSP_CAP_DUPLEX;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETFMTS:
- ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW );
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- if (ival != AFMT_QUERY) {
- switch (ival) {
- case AFMT_MU_LAW: new_format = HARMONY_DF_8BIT_ULAW; break;
- case AFMT_A_LAW: new_format = HARMONY_DF_8BIT_ALAW; break;
- case AFMT_S16_BE: new_format = HARMONY_DF_16BIT_LINEAR; break;
- default: {
- DPRINTK(KERN_WARNING PFX
- "unsupported sound format 0x%04x requested.\n",
- ival);
- ival = AFMT_S16_BE;
- return put_user(ival, (int *) arg);
- }
- }
- harmony_set_format(new_format);
- return 0;
- } else {
- switch (harmony.data_format) {
- case HARMONY_DF_8BIT_ULAW: ival = AFMT_MU_LAW; break;
- case HARMONY_DF_8BIT_ALAW: ival = AFMT_A_LAW; break;
- case HARMONY_DF_16BIT_LINEAR: ival = AFMT_U16_BE; break;
- default: ival = 0;
- }
- return put_user(ival, (int *) arg);
- }
-
- case SOUND_PCM_READ_RATE:
- ival = harmony.dac_rate;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SPEED:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- harmony_set_rate(harmony_detect_rate(&ival));
- harmony.dac_rate = ival;
- return put_user(ival, (int*) arg);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- if (ival != 0 && ival != 1)
- return -EINVAL;
- harmony_set_stereo(ival);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- if (ival != 1 && ival != 2) {
- ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2;
- return put_user(ival, (int *) arg);
- }
- harmony_set_stereo(ival-1);
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- ival = HARMONY_BUF_SIZE;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_RESET:
- if (!harmony.suspended_recording) {
- /* TODO: stop_recording() */
- }
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(ival, (int *)arg))
- return -EFAULT;
- frag_size = ival & 0xffff;
- frag_buf = (ival>>16) & 0xffff;
- /* TODO: We use hardcoded fragment sizes and numbers for now */
- frag_size = 12; /* 4096 == 2^12 */
- frag_buf = MAX_BUFS;
- ival = (frag_buf << 16) + frag_size;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- info.fragstotal = MAX_BUFS;
- info.fragments = MAX_BUFS - harmony.nb_filled_play;
- info.fragsize = HARMONY_BUF_SIZE;
- info.bytes = info.fragments * info.fragsize;
- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- info.fragstotal = MAX_BUFS;
- info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record;
- info.fragsize = HARMONY_BUF_SIZE;
- info.bytes = info.fragments * info.fragsize;
- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_SYNC:
- return 0;
- }
-
- return -EINVAL;
-}
-
-
-/*
- * harmony_interrupt()
- *
- * harmony interruption service routine
- *
- */
-
-static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
-{
- u32 dstatus;
- struct harmony_hpa *hpa;
-
- /* Setup the hpa */
- hpa = ((struct harmony_dev *)dev)->hpa;
- harmony_wait_CNTL();
-
- /* Read dstatus and pcuradd (the current address) */
- dstatus = gsc_readl(&hpa->dstatus);
-
- /* Turn off interrupts */
- harmony_disable_interrupts();
-
- /* Check if this is a request to get the next play buffer */
- if (dstatus & DSTATUS_PN) {
- if (!harmony.nb_filled_play) {
- harmony.suspended_playing = 1;
- gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd);
-
- if (!harmony.suspended_recording)
- harmony_enable_interrupts();
- } else {
- harmony.suspended_playing = 0;
- gsc_writel((unsigned long)played_buf.dma_handle +
- (HARMONY_BUF_SIZE*harmony.first_filled_play),
- &hpa->pnxtadd);
- harmony.first_filled_play++;
- harmony.first_filled_play %= MAX_BUFS;
- harmony.nb_filled_play--;
-
- harmony_enable_interrupts();
- }
-
- if (harmony.blocked_playing)
- wake_up_interruptible(&harmony.wq_play);
- }
-
- /* Check if we're being asked to fill in a recording buffer */
- if (dstatus & DSTATUS_RN) {
- if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)
- {
- harmony.nb_filled_record = 0;
- harmony.first_filled_record = 0;
- harmony.suspended_recording = 1;
- gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd);
- if (!harmony.suspended_playing)
- harmony_enable_interrupts();
- } else {
- int buf_to_fill;
- buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS;
- CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE);
- gsc_writel((unsigned long)recorded_buf.dma_handle +
- HARMONY_BUF_SIZE*buf_to_fill,
- &hpa->rnxtadd);
- harmony.nb_filled_record++;
- harmony_enable_interrupts();
- }
-
- if (harmony.blocked_recording && harmony.nb_filled_record>3)
- wake_up_interruptible(&harmony.wq_record);
- }
- return IRQ_HANDLED;
-}
-
-/*
- * Sound playing functions
- */
-
-static struct file_operations harmony_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = harmony_audio_read,
- .write = harmony_audio_write,
- .poll = harmony_audio_poll,
- .ioctl = harmony_audio_ioctl,
- .open = harmony_audio_open,
- .release = harmony_audio_release,
-};
-
-static int harmony_audio_init(void)
-{
- /* Request that IRQ */
- if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) {
- printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq);
- return -EFAULT;
- }
-
- harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1);
- if (harmony.dsp_unit < 0) {
- printk(KERN_ERR PFX "Error registering dsp\n");
- free_irq(harmony.dev->irq, &harmony);
- return -EFAULT;
- }
-
- /* Clear the buffers so you don't end up with crap in the buffers. */
- harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
- /* Make sure this makes it to cache */
- CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
- /* Clear out the silent buffer and flush to cache */
- harmony_silence(&silent, 0, HARMONY_BUF_SIZE);
- CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE);
-
- harmony.audio_open = 0;
-
- return 0;
-}
-
-
-/*
- * mixer functions
- */
-
-static void harmony_mixer_set_gain(void)
-{
- harmony_wait_CNTL();
- gsc_writel(harmony.current_gain, &harmony.hpa->gainctl);
-}
-
-/*
- * Read gain of selected channel.
- * The OSS rate is from 0 (silent) to 100 -> need some conversions
- *
- * The harmony gain are attenuation for output and monitor gain.
- * is amplifaction for input gain
- */
-#define to_harmony_level(level,max) ((level)*max/100)
-#define to_oss_level(level,max) ((level)*100/max)
-
-static int harmony_mixer_get_level(int channel)
-{
- int left_level;
- int right_level;
-
- switch (channel) {
- case SOUND_MIXER_VOLUME:
- left_level = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT;
- right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT;
- left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
- right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
- return (right_level << 8)+left_level;
-
- case SOUND_MIXER_IGAIN:
- left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT;
- right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT;
- left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
- right_level= to_oss_level(right_level, MAX_INPUT_LEVEL);
- return (right_level << 8)+left_level;
-
- case SOUND_MIXER_MONITOR:
- left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT;
- left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
- return (left_level << 8)+left_level;
- }
- return -EINVAL;
-}
-
-
-
-/*
- * Some conversions for the same reasons.
- * We give back the new real value(s) due to
- * the rescale.
- */
-
-static int harmony_mixer_set_level(int channel, int value)
-{
- int left_level;
- int right_level;
- int new_left_level;
- int new_right_level;
-
- right_level = (value & 0x0000ff00) >> 8;
- left_level = value & 0x000000ff;
- if (right_level > 100) right_level = 100;
- if (left_level > 100) left_level = 100;
-
- switch (channel) {
- case SOUND_MIXER_VOLUME:
- right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL);
- left_level = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL);
- new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
- new_left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
- harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK))
- | (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT);
- harmony_mixer_set_gain();
- return (new_right_level << 8) + new_left_level;
-
- case SOUND_MIXER_IGAIN:
- right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL);
- left_level = to_harmony_level(left_level, MAX_INPUT_LEVEL);
- new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL);
- new_left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
- harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK))
- | (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT);
- harmony_mixer_set_gain();
- return (new_right_level << 8) + new_left_level;
-
- case SOUND_MIXER_MONITOR:
- left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL);
- new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
- harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT);
- harmony_mixer_set_gain();
- return (new_left_level << 8) + new_left_level;
- }
-
- return -EINVAL;
-}
-
-#undef to_harmony_level
-#undef to_oss_level
-
-/*
- * Return the selected input device (mic or line)
- */
-
-static int harmony_mixer_get_recmask(void)
-{
- int current_input_line;
-
- current_input_line = (harmony.current_gain & GAIN_IS_MASK)
- >> GAIN_IS_SHIFT;
- if (current_input_line)
- return SOUND_MASK_MIC;
-
- return SOUND_MASK_LINE;
-}
-
-/*
- * Set the input (only one at time, arbitrary priority to line in)
- */
-
-static int harmony_mixer_set_recmask(int recmask)
-{
- int new_input_line;
- int new_input_mask;
- int current_input_line;
-
- current_input_line = (harmony.current_gain & GAIN_IS_MASK)
- >> GAIN_IS_SHIFT;
- if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) ||
- (!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) {
- new_input_line = 0;
- new_input_mask = SOUND_MASK_LINE;
- } else {
- new_input_line = 1;
- new_input_mask = SOUND_MASK_MIC;
- }
- harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) |
- (new_input_line << GAIN_IS_SHIFT ));
- harmony_mixer_set_gain();
- return new_input_mask;
-}
-
-
-/*
- * give the active outlines
- */
-
-static int harmony_mixer_get_outmask(void)
-{
- int outmask = 0;
-
- if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL;
- if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT;
- if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES;
-
- return outmask;
-}
-
-
-static int harmony_mixer_set_outmask(int outmask)
-{
- if (outmask & MASK_INTERNAL)
- harmony.current_gain |= GAIN_SE_MASK;
- else
- harmony.current_gain &= ~GAIN_SE_MASK;
-
- if (outmask & MASK_LINEOUT)
- harmony.current_gain |= GAIN_LE_MASK;
- else
- harmony.current_gain &= ~GAIN_LE_MASK;
-
- if (outmask & MASK_HEADPHONES)
- harmony.current_gain |= GAIN_HE_MASK;
- else
- harmony.current_gain &= ~GAIN_HE_MASK;
-
- harmony_mixer_set_gain();
-
- return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES));
-}
-
-/*
- * This code is inspired from sb_mixer.c
- */
-
-static int harmony_mixer_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- int val;
- int ret;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strncpy(info.id, "harmony", sizeof(info.id)-1);
- strncpy(info.name, "Harmony audio", sizeof(info.name)-1);
- info.modify_counter = 1; /* ? */
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
-
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
-
- /* read */
- val = 0;
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- if (get_user(val, (int *)arg))
- return -EFAULT;
-
- switch (cmd) {
- case MIXER_READ(SOUND_MIXER_CAPS):
- ret = SOUND_CAP_EXCL_INPUT;
- break;
- case MIXER_READ(SOUND_MIXER_STEREODEVS):
- ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
- break;
-
- case MIXER_READ(SOUND_MIXER_RECMASK):
- ret = SOUND_MASK_MIC | SOUND_MASK_LINE;
- break;
- case MIXER_READ(SOUND_MIXER_DEVMASK):
- ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN |
- SOUND_MASK_MONITOR;
- break;
- case MIXER_READ(SOUND_MIXER_OUTMASK):
- ret = MASK_INTERNAL | MASK_LINEOUT |
- MASK_HEADPHONES;
- break;
-
- case MIXER_WRITE(SOUND_MIXER_RECSRC):
- ret = harmony_mixer_set_recmask(val);
- break;
- case MIXER_READ(SOUND_MIXER_RECSRC):
- ret = harmony_mixer_get_recmask();
- break;
-
- case MIXER_WRITE(SOUND_MIXER_OUTSRC):
- ret = harmony_mixer_set_outmask(val);
- break;
- case MIXER_READ(SOUND_MIXER_OUTSRC):
- ret = harmony_mixer_get_outmask();
- break;
-
- case MIXER_WRITE(SOUND_MIXER_VOLUME):
- case MIXER_WRITE(SOUND_MIXER_IGAIN):
- case MIXER_WRITE(SOUND_MIXER_MONITOR):
- ret = harmony_mixer_set_level(cmd & 0xff, val);
- break;
-
- case MIXER_READ(SOUND_MIXER_VOLUME):
- case MIXER_READ(SOUND_MIXER_IGAIN):
- case MIXER_READ(SOUND_MIXER_MONITOR):
- ret = harmony_mixer_get_level(cmd & 0xff);
- break;
-
- default:
- return -EINVAL;
- }
-
- if (put_user(ret, (int *)arg))
- return -EFAULT;
- return 0;
-}
-
-
-static int harmony_mixer_open(struct inode *inode, struct file *file)
-{
- if (harmony.mixer_open)
- return -EBUSY;
- harmony.mixer_open = 1;
- return 0;
-}
-
-static int harmony_mixer_release(struct inode *inode, struct file *file)
-{
- if (!harmony.mixer_open)
- return -EBUSY;
- harmony.mixer_open = 0;
- return 0;
-}
-
-static struct file_operations harmony_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = harmony_mixer_open,
- .release = harmony_mixer_release,
- .ioctl = harmony_mixer_ioctl,
-};
-
-
-/*
- * Mute all the output and reset Harmony.
- */
-
-static void __init harmony_mixer_reset(void)
-{
- harmony.current_gain = GAIN_TOTAL_SILENCE;
- harmony_mixer_set_gain();
- harmony_wait_CNTL();
- gsc_writel(1, &harmony.hpa->reset);
- mdelay(50); /* wait 50 ms */
- gsc_writel(0, &harmony.hpa->reset);
- harmony.current_gain = GAIN_DEFAULT;
- harmony_mixer_set_gain();
-}
-
-static int __init harmony_mixer_init(void)
-{
- /* Register the device file operations */
- harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1);
- if (harmony.mixer_unit < 0) {
- printk(KERN_WARNING PFX "Error Registering Mixer Driver\n");
- return -EFAULT;
- }
-
- harmony_mixer_reset();
- harmony.mixer_open = 0;
-
- return 0;
-}
-
-
-
-/*
- * This is the callback that's called by the inventory hardware code
- * if it finds a match to the registered driver.
- */
-static int __devinit
-harmony_driver_probe(struct parisc_device *dev)
-{
- u8 id;
- u8 rev;
- u32 cntl;
- int ret;
-
- if (harmony.hpa) {
- /* We only support one Harmony at this time */
- printk(KERN_ERR PFX "driver already registered\n");
- return -EBUSY;
- }
-
- if (!dev->irq) {
- printk(KERN_ERR PFX "no irq found\n");
- return -ENODEV;
- }
-
- /* Set the HPA of harmony */
- harmony.hpa = (struct harmony_hpa *)dev->hpa.start;
- harmony.dev = dev;
-
- /* Grab the ID and revision from the device */
- id = gsc_readb(&harmony.hpa->id);
- if ((id | 1) != 0x15) {
- printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id);
- return -EBUSY;
- }
- cntl = gsc_readl(&harmony.hpa->cntl);
- rev = (cntl>>20) & 0xff;
-
- printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", "
- "h/w id %i, rev. %i at 0x%lx, IRQ %i\n",
- id, rev, dev->hpa.start, harmony.dev->irq);
-
- /* Make sure the control bit isn't set, although I don't think it
- ever is. */
- if (cntl & CNTL_C) {
- printk(KERN_WARNING PFX "CNTL busy\n");
- harmony.hpa = 0;
- return -EBUSY;
- }
-
- /* Initialize the memory buffers */
- if (harmony_alloc_buffer(&played_buf, MAX_BUFS) ||
- harmony_alloc_buffer(&recorded_buf, MAX_BUFS) ||
- harmony_alloc_buffer(&graveyard, 1) ||
- harmony_alloc_buffer(&silent, 1)) {
- ret = -EBUSY;
- goto out_err;
- }
-
- /* Initialize /dev/mixer and /dev/audio */
- if ((ret=harmony_mixer_init()))
- goto out_err;
- if ((ret=harmony_audio_init()))
- goto out_err;
-
- return 0;
-
-out_err:
- harmony.hpa = 0;
- harmony_free_buffer(&played_buf);
- harmony_free_buffer(&recorded_buf);
- harmony_free_buffer(&graveyard);
- harmony_free_buffer(&silent);
- return ret;
-}
-
-
-static struct parisc_device_id harmony_tbl[] = {
- /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(parisc, harmony_tbl);
-
-static struct parisc_driver harmony_driver = {
- .name = "Lasi Harmony",
- .id_table = harmony_tbl,
- .probe = harmony_driver_probe,
-};
-
-static int __init init_harmony(void)
-{
- return register_parisc_driver(&harmony_driver);
-}
-
-static void __exit cleanup_harmony(void)
-{
- free_irq(harmony.dev->irq, &harmony);
- unregister_sound_mixer(harmony.mixer_unit);
- unregister_sound_dsp(harmony.dsp_unit);
- harmony_free_buffer(&played_buf);
- harmony_free_buffer(&recorded_buf);
- harmony_free_buffer(&graveyard);
- harmony_free_buffer(&silent);
- unregister_parisc_driver(&harmony_driver);
-}
-
-
-MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>");
-MODULE_DESCRIPTION("Harmony sound driver");
-MODULE_LICENSE("GPL");
-
-module_init(init_harmony);
-module_exit(cleanup_harmony);
-
diff --git a/sound/oss/ics2101.c b/sound/oss/ics2101.c
deleted file mode 100644
index 45918df..0000000
--- a/sound/oss/ics2101.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * sound/oss/ics2101.c
- *
- * Driver for the ICS2101 mixer of GUS v3.7.
- *
- *
- * 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)
- * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
- */
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include <linux/ultrasound.h>
-
-#include "gus.h"
-#include "gus_hw.h"
-
-#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
- SOUND_MASK_SYNTH| \
- SOUND_MASK_CD | SOUND_MASK_VOLUME)
-
-extern int *gus_osp;
-extern int gus_base;
-extern spinlock_t gus_lock;
-static int volumes[ICS_MIXDEVS];
-static int left_fix[ICS_MIXDEVS] =
-{1, 1, 1, 2, 1, 2};
-static int right_fix[ICS_MIXDEVS] =
-{2, 2, 2, 1, 2, 1};
-
-static int scale_vol(int vol)
-{
- /*
- * Experimental volume scaling by Risto Kankkunen.
- * This should give smoother volume response than just
- * a plain multiplication.
- */
-
- int e;
-
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- vol = (31 * vol + 50) / 100;
- e = 0;
- if (vol)
- {
- while (vol < 16)
- {
- vol <<= 1;
- e--;
- }
- vol -= 16;
- e += 7;
- }
- return ((e << 4) + vol);
-}
-
-static void write_mix(int dev, int chn, int vol)
-{
- int *selector;
- unsigned long flags;
- int ctrl_addr = dev << 3;
- int attn_addr = dev << 3;
-
- vol = scale_vol(vol);
-
- if (chn == CHN_LEFT)
- {
- selector = left_fix;
- ctrl_addr |= 0x00;
- attn_addr |= 0x02;
- }
- else
- {
- selector = right_fix;
- ctrl_addr |= 0x01;
- attn_addr |= 0x03;
- }
-
- spin_lock_irqsave(&gus_lock, flags);
- outb((ctrl_addr), u_MixSelect);
- outb((selector[dev]), u_MixData);
- outb((attn_addr), u_MixSelect);
- outb(((unsigned char) vol), u_MixData);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int set_volumes(int dev, int vol)
-{
- int left = vol & 0x00ff;
- int right = (vol >> 8) & 0x00ff;
-
- if (left < 0)
- left = 0;
- if (left > 100)
- left = 100;
- if (right < 0)
- right = 0;
- if (right > 100)
- right = 100;
-
- write_mix(dev, CHN_LEFT, left);
- write_mix(dev, CHN_RIGHT, right);
-
- vol = left + (right << 8);
- volumes[dev] = vol;
- return vol;
-}
-
-static int ics2101_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int val;
-
- if (((cmd >> 8) & 0xff) == 'M') {
- if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
-
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- switch (cmd & 0xff) {
- case SOUND_MIXER_RECSRC:
- return gus_default_mixer_ioctl(dev, cmd, arg);
-
- case SOUND_MIXER_MIC:
- val = set_volumes(DEV_MIC, val);
- break;
-
- case SOUND_MIXER_CD:
- val = set_volumes(DEV_CD, val);
- break;
-
- case SOUND_MIXER_LINE:
- val = set_volumes(DEV_LINE, val);
- break;
-
- case SOUND_MIXER_SYNTH:
- val = set_volumes(DEV_GF1, val);
- break;
-
- case SOUND_MIXER_VOLUME:
- val = set_volumes(DEV_VOL, val);
- break;
-
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *)arg);
- } else {
- switch (cmd & 0xff) {
- /*
- * Return parameters
- */
- case SOUND_MIXER_RECSRC:
- return gus_default_mixer_ioctl(dev, cmd, arg);
-
- case SOUND_MIXER_DEVMASK:
- val = MIX_DEVS;
- break;
-
- case SOUND_MIXER_STEREODEVS:
- val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC;
- break;
-
- case SOUND_MIXER_RECMASK:
- val = SOUND_MASK_MIC | SOUND_MASK_LINE;
- break;
-
- case SOUND_MIXER_CAPS:
- val = 0;
- break;
-
- case SOUND_MIXER_MIC:
- val = volumes[DEV_MIC];
- break;
-
- case SOUND_MIXER_LINE:
- val = volumes[DEV_LINE];
- break;
-
- case SOUND_MIXER_CD:
- val = volumes[DEV_CD];
- break;
-
- case SOUND_MIXER_VOLUME:
- val = volumes[DEV_VOL];
- break;
-
- case SOUND_MIXER_SYNTH:
- val = volumes[DEV_GF1];
- break;
-
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *)arg);
- }
- }
- return -EINVAL;
-}
-
-static struct mixer_operations ics2101_mixer_operations =
-{
- .owner = THIS_MODULE,
- .id = "ICS2101",
- .name = "ICS2101 Multimedia Mixer",
- .ioctl = ics2101_mixer_ioctl
-};
-
-int __init ics2101_mixer_init(void)
-{
- int i;
- int n;
-
- if ((n = sound_alloc_mixerdev()) != -1)
- {
- mixer_devs[n] = &ics2101_mixer_operations;
-
- /*
- * Some GUS v3.7 cards had some channels flipped. Disable
- * the flipping feature if the model id is other than 5.
- */
-
- if (inb(u_MixSelect) != 5)
- {
- for (i = 0; i < ICS_MIXDEVS; i++)
- left_fix[i] = 1;
- for (i = 0; i < ICS_MIXDEVS; i++)
- right_fix[i] = 2;
- }
- set_volumes(DEV_GF1, 0x5a5a);
- set_volumes(DEV_CD, 0x5a5a);
- set_volumes(DEV_MIC, 0x0000);
- set_volumes(DEV_LINE, 0x5a5a);
- set_volumes(DEV_VOL, 0x5a5a);
- set_volumes(DEV_UNUSED, 0x0000);
- }
- return n;
-}
diff --git a/sound/oss/iwmem.h b/sound/oss/iwmem.h
deleted file mode 100644
index 48d333c..0000000
--- a/sound/oss/iwmem.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * sound/oss/iwmem.h
- *
- * DRAM size encoding table for AMD Interwave chip.
- */
-/*
- * 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.
- *
- * Changes:
- * Bartlomiej Zolnierkiewicz : added __initdata to mem_decode
- */
-
-
-#define K 1024
-#define M (1024*K)
-static int mem_decode[][4] __initdata =
-{
-/* Bank0 Bank1 Bank2 Bank3 Encoding bits */
- {256*K, 0, 0, 0}, /* 0 */
- {256*K, 256*K, 0, 0}, /* 1 */
- {256*K, 256*K, 256*K, 256*K}, /* 2 */
- {256*K, 1*M, 0, 0}, /* 3 */
- {256*K, 1*M, 1*M, 1*M}, /* 4 */
- {256*K, 256*K, 1*M, 0}, /* 5 */
- {256*K, 256*K, 1*M, 1*M}, /* 6 */
- {1*M, 0, 0, 0}, /* 7 */
- {1*M, 1*M, 0, 0}, /* 8 */
- {1*M, 1*M, 1*M, 1*M}, /* 9 */
- {4*M, 0, 0, 0}, /* 10 */
- {4*M, 4*M, 0, 0}, /* 11 */
- {4*M, 4*M, 4*M, 4*M} /* 12 */
-};
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
deleted file mode 100644
index aa3c50d..0000000
--- a/sound/oss/mad16.c
+++ /dev/null
@@ -1,1113 +0,0 @@
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * mad16.c
- *
- * Initialization code for OPTi MAD16 compatible audio chips. Including
- *
- * OPTi 82C928 MAD16 (replaced by C929)
- * OAK OTI-601D Mozart
- * OAK OTI-605 Mozart (later version with MPU401 Midi)
- * OPTi 82C929 MAD16 Pro
- * OPTi 82C930
- * OPTi 82C924
- *
- * These audio interface chips don't produce sound themselves. They just
- * connect some other components (OPL-[234] and a WSS compatible codec)
- * to the PC bus and perform I/O, DMA and IRQ address decoding. There is
- * also a UART for the MPU-401 mode (not 82C928/Mozart).
- * The Mozart chip appears to be compatible with the 82C928, although later
- * issues of the card, using the OTI-605 chip, have an MPU-401 compatible Midi
- * port. This port is configured differently to that of the OPTi audio chips.
- *
- * Changes
- *
- * Alan Cox Clean up, added module selections.
- *
- * A. Wik Added support for Opti924 PnP.
- * Improved debugging support. 16-May-1998
- * Fixed bug. 16-Jun-1998
- *
- * Torsten Duwe Made Opti924 PnP support non-destructive
- * 23-Dec-1998
- *
- * Paul Grayson Added support for Midi on later Mozart cards.
- * 25-Nov-1999
- * Christoph Hellwig Adapted to module_init/module_exit.
- * Arnaldo C. de Melo got rid of attach_uart401 21-Sep-2000
- *
- * Pavel Rabel Clean up Nov-2000
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gameport.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "sb.h"
-#include "mpu401.h"
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-static int mad16_conf;
-static int mad16_cdsel;
-static DEFINE_SPINLOCK(lock);
-
-#define C928 1
-#define MOZART 2
-#define C929 3
-#define C930 4
-#define C924 5
-
-/*
- * Registers
- *
- * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations).
- * All ports are inactive by default. They can be activated by
- * writing 0xE2 or 0xE3 to the password register. The password is valid
- * only until the next I/O read or write.
- *
- * 82C930 uses 0xE4 as the password and indirect addressing to access
- * the config registers.
- */
-
-#define MC0_PORT 0xf8c /* Dummy port */
-#define MC1_PORT 0xf8d /* SB address, CD-ROM interface type, joystick */
-#define MC2_PORT 0xf8e /* CD-ROM address, IRQ, DMA, plus OPL4 bit */
-#define MC3_PORT 0xf8f
-#define PASSWD_REG 0xf8f
-#define MC4_PORT 0xf90
-#define MC5_PORT 0xf91
-#define MC6_PORT 0xf92
-#define MC7_PORT 0xf93
-#define MC8_PORT 0xf94
-#define MC9_PORT 0xf95
-#define MC10_PORT 0xf96
-#define MC11_PORT 0xf97
-#define MC12_PORT 0xf98
-
-static int board_type = C928;
-
-static int *mad16_osp;
-static int c931_detected; /* minor differences from C930 */
-static char c924pnp; /* " " " C924 */
-static int debug; /* debugging output */
-
-#ifdef DDB
-#undef DDB
-#endif
-#define DDB(x) do {if (debug) x;} while (0)
-
-static unsigned char mad_read(int port)
-{
- unsigned long flags;
- unsigned char tmp;
-
- spin_lock_irqsave(&lock,flags);
-
- switch (board_type) /* Output password */
- {
- case C928:
- case MOZART:
- outb((0xE2), PASSWD_REG);
- break;
-
- case C929:
- outb((0xE3), PASSWD_REG);
- break;
-
- case C930:
- /* outb(( 0xE4), PASSWD_REG); */
- break;
-
- case C924:
- /* the c924 has its ports relocated by -128 if
- PnP is enabled -aw */
- if (!c924pnp)
- outb((0xE5), PASSWD_REG); else
- outb((0xE5), PASSWD_REG - 0x80);
- break;
- }
-
- if (board_type == C930)
- {
- outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
- tmp = inb(0xe0f); /* Read from data reg */
- }
- else
- if (!c924pnp)
- tmp = inb(port); else
- tmp = inb(port-0x80);
- spin_unlock_irqrestore(&lock,flags);
-
- return tmp;
-}
-
-static void mad_write(int port, int value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
-
- switch (board_type) /* Output password */
- {
- case C928:
- case MOZART:
- outb((0xE2), PASSWD_REG);
- break;
-
- case C929:
- outb((0xE3), PASSWD_REG);
- break;
-
- case C930:
- /* outb(( 0xE4), PASSWD_REG); */
- break;
-
- case C924:
- if (!c924pnp)
- outb((0xE5), PASSWD_REG); else
- outb((0xE5), PASSWD_REG - 0x80);
- break;
- }
-
- if (board_type == C930)
- {
- outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
- outb(((unsigned char) (value & 0xff)), 0xe0f);
- }
- else
- if (!c924pnp)
- outb(((unsigned char) (value & 0xff)), port); else
- outb(((unsigned char) (value & 0xff)), port-0x80);
- spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init detect_c930(void)
-{
- unsigned char tmp = mad_read(MC1_PORT);
-
- if ((tmp & 0x06) != 0x06)
- {
- DDB(printk("Wrong C930 signature (%x)\n", tmp));
- /* return 0; */
- }
- mad_write(MC1_PORT, 0);
-
- if (mad_read(MC1_PORT) != 0x06)
- {
- DDB(printk("Wrong C930 signature2 (%x)\n", tmp));
- /* return 0; */
- }
- mad_write(MC1_PORT, tmp); /* Restore bits */
-
- mad_write(MC7_PORT, 0);
- if ((tmp = mad_read(MC7_PORT)) != 0)
- {
- DDB(printk("MC7 not writable (%x)\n", tmp));
- return 0;
- }
- mad_write(MC7_PORT, 0xcb);
- if ((tmp = mad_read(MC7_PORT)) != 0xcb)
- {
- DDB(printk("MC7 not writable2 (%x)\n", tmp));
- return 0;
- }
-
- tmp = mad_read(MC0_PORT+18);
- if (tmp == 0xff || tmp == 0x00)
- return 1;
- /* We probably have a C931 */
- DDB(printk("Detected C931 config=0x%02x\n", tmp));
- c931_detected = 1;
-
- /*
- * We cannot configure the chip if it is in PnP mode.
- * If we have a CSN assigned (bit 8 in MC13) we first try
- * a software reset, then a software power off, finally
- * Clearing PnP mode. The last option is not
- * Bit 8 in MC13
- */
- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
- return 1;
-
- /* Software reset */
- mad_write(MC9_PORT, 0x02);
- mad_write(MC9_PORT, 0x00);
-
- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
- return 1;
-
- /* Power off, and on again */
- mad_write(MC9_PORT, 0xc2);
- mad_write(MC9_PORT, 0xc0);
-
- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
- return 1;
-
-#if 0
- /* Force off PnP mode. This is not recommended because
- * the PnP bios will not recognize the chip on the next
- * warm boot and may assignd different resources to other
- * PnP/PCI cards.
- */
- mad_write(MC0_PORT+17, 0x04);
-#endif
- return 1;
-}
-
-static int __init detect_mad16(void)
-{
- unsigned char tmp, tmp2, bit;
- int i, port;
-
- /*
- * Check that reading a register doesn't return bus float (0xff)
- * when the card is accessed using password. This may fail in case
- * the card is in low power mode. Normally at least the power saving
- * mode bit should be 0.
- */
-
- if ((tmp = mad_read(MC1_PORT)) == 0xff)
- {
- DDB(printk("MC1_PORT returned 0xff\n"));
- return 0;
- }
- for (i = 0xf8d; i <= 0xf98; i++)
- if (!c924pnp)
- DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i)));
- else
- DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i)));
-
- if (board_type == C930)
- return detect_c930();
-
- /*
- * Now check that the gate is closed on first I/O after writing
- * the password. (This is how a MAD16 compatible card works).
- */
-
- if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */
- {
- DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
- return 0;
- }
-
- bit = (c924pnp) ? 0x20 : 0x80;
- port = (c924pnp) ? MC2_PORT : MC1_PORT;
-
- tmp = mad_read(port);
- mad_write(port, tmp ^ bit); /* Toggle a bit */
- if ((tmp2 = mad_read(port)) != (tmp ^ bit)) /* Compare the bit */
- {
- mad_write(port, tmp); /* Restore */
- DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
- return 0;
- }
- mad_write(port, tmp); /* Restore */
- return 1; /* Bingo */
-}
-
-static int __init wss_init(struct address_info *hw_config)
-{
- /*
- * Check if the IO port returns valid signature. The original MS Sound
- * system returns 0x04 while some cards (AudioTrix Pro for example)
- * return 0x00.
- */
-
- if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
- (inb(hw_config->io_base + 3) & 0x3f) != 0x00)
- {
- DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));
- return 0;
- }
- /*
- * Check that DMA0 is not in use with a 8 bit board.
- */
- if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)
- {
- printk("MSS: Can't use DMA0 with a 8 bit card/slot\n");
- return 0;
- }
- if (hw_config->irq > 9 && inb(hw_config->io_base + 3) & 0x80)
- printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
- return 1;
-}
-
-static void __init init_c930(struct address_info *hw_config, int base)
-{
- unsigned char cfg = 0;
-
- cfg |= (0x0f & mad16_conf);
-
- if(c931_detected)
- {
- /* Bit 0 has reversd meaning. Bits 1 and 2 sese
- reversed on write.
- Support only IDE cdrom. IDE port programmed
- somewhere else. */
- cfg = (cfg & 0x09) ^ 0x07;
- }
- cfg |= base << 4;
- mad_write(MC1_PORT, cfg);
-
- /* MC2 is CD configuration. Don't touch it. */
-
- mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */
-
- /* bit 2 of MC4 reverses it's meaning between the C930
- and the C931. */
- cfg = c931_detected ? 0x04 : 0x00;
-
- if(mad16_cdsel & 0x20)
- mad_write(MC4_PORT, 0x62|cfg); /* opl4 */
- else
- mad_write(MC4_PORT, 0x52|cfg); /* opl3 */
-
- mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */
- mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */
- mad_write(MC7_PORT, 0xCB);
- mad_write(MC10_PORT, 0x11);
-}
-
-static int __init chip_detect(void)
-{
- int i;
-
- /*
- * Then try to detect with the old password
- */
- board_type = C924;
-
- DDB(printk("Detect using password = 0xE5\n"));
-
- if (detect_mad16()) {
- return 1;
- }
-
- board_type = C928;
-
- DDB(printk("Detect using password = 0xE2\n"));
-
- if (detect_mad16())
- {
- unsigned char model;
-
- if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
- DDB(printk("mad16.c: Mozart detected\n"));
- board_type = MOZART;
- } else {
- DDB(printk("mad16.c: 82C928 detected???\n"));
- board_type = C928;
- }
- return 1;
- }
-
- board_type = C929;
-
- DDB(printk("Detect using password = 0xE3\n"));
-
- if (detect_mad16())
- {
- DDB(printk("mad16.c: 82C929 detected\n"));
- return 1;
- }
-
- if (inb(PASSWD_REG) != 0xff)
- return 0;
-
- /*
- * First relocate MC# registers to 0xe0e/0xe0f, disable password
- */
-
- outb((0xE4), PASSWD_REG);
- outb((0x80), PASSWD_REG);
-
- board_type = C930;
-
- DDB(printk("Detect using password = 0xE4\n"));
-
- for (i = 0xf8d; i <= 0xf93; i++)
- DDB(printk("port %03x = %02x\n", i, mad_read(i)));
-
- if(detect_mad16()) {
- DDB(printk("mad16.c: 82C930 detected\n"));
- return 1;
- }
-
- /* The C931 has the password reg at F8D */
- outb((0xE4), 0xF8D);
- outb((0x80), 0xF8D);
- DDB(printk("Detect using password = 0xE4 for C931\n"));
-
- if (detect_mad16()) {
- return 1;
- }
-
- board_type = C924;
- c924pnp++;
- DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
- if (detect_mad16()) {
- DDB(printk("mad16.c: 82C924 PnP detected\n"));
- return 1;
- }
-
- c924pnp=0;
-
- return 0;
-}
-
-static int __init probe_mad16(struct address_info *hw_config)
-{
- int i;
- unsigned char tmp;
- unsigned char cs4231_mode = 0;
-
- int ad_flags = 0;
-
- signed char bits;
-
- static char dma_bits[4] = {
- 1, 2, 0, 3
- };
-
- int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
- int dma = hw_config->dma, dma2 = hw_config->dma2;
- unsigned char dma2_bit = 0;
- int base;
- struct resource *ports;
-
- mad16_osp = hw_config->osp;
-
- switch (hw_config->io_base) {
- case 0x530:
- base = 0;
- break;
- case 0xe80:
- base = 1;
- break;
- case 0xf40:
- base = 2;
- break;
- case 0x604:
- base = 3;
- break;
- default:
- printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
- return 0;
- }
-
- if (dma != 0 && dma != 1 && dma != 3) {
- printk(KERN_ERR "MSS: Bad DMA %d\n", dma);
- return 0;
- }
-
- /*
- * Check that all ports return 0xff (bus float) when no password
- * is written to the password register.
- */
-
- DDB(printk("--- Detecting MAD16 / Mozart ---\n"));
- if (!chip_detect())
- return 0;
-
- switch (hw_config->irq) {
- case 7:
- bits = 8;
- break;
- case 9:
- bits = 0x10;
- break;
- case 10:
- bits = 0x18;
- break;
- case 12:
- bits = 0x20;
- break;
- case 5: /* Also IRQ5 is possible on C930 */
- if (board_type == C930 || c924pnp) {
- bits = 0x28;
- break;
- }
- default:
- printk(KERN_ERR "MAD16/Mozart: Bad IRQ %d\n", hw_config->irq);
- return 0;
- }
-
- ports = request_region(hw_config->io_base + 4, 4, "ad1848");
- if (!ports) {
- printk(KERN_ERR "MSS: I/O port conflict\n");
- return 0;
- }
- if (!request_region(hw_config->io_base, 4, "mad16 WSS config")) {
- release_region(hw_config->io_base + 4, 4);
- printk(KERN_ERR "MSS: I/O port conflict\n");
- return 0;
- }
-
- if (board_type == C930) {
- init_c930(hw_config, base);
- goto got_it;
- }
-
- for (i = 0xf8d; i <= 0xf93; i++) {
- if (!c924pnp)
- DDB(printk("port %03x = %02x\n", i, mad_read(i)));
- else
- DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i)));
- }
-
-/*
- * Set the WSS address
- */
-
- tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */
- tmp |= base << 4; /* WSS port select bits */
-
- /*
- * Set optional CD-ROM and joystick settings.
- */
-
- tmp &= ~0x0f;
- tmp |= (mad16_conf & 0x0f); /* CD-ROM and joystick bits */
- mad_write(MC1_PORT, tmp);
-
- tmp = mad16_cdsel;
- mad_write(MC2_PORT, tmp);
- mad_write(MC3_PORT, 0xf0); /* Disable SB */
-
- if (board_type == C924) /* Specific C924 init values */
- {
- mad_write(MC4_PORT, 0xA0);
- mad_write(MC5_PORT, 0x05);
- mad_write(MC6_PORT, 0x03);
- }
- if (!ad1848_detect(ports, &ad_flags, mad16_osp))
- goto fail;
-
- if (ad_flags & (AD_F_CS4231 | AD_F_CS4248))
- cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */
-
- if (board_type == C929)
- {
- mad_write(MC4_PORT, 0xa2);
- mad_write(MC5_PORT, 0xA5 | cs4231_mode);
- mad_write(MC6_PORT, 0x03); /* Disable MPU401 */
- }
- else
- {
- mad_write(MC4_PORT, 0x02);
- mad_write(MC5_PORT, 0x30 | cs4231_mode);
- }
-
- for (i = 0xf8d; i <= 0xf93; i++) {
- if (!c924pnp)
- DDB(printk("port %03x after init = %02x\n", i, mad_read(i)));
- else
- DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i)));
- }
-
-got_it:
- ad_flags = 0;
- if (!ad1848_detect(ports, &ad_flags, mad16_osp))
- goto fail;
-
- if (!wss_init(hw_config))
- goto fail;
-
- /*
- * Set the IRQ and DMA addresses.
- */
-
- outb((bits | 0x40), config_port);
- if ((inb(version_port) & 0x40) == 0)
- printk(KERN_ERR "[IRQ Conflict?]\n");
-
- /*
- * Handle the capture DMA channel
- */
-
- if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
- {
- if (!((dma == 0 && dma2 == 1) ||
- (dma == 1 && dma2 == 0) ||
- (dma == 3 && dma2 == 0)))
- { /* Unsupported combination. Try to swap channels */
- int tmp = dma;
-
- dma = dma2;
- dma2 = tmp;
- }
- if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) ||
- (dma == 3 && dma2 == 0))
- {
- dma2_bit = 0x04; /* Enable capture DMA */
- }
- else
- {
- printk("MAD16: Invalid capture DMA\n");
- dma2 = dma;
- }
- }
- else dma2 = dma;
-
- outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
-
- hw_config->slots[0] = ad1848_init("mad16 WSS", ports,
- hw_config->irq,
- dma,
- dma2, 0,
- hw_config->osp,
- THIS_MODULE);
- return 1;
-
-fail:
- release_region(hw_config->io_base + 4, 4);
- release_region(hw_config->io_base, 4);
- return 0;
-}
-
-static int __init probe_mad16_mpu(struct address_info *hw_config)
-{
- unsigned char tmp;
-
- if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
- {
-
-#ifdef CONFIG_MAD16_OLDCARD
-
- tmp = mad_read(MC3_PORT);
-
- /*
- * MAD16 SB base is defined by the WSS base. It cannot be changed
- * alone.
- * Ignore configured I/O base. Use the active setting.
- */
-
- if (mad_read(MC1_PORT) & 0x20)
- hw_config->io_base = 0x240;
- else
- hw_config->io_base = 0x220;
-
- switch (hw_config->irq)
- {
- case 5:
- tmp = (tmp & 0x3f) | 0x80;
- break;
- case 7:
- tmp = (tmp & 0x3f);
- break;
- case 11:
- tmp = (tmp & 0x3f) | 0x40;
- break;
- default:
- printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n");
- return 0;
- }
-
- mad_write(MC3_PORT, tmp | 0x04);
- hw_config->driver_use_1 = SB_MIDI_ONLY;
- if (!request_region(hw_config->io_base, 16, "soundblaster"))
- return 0;
- if (!sb_dsp_detect(hw_config, 0, 0, NULL)) {
- release_region(hw_config->io_base, 16);
- return 0;
- }
-
- if (mad_read(MC1_PORT) & 0x20)
- hw_config->io_base = 0x240;
- else
- hw_config->io_base = 0x220;
-
- hw_config->name = "Mad16/Mozart";
- sb_dsp_init(hw_config, THIS_MODULE);
- return 1;
-#else
- /* assuming all later Mozart cards are identified as
- * either 82C928 or Mozart. If so, following code attempts
- * to set MPU register. TODO - add probing
- */
-
- tmp = mad_read(MC8_PORT);
-
- switch (hw_config->irq)
- {
- case 5:
- tmp |= 0x08;
- break;
- case 7:
- tmp |= 0x10;
- break;
- case 9:
- tmp |= 0x18;
- break;
- case 10:
- tmp |= 0x20;
- break;
- case 11:
- tmp |= 0x28;
- break;
- default:
- printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n");
- return 0;
- }
-
- switch (hw_config->io_base)
- {
- case 0x300:
- tmp |= 0x01;
- break;
- case 0x310:
- tmp |= 0x03;
- break;
- case 0x320:
- tmp |= 0x05;
- break;
- case 0x330:
- tmp |= 0x07;
- break;
- default:
- printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n");
- return 0;
- }
-
- mad_write(MC8_PORT, tmp); /* write MPU port parameters */
- goto probe_401;
-#endif
- }
- tmp = mad_read(MC6_PORT) & 0x83;
- tmp |= 0x80; /* MPU-401 enable */
-
- /* Set the MPU base bits */
-
- switch (hw_config->io_base)
- {
- case 0x300:
- tmp |= 0x60;
- break;
- case 0x310:
- tmp |= 0x40;
- break;
- case 0x320:
- tmp |= 0x20;
- break;
- case 0x330:
- tmp |= 0x00;
- break;
- default:
- printk(KERN_ERR "MAD16: Invalid MIDI port 0x%x\n", hw_config->io_base);
- return 0;
- }
-
- /* Set the MPU IRQ bits */
-
- switch (hw_config->irq)
- {
- case 5:
- tmp |= 0x10;
- break;
- case 7:
- tmp |= 0x18;
- break;
- case 9:
- tmp |= 0x00;
- break;
- case 10:
- tmp |= 0x08;
- break;
- default:
- printk(KERN_ERR "MAD16: Invalid MIDI IRQ %d\n", hw_config->irq);
- break;
- }
-
- mad_write(MC6_PORT, tmp); /* Write MPU401 config */
-
-#ifndef CONFIG_MAD16_OLDCARD
-probe_401:
-#endif
- hw_config->driver_use_1 = SB_MIDI_ONLY;
- hw_config->name = "Mad16/Mozart";
- return probe_uart401(hw_config, THIS_MODULE);
-}
-
-static void __exit unload_mad16(struct address_info *hw_config)
-{
- ad1848_unload(hw_config->io_base + 4,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma2, 0);
- release_region(hw_config->io_base, 4);
- sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static void __exit unload_mad16_mpu(struct address_info *hw_config)
-{
-#ifdef CONFIG_MAD16_OLDCARD
- if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
- {
- sb_dsp_unload(hw_config, 0);
- return;
- }
-#endif
-
- unload_uart401(hw_config);
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int found_mpu;
-
-static int __initdata mpu_io = 0;
-static int __initdata mpu_irq = 0;
-static int __initdata io = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1; /* Set this for modules that need it */
-static int __initdata irq = -1;
-static int __initdata cdtype = 0;
-static int __initdata cdirq = 0;
-static int __initdata cdport = 0x340;
-static int __initdata cddma = -1;
-static int __initdata opl4 = 0;
-static int __initdata joystick = 0;
-
-module_param(mpu_io, int, 0);
-module_param(mpu_irq, int, 0);
-module_param(io, int, 0);
-module_param(dma, int, 0);
-module_param(dma16, int, 0);
-module_param(irq, int, 0);
-module_param(cdtype, int, 0);
-module_param(cdirq, int, 0);
-module_param(cdport, int, 0);
-module_param(cddma, int, 0);
-module_param(opl4, int, 0);
-module_param(joystick, bool, 0);
-module_param(debug, bool, 0644);
-
-static int __initdata dma_map[2][8] =
-{
- {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02},
- {0x03, -1, 0x01, 0x00, -1, -1, -1, -1}
-};
-
-static int __initdata irq_map[16] =
-{
- 0x00, -1, -1, 0x0A,
- -1, 0x04, -1, 0x08,
- -1, 0x10, 0x14, 0x18,
- -1, -1, -1, -1
-};
-
-#ifdef SUPPORT_JOYSTICK
-
-static struct gameport *gameport;
-
-static int __devinit mad16_register_gameport(int io_port)
-{
- if (!request_region(io_port, 1, "mad16 gameport")) {
- printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port);
- return -EBUSY;
- }
-
- gameport = gameport_allocate_port();
- if (!gameport) {
- printk(KERN_ERR "mad16: can not allocate memory for gameport\n");
- release_region(io_port, 1);
- return -ENOMEM;
- }
-
- gameport_set_name(gameport, "MAD16 Gameport");
- gameport_set_phys(gameport, "isa%04x/gameport0", io_port);
- gameport->io = io_port;
-
- gameport_register_port(gameport);
-
- return 0;
-}
-
-static inline void mad16_unregister_gameport(void)
-{
- if (gameport) {
- /* the gameport was initialized so we must free it up */
- gameport_unregister_port(gameport);
- gameport = NULL;
- release_region(0x201, 1);
- }
-}
-#else
-static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
-static inline void mad16_unregister_gameport(void) { }
-#endif
-
-static int __devinit init_mad16(void)
-{
- int dmatype = 0;
-
- printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-
- printk(KERN_INFO "CDROM ");
- switch (cdtype)
- {
- case 0x00:
- printk("Disabled");
- cdirq = 0;
- break;
- case 0x02:
- printk("Sony CDU31A");
- dmatype = 1;
- if(cddma == -1) cddma = 3;
- break;
- case 0x04:
- printk("Mitsumi");
- dmatype = 0;
- if(cddma == -1) cddma = 5;
- break;
- case 0x06:
- printk("Panasonic Lasermate");
- dmatype = 1;
- if(cddma == -1) cddma = 3;
- break;
- case 0x08:
- printk("Secondary IDE");
- dmatype = 0;
- if(cddma == -1) cddma = 5;
- break;
- case 0x0A:
- printk("Primary IDE");
- dmatype = 0;
- if(cddma == -1) cddma = 5;
- break;
- default:
- printk("\n");
- printk(KERN_ERR "Invalid CDROM type\n");
- return -EINVAL;
- }
-
- /*
- * Build the config words
- */
-
- mad16_conf = (joystick ^ 1) | cdtype;
- mad16_cdsel = 0;
- if (opl4)
- mad16_cdsel |= 0x20;
-
- if(cdtype){
- if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1)
- {
- printk("\n");
- printk(KERN_ERR "Invalid CDROM DMA\n");
- return -EINVAL;
- }
- if (cddma)
- printk(", DMA %d", cddma);
- else
- printk(", no DMA");
-
- if (!cdirq)
- printk(", no IRQ");
- else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1)
- {
- printk(", invalid IRQ (disabling)");
- cdirq = 0;
- }
- else printk(", IRQ %d", cdirq);
-
- mad16_cdsel |= dma_map[dmatype][cddma];
-
- if (cdtype < 0x08)
- {
- switch (cdport)
- {
- case 0x340:
- mad16_cdsel |= 0x00;
- break;
- case 0x330:
- mad16_cdsel |= 0x40;
- break;
- case 0x360:
- mad16_cdsel |= 0x80;
- break;
- case 0x320:
- mad16_cdsel |= 0xC0;
- break;
- default:
- printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport);
- return -EINVAL;
- }
- }
- mad16_cdsel |= irq_map[cdirq];
- }
-
- printk(".\n");
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma16;
-
- if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
- printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
- return -EINVAL;
- }
-
- if (!request_region(MC0_PORT, 12, "mad16"))
- return -EBUSY;
-
- if (!probe_mad16(&cfg)) {
- release_region(MC0_PORT, 12);
- return -ENODEV;
- }
-
- cfg_mpu.io_base = mpu_io;
- cfg_mpu.irq = mpu_irq;
-
- found_mpu = probe_mad16_mpu(&cfg_mpu);
-
- if (joystick)
- mad16_register_gameport(0x201);
-
- return 0;
-}
-
-static void __exit cleanup_mad16(void)
-{
- if (found_mpu)
- unload_mad16_mpu(&cfg_mpu);
- mad16_unregister_gameport();
- unload_mad16(&cfg);
- release_region(MC0_PORT, 12);
-}
-
-module_init(init_mad16);
-module_exit(cleanup_mad16);
-
-#ifndef MODULE
-static int __init setup_mad16(char *str)
-{
- /* io, irq */
- int ints[8];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma16 = ints[4];
- mpu_io = ints[5];
- mpu_irq = ints[6];
- joystick = ints[7];
-
- return 1;
-}
-
-__setup("mad16=", setup_mad16);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
deleted file mode 100644
index 1d98d10..0000000
--- a/sound/oss/maestro.c
+++ /dev/null
@@ -1,3686 +0,0 @@
-/*****************************************************************************
- *
- * ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
- *
- * 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.
- *
- * (c) Copyright 1999 Alan Cox <alan.cox@linux.org>
- *
- * Based heavily on SonicVibes.c:
- * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Heavily modified by Zach Brown <zab@zabbo.net> based on lunch
- * with ESS engineers. Many thanks to Howard Kim for providing
- * contacts and hardware. Honorable mention goes to Eric
- * Brombaugh for all sorts of things. Best regards to the
- * proprietors of Hack Central for fine lodging.
- *
- * Supported devices:
- * /dev/dsp0-3 standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- *
- * Hardware Description
- *
- * A working Maestro setup contains the Maestro chip wired to a
- * codec or 2. In the Maestro we have the APUs, the ASSP, and the
- * Wavecache. The APUs can be though of as virtual audio routing
- * channels. They can take data from a number of sources and perform
- * basic encodings of the data. The wavecache is a storehouse for
- * PCM data. Typically it deals with PCI and interracts with the
- * APUs. The ASSP is a wacky DSP like device that ESS is loth
- * to release docs on. Thankfully it isn't required on the Maestro
- * until you start doing insane things like FM emulation and surround
- * encoding. The codecs are almost always AC-97 compliant codecs,
- * but it appears that early Maestros may have had PT101 (an ESS
- * part?) wired to them. The only real difference in the Maestro
- * families is external goop like docking capability, memory for
- * the ASSP, and initialization differences.
- *
- * Driver Operation
- *
- * We only drive the APU/Wavecache as typical DACs and drive the
- * mixers in the codecs. There are 64 APUs. We assign 6 to each
- * /dev/dsp? device. 2 channels for output, and 4 channels for
- * input.
- *
- * Each APU can do a number of things, but we only really use
- * 3 basic functions. For playback we use them to convert PCM
- * data fetched over PCI by the wavecahche into analog data that
- * is handed to the codec. One APU for mono, and a pair for stereo.
- * When in stereo, the combination of smarts in the APU and Wavecache
- * decide which wavecache gets the left or right channel.
- *
- * For record we still use the old overly mono system. For each in
- * coming channel the data comes in from the codec, through a 'input'
- * APU, through another rate converter APU, and then into memory via
- * the wavecache and PCI. If its stereo, we mash it back into LRLR in
- * software. The pass between the 2 APUs is supposedly what requires us
- * to have a 512 byte buffer sitting around in wavecache/memory.
- *
- * The wavecache makes our life even more fun. First off, it can
- * only address the first 28 bits of PCI address space, making it
- * useless on quite a few architectures. Secondly, its insane.
- * It claims to fetch from 4 regions of PCI space, each 4 meg in length.
- * But that doesn't really work. You can only use 1 region. So all our
- * allocations have to be in 4meg of each other. Booo. Hiss.
- * So we have a module parameter, dsps_order, that is the order of
- * the number of dsps to provide. All their buffer space is allocated
- * on open time. The sonicvibes OSS routines we inherited really want
- * power of 2 buffers, so we have all those next to each other, then
- * 512 byte regions for the recording wavecaches. This ends up
- * wasting quite a bit of memory. The only fixes I can see would be
- * getting a kernel allocator that could work in zones, or figuring out
- * just how to coerce the WP into doing what we want.
- *
- * The indirection of the various registers means we have to spinlock
- * nearly all register accesses. We have the main register indirection
- * like the wave cache, maestro registers, etc. Then we have beasts
- * like the APU interface that is indirect registers gotten at through
- * the main maestro indirection. Ouch. We spinlock around the actual
- * ports on a per card basis. This means spinlock activity at each IO
- * operation, but the only IO operation clusters are in non critical
- * paths and it makes the code far easier to follow. Interrupts are
- * blocked while holding the locks because the int handler has to
- * get at some of them :(. The mixer interface doesn't, however.
- * We also have an OSS state lock that is thrown around in a few
- * places.
- *
- * This driver has brute force APM suspend support. We catch suspend
- * notifications and stop all work being done on the chip. Any people
- * that try between this shutdown and the real suspend operation will
- * be put to sleep. When we resume we restore our software state on
- * the chip and wake up the people that were using it. The code thats
- * being used now is quite dirty and assumes we're on a uni-processor
- * machine. Much of it will need to be cleaned up for SMP ACPI or
- * similar.
- *
- * We also pay attention to PCI power management now. The driver
- * will power down units of the chip that it knows aren't needed.
- * The WaveProcessor and company are only powered on when people
- * have /dev/dsp*s open. On removal the driver will
- * power down the maestro entirely. There could still be
- * trouble with BIOSen that magically change power states
- * themselves, but we'll see.
- *
- * History
- * v0.15 - May 21 2001 - Marcus Meissner <mm@caldera.de>
- * Ported to Linux 2.4 PCI API. Some clean ups, global devs list
- * removed (now using pci device driver data).
- * PM needs to be polished still. Bumped version.
- * (still kind of v0.14) May 13 2001 - Ben Pfaff <pfaffben@msu.edu>
- * Add support for 978 docking and basic hardware volume control
- * (still kind of v0.14) Nov 23 - Alan Cox <alan@redhat.com>
- * Add clocking= for people with seriously warped hardware
- * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * add __init to maestro_ac97_init() and maestro_install()
- * (still based on v0.14) Mar 29 2000 - Zach Brown <zab@redhat.com>
- * move to 2.3 power management interface, which
- * required hacking some suspend/resume/check paths
- * make static compilation work
- * v0.14 - Jan 28 2000 - Zach Brown <zab@redhat.com>
- * add PCI power management through ACPI regs.
- * we now shut down on machine reboot/halt
- * leave scary PCI config items alone (isa stuff, mostly)
- * enable 1921s, it seems only mine was broke.
- * fix swapped left/right pcm dac. har har.
- * up bob freq, increase buffers, fix pointers at underflow
- * silly compilation problems
- * v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
- * fix nec Versas? man would that be cool.
- * v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
- * brown bag volume max fix..
- * v0.11 - Nov 11 1999 - Zach Brown <zab@redhat.com>
- * use proper stereo apu decoding, mmap/write should work.
- * make volume sliders more useful, tweak rate calculation.
- * fix lame 8bit format reporting bug. duh. apm apu saving buglet also
- * fix maestro 1 clock freq "bug", remove pt101 support
- * v0.10 - Oct 28 1999 - Zach Brown <zab@redhat.com>
- * aha, so, sometimes the WP writes a status word to offset 0
- * from one of the PCMBARs. rearrange allocation accordingly..
- * cheers again to Eric for being a good hacker in investigating this.
- * Jeroen Hoogervorst submits 7500 fix out of nowhere. yay. :)
- * v0.09 - Oct 23 1999 - Zach Brown <zab@redhat.com>
- * added APM support.
- * re-order something such that some 2Es now work. Magic!
- * new codec reset routine. made some codecs come to life.
- * fix clear_advance, sync some control with ESS.
- * now write to all base regs to be paranoid.
- * v0.08 - Oct 20 1999 - Zach Brown <zab@redhat.com>
- * Fix initial buflen bug. I am so smart. also smp compiling..
- * I owe Eric yet another beer: fixed recmask, igain,
- * muting, and adc sync consistency. Go Team.
- * v0.07 - Oct 4 1999 - Zach Brown <zab@redhat.com>
- * tweak adc/dac, formating, and stuff to allow full duplex
- * allocate dsps memory at open() so we can fit in the wavecache window
- * fix wavecache braindamage. again. no more scribbling?
- * fix ess 1921 codec bug on some laptops.
- * fix dumb pci scanning bug
- * started 2.3 cleanup, redid spinlocks, little cleanups
- * v0.06 - Sep 20 1999 - Zach Brown <zab@redhat.com>
- * fix wavecache thinkos. limit to 1 /dev/dsp.
- * eric is wearing his thinking toque this week.
- * spotted apu mode bugs and gain ramping problem
- * don't touch weird mixer regs, make recmask optional
- * fixed igain inversion, defaults for mixers, clean up rec_start
- * make mono recording work.
- * report subsystem stuff, please send reports.
- * littles: parallel out, amp now
- * v0.05 - Sep 17 1999 - Zach Brown <zab@redhat.com>
- * merged and fixed up Eric's initial recording code
- * munged format handling to catch misuse, needs rewrite.
- * revert ring bus init, fixup shared int, add pci busmaster setting
- * fix mixer oss interface, fix mic mute and recmask
- * mask off unsupported mixers, reset with all 1s, modularize defaults
- * make sure bob is running while we need it
- * got rid of device limit, initial minimal apm hooks
- * pull out dead code/includes, only allow multimedia/audio maestros
- * v0.04 - Sep 01 1999 - Zach Brown <zab@redhat.com>
- * copied memory leak fix from sonicvibes driver
- * different ac97 reset, play with 2.0 ac97, simplify ring bus setup
- * bob freq code, region sanity, jitter sync fix; all from Eric
- *
- * TODO
- * fix bob frequency
- * endianness
- * do smart things with ac97 2.0 bits.
- * dual codecs
- * leave 54->61 open
- *
- * it also would be fun to have a mode that would not use pci dma at all
- * but would copy into the wavecache on board memory and use that
- * on architectures that don't like the maestro's pci dma ickiness.
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/reboot.h>
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-
-#include <asm/current.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "maestro.h"
-
-static struct pci_driver maestro_pci_driver;
-
-/* --------------------------------------------------------------------- */
-
-#define M_DEBUG 1
-
-#ifdef M_DEBUG
-static int debug;
-#define M_printk(args...) {if (debug) printk(args);}
-#else
-#define M_printk(x)
-#endif
-
-/* we try to setup 2^(dsps_order) /dev/dsp devices */
-static int dsps_order;
-/* whether or not we mess around with power management */
-static int use_pm=2; /* set to 1 for force */
-/* clocking for broken hardware - a few laptops seem to use a 50Khz clock
- ie insmod with clocking=50000 or so */
-
-static int clocking=48000;
-
-MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("ESS Maestro Driver");
-MODULE_LICENSE("GPL");
-
-#ifdef M_DEBUG
-module_param(debug, bool, 0644);
-#endif
-module_param(dsps_order, int, 0);
-module_param(use_pm, int, 0);
-module_param(clocking, int, 0);
-
-/* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.15"
-
-#ifndef PCI_VENDOR_ESS
-#define PCI_VENDOR_ESS 0x125D
-#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */
-#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */
-
-#define PCI_VENDOR_ESS_OLD 0x1285 /* Platform Tech,
- the people the maestro
- was bought from */
-#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 /* maestro 1 */
-#endif /* PCI_VENDOR_ESS */
-
-#define ESS_CHAN_HARD 0x100
-
-/* NEC Versas ? */
-#define NEC_VERSA_SUBID1 0x80581033
-#define NEC_VERSA_SUBID2 0x803c1033
-
-
-/* changed so that I could actually find all the
- references and fix them up. it's a little more readable now. */
-#define ESS_FMT_STEREO 0x01
-#define ESS_FMT_16BIT 0x02
-#define ESS_FMT_MASK 0x03
-#define ESS_DAC_SHIFT 0
-#define ESS_ADC_SHIFT 4
-
-#define ESS_STATE_MAGIC 0x125D1968
-#define ESS_CARD_MAGIC 0x19283746
-
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
-
-#define MAX_DSP_ORDER 2
-#define MAX_DSPS (1<<MAX_DSP_ORDER)
-#define NR_DSPS (1<<dsps_order)
-#define NR_IDRS 32
-
-#define NR_APUS 64
-#define NR_APU_REGS 16
-
-/* acpi states */
-enum {
- ACPI_D0=0,
- ACPI_D1,
- ACPI_D2,
- ACPI_D3
-};
-
-/* bits in the acpi masks */
-#define ACPI_12MHZ ( 1 << 15)
-#define ACPI_24MHZ ( 1 << 14)
-#define ACPI_978 ( 1 << 13)
-#define ACPI_SPDIF ( 1 << 12)
-#define ACPI_GLUE ( 1 << 11)
-#define ACPI__10 ( 1 << 10) /* reserved */
-#define ACPI_PCIINT ( 1 << 9)
-#define ACPI_HV ( 1 << 8) /* hardware volume */
-#define ACPI_GPIO ( 1 << 7)
-#define ACPI_ASSP ( 1 << 6)
-#define ACPI_SB ( 1 << 5) /* sb emul */
-#define ACPI_FM ( 1 << 4) /* fm emul */
-#define ACPI_RB ( 1 << 3) /* ringbus / aclink */
-#define ACPI_MIDI ( 1 << 2)
-#define ACPI_GP ( 1 << 1) /* game port */
-#define ACPI_WP ( 1 << 0) /* wave processor */
-
-#define ACPI_ALL (0xffff)
-#define ACPI_SLEEP (~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \
- ACPI_MIDI|ACPI_GP|ACPI_WP))
-#define ACPI_NONE (ACPI__10)
-
-/* these masks indicate which units we care about at
- which states */
-static u16 acpi_state_mask[] = {
- [ACPI_D0] = ACPI_ALL,
- [ACPI_D1] = ACPI_SLEEP,
- [ACPI_D2] = ACPI_SLEEP,
- [ACPI_D3] = ACPI_NONE
-};
-
-static char version[] __devinitdata =
-KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n";
-
-
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-enum card_types_t {
- TYPE_MAESTRO,
- TYPE_MAESTRO2,
- TYPE_MAESTRO2E
-};
-
-static const char *card_names[]={
- [TYPE_MAESTRO] = "ESS Maestro",
- [TYPE_MAESTRO2] = "ESS Maestro 2",
- [TYPE_MAESTRO2E] = "ESS Maestro 2E"
-};
-
-static int clock_freq[]={
- [TYPE_MAESTRO] = (49152000L / 1024L),
- [TYPE_MAESTRO2] = (50000000L / 1024L),
- [TYPE_MAESTRO2E] = (50000000L / 1024L)
-};
-
-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-
-static struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
-
-/* --------------------------------------------------------------------- */
-
-struct ess_state {
- unsigned int magic;
- /* FIXME: we probably want submixers in here, but only one record pair */
- u8 apu[6]; /* l/r output, l/r intput converters, l/r input apus */
- u8 apu_mode[6]; /* Running mode for this APU */
- u8 apu_pan[6]; /* Panning setup for this APU */
- u32 apu_base[6]; /* base address for this apu */
- struct ess_card *card; /* Card info */
- /* wave stuff */
- unsigned int rateadc, ratedac;
- unsigned char fmt, enable;
-
- int index;
-
- /* this locks around the oss state in the driver */
- spinlock_t lock;
- /* only let 1 be opening at a time */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
- mode_t open_mode;
-
- /* soundcore stuff */
- int dev_audio;
-
- struct dmabuf {
- void *rawbuf;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- /* XXX zab - swptr only in here so that it can be referenced by
- clear_advance, as far as I can tell :( */
- 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; /* our oss buffers are ready to go */
- unsigned endcleared:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- u16 base; /* Offset for ptr */
- } dma_dac, dma_adc;
-
- /* pointer to each dsp?s piece of the apu->src buffer page */
- void *mixbuf;
-
-};
-
-struct ess_card {
- unsigned int magic;
-
- /* We keep maestro cards in a linked list */
- struct ess_card *next;
-
- int dev_mixer;
-
- int card_type;
-
- /* as most of this is static,
- perhaps it should be a pointer to a global struct */
- struct mixer_goo {
- int modcnt;
- int supported_mixers;
- int stereo_mixers;
- int record_sources;
- /* the caller must guarantee arg sanity before calling these */
-/* int (*read_mixer)(struct ess_card *card, int index);*/
- void (*write_mixer)(struct ess_card *card,int mixer, unsigned int left,unsigned int right);
- int (*recmask_io)(struct ess_card *card,int rw,int mask);
- unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
- } mix;
-
- int power_regs;
-
- int in_suspend;
- wait_queue_head_t suspend_queue;
-
- struct ess_state channels[MAX_DSPS];
- u16 maestro_map[NR_IDRS]; /* Register map */
- /* we have to store this junk so that we can come back from a
- suspend */
- u16 apu_map[NR_APUS][NR_APU_REGS]; /* contents of apu regs */
-
- /* this locks around the physical registers on the card */
- spinlock_t lock;
-
- /* memory for this card.. wavecache limited :(*/
- void *dmapages;
- int dmaorder;
-
- /* hardware resources */
- struct pci_dev *pcidev;
- u32 iobase;
- u32 irq;
-
- int bob_freq;
- char dsps_open;
-
- int dock_mute_vol;
-};
-
-static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val );
-
-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 check_suspend(struct ess_card *card);
-
-/* --------------------------------------------------------------------- */
-
-
-/*
- * ESS Maestro AC97 codec programming interface.
- */
-
-static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val)
-{
- int io = card->iobase;
- int i;
- /*
- * Wait for the codec bus to be free
- */
-
- check_suspend(card);
-
- for(i=0;i<10000;i++)
- {
- if(!(inb(io+ESS_AC97_INDEX)&1))
- break;
- }
- /*
- * Write the bus
- */
- outw(val, io+ESS_AC97_DATA);
- mdelay(1);
- outb(cmd, io+ESS_AC97_INDEX);
- mdelay(1);
-}
-
-static u16 maestro_ac97_get(struct ess_card *card, u8 cmd)
-{
- int io = card->iobase;
- int sanity=10000;
- u16 data;
- int i;
-
- check_suspend(card);
- /*
- * Wait for the codec bus to be free
- */
-
- for(i=0;i<10000;i++)
- {
- if(!(inb(io+ESS_AC97_INDEX)&1))
- break;
- }
-
- outb(cmd|0x80, io+ESS_AC97_INDEX);
- mdelay(1);
-
- while(inb(io+ESS_AC97_INDEX)&1)
- {
- sanity--;
- if(!sanity)
- {
- printk(KERN_ERR "maestro: ac97 codec timeout reading 0x%x.\n",cmd);
- return 0;
- }
- }
- data=inw(io+ESS_AC97_DATA);
- mdelay(1);
- return data;
-}
-
-/* OSS interface to the ac97s.. */
-
-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\
- SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\
- SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN)
-
-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
- SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\
- SOUND_MASK_SPEAKER)
-
-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
- SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
- SOUND_MASK_PHONEIN)
-
-#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<<FOO) )
-
-/* this table has default mixer values for all OSS mixers.
- be sure to fill it in if you add oss mixers
- to anyone's supported mixer defines */
-
-static unsigned int mixer_defaults[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_VOLUME] = 0x3232,
- [SOUND_MIXER_BASS] = 0x3232,
- [SOUND_MIXER_TREBLE] = 0x3232,
- [SOUND_MIXER_SPEAKER] = 0x3232,
- [SOUND_MIXER_MIC] = 0x8000, /* annoying */
- [SOUND_MIXER_LINE] = 0x3232,
- [SOUND_MIXER_CD] = 0x3232,
- [SOUND_MIXER_VIDEO] = 0x3232,
- [SOUND_MIXER_LINE1] = 0x3232,
- [SOUND_MIXER_PCM] = 0x3232,
- [SOUND_MIXER_IGAIN] = 0x3232
-};
-
-static struct ac97_mixer_hw {
- unsigned char offset;
- int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
- [SOUND_MIXER_VOLUME] = {0x02,63},
- [SOUND_MIXER_BASS] = {0x08,15},
- [SOUND_MIXER_TREBLE] = {0x08,15},
- [SOUND_MIXER_SPEAKER] = {0x0a,15},
- [SOUND_MIXER_MIC] = {0x0e,31},
- [SOUND_MIXER_LINE] = {0x10,31},
- [SOUND_MIXER_CD] = {0x12,31},
- [SOUND_MIXER_VIDEO] = {0x14,31},
- [SOUND_MIXER_LINE1] = {0x16,31},
- [SOUND_MIXER_PCM] = {0x18,31},
- [SOUND_MIXER_IGAIN] = {0x1c,15}
-};
-
-#if 0 /* *shrug* removed simply because we never used it.
- feel free to implement again if needed */
-
-/* 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 ess_card *card, int mixer)
-{
- u16 val;
- int ret=0;
- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
- val = maestro_ac97_get(card, mh->offset);
-
- if(AC97_STEREO_MASK & (1<<mixer)) {
- /* nice stereo mixers .. */
- int left,right;
-
- left = (val >> 8) & 0x7f;
- right = val & 0x7f;
-
- if (mixer == SOUND_MIXER_IGAIN) {
- right = (right * 100) / mh->scale;
- left = (left * 100) / mh->scale;
- } else {
- right = 100 - ((right * 100) / mh->scale);
- left = 100 - ((left * 100) / mh->scale);
- }
-
- ret = left | (right << 8);
- } else if (mixer == SOUND_MIXER_SPEAKER) {
- ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
- } else if (mixer == SOUND_MIXER_MIC) {
- ret = 100 - (((val & 0x1f) * 100) / mh->scale);
- /* the low bit is optional in the tone sliders and masking
- it lets is avoid the 0xf 'bypass'.. */
- } else if (mixer == SOUND_MIXER_BASS) {
- ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
- } else if (mixer == SOUND_MIXER_TREBLE) {
- ret = 100 - (((val & 0xe) * 100) / mh->scale);
- }
-
- M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
-
- return ret;
-}
-#endif
-
-/* 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 */
-
-/* linear scale -> log */
-static unsigned char lin2log[101] =
-{
-0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
-50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
-63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
-72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
-78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
-83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
-87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
-90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
-93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
-95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
-97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99
-};
-
-static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
-{
- u16 val=0;
- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
- M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
-
- if(AC97_STEREO_MASK & (1<<mixer)) {
- /* stereo mixers, mute them if we can */
-
- if (mixer == SOUND_MIXER_IGAIN) {
- /* igain's slider is reversed.. */
- right = (right * mh->scale) / 100;
- left = (left * mh->scale) / 100;
- if ((left == 0) && (right == 0))
- val |= 0x8000;
- } else if (mixer == SOUND_MIXER_PCM || mixer == SOUND_MIXER_CD) {
- /* log conversion seems bad for them */
- if ((left == 0) && (right == 0))
- val = 0x8000;
- right = ((100 - right) * mh->scale) / 100;
- left = ((100 - left) * mh->scale) / 100;
- } else {
- /* log conversion for the stereo controls */
- if((left == 0) && (right == 0))
- val = 0x8000;
- right = ((100 - lin2log[right]) * mh->scale) / 100;
- left = ((100 - lin2log[left]) * mh->scale) / 100;
- }
-
- val |= (left << 8) | right;
-
- } else if (mixer == SOUND_MIXER_SPEAKER) {
- val = (((100 - left) * mh->scale) / 100) << 1;
- } else if (mixer == SOUND_MIXER_MIC) {
- val = maestro_ac97_get(card, mh->offset) & ~0x801f;
- val |= (((100 - left) * mh->scale) / 100);
- /* the low bit is optional in the tone sliders and masking
- it lets is avoid the 0xf 'bypass'.. */
- } else if (mixer == SOUND_MIXER_BASS) {
- val = maestro_ac97_get(card , mh->offset) & ~0x0f00;
- val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (mixer == SOUND_MIXER_TREBLE) {
- val = maestro_ac97_get(card , mh->offset) & ~0x000f;
- val |= (((100 - left) * mh->scale) / 100) & 0x000e;
- }
-
- maestro_ac97_set(card , mh->offset, val);
-
- M_printk(" -> %x\n",val);
-}
-
-/* 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 unsigned int ac97_oss_mask[] = {
- [AC97_REC_MIC] = SOUND_MASK_MIC,
- [AC97_REC_CD] = SOUND_MASK_CD,
- [AC97_REC_VIDEO] = SOUND_MASK_VIDEO,
- [AC97_REC_AUX] = SOUND_MASK_LINE1,
- [AC97_REC_LINE] = SOUND_MASK_LINE,
- [AC97_REC_PHONE] = SOUND_MASK_PHONEIN
-};
-
-/* indexed by bit position */
-static 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_PHONEIN] = AC97_REC_PHONE
-};
-
-/* read or write the recmask
- the ac97 can really have left and right recording
- inputs independently 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 ess_card *card, int read, int mask)
-{
- unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ];
-
- if (read) return val;
-
- /* oss can have many inputs, maestro can't. try
- to pick the 'new' one */
-
- if (mask != val) mask &= ~val;
-
- val = ffs(mask) - 1;
- val = ac97_oss_rm[val];
- val |= val << 8; /* set both channels */
-
- M_printk("maestro: setting ac97 recmask to 0x%x\n",val);
-
- maestro_ac97_set(card,0x1a,val);
-
- return 0;
-};
-
-/*
- * The Maestro can be wired to a standard AC97 compliant codec
- * (see www.intel.com for the pdf's on this), or to a PT101 codec
- * which appears to be the ES1918 (data sheet on the esstech.com.tw site)
- *
- * The PT101 setup is untested.
- */
-
-static u16 __init maestro_ac97_init(struct ess_card *card)
-{
- u16 vend1, vend2, caps;
-
- card->mix.supported_mixers = AC97_SUPPORTED_MASK;
- card->mix.stereo_mixers = AC97_STEREO_MASK;
- card->mix.record_sources = AC97_RECORD_MASK;
-/* card->mix.read_mixer = ac97_read_mixer;*/
- card->mix.write_mixer = ac97_write_mixer;
- card->mix.recmask_io = ac97_recmask_io;
-
- vend1 = maestro_ac97_get(card, 0x7c);
- vend2 = maestro_ac97_get(card, 0x7e);
-
- caps = maestro_ac97_get(card, 0x00);
-
- printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n",
- vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf);
-
- if (! (caps & 0x4) ) {
- /* no bass/treble nobs */
- card->mix.supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
- }
-
- /* XXX endianness, dork head. */
- /* vendor specifc bits.. */
- switch ((long)(vend1 << 16) | vend2) {
- case 0x545200ff: /* TriTech */
- /* no idea what this does */
- maestro_ac97_set(card,0x2a,0x0001);
- maestro_ac97_set(card,0x2c,0x0000);
- maestro_ac97_set(card,0x2c,0xffff);
- break;
-#if 0 /* i thought the problems I was seeing were with
- the 1921, but apparently they were with the pci board
- it was on, so this code is commented out.
- lets see if this holds true. */
- case 0x83847609: /* ESS 1921 */
- /* writing to 0xe (mic) or 0x1a (recmask) seems
- to hang this codec */
- card->mix.supported_mixers &= ~(SOUND_MASK_MIC);
- card->mix.record_sources = 0;
- card->mix.recmask_io = NULL;
-#if 0 /* don't ask. I have yet to see what these actually do. */
- maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
- udelay(20);
- maestro_ac97_set(card,0x78,0x3002);
- udelay(20);
- maestro_ac97_set(card,0x78,0x3802);
- udelay(20);
-#endif
- break;
-#endif
- default: break;
- }
-
- maestro_ac97_set(card, 0x1E, 0x0404);
- /* null misc stuff */
- maestro_ac97_set(card, 0x20, 0x0000);
-
- return 0;
-}
-
-#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 u16 maestro_pt101_init(struct ess_card *card,int iobase)
-{
- printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
- /* who knows.. */
- maestro_ac97_set(iobase, 0x2A, 0x0001);
- maestro_ac97_set(iobase, 0x2C, 0x0000);
- maestro_ac97_set(iobase, 0x2C, 0xFFFF);
- maestro_ac97_set(iobase, 0x10, 0x9F1F);
- maestro_ac97_set(iobase, 0x12, 0x0808);
- maestro_ac97_set(iobase, 0x14, 0x9F1F);
- maestro_ac97_set(iobase, 0x16, 0x9F1F);
- maestro_ac97_set(iobase, 0x18, 0x0404);
- maestro_ac97_set(iobase, 0x1A, 0x0000);
- maestro_ac97_set(iobase, 0x1C, 0x0000);
- maestro_ac97_set(iobase, 0x02, 0x0404);
- maestro_ac97_set(iobase, 0x04, 0x0808);
- maestro_ac97_set(iobase, 0x0C, 0x801F);
- maestro_ac97_set(iobase, 0x0E, 0x801F);
- return 0;
-}
-#endif
-
-/* this is very magic, and very slow.. */
-static void
-maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
-{
- u16 save_68;
- u16 w;
- u32 vend;
-
- outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
- outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
- outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
-
- /* reset the first codec */
- outw(0x0000, ioaddr+0x36);
- save_68 = inw(ioaddr+0x68);
- pci_read_config_word(pcidev, 0x58, &w); /* something magical with gpio and bus arb. */
- pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);
- if( w & 0x1)
- save_68 |= 0x10;
- outw(0xfffe, ioaddr + 0x64); /* tickly gpio 0.. */
- outw(0x0001, ioaddr + 0x68);
- outw(0x0000, ioaddr + 0x60);
- udelay(20);
- outw(0x0001, ioaddr + 0x60);
- mdelay(20);
-
- outw(save_68 | 0x1, ioaddr + 0x68); /* now restore .. */
- outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38);
- outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a);
- outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c);
-
- /* now the second codec */
- outw(0x0000, ioaddr+0x36);
- outw(0xfff7, ioaddr + 0x64);
- save_68 = inw(ioaddr+0x68);
- outw(0x0009, ioaddr + 0x68);
- outw(0x0001, ioaddr + 0x60);
- udelay(20);
- outw(0x0009, ioaddr + 0x60);
- mdelay(500); /* .. ouch.. */
- outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
- outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
- outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
-
-#if 0 /* the loop here needs to be much better if we want it.. */
- M_printk("trying software reset\n");
- /* try and do a software reset */
- outb(0x80|0x7c, ioaddr + 0x30);
- for (w=0; ; w++) {
- if ((inw(ioaddr+ 0x30) & 1) == 0) {
- if(inb(ioaddr + 0x32) !=0) break;
-
- outb(0x80|0x7d, ioaddr + 0x30);
- if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
- outb(0x80|0x7f, ioaddr + 0x30);
- if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
- }
-
- if( w > 10000) {
- outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37); /* do a software reset */
- mdelay(500); /* oh my.. */
- outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37);
- udelay(1);
- outw( 0x80, ioaddr+0x30);
- for(w = 0 ; w < 10000; w++) {
- if((inw(ioaddr + 0x30) & 1) ==0) break;
- }
- }
- }
-#endif
- if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {
- /* turn on external amp? */
- outw(0xf9ff, ioaddr + 0x64);
- outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
- outw(0x0209, ioaddr + 0x60);
- }
-
- /* Turn on the 978 docking chip.
- First frob the "master output enable" bit,
- then set most of the playback volume control registers to max. */
- outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);
- outb(0xff, ioaddr+0xc3);
- outb(0xff, ioaddr+0xc4);
- outb(0xff, ioaddr+0xc6);
- outb(0xff, ioaddr+0xc8);
- outb(0x3f, ioaddr+0xcf);
- outb(0x3f, ioaddr+0xd0);
-}
-/*
- * Indirect register access. Not all registers are readable so we
- * need to keep register state ourselves
- */
-
-#define WRITEABLE_MAP 0xEFFFFF
-#define READABLE_MAP 0x64003F
-
-/*
- * The Maestro engineers were a little indirection happy. These indirected
- * registers themselves include indirect registers at another layer
- */
-
-static void __maestro_write(struct ess_card *card, u16 reg, u16 data)
-{
- long ioaddr = card->iobase;
-
- outw(reg, ioaddr+0x02);
- outw(data, ioaddr+0x00);
- if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg);
- else card->maestro_map[reg]=data;
-
-}
-
-static void maestro_write(struct ess_state *s, u16 reg, u16 data)
-{
- unsigned long flags;
-
- check_suspend(s->card);
- spin_lock_irqsave(&s->card->lock,flags);
-
- __maestro_write(s->card,reg,data);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 __maestro_read(struct ess_card *card, u16 reg)
-{
- long ioaddr = card->iobase;
-
- outw(reg, ioaddr+0x02);
- return card->maestro_map[reg]=inw(ioaddr+0x00);
-}
-
-static u16 maestro_read(struct ess_state *s, u16 reg)
-{
- if(READABLE_MAP & (1<<reg))
- {
- unsigned long flags;
- check_suspend(s->card);
- spin_lock_irqsave(&s->card->lock,flags);
-
- __maestro_read(s->card,reg);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
- }
- return s->card->maestro_map[reg];
-}
-
-/*
- * These routines handle accessing the second level indirections to the
- * wave ram.
- */
-
-/*
- * The register names are the ones ESS uses (see 104T31.ZIP)
- */
-
-#define IDR0_DATA_PORT 0x00
-#define IDR1_CRAM_POINTER 0x01
-#define IDR2_CRAM_DATA 0x02
-#define IDR3_WAVE_DATA 0x03
-#define IDR4_WAVE_PTR_LOW 0x04
-#define IDR5_WAVE_PTR_HI 0x05
-#define IDR6_TIMER_CTRL 0x06
-#define IDR7_WAVE_ROMRAM 0x07
-
-static void apu_index_set(struct ess_card *card, u16 index)
-{
- int i;
- __maestro_write(card, IDR1_CRAM_POINTER, index);
- for(i=0;i<1000;i++)
- if(__maestro_read(card, IDR1_CRAM_POINTER)==index)
- return;
- printk(KERN_WARNING "maestro: APU register select failed.\n");
-}
-
-static void apu_data_set(struct ess_card *card, u16 data)
-{
- int i;
- for(i=0;i<1000;i++)
- {
- if(__maestro_read(card, IDR0_DATA_PORT)==data)
- return;
- __maestro_write(card, IDR0_DATA_PORT, data);
- }
-}
-
-/*
- * This is the public interface for APU manipulation. It handles the
- * interlock to avoid two APU writes in parallel etc. Don't diddle
- * directly with the stuff above.
- */
-
-static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data)
-{
- unsigned long flags;
-
- check_suspend(s->card);
-
- if(channel&ESS_CHAN_HARD)
- channel&=~ESS_CHAN_HARD;
- else
- {
- if(channel>5)
- printk("BAD CHANNEL %d.\n",channel);
- else
- channel = s->apu[channel];
- /* store based on real hardware apu/reg */
- s->card->apu_map[channel][reg]=data;
- }
- reg|=(channel<<4);
-
- /* hooray for double indirection!! */
- spin_lock_irqsave(&s->card->lock,flags);
-
- apu_index_set(s->card, reg);
- apu_data_set(s->card, data);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg)
-{
- unsigned long flags;
- u16 v;
-
- check_suspend(s->card);
-
- if(channel&ESS_CHAN_HARD)
- channel&=~ESS_CHAN_HARD;
- else
- channel = s->apu[channel];
-
- reg|=(channel<<4);
-
- spin_lock_irqsave(&s->card->lock,flags);
-
- apu_index_set(s->card, reg);
- v=__maestro_read(s->card, IDR0_DATA_PORT);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
- return v;
-}
-
-
-/*
- * The wavecache buffers between the APUs and
- * pci bus mastering
- */
-
-static void wave_set_register(struct ess_state *s, u16 reg, u16 value)
-{
- long ioaddr = s->card->iobase;
- unsigned long flags;
- check_suspend(s->card);
-
- spin_lock_irqsave(&s->card->lock,flags);
-
- outw(reg, ioaddr+0x10);
- outw(value, ioaddr+0x12);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 wave_get_register(struct ess_state *s, u16 reg)
-{
- long ioaddr = s->card->iobase;
- unsigned long flags;
- u16 value;
- check_suspend(s->card);
-
- spin_lock_irqsave(&s->card->lock,flags);
- outw(reg, ioaddr+0x10);
- value=inw(ioaddr+0x12);
- spin_unlock_irqrestore(&s->card->lock,flags);
-
- return value;
-}
-
-static void sound_reset(int ioaddr)
-{
- outw(0x2000, 0x18+ioaddr);
- udelay(1);
- outw(0x0000, 0x18+ioaddr);
- udelay(1);
-}
-
-/* sets the play formats of these apus, should be passed the already shifted format */
-static void set_apu_fmt(struct ess_state *s, int apu, int mode)
-{
- int apu_fmt = 0x10;
-
- if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20;
- if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10;
- s->apu_mode[apu] = apu_fmt;
- s->apu_mode[apu+1] = apu_fmt;
-}
-
-/* this only fixes the output apu mode to be later set by start_dac and
- company. output apu modes are set in ess_rec_setup */
-static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
-{
- s->fmt = (s->fmt & mask) | data;
- set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
-}
-
-/* this is off by a little bit.. */
-static u32 compute_rate(struct ess_state *s, u32 freq)
-{
- u32 clock = clock_freq[s->card->card_type];
-
- freq = (freq * clocking)/48000;
-
- if (freq == 48000)
- return 0x10000;
-
- return ((freq / clock) <<16 )+
- (((freq % clock) << 16) / clock);
-}
-
-static void set_dac_rate(struct ess_state *s, unsigned int rate)
-{
- u32 freq;
- int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
-
- s->ratedac = rate;
-
- if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
- rate >>= 1;
-
-/* M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
-
- freq = compute_rate(s, rate);
-
- /* Load the frequency, turn on 6dB */
- apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 0, 3, freq>>8);
- apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 1, 3, freq>>8);
-}
-
-static void set_adc_rate(struct ess_state *s, unsigned rate)
-{
- u32 freq;
-
- /* Sample Rate conversion APUs don't like 0x10000 for their rate */
- if (rate > 47999)
- rate = 47999;
- if (rate < 4000)
- rate = 4000;
-
- s->rateadc = rate;
-
- freq = compute_rate(s, rate);
-
- /* Load the frequency, turn on 6dB */
- apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 2, 3, freq>>8);
- apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 3, 3, freq>>8);
-
- /* fix mixer rate at 48khz. and its _must_ be 0x10000. */
- freq = 0x10000;
-
- apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 4, 3, freq>>8);
- apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 5, 3, freq>>8);
-}
-
-/* Stop our host of recording apus */
-static inline void stop_adc(struct ess_state *s)
-{
- /* XXX lets hope we don't have to lock around this */
- if (! (s->enable & ADC_RUNNING)) return;
-
- s->enable &= ~ADC_RUNNING;
- apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F);
- apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F);
- apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F);
- apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F);
-}
-
-/* stop output apus */
-static void stop_dac(struct ess_state *s)
-{
- /* XXX have to lock around this? */
- if (! (s->enable & DAC_RUNNING)) return;
-
- s->enable &= ~DAC_RUNNING;
- apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F);
- apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F);
-}
-
-static void start_dac(struct ess_state *s)
-{
- /* XXX locks? */
- if ( (s->dma_dac.mapped || s->dma_dac.count > 0) &&
- s->dma_dac.ready &&
- (! (s->enable & DAC_RUNNING)) ) {
-
- s->enable |= DAC_RUNNING;
-
- apu_set_register(s, 0, 0,
- (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]);
-
- if((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_STEREO)
- apu_set_register(s, 1, 0,
- (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]);
- }
-}
-
-static void start_adc(struct ess_state *s)
-{
- /* XXX locks? */
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) {
-
- s->enable |= ADC_RUNNING;
- apu_set_register(s, 2, 0,
- (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]);
- apu_set_register(s, 4, 0,
- (apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]);
-
- if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
- apu_set_register(s, 3, 0,
- (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]);
- apu_set_register(s, 5, 0,
- (apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]);
- }
-
- }
-}
-
-
-/*
- * Native play back driver
- */
-
-/* the mode passed should be already shifted and masked */
-static void
-ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
-{
- u32 pa;
- u32 tmpval;
- int high_apu = 0;
- int channel;
-
- M_printk("mode=%d rate=%d buf=%p len=%d.\n",
- mode, rate, buffer, size);
-
- /* all maestro sizes are in 16bit words */
- size >>=1;
-
- if(mode&ESS_FMT_STEREO) {
- high_apu++;
- /* only 16/stereo gets size divided */
- if(mode&ESS_FMT_16BIT)
- size>>=1;
- }
-
- for(channel=0; channel <= high_apu; channel++)
- {
- pa = virt_to_bus(buffer);
-
- /* set the wavecache control reg */
- tmpval = (pa - 0x10) & 0xFFF8;
- if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
- if(mode & ESS_FMT_STEREO) tmpval |= 2;
- ess->apu_base[channel]=tmpval;
- wave_set_register(ess, ess->apu[channel]<<3, tmpval);
-
- pa -= virt_to_bus(ess->card->dmapages);
- pa>>=1; /* words */
-
- /* base offset of dma calcs when reading the pointer
- on the left one */
- if(!channel) ess->dma_dac.base = pa&0xFFFF;
-
- pa|=0x00400000; /* System RAM */
-
- /* XXX the 16bit here might not be needed.. */
- if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
- if(channel)
- pa|=0x00800000; /* Stereo */
- pa>>=1;
- }
-
-/* XXX think about endianess when writing these registers */
- M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
- /* start of sample */
- apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
- apu_set_register(ess, channel, 5, pa&0xFFFF);
- /* sample end */
- apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
- /* setting loop len == sample len */
- apu_set_register(ess, channel, 7, size);
-
- /* clear effects/env.. */
- apu_set_register(ess, channel, 8, 0x0000);
- /* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */
- apu_set_register(ess, channel, 9, 0xD000);
-
- /* clear routing stuff */
- apu_set_register(ess, channel, 11, 0x0000);
- /* dma on, no envelopes, filter to all 1s) */
- apu_set_register(ess, channel, 0, 0x400F);
-
- if(mode&ESS_FMT_16BIT)
- ess->apu_mode[channel]=0x10;
- else
- ess->apu_mode[channel]=0x30;
-
- if(mode&ESS_FMT_STEREO) {
- /* set panning: left or right */
- apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10));
- ess->apu_mode[channel] += 0x10;
- } else
- apu_set_register(ess, channel, 10, 0x8F08);
- }
-
- /* clear WP interrupts */
- outw(1, ess->card->iobase+0x04);
- /* enable WP ints */
- outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
-
- /* go team! */
- set_dac_rate(ess,rate);
- start_dac(ess);
-}
-
-/*
- * Native record driver
- */
-
-/* again, passed mode is alrady shifted/masked */
-static void
-ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
-{
- int apu_step = 2;
- int channel;
-
- M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n",
- mode, rate, buffer, size);
-
- /* all maestro sizes are in 16bit words */
- size >>=1;
-
- /* we're given the full size of the buffer, but
- in stereo each channel will only use its half */
- if(mode&ESS_FMT_STEREO) {
- size >>=1;
- apu_step = 1;
- }
-
- /* APU assignments: 2 = mono/left SRC
- 3 = right SRC
- 4 = mono/left Input Mixer
- 5 = right Input Mixer */
- for(channel=2;channel<6;channel+=apu_step)
- {
- int i;
- int bsize, route;
- u32 pa;
- u32 tmpval;
-
- /* data seems to flow from the codec, through an apu into
- the 'mixbuf' bit of page, then through the SRC apu
- and out to the real 'buffer'. ok. sure. */
-
- if(channel & 0x04) {
- /* ok, we're an input mixer going from adc
- through the mixbuf to the other apus */
-
- if(!(channel & 0x01)) {
- pa = virt_to_bus(ess->mixbuf);
- } else {
- pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4));
- }
-
- /* we source from a 'magic' apu */
- bsize = PAGE_SIZE >> 5; /* half of this channels alloc, in words */
- route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */
- ess->apu_mode[channel] = 0x90; /* Input Mixer */
-
- } else {
- /* we're a rate converter taking
- input from the input apus and outputing it to
- system memory */
- if(!(channel & 0x01)) {
- pa = virt_to_bus(buffer);
- } else {
- /* right channel records its split half.
- *2 accommodates for rampant shifting earlier */
- pa = virt_to_bus(buffer + size*2);
- }
-
- ess->apu_mode[channel] = 0xB0; /* Sample Rate Converter */
-
- bsize = size;
- /* get input from inputing apu */
- route = channel + 2;
- }
-
- M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel);
-
- /* set the wavecache control reg */
- tmpval = (pa - 0x10) & 0xFFF8;
- ess->apu_base[channel]=tmpval;
- wave_set_register(ess, ess->apu[channel]<<3, tmpval);
-
- pa -= virt_to_bus(ess->card->dmapages);
- pa>>=1; /* words */
-
- /* base offset of dma calcs when reading the pointer
- on this left one */
- if(channel==2) ess->dma_adc.base = pa&0xFFFF;
-
- pa|=0x00400000; /* bit 22 -> System RAM */
-
- M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n",
- ess->apu[channel], pa, bsize, route);
-
- /* Begin loading the APU */
- for(i=0;i<15;i++) /* clear all PBRs */
- apu_set_register(ess, channel, i, 0x0000);
-
- apu_set_register(ess, channel, 0, 0x400F);
-
- /* need to enable subgroups.. and we should probably
- have different groups for different /dev/dsps.. */
- apu_set_register(ess, channel, 2, 0x8);
-
- /* Load the buffer into the wave engine */
- apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
- /* XXX reg is little endian.. */
- apu_set_register(ess, channel, 5, pa&0xFFFF);
- apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF);
- apu_set_register(ess, channel, 7, bsize);
-
- /* clear effects/env.. */
- apu_set_register(ess, channel, 8, 0x00F0);
-
- /* amplitude now? sure. why not. */
- apu_set_register(ess, channel, 9, 0x0000);
-
- /* set filter tune, radius, polar pan */
- apu_set_register(ess, channel, 10, 0x8F08);
-
- /* route input */
- apu_set_register(ess, channel, 11, route);
- }
-
- /* clear WP interrupts */
- outw(1, ess->card->iobase+0x04);
- /* enable WP ints */
- outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
-
- /* let 'er rip */
- set_adc_rate(ess,rate);
- start_adc(ess);
-}
-/* --------------------------------------------------------------------- */
-
-static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count)
-{
- M_printk("set_dmaa??\n");
-}
-
-static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count)
-{
- M_printk("set_dmac??\n");
-}
-
-/* Playback pointer */
-static inline unsigned get_dmaa(struct ess_state *s)
-{
- int offset;
-
- offset = apu_get_register(s,0,5);
-
-/* M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */
-
- offset-=s->dma_dac.base;
-
- return (offset&0xFFFE)<<1; /* hardware is in words */
-}
-
-/* Record pointer */
-static inline unsigned get_dmac(struct ess_state *s)
-{
- int offset;
-
- offset = apu_get_register(s,2,5);
-
-/* M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */
-
- /* The offset is an address not a position relative to base */
- offset-=s->dma_adc.base;
-
- return (offset&0xFFFE)<<1; /* hardware is in words */
-}
-
-/*
- * Meet Bob, the timer...
- */
-
-static irqreturn_t ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-static void stop_bob(struct ess_state *s)
-{
- /* Mask IDR 11,17 */
- maestro_write(s, 0x11, maestro_read(s, 0x11)&~1);
- maestro_write(s, 0x17, maestro_read(s, 0x17)&~1);
-}
-
-/* eventually we could be clever and limit bob ints
- to the frequency at which our smallest duration
- chunks may expire */
-#define ESS_SYSCLK 50000000
-static void start_bob(struct ess_state *s)
-{
- int prescale;
- int divide;
-
- /* XXX make freq selector much smarter, see calc_bob_rate */
- int freq = 200;
-
- /* compute ideal interrupt frequency for buffer size & play rate */
- /* first, find best prescaler value to match freq */
- for(prescale=5;prescale<12;prescale++)
- if(freq > (ESS_SYSCLK>>(prescale+9)))
- break;
-
- /* next, back off prescaler whilst getting divider into optimum range */
- divide=1;
- while((prescale > 5) && (divide<32))
- {
- prescale--;
- divide <<=1;
- }
- divide>>=1;
-
- /* now fine-tune the divider for best match */
- for(;divide<31;divide++)
- if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1)))
- break;
-
- /* divide = 0 is illegal, but don't let prescale = 4! */
- if(divide == 0)
- {
- divide++;
- if(prescale>5)
- prescale--;
- }
-
- maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */
-
- /* Now set IDR 11/17 */
- maestro_write(s, 0x11, maestro_read(s, 0x11)|1);
- maestro_write(s, 0x17, maestro_read(s, 0x17)|1);
-}
-/* --------------------------------------------------------------------- */
-
-/* this quickly calculates the frequency needed for bob
- and sets it if its different than what bob is
- currently running at. its called often so
- needs to be fairly quick. */
-#define BOB_MIN 50
-#define BOB_MAX 400
-static void calc_bob_rate(struct ess_state *s) {
-#if 0 /* this thing tries to set the frequency of bob such that
- there are 2 interrupts / buffer walked by the dac/adc. That
- is probably very wrong for people who actually care about
- mid buffer positioning. it should be calculated as bytes/interrupt
- and that needs to be decided :) so for now just use the static 150
- in start_bob.*/
-
- unsigned int dac_rate=2,adc_rate=1,newrate;
- static int israte=-1;
-
- if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN;
- else {
- dac_rate = (2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
- (s->dma_dac.fragsize) ;
- }
-
- if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN;
- else {
- adc_rate = (2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
- (s->dma_adc.fragsize) ;
- }
-
- if(dac_rate > adc_rate) newrate = adc_rate;
- else newrate=dac_rate;
-
- if(newrate > BOB_MAX) newrate = BOB_MAX;
- else {
- if(newrate < BOB_MIN)
- newrate = BOB_MIN;
- }
-
- if( israte != newrate) {
- printk("dac: %d adc: %d rate: %d\n",dac_rate,adc_rate,israte);
- israte=newrate;
- }
-#endif
-
-}
-
-static int
-prog_dmabuf(struct ess_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- unsigned bytepersec;
- unsigned bufs;
- unsigned char fmt;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- fmt = s->fmt;
- if (rec) {
- stop_adc(s);
- fmt >>= ESS_ADC_SHIFT;
- } else {
- stop_dac(s);
- fmt >>= ESS_DAC_SHIFT;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- fmt &= ESS_FMT_MASK;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
- /* this algorithm is a little nuts.. where did /1000 come from? */
- 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;
-
- M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
-
- memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
-
- spin_lock_irqsave(&s->lock, flags);
- if (rec)
- ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
- else
- ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
-
- spin_unlock_irqrestore(&s->lock, flags);
- db->ready = 1;
-
- return 0;
-}
-
-static __inline__ void
-clear_advance(struct ess_state *s)
-{
- unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
-
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- /* account for wrapping? */
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void
-ess_update_ptr(struct ess_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- /* oh boy should this all be re-written. everything in the current code paths think
- that the various counters/pointers are expressed in bytes to the user but we have
- two apus doing stereo stuff so we fix it up here.. it propagates to all the various
- counters from here. */
- if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
- hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize;
- } else {
- hwptr = get_dmac(s) % s->dma_adc.dmasize;
- }
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- 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))) {
- /* FILL ME
- wrindir(s, SV_CIENABLE, s->enable); */
- stop_adc(s);
- /* brute force everyone back in sync, sigh */
- s->dma_adc.count = 0;
- s->dma_adc.swptr = 0;
- s->dma_adc.hwptr = 0;
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = get_dmaa(s) % s->dma_dac.dmasize;
- /* the apu only reports the length it has seen, not the
- length of the memory that has been used (the WP
- knows that) */
- if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
- hwptr<<=1;
-
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-/* M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
- wake_up(&s->dma_dac.wait);
- }
- } else {
- s->dma_dac.count -= diff;
-/* M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
- if (s->dma_dac.count <= 0) {
- M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count,
- hwptr, s->dma_dac.swptr);
- /* FILL ME
- wrindir(s, SV_CIENABLE, s->enable); */
- /* XXX how on earth can calling this with the lock held work.. */
- stop_dac(s);
- /* brute force everyone back in sync, sigh */
- s->dma_dac.count = 0;
- s->dma_dac.swptr = hwptr;
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
- wake_up(&s->dma_dac.wait);
-/* printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr,
- hwptr);*/
- }
- }
- }
-}
-
-static irqreturn_t
-ess_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct ess_state *s;
- struct ess_card *c = (struct ess_card *)dev_id;
- int i;
- u32 event;
-
- if ( ! (event = inb(c->iobase+0x1A)) )
- return IRQ_NONE;
-
- outw(inw(c->iobase+4)&1, c->iobase+4);
-
-/* M_printk("maestro int: %x\n",event);*/
- if(event&(1<<6))
- {
- int x;
- enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt;
- int volume;
-
- /* Figure out which volume control button was pushed,
- based on differences from the default register
- values. */
- x = inb(c->iobase+0x1c);
- if (x&1) vol_evt = MUTE_EVT;
- else if (((x>>1)&7) > 4) vol_evt = UP_EVT;
- else vol_evt = DOWN_EVT;
-
- /* Reset the volume control registers. */
- outb(0x88, c->iobase+0x1c);
- outb(0x88, c->iobase+0x1d);
- outb(0x88, c->iobase+0x1e);
- outb(0x88, c->iobase+0x1f);
-
- /* Deal with the button press in a hammer-handed
- manner by adjusting the master mixer volume. */
- volume = c->mix.mixer_state[0] & 0xff;
- if (vol_evt == UP_EVT) {
- volume += 5;
- if (volume > 100)
- volume = 100;
- }
- else if (vol_evt == DOWN_EVT) {
- volume -= 5;
- if (volume < 0)
- volume = 0;
- } else {
- /* vol_evt == MUTE_EVT */
- if (volume == 0)
- volume = c->dock_mute_vol;
- else {
- c->dock_mute_vol = volume;
- volume = 0;
- }
- }
- set_mixer (c, 0, (volume << 8) | volume);
- }
-
- /* Ack all the interrupts. */
- outb(0xFF, c->iobase+0x1A);
-
- /*
- * Update the pointers for all APU's we are running.
- */
- for(i=0;i<NR_DSPS;i++)
- {
- s=&c->channels[i];
- if(s->dev_audio == -1)
- break;
- spin_lock(&s->lock);
- ess_update_ptr(s);
- spin_unlock(&s->lock);
- }
- return IRQ_HANDLED;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n";
-
-#define VALIDATE_MAGIC(FOO,MAG) \
-({ \
- if (!(FOO) || (FOO)->magic != MAG) { \
- printk(invalid_magic,__FUNCTION__); \
- return -ENXIO; \
- } \
-})
-
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC)
-
-static void set_mixer(struct ess_card *card,unsigned int 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;
-
- card->mix.mixer_state[mixer]=(right << 8) | left;
- card->mix.write_mixer(card,mixer,left,right);
-}
-
-static void
-mixer_push_state(struct ess_card *card)
-{
- int i;
- for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
- if( ! supported_mixer(card,i)) continue;
-
- set_mixer(card,i,card->mix.mixer_state[i]);
- }
-}
-
-static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg)
-{
- int i, val=0;
- unsigned long flags;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_CARD(card);
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
- strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
- info.modify_counter = card->mix.modcnt;
- 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, card_names[card->card_type], sizeof(info.id));
- strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
-
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* give them the current record source */
-
- if(!card->mix.recmask_io) {
- val = 0;
- } else {
- spin_lock_irqsave(&card->lock, flags);
- val = card->mix.recmask_io(card,1,0);
- spin_unlock_irqrestore(&card->lock, flags);
- }
- break;
-
- case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
- val = card->mix.supported_mixers;
- break;
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- val = card->mix.record_sources;
- break;
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- val = card->mix.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(card,i))
- return -EINVAL;
-
- /* do we ever want to touch the hardware? */
-/* spin_lock_irqsave(&card->lock, flags);
- val = card->mix.read_mixer(card,i);
- spin_unlock_irqrestore(&card->lock, flags);*/
-
- val = card->mix.mixer_state[i];
-/* M_printk("returned 0x%x for mixer %d\n",val,i);*/
-
- break;
- }
- return put_user(val, p);
- }
-
- if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
- return -EINVAL;
-
- card->mix.modcnt++;
-
- if (get_user(val, p))
- return -EFAULT;
-
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-
- if (!card->mix.recmask_io) return -EINVAL;
- if(!val) return 0;
- if(! (val &= card->mix.record_sources)) return -EINVAL;
-
- spin_lock_irqsave(&card->lock, flags);
- card->mix.recmask_io(card,0,val);
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
-
- if ( ! supported_mixer(card,i))
- return -EINVAL;
-
- spin_lock_irqsave(&card->lock, flags);
- set_mixer(card,i,val);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return 0;
- }
-}
-
-/* --------------------------------------------------------------------- */
-static int ess_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct ess_card *card = NULL;
- struct pci_dev *pdev = NULL;
- struct pci_driver *drvr;
-
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- drvr = pci_dev_driver (pdev);
- if (drvr == &maestro_pci_driver) {
- card = (struct ess_card*)pci_get_drvdata (pdev);
- if (!card)
- continue;
- if (card->dev_mixer == minor)
- break;
- }
- }
- if (!card)
- return -ENODEV;
- file->private_data = card;
- return nonseekable_open(inode, file);
-}
-
-static int ess_release_mixdev(struct inode *inode, struct file *file)
-{
- struct ess_card *card = (struct ess_card *)file->private_data;
-
- VALIDATE_CARD(card);
-
- return 0;
-}
-
-static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct ess_card *card = (struct ess_card *)file->private_data;
-
- VALIDATE_CARD(card);
-
- return mixer_ioctl(card, cmd, arg);
-}
-
-static /*const*/ struct file_operations ess_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = ess_ioctl_mixdev,
- .open = ess_open_mixdev,
- .release = ess_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct ess_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait,current);
- unsigned long flags;
- int count;
- signed long tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- /* XXX uhm.. questionable locking*/
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo = (count * HZ) / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
- or something. who cares. - zach */
- if (!schedule_timeout(tmo ? tmo : 1) && tmo)
- M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/* Zach sez: "god this is gross.." */
-static int
-comb_stereo(unsigned char *real_buffer,unsigned char *tmp_buffer, int offset,
- int count, int bufsize)
-{
- /* No such thing as stereo recording, so we
- use dual input mixers. which means we have to
- combine mono to stereo buffer. yuck.
-
- but we don't have to be able to work a byte at a time..*/
-
- unsigned char *so,*left,*right;
- int i;
-
- so = tmp_buffer;
- left = real_buffer + offset;
- right = real_buffer + bufsize/2 + offset;
-
-/* M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/
-
- for(i=count/4; i ; i--) {
- (*(so+2)) = *(right++);
- (*(so+3)) = *(right++);
- (*so) = *(left++);
- (*(so+1)) = *(left++);
- so+=4;
- }
-
- return 0;
-}
-
-/* in this loop, dma_adc.count signifies the amount of data thats waiting
- to be copied to the user's buffer. it is filled by the interrupt
- handler and drained by this loop. */
-static ssize_t
-ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
- unsigned char *combbuf = NULL;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- if(!(combbuf = kmalloc(count,GFP_KERNEL)))
- return -ENOMEM;
- ret = 0;
-
- calc_bob_rate(s);
-
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- /* remember, all these things are expressed in bytes to be
- sent to the user.. hence the evil / 2 down below */
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (cnt > count)
- cnt = count;
-
- if ( cnt > 0 ) cnt &= ~3;
-
- if (cnt <= 0) {
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- {
- ret = ret ? ret : -EAGAIN;
- goto rec_return_free;
- }
- if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
- if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- /* program enhanced mode registers */
- /* FILL ME */
-/* wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current))
- {
- ret = ret ? ret : -ERESTARTSYS;
- goto rec_return_free;
- }
- continue;
- }
-
- if(s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
- /* swptr/2 so that we know the real offset in each apu's buffer */
- comb_stereo(s->dma_adc.rawbuf,combbuf,swptr/2,cnt,s->dma_adc.dmasize);
- if (copy_to_user(buffer, combbuf, cnt)) {
- ret = ret ? ret : -EFAULT;
- goto rec_return_free;
- }
- } else {
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- ret = ret ? ret : -EFAULT;
- goto rec_return_free;
- }
- }
-
- 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;
- start_adc(s);
- }
-
-rec_return_free:
- kfree(combbuf);
- return ret;
-}
-
-static ssize_t
-ess_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- calc_bob_rate(s);
-
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
-
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
-
- cnt = s->dma_dac.dmasize-swptr;
-
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if(!ret) ret = -EAGAIN;
- goto return_free;
- }
- if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
- if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- stop_dac(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- /* program enhanced mode registers */
-/* wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */
- /* FILL ME */
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- goto return_free;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
- goto return_free;
- }
-/* printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/
-
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
-
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(s);
- }
-return_free:
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
-
-/* In 0.14 prog_dmabuf always returns success anyway ... */
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf(s, 0))
- return 0;
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf(s, 1))
- return 0;
- }
-
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &s->dma_dac.wait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &s->dma_adc.wait, wait);
- spin_lock_irqsave(&s->lock, flags);
- ess_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_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int ess_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- goto out;
- db = &s->dma_dac;
- } else
-#if 0
- /* if we can have the wp/wc do the combining
- we can turn this back on. */
- if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
-#endif
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
-/* printk("maestro: ess_ioctl: cmd %d\n", cmd);*/
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.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_dac(s, file->f_flags & O_NONBLOCK);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- /* XXX fix */
- 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_dac(s);
- synchronize_irq(s->card->pcidev->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->card->pcidev->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_dac(s);
- s->dma_dac.ready = 0;
- set_dac_rate(s, val);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_U8|AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- /* fixed at 16bit for now */
- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
-#if 0
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
-#endif
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
- 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->enable & ADC_RUNNING))
- val |= PCM_ENABLE_INPUT;
- if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING))
- 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(s, 1)))
- return ret;
- start_adc(s);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- start_dac(s);
- } else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.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 && (ret = prog_dmabuf(s, 1)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.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_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.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_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.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(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- M_printk("maestro: SETFRAGMENT: %0x\n",val);
- 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_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;
- }
- 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, 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_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return -EINVAL;
-}
-
-static void
-set_base_registers(struct ess_state *s,void *vaddr)
-{
- unsigned long packed_phys = virt_to_bus(vaddr)>>12;
- wave_set_register(s, 0x01FC , packed_phys);
- wave_set_register(s, 0x01FD , packed_phys);
- wave_set_register(s, 0x01FE , packed_phys);
- wave_set_register(s, 0x01FF , packed_phys);
-}
-
-/*
- * this guy makes sure we're in the right power
- * state for what we want to be doing
- */
-static void maestro_power(struct ess_card *card, int tostate)
-{
- u16 active_mask = acpi_state_mask[tostate];
- u8 state;
-
- if(!use_pm) return;
-
- pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state);
- state&=3;
-
- /* make sure we're in the right state */
- if(state != tostate) {
- M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n",
- card->pcidev->bus->number,
- PCI_SLOT(card->pcidev->devfn),
- PCI_FUNC(card->pcidev->devfn),
- state,tostate);
- pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate);
- }
-
- /* and make sure the units we care about are on
- XXX we might want to do this before state flipping? */
- pci_write_config_word(card->pcidev, 0x54, ~ active_mask);
- pci_write_config_word(card->pcidev, 0x56, ~ active_mask);
-}
-
-/* we allocate a large power of two for all our memory.
- this is cut up into (not to scale :):
- |silly fifo word | 512byte mixbuf per adc | dac/adc * channels |
-*/
-static int
-allocate_buffers(struct ess_state *s)
-{
- void *rawbuf=NULL;
- int order,i;
- struct page *page, *pend;
-
- /* alloc as big a chunk as we can */
- for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
- if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
- break;
-
- if (!rawbuf)
- return 1;
-
- M_printk("maestro: allocated %ld (%d) bytes at %p\n",PAGE_SIZE<<order,order, rawbuf);
-
- if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~((1<<28)-1)) {
- printk(KERN_ERR "maestro: DMA buffer beyond 256MB! busaddr 0x%lx size %ld\n",
- virt_to_bus(rawbuf), PAGE_SIZE << order);
- kfree(rawbuf);
- return 1;
- }
-
- s->card->dmapages = rawbuf;
- s->card->dmaorder = order;
-
- for(i=0;i<NR_DSPS;i++) {
- struct ess_state *ess = &s->card->channels[i];
-
- if(ess->dev_audio == -1)
- continue;
-
- ess->dma_dac.ready = s->dma_dac.mapped = 0;
- ess->dma_adc.ready = s->dma_adc.mapped = 0;
- ess->dma_adc.buforder = ess->dma_dac.buforder = order - 1 - dsps_order - 1;
-
- /* offset dac and adc buffers starting half way through and then at each [da][ad]c's
- order's intervals.. */
- ess->dma_dac.rawbuf = rawbuf + (PAGE_SIZE<<(order-1)) + (i * ( PAGE_SIZE << (ess->dma_dac.buforder + 1 )));
- ess->dma_adc.rawbuf = ess->dma_dac.rawbuf + ( PAGE_SIZE << ess->dma_dac.buforder);
- /* offset mixbuf by a mixbuf so that the lame status fifo can
- happily scribble away.. */
- ess->mixbuf = rawbuf + (512 * (i+1));
-
- M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf,
- ess->dma_adc.rawbuf, ess->mixbuf);
-
- }
-
- /* 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;
-}
-static void
-free_buffers(struct ess_state *s)
-{
- struct page *page, *pend;
-
- s->dma_dac.rawbuf = s->dma_adc.rawbuf = NULL;
- s->dma_dac.mapped = s->dma_adc.mapped = 0;
- s->dma_dac.ready = s->dma_adc.ready = 0;
-
- M_printk("maestro: freeing %p\n",s->card->dmapages);
- /* undo marking the pages as reserved */
-
- pend = virt_to_page(s->card->dmapages + (PAGE_SIZE << s->card->dmaorder) - 1);
- for (page = virt_to_page(s->card->dmapages); page <= pend; page++)
- ClearPageReserved(page);
-
- free_pages((unsigned long)s->card->dmapages,s->card->dmaorder);
- s->card->dmapages = NULL;
-}
-
-static int
-ess_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct ess_state *s = NULL;
- unsigned char fmtm = ~0, fmts = 0;
- struct pci_dev *pdev = NULL;
- /*
- * Scan the cards and find the channel. We only
- * do this at open time so it is ok
- */
-
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- struct ess_card *c;
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver (pdev);
- if (drvr == &maestro_pci_driver) {
- int i;
- struct ess_state *sp;
-
- c = (struct ess_card*)pci_get_drvdata (pdev);
- if (!c)
- continue;
- for(i=0;i<NR_DSPS;i++)
- {
- sp=&c->channels[i];
- if(sp->dev_audio < 0)
- continue;
- if((sp->dev_audio ^ minor) & ~0xf)
- continue;
- s=sp;
- }
- }
- }
- if (!s)
- return -ENODEV;
-
- 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 -EWOULDBLOCK;
- }
- mutex_unlock(&s->open_mutex);
- interruptible_sleep_on(&s->open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
-
- /* under semaphore.. */
- if ((s->card->dmapages==NULL) && allocate_buffers(s)) {
- mutex_unlock(&s->open_mutex);
- return -ENOMEM;
- }
-
- /* we're covered by the open_mutex */
- if( ! s->card->dsps_open ) {
- maestro_power(s->card,ACPI_D0);
- start_bob(s);
- }
- s->card->dsps_open++;
- M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
-
- /* ok, lets write WC base regs now that we've
- powered up the chip */
- M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages),
- ((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12);
- set_base_registers(s,s->card->dmapages);
-
- if (file->f_mode & FMODE_READ) {
-/*
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; */
-
- fmtm &= ~((ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT);
- fmts = (ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT;
-
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- set_adc_rate(s, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- set_dac_rate(s, 8000);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int
-ess_release(struct inode *inode, struct file *file)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- }
-
- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- /* we're covered by the open_mutex */
- M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
- if( --s->card->dsps_open <= 0) {
- s->card->dsps_open = 0;
- stop_bob(s);
- free_buffers(s);
- maestro_power(s->card,ACPI_D2);
- }
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static struct file_operations ess_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ess_read,
- .write = ess_write,
- .poll = ess_poll,
- .ioctl = ess_ioctl,
- .mmap = ess_mmap,
- .open = ess_open,
- .release = ess_release,
-};
-
-static int
-maestro_config(struct ess_card *card)
-{
- struct pci_dev *pcidev = card->pcidev;
- struct ess_state *ess = &card->channels[0];
- int apu,iobase = card->iobase;
- u16 w;
- u32 n;
-
- /* We used to muck around with pci config space that
- * we had no business messing with. We don't know enough
- * about the machine to know which DMA mode is appropriate,
- * etc. We were guessing wrong on some machines and making
- * them unhappy. We now trust in the BIOS to do things right,
- * which almost certainly means a new host of problems will
- * arise with broken BIOS implementations. screw 'em.
- * We're already intolerant of machines that don't assign
- * IRQs.
- */
-
- /* do config work at full power */
- maestro_power(card,ACPI_D0);
-
- pci_read_config_word(pcidev, 0x50, &w);
-
- w&=~(1<<5); /* Don't swap left/right (undoc)*/
-
- pci_write_config_word(pcidev, 0x50, w);
-
- pci_read_config_word(pcidev, 0x52, &w);
- w&=~(1<<15); /* Turn off internal clock multiplier */
- /* XXX how do we know which to use? */
- w&=~(1<<14); /* External clock */
-
- w|= (1<<7); /* Hardware volume control on */
- w|= (1<<6); /* Debounce off: easier to push the HWV buttons. */
- w&=~(1<<5); /* GPIO 4:5 */
- w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */
- w&=~(1<<2); /* MIDI fix off (undoc) */
- w&=~(1<<1); /* reserved, always write 0 */
- pci_write_config_word(pcidev, 0x52, w);
-
- /*
- * Legacy mode
- */
-
- pci_read_config_word(pcidev, 0x40, &w);
- w|=(1<<15); /* legacy decode off */
- w&=~(1<<14); /* Disable SIRQ */
- w&=~(0x1f); /* disable mpu irq/io, game port, fm, SB */
-
- pci_write_config_word(pcidev, 0x40, w);
-
- /* Set up 978 docking control chip. */
- pci_read_config_word(pcidev, 0x58, &w);
- w|=1<<2; /* Enable 978. */
- w|=1<<3; /* Turn on 978 hardware volume control. */
- w&=~(1<<11); /* Turn on 978 mixer volume control. */
- pci_write_config_word(pcidev, 0x58, w);
-
- sound_reset(iobase);
-
- /*
- * Ring Bus Setup
- */
-
- /* setup usual 0x34 stuff.. 0x36 may be chip specific */
- outw(0xC090, iobase+0x34); /* direct sound, stereo */
- udelay(20);
- outw(0x3000, iobase+0x36); /* direct sound, stereo */
- udelay(20);
-
-
- /*
- * Reset the CODEC
- */
-
- maestro_ac97_reset(iobase,pcidev);
-
- /*
- * Ring Bus Setup
- */
-
- n=inl(iobase+0x34);
- n&=~0xF000;
- n|=12<<12; /* Direct Sound, Stereo */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x0F00; /* Modem off */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x00F0;
- n|=9<<4; /* DAC, Stereo */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x000F; /* ASSP off */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n|=(1<<29); /* Enable ring bus */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n|=(1<<28); /* Enable serial bus */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x00F00000; /* MIC off */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x000F0000; /* I2S off */
- outl(n, iobase+0x34);
-
-
- w=inw(iobase+0x18);
- w&=~(1<<7); /* ClkRun off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<6); /* Hardware volume control interrupt off... for now. */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<4); /* ASSP irq off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<3); /* ISDN irq off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w|=(1<<2); /* Direct Sound IRQ on */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<1); /* MPU401 IRQ off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w|=(1<<0); /* SB IRQ on */
- outw(w, iobase+0x18);
-
- /* Set hardware volume control registers to midpoints.
- We can tell which button was pushed based on how they change. */
- outb(0x88, iobase+0x1c);
- outb(0x88, iobase+0x1d);
- outb(0x88, iobase+0x1e);
- outb(0x88, iobase+0x1f);
-
- /* it appears some maestros (dell 7500) only work if these are set,
- regardless of whether we use the assp or not. */
-
- outb(0, iobase+0xA4);
- outb(3, iobase+0xA2);
- outb(0, iobase+0xA6);
-
- for(apu=0;apu<16;apu++)
- {
- /* Write 0 into the buffer area 0x1E0->1EF */
- outw(0x01E0+apu, 0x10+iobase);
- outw(0x0000, 0x12+iobase);
-
- /*
- * The 1.10 test program seem to write 0 into the buffer area
- * 0x1D0-0x1DF too.
- */
- outw(0x01D0+apu, 0x10+iobase);
- outw(0x0000, 0x12+iobase);
- }
-
-#if 1
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00));
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100);
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200);
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400);
-#else
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00));
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100);
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200);
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400);
-#endif
-
- maestro_write(ess, IDR2_CRAM_DATA, 0x0000);
- maestro_write(ess, 0x08, 0xB004);
- /* Now back to the DirectSound stuff */
- maestro_write(ess, 0x09, 0x001B);
- maestro_write(ess, 0x0A, 0x8000);
- maestro_write(ess, 0x0B, 0x3F37);
- maestro_write(ess, 0x0C, 0x0098);
-
- /* parallel out ?? */
- maestro_write(ess, 0x0C,
- (maestro_read(ess, 0x0C)&~0xF000)|0x8000);
- /* parallel in, has something to do with recording :) */
- maestro_write(ess, 0x0C,
- (maestro_read(ess, 0x0C)&~0x0F00)|0x0500);
-
- maestro_write(ess, 0x0D, 0x7632);
-
- /* Wave cache control on - test off, sg off,
- enable, enable extra chans 1Mb */
-
- outw(inw(0x14+iobase)|(1<<8),0x14+iobase);
- outw(inw(0x14+iobase)&0xFE03,0x14+iobase);
- outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase);
- outw(inw(0x14+iobase)|(1<<7),0x14+iobase);
-
- outw(0xA1A0, 0x14+iobase); /* 0300 ? */
-
- /* Now clear the APU control ram */
- for(apu=0;apu<NR_APUS;apu++)
- {
- for(w=0;w<NR_APU_REGS;w++)
- apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0);
-
- }
-
- return 0;
-
-}
-
-/* this guy tries to find the pci power management
- * register bank. this should really be in core
- * code somewhere. 1 on success. */
-static int
-parse_power(struct ess_card *card, struct pci_dev *pcidev)
-{
- u32 n;
- u16 w;
- u8 next;
- int max = 64; /* an a 8bit guy pointing to 32bit guys
- can only express so much. */
-
- card->power_regs = 0;
-
- /* check to see if we have a capabilities list in
- the config register */
- pci_read_config_word(pcidev, PCI_STATUS, &w);
- if(!(w & PCI_STATUS_CAP_LIST)) return 0;
-
- /* walk the list, starting at the head. */
- pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next);
-
- while(next && max--) {
- pci_read_config_dword(pcidev, next & ~3, &n);
- if((n & 0xff) == PCI_CAP_ID_PM) {
- card->power_regs = next;
- break;
- }
- next = ((n>>8) & 0xff);
- }
-
- return card->power_regs ? 1 : 0;
-}
-
-static int __init
-maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid)
-{
- int card_type = pdid->driver_data;
- u32 n;
- int iobase;
- int i, ret;
- struct ess_card *card;
- struct ess_state *ess;
- int num = 0;
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
- static int printed_version;
- if (!printed_version++)
- printk(version);
-#endif
-
- /* don't pick up weird modem maestros */
- if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
- return -ENODEV;
-
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
-
- iobase = pci_resource_start(pcidev,0);
- if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO))
- return -ENODEV;
-
- if(pcidev->irq == 0)
- return -ENODEV;
-
- /* stake our claim on the iospace */
- if( request_region(iobase, 256, card_names[card_type]) == NULL )
- {
- printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
- return -EBUSY;
- }
-
- /* just to be sure */
- pci_set_master(pcidev);
-
- card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
- if(card == NULL)
- {
- printk(KERN_WARNING "maestro: out of memory\n");
- release_region(iobase, 256);
- return -ENOMEM;
- }
-
- memset(card, 0, sizeof(*card));
- card->pcidev = pcidev;
-
- card->iobase = iobase;
- card->card_type = card_type;
- card->irq = pcidev->irq;
- card->magic = ESS_CARD_MAGIC;
- spin_lock_init(&card->lock);
- init_waitqueue_head(&card->suspend_queue);
-
- card->dock_mute_vol = 50;
-
- /* init our groups of 6 apus */
- for(i=0;i<NR_DSPS;i++)
- {
- struct ess_state *s=&card->channels[i];
-
- s->index = i;
-
- s->card = card;
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- spin_lock_init(&s->lock);
- mutex_init(&s->open_mutex);
- s->magic = ESS_STATE_MAGIC;
-
- s->apu[0] = 6*i;
- s->apu[1] = (6*i)+1;
- s->apu[2] = (6*i)+2;
- s->apu[3] = (6*i)+3;
- s->apu[4] = (6*i)+4;
- s->apu[5] = (6*i)+5;
-
- if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
- printk("maestro: BOTCH!\n");
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0)
- break;
- }
-
- num = i;
-
- /* clear the rest if we ran out of slots to register */
- for(;i<NR_DSPS;i++)
- {
- struct ess_state *s=&card->channels[i];
- s->dev_audio = -1;
- }
-
- ess = &card->channels[0];
-
- /*
- * Ok card ready. Begin setup proper
- */
-
- printk(KERN_INFO "maestro: Configuring %s found at IO 0x%04X IRQ %d\n",
- card_names[card_type],iobase,card->irq);
- pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
- printk(KERN_INFO "maestro: subvendor id: 0x%08x\n",n);
-
- /* turn off power management unless:
- * - the user explicitly asks for it
- * or
- * - we're not a 2e, lesser chipps seem to have problems.
- * - we're not on our _very_ small whitelist. some implemenetations
- * really don't like the pm code, others require it.
- * feel free to expand this as required.
- */
-#define SUBSYSTEM_VENDOR(x) (x&0xffff)
- if( (use_pm != 1) &&
- ((card_type != TYPE_MAESTRO2E) || (SUBSYSTEM_VENDOR(n) != 0x1028)))
- use_pm = 0;
-
- if(!use_pm)
- printk(KERN_INFO "maestro: not attempting power management.\n");
- else {
- if(!parse_power(card,pcidev))
- printk(KERN_INFO "maestro: no PCI power management interface found.\n");
- else {
- pci_read_config_dword(pcidev, card->power_regs, &n);
- printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16);
- }
- }
-
- maestro_config(card);
-
- if(maestro_ac97_get(card, 0x00)==0x0080) {
- printk(KERN_ERR "maestro: my goodness! you seem to have a pt101 codec, which is quite rare.\n"
- "\tyou should tell someone about this.\n");
- } else {
- maestro_ac97_init(card);
- }
-
- if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) {
- printk("maestro: couldn't register mixer!\n");
- } else {
- memcpy(card->mix.mixer_state,mixer_defaults,sizeof(card->mix.mixer_state));
- mixer_push_state(card);
- }
-
- if((ret=request_irq(card->irq, ess_interrupt, IRQF_SHARED, card_names[card_type], card)))
- {
- printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq);
- unregister_sound_mixer(card->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
- struct ess_state *s = &card->channels[i];
- if(s->dev_audio != -1)
- unregister_sound_dsp(s->dev_audio);
- }
- release_region(card->iobase, 256);
- unregister_reboot_notifier(&maestro_nb);
- kfree(card);
- return ret;
- }
-
- /* Turn on hardware volume control interrupt.
- This has to come after we grab the IRQ above,
- or a crash will result on installation if a button has been pressed,
- because in that case we'll get an immediate interrupt. */
- n = inw(iobase+0x18);
- n|=(1<<6);
- outw(n, iobase+0x18);
-
- pci_set_drvdata(pcidev,card);
- /* now go to sleep 'till something interesting happens */
- maestro_power(card,ACPI_D2);
-
- printk(KERN_INFO "maestro: %d channels configured.\n", num);
- return 0;
-}
-
-static void maestro_remove(struct pci_dev *pcidev) {
- struct ess_card *card = pci_get_drvdata(pcidev);
- int i;
- u32 n;
-
- /* XXX maybe should force stop bob, but should be all
- stopped by _release by now */
-
- /* Turn off hardware volume control interrupt.
- This has to come before we leave the IRQ below,
- or a crash results if a button is pressed ! */
- n = inw(card->iobase+0x18);
- n&=~(1<<6);
- outw(n, card->iobase+0x18);
-
- free_irq(card->irq, card);
- unregister_sound_mixer(card->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
- struct ess_state *ess = &card->channels[i];
- if(ess->dev_audio != -1)
- unregister_sound_dsp(ess->dev_audio);
- }
- /* Goodbye, Mr. Bond. */
- maestro_power(card,ACPI_D3);
- release_region(card->iobase, 256);
- kfree(card);
- pci_set_drvdata(pcidev,NULL);
-}
-
-static struct pci_device_id maestro_pci_tbl[] = {
- {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2},
- {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E},
- {PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO},
- {0,}
-};
-MODULE_DEVICE_TABLE(pci, maestro_pci_tbl);
-
-static struct pci_driver maestro_pci_driver = {
- .name = "maestro",
- .id_table = maestro_pci_tbl,
- .probe = maestro_probe,
- .remove = maestro_remove,
-};
-
-static int __init init_maestro(void)
-{
- int rc;
-
- rc = pci_register_driver(&maestro_pci_driver);
- if (rc < 0)
- return rc;
-
- if (register_reboot_notifier(&maestro_nb))
- printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
-#ifdef MODULE
- printk(version);
-#endif
- if (dsps_order < 0) {
- dsps_order = 1;
- printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
- }
- else if (dsps_order > MAX_DSP_ORDER) {
- dsps_order = MAX_DSP_ORDER;
- printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
- }
- return 0;
-}
-
-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
-{
- /* this notifier is called when the kernel is really shut down. */
- M_printk("maestro: shutting down\n");
- /* this will remove all card instances too */
- pci_unregister_driver(&maestro_pci_driver);
- /* XXX dunno about power management */
- return NOTIFY_OK;
-}
-
-/* --------------------------------------------------------------------- */
-
-
-static void cleanup_maestro(void) {
- M_printk("maestro: unloading\n");
- pci_unregister_driver(&maestro_pci_driver);
- unregister_reboot_notifier(&maestro_nb);
-}
-
-/* --------------------------------------------------------------------- */
-
-void
-check_suspend(struct ess_card *card)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- if(!card->in_suspend) return;
-
- card->in_suspend++;
- add_wait_queue(&(card->suspend_queue), &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- schedule();
- remove_wait_queue(&(card->suspend_queue), &wait);
- current->state = TASK_RUNNING;
-}
-
-module_init(init_maestro);
-module_exit(cleanup_maestro);
diff --git a/sound/oss/maestro.h b/sound/oss/maestro.h
deleted file mode 100644
index 023ec7f..0000000
--- a/sound/oss/maestro.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Registers for the ESS PCI cards
- */
-
-/*
- * Memory access
- */
-
-#define ESS_MEM_DATA 0x00
-#define ESS_MEM_INDEX 0x02
-
-/*
- * AC-97 Codec port. Delay 1uS after each write. This is used to
- * talk AC-97 (see intel.com). Write data then register.
- */
-
-#define ESS_AC97_INDEX 0x30 /* byte wide */
-#define ESS_AC97_DATA 0x32
-
-/*
- * Reading is a bit different. You write register|0x80 to ubdex
- * delay 1uS poll the low bit of index, when it clears read the
- * data value.
- */
-
-/*
- * Control port. Not yet fully understood
- * The value 0xC090 gets loaded to it then 0x0000 and 0x2800
- * to the data port. Then after 4uS the value 0x300 is written
- */
-
-#define RING_BUS_CTRL_L 0x34
-#define RING_BUS_CTRL_H 0x36
-
-/*
- * This is also used during setup. The value 0x17 is written to it
- */
-
-#define ESS_SETUP_18 0x18
-
-/*
- * And this one gets 0x000b
- */
-
-#define ESS_SETUP_A2 0xA2
-
-/*
- * And this 0x0000
- */
-
-#define ESS_SETUP_A4 0xA4
-#define ESS_SETUP_A6 0xA6
-
-/*
- * Stuff to do with Harpo - the wave stuff
- */
-
-#define ESS_WAVETABLE_SIZE 0x14
-#define ESS_WAVETABLE_2M 0xA180
-
diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c
deleted file mode 100644
index 5548e3c..0000000
--- a/sound/oss/maestro3.c
+++ /dev/null
@@ -1,2969 +0,0 @@
-/*****************************************************************************
- *
- * ESS Maestro3/Allegro driver for Linux 2.4.x
- *
- * 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.
- *
- * (c) Copyright 2000 Zach Brown <zab@zabbo.net>
- *
- * I need to thank many people for helping make this driver happen.
- * As always, Eric Brombaugh was a hacking machine and killed many bugs
- * that I was too dumb to notice. Howard Kim at ESS provided reference boards
- * and as much docs as he could. Todd and Mick at Dell tested snapshots on
- * an army of laptops. msw and deviant at Red Hat also humoured me by hanging
- * their laptops every few hours in the name of science.
- *
- * Shouts go out to Mike "DJ XPCom" Ang.
- *
- * History
- * v1.23 - Jun 5 2002 - Michael Olson <olson@cs.odu.edu>
- * added a module option to allow selection of GPIO pin number
- * for external amp
- * v1.22 - Feb 28 2001 - Zach Brown <zab@zabbo.net>
- * allocate mem at insmod/setup, rather than open
- * limit pci dma addresses to 28bit, thanks guys.
- * v1.21 - Feb 04 2001 - Zach Brown <zab@zabbo.net>
- * fix up really dumb notifier -> suspend oops
- * v1.20 - Jan 30 2001 - Zach Brown <zab@zabbo.net>
- * get rid of pm callback and use pci_dev suspend/resume instead
- * m3_probe cleanups, including pm oops think-o
- * v1.10 - Jan 6 2001 - Zach Brown <zab@zabbo.net>
- * revert to lame remap_page_range mmap() just to make it work
- * record mmap fixed.
- * fix up incredibly broken open/release resource management
- * duh. fix record format setting.
- * add SMP locking and cleanup formatting here and there
- * v1.00 - Dec 16 2000 - Zach Brown <zab@zabbo.net>
- * port to sexy 2.4 interfaces
- * properly align instance allocations so recording works
- * clean up function namespace a little :/
- * update PCI IDs based on mail from ESS
- * arbitrarily bump version number to show its 2.4 now,
- * 2.2 will stay 0., oss_audio port gets 2.
- * v0.03 - Nov 05 2000 - Zach Brown <zab@zabbo.net>
- * disable recording but allow dsp to be opened read
- * pull out most silly compat defines
- * v0.02 - Nov 04 2000 - Zach Brown <zab@zabbo.net>
- * changed clocking setup for m3, slowdown fixed.
- * codec reset is hopefully reliable now
- * rudimentary apm/power management makes suspend/resume work
- * v0.01 - Oct 31 2000 - Zach Brown <zab@zabbo.net>
- * first release
- * v0.00 - Sep 09 2000 - Zach Brown <zab@zabbo.net>
- * first pass derivation from maestro.c
- *
- * TODO
- * in/out allocated contiguously so fullduplex mmap will work?
- * no beep on init (mute)
- * resetup msrc data memory if freq changes?
- *
- * --
- *
- * Allow me to ramble a bit about the m3 architecture. The core of the
- * chip is the 'assp', the custom ESS dsp that runs the show. It has
- * a small amount of code and data ram. ESS drops binary dsp code images
- * on our heads, but we don't get to see specs on the dsp.
- *
- * The constant piece of code on the dsp is the 'kernel'. It also has a
- * chunk of the dsp memory that is statically set aside for its control
- * info. This is the KDATA defines in maestro3.h. Part of its core
- * data is a list of code addresses that point to the pieces of DSP code
- * that it should walk through in its loop. These other pieces of code
- * do the real work. The kernel presumably jumps into each of them in turn.
- * These code images tend to have their own data area, and one can have
- * multiple data areas representing different states for each of the 'client
- * instance' code portions. There is generally a list in the kernel data
- * that points to the data instances for a given piece of code.
- *
- * We've only been given the binary image for the 'minisrc', mini sample
- * rate converter. This is rather annoying because it limits the work
- * we can do on the dsp, but it also greatly simplifies the job of managing
- * dsp data memory for the code and data for our playing streams :). We
- * statically allocate the minisrc code into a region we 'know' to be free
- * based on the map of the binary kernel image we're loading. We also
- * statically allocate the data areas for the maximum number of pcm streams
- * we can be dealing with. This max is set by the length of the static list
- * in the kernel data that records the number of minisrc data regions we
- * can have. Thats right, all software dsp mixing with static code list
- * limits. Rock.
- *
- * How sound goes in and out is still a relative mystery. It appears
- * that the dsp has the ability to get input and output through various
- * 'connections'. To do IO from or to a connection, you put the address
- * of the minisrc client area in the static kernel data lists for that
- * input or output. so for pcm -> dsp -> mixer, we put the minisrc data
- * instance in the DMA list and also in the list for the mixer. I guess
- * it Just Knows which is in/out, and we give some dma control info that
- * helps. There are all sorts of cool inputs/outputs that it seems we can't
- * use without dsp code images that know how to use them.
- *
- * So at init time we preload all the memory allocation stuff and set some
- * system wide parameters. When we really get a sound to play we build
- * up its minisrc header (stream parameters, buffer addresses, input/output
- * settings). Then we throw its header on the various lists. We also
- * tickle some KDATA settings that ask the assp to raise clock interrupts
- * and do some amount of software mixing before handing data to the ac97.
- *
- * Sorry for the vague details. Feel free to ask Eric or myself if you
- * happen to be trying to use this driver elsewhere. Please accept my
- * apologies for the quality of the OSS support code, its passed through
- * too many hands now and desperately wants to be rethought.
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.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/vmalloc.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/reboot.h>
-#include <linux/spinlock.h>
-#include <linux/ac97_codec.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "maestro3.h"
-
-#define M_DEBUG 1
-
-#define DRIVER_VERSION "1.23"
-#define M3_MODULE_NAME "maestro3"
-#define PFX M3_MODULE_NAME ": "
-
-#define M3_STATE_MAGIC 0x734d724d
-#define M3_CARD_MAGIC 0x646e6f50
-
-#define ESS_FMT_STEREO 0x01
-#define ESS_FMT_16BIT 0x02
-#define ESS_FMT_MASK 0x03
-#define ESS_DAC_SHIFT 0
-#define ESS_ADC_SHIFT 4
-
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
-
-#define SND_DEV_DSP16 5
-
-#ifdef M_DEBUG
-static int debug;
-#define DPMOD 1 /* per module load */
-#define DPSTR 2 /* per 'stream' */
-#define DPSYS 3 /* per syscall */
-#define DPCRAP 4 /* stuff the user shouldn't see unless they're really debuggin */
-#define DPINT 5 /* per interrupt, LOTS */
-#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);}
-#else
-#define DPRINTK(x)
-#endif
-
-struct m3_list {
- int curlen;
- u16 mem_addr;
- int max;
-};
-
-static int external_amp = 1;
-static int gpio_pin = -1;
-
-struct m3_state {
- unsigned int magic;
- struct m3_card *card;
- unsigned char fmt, enable;
-
- int index;
-
- /* this locks around the oss state in the driver */
- /* no, this lock is removed - only use card->lock */
- /* otherwise: against what are you protecting on SMP
- when irqhandler uses s->lock
- and m3_assp_read uses card->lock ?
- */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
- mode_t open_mode;
-
- int dev_audio;
-
- struct assp_instance {
- u16 code, data;
- } dac_inst, adc_inst;
-
- /* should be in dmabuf */
- unsigned int rateadc, ratedac;
-
- struct dmabuf {
- void *rawbuf;
- 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 ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- /* new in m3 */
- int mixer_index, dma_index, msrc_index, adc1_index;
- int in_lists;
- /* 2.4.. */
- dma_addr_t handle;
-
- } dma_dac, dma_adc;
-};
-
-struct m3_card {
- unsigned int magic;
-
- struct m3_card *next;
-
- struct ac97_codec *ac97;
- spinlock_t ac97_lock;
-
- int card_type;
-
-#define NR_DSPS 1
-#define MAX_DSPS NR_DSPS
- struct m3_state channels[MAX_DSPS];
-
- /* this locks around the physical registers on the card */
- spinlock_t lock;
-
- /* hardware resources */
- struct pci_dev *pcidev;
- u32 iobase;
- u32 irq;
-
- int dacs_active;
-
- int timer_users;
-
- struct m3_list msrc_list,
- mixer_list,
- adc1_list,
- dma_list;
-
- /* for storing reset state..*/
- u8 reset_state;
-
- u16 *suspend_mem;
- int in_suspend;
- wait_queue_head_t suspend_queue;
-};
-
-/*
- * an arbitrary volume we set the internal
- * volume settings to so that the ac97 volume
- * range is a little less insane. 0x7fff is
- * max.
- */
-#define ARB_VOLUME ( 0x6800 )
-
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-enum {
- ESS_ALLEGRO,
- ESS_MAESTRO3,
- /*
- * a maestro3 with 'hardware strapping', only
- * found inside ESS?
- */
- ESS_MAESTRO3HW,
-};
-
-static char *card_names[] = {
- [ESS_ALLEGRO] = "Allegro",
- [ESS_MAESTRO3] = "Maestro3(i)",
- [ESS_MAESTRO3HW] = "Maestro3(i)hw"
-};
-
-#ifndef PCI_VENDOR_ESS
-#define PCI_VENDOR_ESS 0x125D
-#endif
-
-#define M3_DEVICE(DEV, TYPE) \
-{ \
-.vendor = PCI_VENDOR_ESS, \
-.device = DEV, \
-.subvendor = PCI_ANY_ID, \
-.subdevice = PCI_ANY_ID, \
-.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, \
-.class_mask = 0xffff << 8, \
-.driver_data = TYPE, \
-}
-
-static struct pci_device_id m3_id_table[] = {
- M3_DEVICE(0x1988, ESS_ALLEGRO),
- M3_DEVICE(0x1998, ESS_MAESTRO3),
- M3_DEVICE(0x199a, ESS_MAESTRO3HW),
- {0,}
-};
-
-MODULE_DEVICE_TABLE (pci, m3_id_table);
-
-/*
- * reports seem to indicate that the m3 is limited
- * to 28bit bus addresses. aaaargggh...
- */
-#define M3_PCI_DMA_MASK 0x0fffffff
-
-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 struct m3_card *devs;
-
-/*
- * I'm not very good at laying out functions in a file :)
- */
-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state);
-static void check_suspend(struct m3_card *card);
-
-static struct notifier_block m3_reboot_nb = {
- .notifier_call = m3_notifier,
-};
-
-static void m3_outw(struct m3_card *card,
- u16 value, unsigned long reg)
-{
- check_suspend(card);
- outw(value, card->iobase + reg);
-}
-
-static u16 m3_inw(struct m3_card *card, unsigned long reg)
-{
- check_suspend(card);
- return inw(card->iobase + reg);
-}
-static void m3_outb(struct m3_card *card,
- u8 value, unsigned long reg)
-{
- check_suspend(card);
- outb(value, card->iobase + reg);
-}
-static u8 m3_inb(struct m3_card *card, unsigned long reg)
-{
- check_suspend(card);
- return inb(card->iobase + reg);
-}
-
-/*
- * access 16bit words to the code or data regions of the dsp's memory.
- * index addresses 16bit words.
- */
-static u16 __m3_assp_read(struct m3_card *card, u16 region, u16 index)
-{
- m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
- m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
- return m3_inw(card, DSP_PORT_MEMORY_DATA);
-}
-static u16 m3_assp_read(struct m3_card *card, u16 region, u16 index)
-{
- unsigned long flags;
- u16 ret;
-
- spin_lock_irqsave(&(card->lock), flags);
- ret = __m3_assp_read(card, region, index);
- spin_unlock_irqrestore(&(card->lock), flags);
-
- return ret;
-}
-
-static void __m3_assp_write(struct m3_card *card,
- u16 region, u16 index, u16 data)
-{
- m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
- m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
- m3_outw(card, data, DSP_PORT_MEMORY_DATA);
-}
-static void m3_assp_write(struct m3_card *card,
- u16 region, u16 index, u16 data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&(card->lock), flags);
- __m3_assp_write(card, region, index, data);
- spin_unlock_irqrestore(&(card->lock), flags);
-}
-
-static void m3_assp_halt(struct m3_card *card)
-{
- card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
- mdelay(10);
- m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
-}
-
-static void m3_assp_continue(struct m3_card *card)
-{
- m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
-}
-
-/*
- * This makes me sad. the maestro3 has lists
- * internally that must be packed.. 0 terminates,
- * apparently, or maybe all unused entries have
- * to be 0, the lists have static lengths set
- * by the binary code images.
- */
-
-static int m3_add_list(struct m3_card *card,
- struct m3_list *list, u16 val)
-{
- DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n",
- val, list, list->curlen);
-
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + list->curlen,
- val);
-
- return list->curlen++;
-
-}
-
-static void m3_remove_list(struct m3_card *card,
- struct m3_list *list, int index)
-{
- u16 val;
- int lastindex = list->curlen - 1;
-
- DPRINTK(DPSTR, "removing ind %d from list 0x%p\n",
- index, list);
-
- if(index != lastindex) {
- val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + lastindex);
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + index,
- val);
- }
-
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + lastindex,
- 0);
-
- list->curlen--;
-}
-
-static void set_fmt(struct m3_state *s, unsigned char mask, unsigned char data)
-{
- int tmp;
-
- s->fmt = (s->fmt & mask) | data;
-
- tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
-
- /* write to 'mono' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1,
- (tmp & ESS_FMT_STEREO) ? 0 : 1);
- /* write to '8bit' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2,
- (tmp & ESS_FMT_16BIT) ? 0 : 1);
-
- tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK;
-
- /* write to 'mono' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1,
- (tmp & ESS_FMT_STEREO) ? 0 : 1);
- /* write to '8bit' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2,
- (tmp & ESS_FMT_16BIT) ? 0 : 1);
-}
-
-static void set_dac_rate(struct m3_state *s, unsigned int rate)
-{
- u32 freq;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
-
- s->ratedac = rate;
-
- freq = ((rate << 15) + 24000 ) / 48000;
- if(freq)
- freq--;
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_FREQUENCY,
- freq);
-}
-
-static void set_adc_rate(struct m3_state *s, unsigned int rate)
-{
- u32 freq;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
-
- s->rateadc = rate;
-
- freq = ((rate << 15) + 24000 ) / 48000;
- if(freq)
- freq--;
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_FREQUENCY,
- freq);
-}
-
-static void inc_timer_users(struct m3_card *card)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- card->timer_users++;
- DPRINTK(DPSYS, "inc timer users now %d\n",
- card->timer_users);
- if(card->timer_users != 1)
- goto out;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_RELOAD,
- 240 ) ;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_CURRENT,
- 240 ) ;
-
- m3_outw(card,
- m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE,
- HOST_INT_CTRL);
-out:
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void dec_timer_users(struct m3_card *card)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- card->timer_users--;
- DPRINTK(DPSYS, "dec timer users now %d\n",
- card->timer_users);
- if(card->timer_users > 0 )
- goto out;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_RELOAD,
- 0 ) ;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_CURRENT,
- 0 ) ;
-
- m3_outw(card, m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE,
- HOST_INT_CTRL);
-out:
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/*
- * {start,stop}_{adc,dac} should be called
- * while holding the 'state' lock and they
- * will try to grab the 'card' lock..
- */
-static void stop_adc(struct m3_state *s)
-{
- if (! (s->enable & ADC_RUNNING))
- return;
-
- s->enable &= ~ADC_RUNNING;
- dec_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_INSTANCE_READY, 0);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_ADC1_REQUEST, 0);
-}
-
-static void stop_dac(struct m3_state *s)
-{
- if (! (s->enable & DAC_RUNNING))
- return;
-
- DPRINTK(DPSYS, "stop_dac()\n");
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_INSTANCE_READY, 0);
-
- s->enable &= ~DAC_RUNNING;
- s->card->dacs_active--;
- dec_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_MIXER_TASK_NUMBER,
- s->card->dacs_active ) ;
-}
-
-static void start_dac(struct m3_state *s)
-{
- if( (!s->dma_dac.mapped && s->dma_dac.count < 1) ||
- !s->dma_dac.ready ||
- (s->enable & DAC_RUNNING))
- return;
-
- DPRINTK(DPSYS, "start_dac()\n");
-
- s->enable |= DAC_RUNNING;
- s->card->dacs_active++;
- inc_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_INSTANCE_READY, 1);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_MIXER_TASK_NUMBER,
- s->card->dacs_active ) ;
-}
-
-static void start_adc(struct m3_state *s)
-{
- if ((! s->dma_adc.mapped &&
- s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- || !s->dma_adc.ready
- || (s->enable & ADC_RUNNING) )
- return;
-
- DPRINTK(DPSYS, "start_adc()\n");
-
- s->enable |= ADC_RUNNING;
- inc_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_ADC1_REQUEST, 1);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_INSTANCE_READY, 1);
-}
-
-static struct play_vals {
- u16 addr, val;
-} pv[] = {
- {CDATA_LEFT_VOLUME, ARB_VOLUME},
- {CDATA_RIGHT_VOLUME, ARB_VOLUME},
- {SRC3_DIRECTION_OFFSET, 0} ,
- /* +1, +2 are stereo/16 bit */
- {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
- {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
- {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
- {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
- {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
- {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
- {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
- {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
- {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
- {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
- {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
- {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
- {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */
- {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */
- {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */
- {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
- {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */
-};
-
-
-/* the mode passed should be already shifted and masked */
-static void m3_play_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
-{
- int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
- int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
- int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
- int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
- struct dmabuf *db = &s->dma_dac;
- int i;
-
- DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n",
- mode, rate, buffer, size);
-
-#define LO(x) ((x) & 0xffff)
-#define HI(x) LO((x) >> 16)
-
- /* host dma buffer pointers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_ADDRL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_ADDRH,
- HI(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
- LO(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
- HI(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_CURRENTL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_CURRENTH,
- HI(virt_to_bus(buffer)));
-#undef LO
-#undef HI
-
- /* dsp buffers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_BEGIN,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1,
- dsp_in_buffer + (dsp_in_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_HEAD,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_TAIL,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_BEGIN,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1,
- dsp_out_buffer + (dsp_out_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_HEAD,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_TAIL,
- dsp_out_buffer);
-
- /*
- * some per client initializers
- */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12,
- s->dac_inst.data + 40 + 8);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19,
- s->dac_inst.code + MINISRC_COEF_LOC);
-
- /* enable or disable low pass filter? */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22,
- s->ratedac > 45000 ? 0xff : 0 );
-
- /* tell it which way dma is going? */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_DMA_CONTROL,
- DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
-
- /*
- * set an armload of static initializers
- */
- for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++)
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + pv[i].addr, pv[i].val);
-
- /*
- * put us in the lists if we're not already there
- */
-
- if(db->in_lists == 0) {
-
- db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
- s->dac_inst.data >> DP_SHIFT_COUNT);
-
- db->dma_index = m3_add_list(s->card, &s->card->dma_list,
- s->dac_inst.data >> DP_SHIFT_COUNT);
-
- db->mixer_index = m3_add_list(s->card, &s->card->mixer_list,
- s->dac_inst.data >> DP_SHIFT_COUNT);
-
- db->in_lists = 1;
- }
-
- set_dac_rate(s,rate);
- start_dac(s);
-}
-
-/*
- * Native record driver
- */
-static struct rec_vals {
- u16 addr, val;
-} rv[] = {
- {CDATA_LEFT_VOLUME, ARB_VOLUME},
- {CDATA_RIGHT_VOLUME, ARB_VOLUME},
- {SRC3_DIRECTION_OFFSET, 1} ,
- /* +1, +2 are stereo/16 bit */
- {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
- {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
- {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
- {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
- {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
- {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
- {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
- {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
- {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
- {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
- {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
- {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
- {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */
- {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */
- {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */
- {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */
- {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
- {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */
- {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */
-};
-
-/* again, passed mode is alrady shifted/masked */
-static void m3_rec_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
-{
- int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
- int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
- int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
- int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
- struct dmabuf *db = &s->dma_adc;
- int i;
-
- DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n",
- mode, rate, buffer, size);
-
-#define LO(x) ((x) & 0xffff)
-#define HI(x) LO((x) >> 16)
-
- /* host dma buffer pointers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_ADDRL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_ADDRH,
- HI(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
- LO(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
- HI(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_CURRENTL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_CURRENTH,
- HI(virt_to_bus(buffer)));
-#undef LO
-#undef HI
-
- /* dsp buffers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_BEGIN,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1,
- dsp_in_buffer + (dsp_in_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_HEAD,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_TAIL,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_BEGIN,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1,
- dsp_out_buffer + (dsp_out_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_HEAD,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_TAIL,
- dsp_out_buffer);
-
- /*
- * some per client initializers
- */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12,
- s->adc_inst.data + 40 + 8);
-
- /* tell it which way dma is going? */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_DMA_CONTROL,
- DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT +
- DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
-
- /*
- * set an armload of static initializers
- */
- for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++)
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + rv[i].addr, rv[i].val);
-
- /*
- * put us in the lists if we're not already there
- */
-
- if(db->in_lists == 0) {
-
- db->adc1_index = m3_add_list(s->card, &s->card->adc1_list,
- s->adc_inst.data >> DP_SHIFT_COUNT);
-
- db->dma_index = m3_add_list(s->card, &s->card->dma_list,
- s->adc_inst.data >> DP_SHIFT_COUNT);
-
- db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
- s->adc_inst.data >> DP_SHIFT_COUNT);
-
- db->in_lists = 1;
- }
-
- set_adc_rate(s,rate);
- start_adc(s);
-}
-/* --------------------------------------------------------------------- */
-
-static void set_dmaa(struct m3_state *s, unsigned int addr, unsigned int count)
-{
- DPRINTK(DPINT,"set_dmaa??\n");
-}
-
-static void set_dmac(struct m3_state *s, unsigned int addr, unsigned int count)
-{
- DPRINTK(DPINT,"set_dmac??\n");
-}
-
-static u32 get_dma_pos(struct m3_card *card,
- int instance_addr)
-{
- u16 hi = 0, lo = 0;
- int retry = 10;
-
- /*
- * try and get a valid answer
- */
- while(retry--) {
- hi = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- instance_addr + CDATA_HOST_SRC_CURRENTH);
-
- lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- instance_addr + CDATA_HOST_SRC_CURRENTL);
-
- if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- instance_addr + CDATA_HOST_SRC_CURRENTH))
- break;
- }
- return lo | (hi<<16);
-}
-
-static u32 get_dmaa(struct m3_state *s)
-{
- u32 offset;
-
- offset = get_dma_pos(s->card, s->dac_inst.data) -
- virt_to_bus(s->dma_dac.rawbuf);
-
- DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset);
-
- return offset;
-}
-
-static u32 get_dmac(struct m3_state *s)
-{
- u32 offset;
-
- offset = get_dma_pos(s->card, s->adc_inst.data) -
- virt_to_bus(s->dma_adc.rawbuf);
-
- DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset);
-
- return offset;
-
-}
-
-static int
-prog_dmabuf(struct m3_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- unsigned bytepersec;
- unsigned bufs;
- unsigned char fmt;
- unsigned long flags;
-
- spin_lock_irqsave(&s->card->lock, flags);
-
- fmt = s->fmt;
- if (rec) {
- stop_adc(s);
- fmt >>= ESS_ADC_SHIFT;
- } else {
- stop_dac(s);
- fmt >>= ESS_DAC_SHIFT;
- }
- fmt &= ESS_FMT_MASK;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
- 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;
-
- DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
-
- memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
-
- if (rec)
- m3_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
- else
- m3_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
-
- db->ready = 1;
-
- spin_unlock_irqrestore(&s->card->lock, flags);
-
- return 0;
-}
-
-static void clear_advance(struct m3_state *s)
-{
- unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
-
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- /* account for wrapping? */
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void m3_update_ptr(struct m3_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- hwptr = get_dmac(s) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- 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))) {
- stop_adc(s);
- /* brute force everyone back in sync, sigh */
- s->dma_adc.count = 0;
- s->dma_adc.swptr = 0;
- s->dma_adc.hwptr = 0;
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = get_dmaa(s) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-
- DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n",
- hwptr,diff,s->dma_dac.count);
-
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
-
- if (s->dma_dac.mapped) {
-
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
- wake_up(&s->dma_dac.wait);
- }
- } else {
-
- s->dma_dac.count -= diff;
-
- if (s->dma_dac.count <= 0) {
- DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n",
- diff, diff,
- s->dma_dac.count,
- s->dma_dac.count,
- hwptr, hwptr,
- s->dma_dac.swptr,
- s->dma_dac.swptr);
- stop_dac(s);
- /* brute force everyone back in sync, sigh */
- s->dma_dac.count = 0;
- s->dma_dac.swptr = hwptr;
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
- wake_up(&s->dma_dac.wait);
- DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n",
- s->dma_dac.count, s->dma_dac.swptr, hwptr);
- }
- }
- }
-}
-
-static irqreturn_t m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct m3_card *c = (struct m3_card *)dev_id;
- struct m3_state *s = &c->channels[0];
- u8 status;
-
- status = inb(c->iobase+0x1A);
-
- if(status == 0xff)
- return IRQ_NONE;
-
- /* presumably acking the ints? */
- outw(status, c->iobase+0x1A);
-
- if(c->in_suspend)
- return IRQ_HANDLED;
-
- /*
- * ack an assp int if its running
- * and has an int pending
- */
- if( status & ASSP_INT_PENDING) {
- u8 ctl = inb(c->iobase + ASSP_CONTROL_B);
- if( !(ctl & STOP_ASSP_CLOCK)) {
- ctl = inb(c->iobase + ASSP_HOST_INT_STATUS );
- if(ctl & DSP2HOST_REQ_TIMER) {
- outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS);
- /* update adc/dac info if it was a timer int */
- spin_lock(&c->lock);
- m3_update_ptr(s);
- spin_unlock(&c->lock);
- }
- }
- }
-
- /* XXX is this needed? */
- if(status & 0x40)
- outb(0x40, c->iobase+0x1A);
- return IRQ_HANDLED;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n";
-
-#define VALIDATE_MAGIC(FOO,MAG) \
-({ \
- if (!(FOO) || (FOO)->magic != MAG) { \
- printk(invalid_magic,__FUNCTION__); \
- return -ENXIO; \
- } \
-})
-
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC)
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct m3_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait,current);
- unsigned long flags;
- int count;
- signed long tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- spin_lock_irqsave(&s->card->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = (count * HZ) / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
- or something. who cares. - zach */
- if (!schedule_timeout(tmo ? tmo : 1) && tmo)
- DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static ssize_t m3_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- spin_lock_irqsave(&s->card->lock, flags);
-
- while (count > 0) {
- int timed_out;
-
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- {
- ret = ret ? ret : -EAGAIN;
- goto out;
- }
-
- spin_unlock_irqrestore(&s->card->lock, flags);
- timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0;
- spin_lock_irqsave(&s->card->lock, flags);
-
- if(timed_out) {
- printk("read: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- }
- if (signal_pending(current))
- {
- ret = ret ? ret : -ERESTARTSYS;
- goto out;
- }
- continue;
- }
-
- spin_unlock_irqrestore(&s->card->lock, flags);
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- ret = ret ? ret : -EFAULT;
- return ret;
- }
- spin_lock_irqsave(&s->card->lock, flags);
-
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_adc(s);
- }
-
-out:
- spin_unlock_irqrestore(&s->card->lock, flags);
- return ret;
-}
-
-static ssize_t m3_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- spin_lock_irqsave(&s->card->lock, flags);
-
- while (count > 0) {
- int timed_out;
-
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
-
- cnt = s->dma_dac.dmasize-swptr;
-
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if(!ret) ret = -EAGAIN;
- goto out;
- }
- spin_unlock_irqrestore(&s->card->lock, flags);
- timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0;
- spin_lock_irqsave(&s->card->lock, flags);
- if(timed_out) {
- DPRINTK(DPCRAP,"write: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- stop_dac(s);
- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- }
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- goto out;
- }
- continue;
- }
- spin_unlock_irqrestore(&s->card->lock, flags);
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
- return ret;
- }
- spin_lock_irqsave(&s->card->lock, flags);
-
- DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n",
- cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);
-
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
-
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(s);
- }
-out:
- spin_unlock_irqrestore(&s->card->lock, flags);
- return ret;
-}
-
-static unsigned int m3_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &s->dma_dac.wait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &s->dma_adc.wait, wait);
-
- spin_lock_irqsave(&s->card->lock, flags);
- m3_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_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
-
- spin_unlock_irqrestore(&s->card->lock, flags);
- return mask;
-}
-
-static int m3_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- unsigned long max_size, size, start, offset;
- struct dmabuf *db;
- int ret = -EINVAL;
-
- VALIDATE_STATE(s);
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- return ret;
- db = &s->dma_dac;
- } else
- if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- return ret;
- db = &s->dma_adc;
- } else
- return -EINVAL;
-
- max_size = db->dmasize;
-
- start = vma->vm_start;
- offset = (vma->vm_pgoff << PAGE_SHIFT);
- size = vma->vm_end - vma->vm_start;
-
- if(size > max_size)
- goto out;
- if(offset > max_size - size)
- goto out;
-
- /*
- * this will be ->nopage() once I can
- * ask Jeff what the hell I'm doing wrong.
- */
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
-
- db->mapped = 1;
- ret = 0;
-
-out:
- return ret;
-}
-
-/*
- * this function is a disaster..
- */
-#define get_user_ret(x, ptr, ret) ({ if(get_user(x, ptr)) return ret; })
-static int m3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- struct m3_card *card=s->card;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
-
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
- DPRINTK(DPSYS,"m3_ioctl: cmd %d\n", cmd);
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- 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:
- /* XXX fix */
- 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:
- spin_lock_irqsave(&card->lock, flags);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->card->pcidev->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->card->pcidev->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- case SNDCTL_DSP_SPEED:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- 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_dac(s);
- s->dma_dac.ready = 0;
- set_dac_rate(s, val);
- }
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_U8|AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
- 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->enable & ADC_RUNNING))
- val |= PCM_ENABLE_INPUT;
- if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING))
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, p, -EFAULT);
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- start_adc(s);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- start_dac(s);
- } else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&card->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->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&card->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;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.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(&card->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;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&card->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(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- 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_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;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- 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;
- get_user_ret(val, p, -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_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return -EINVAL;
-}
-
-static int
-allocate_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
-{
- int order;
-
- DPRINTK(DPSTR,"allocating for dmabuf %p\n", db);
-
- /*
- * alloc as big a chunk as we can, start with
- * 64k 'cause we're insane. based on order cause
- * the amazingly complicated prog_dmabuf wants it.
- *
- * pci_alloc_sonsistent guarantees that it won't cross a natural
- * boundary; the m3 hardware can't have dma cross a 64k bus
- * address boundary.
- */
- for (order = 16-PAGE_SHIFT; order >= 1; order--) {
- db->rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
- &(db->handle));
- if(db->rawbuf)
- break;
- }
-
- if (!db->rawbuf)
- return 1;
-
- DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n",
- PAGE_SIZE<<order, order, db->rawbuf);
-
- {
- struct page *page, *pend;
-
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
-
-
- db->buforder = order;
- db->ready = 0;
- db->mapped = 0;
-
- return 0;
-}
-
-static void
-nuke_lists(struct m3_card *card, struct dmabuf *db)
-{
- m3_remove_list(card, &(card->dma_list), db->dma_index);
- m3_remove_list(card, &(card->msrc_list), db->msrc_index);
- db->in_lists = 0;
-}
-
-static void
-free_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
-{
- if(db->rawbuf == NULL)
- return;
-
- DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db);
-
- {
- struct page *page, *pend;
- 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(pci_dev, PAGE_SIZE << db->buforder,
- db->rawbuf, db->handle);
-
- db->rawbuf = NULL;
- db->buforder = 0;
- db->mapped = 0;
- db->ready = 0;
-}
-
-static int m3_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct m3_card *c;
- struct m3_state *s = NULL;
- int i;
- unsigned char fmtm = ~0, fmts = 0;
- unsigned long flags;
-
- /*
- * Scan the cards and find the channel. We only
- * do this at open time so it is ok
- */
- for(c = devs ; c != NULL ; c = c->next) {
-
- for(i=0;i<NR_DSPS;i++) {
-
- if(c->channels[i].dev_audio < 0)
- continue;
- if((c->channels[i].dev_audio ^ minor) & ~0xf)
- continue;
-
- s = &c->channels[i];
- break;
- }
- }
-
- if (!s)
- return -ENODEV;
-
- 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 -EWOULDBLOCK;
- }
- mutex_unlock(&s->open_mutex);
- interruptible_sleep_on(&s->open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
-
- spin_lock_irqsave(&c->lock, flags);
-
- if (file->f_mode & FMODE_READ) {
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
-
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- set_adc_rate(s, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- set_dac_rate(s, 8000);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
- mutex_unlock(&s->open_mutex);
- spin_unlock_irqrestore(&c->lock, flags);
- return nonseekable_open(inode, file);
-}
-
-static int m3_release(struct inode *inode, struct file *file)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- struct m3_card *card=s->card;
- unsigned long flags;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
-
- mutex_lock(&s->open_mutex);
- spin_lock_irqsave(&card->lock, flags);
-
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- if(s->dma_dac.in_lists) {
- m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index);
- nuke_lists(s->card, &(s->dma_dac));
- }
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- if(s->dma_adc.in_lists) {
- m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index);
- nuke_lists(s->card, &(s->dma_adc));
- }
- }
-
- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
- spin_unlock_irqrestore(&card->lock, flags);
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
-
- return 0;
-}
-
-/*
- * Wait for the ac97 serial bus to be free.
- * return nonzero if the bus is still busy.
- */
-static int m3_ac97_wait(struct m3_card *card)
-{
- int i = 10000;
-
- while( (m3_inb(card, 0x30) & 1) && i--) ;
-
- return i == 0;
-}
-
-static u16 m3_ac97_read(struct ac97_codec *codec, u8 reg)
-{
- u16 ret = 0;
- struct m3_card *card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- if(m3_ac97_wait(card)) {
- printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg);
- goto out;
- }
-
- m3_outb(card, 0x80 | (reg & 0x7f), 0x30);
-
- if(m3_ac97_wait(card)) {
- printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg);
- goto out;
- }
-
- ret = m3_inw(card, 0x32);
- DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg);
-
-out:
- spin_unlock(&card->ac97_lock);
- return ret;
-}
-
-static void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
-{
- struct m3_card *card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- if(m3_ac97_wait(card)) {
- printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg);
- goto out;
- }
- DPRINTK(DPCRAP,"writing 0x%04x to 0x%02x\n", val, reg);
-
- m3_outw(card, val, 0x32);
- m3_outb(card, reg & 0x7f, 0x30);
-out:
- spin_unlock(&card->ac97_lock);
-}
-/* OSS /dev/mixer file operation methods */
-static int m3_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct m3_card *card = devs;
-
- for (card = devs; card != NULL; card = card->next) {
- if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor))
- break;
- }
-
- if (!card) {
- return -ENODEV;
- }
-
- file->private_data = card->ac97;
-
- return nonseekable_open(inode, file);
-}
-
-static int m3_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int m3_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 struct file_operations m3_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = m3_ioctl_mixdev,
- .open = m3_open_mixdev,
- .release = m3_release_mixdev,
-};
-
-static void remote_codec_config(int io, int isremote)
-{
- isremote = isremote ? 1 : 0;
-
- outw( (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,
- io + RING_BUS_CTRL_B);
- outw( (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
- io + SDO_OUT_DEST_CTRL);
- outw( (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
- io + SDO_IN_DEST_CTRL);
-}
-
-/*
- * hack, returns non zero on err
- */
-static int try_read_vendor(struct m3_card *card)
-{
- u16 ret;
-
- if(m3_ac97_wait(card))
- return 1;
-
- m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);
-
- if(m3_ac97_wait(card))
- return 1;
-
- ret = m3_inw(card, 0x32);
-
- return (ret == 0) || (ret == 0xffff);
-}
-
-static void m3_codec_reset(struct m3_card *card, int busywait)
-{
- u16 dir;
- int delay1 = 0, delay2 = 0, i;
- int io = card->iobase;
-
- switch (card->card_type) {
- /*
- * the onboard codec on the allegro seems
- * to want to wait a very long time before
- * coming back to life
- */
- case ESS_ALLEGRO:
- delay1 = 50;
- delay2 = 800;
- break;
- case ESS_MAESTRO3:
- case ESS_MAESTRO3HW:
- delay1 = 20;
- delay2 = 500;
- break;
- }
-
- for(i = 0; i < 5; i ++) {
- dir = inw(io + GPIO_DIRECTION);
- dir |= 0x10; /* assuming pci bus master? */
-
- remote_codec_config(io, 0);
-
- outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
- udelay(20);
-
- outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);
- outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);
- outw(0, io + GPIO_DATA);
- outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
-
- if(busywait) {
- mdelay(delay1);
- } else {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((delay1 * HZ) / 1000);
- }
-
- outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
- udelay(5);
- /* ok, bring back the ac-link */
- outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
- outw(~0, io + GPIO_MASK);
-
- if(busywait) {
- mdelay(delay2);
- } else {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((delay2 * HZ) / 1000);
- }
- if(! try_read_vendor(card))
- break;
-
- delay1 += 10;
- delay2 += 100;
-
- DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n",
- delay1, delay2);
- }
-
-#if 0
- /* more gung-ho reset that doesn't
- * seem to work anywhere :)
- */
- tmp = inw(io + RING_BUS_CTRL_A);
- outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
- mdelay(20);
- outw(tmp, io + RING_BUS_CTRL_A);
- mdelay(50);
-#endif
-}
-
-static int __devinit m3_codec_install(struct m3_card *card)
-{
- struct ac97_codec *codec;
-
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- codec->private_data = card;
- codec->codec_read = m3_ac97_read;
- codec->codec_write = m3_ac97_write;
- /* someday we should support secondary codecs.. */
- codec->id = 0;
-
- if (ac97_probe_codec(codec) == 0) {
- printk(KERN_ERR PFX "codec probe failed\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) {
- printk(KERN_ERR PFX "couldn't register mixer!\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- card->ac97 = codec;
-
- return 0;
-}
-
-
-#define MINISRC_LPF_LEN 10
-static u16 minisrc_lpf[MINISRC_LPF_LEN] = {
- 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
- 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
-};
-static void m3_assp_init(struct m3_card *card)
-{
- int i;
-
- /* zero kernel data */
- for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_BASE_ADDR + i, 0);
-
- /* zero mixer data? */
- for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_BASE_ADDR2 + i, 0);
-
- /* init dma pointer */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_CURRENT_DMA,
- KDATA_DMA_XFER0);
-
- /* write kernel into code memory.. */
- for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) {
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- REV_B_CODE_MEMORY_BEGIN + i,
- assp_kernel_image[i]);
- }
-
- /*
- * We only have this one client and we know that 0x400
- * is free in our kernel's mem map, so lets just
- * drop it there. It seems that the minisrc doesn't
- * need vectors, so we won't bother with them..
- */
- for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) {
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- 0x400 + i,
- assp_minisrc_image[i]);
- }
-
- /*
- * write the coefficients for the low pass filter?
- */
- for(i = 0; i < MINISRC_LPF_LEN ; i++) {
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- 0x400 + MINISRC_COEF_LOC + i,
- minisrc_lpf[i]);
- }
-
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN,
- 0x8000);
-
- /*
- * the minisrc is the only thing on
- * our task list..
- */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TASK0,
- 0x400);
-
- /*
- * init the mixer number..
- */
-
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_MIXER_TASK_NUMBER,0);
-
- /*
- * EXTREME KERNEL MASTER VOLUME
- */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_DAC_LEFT_VOLUME, ARB_VOLUME);
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME);
-
- card->mixer_list.mem_addr = KDATA_MIXER_XFER0;
- card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS;
- card->adc1_list.mem_addr = KDATA_ADC1_XFER0;
- card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS;
- card->dma_list.mem_addr = KDATA_DMA_XFER0;
- card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS;
- card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC;
- card->msrc_list.max = MAX_INSTANCE_MINISRC;
-}
-
-static int setup_msrc(struct m3_card *card,
- struct assp_instance *inst, int index)
-{
- int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 +
- MINISRC_IN_BUFFER_SIZE / 2 +
- 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 );
- int address, i;
-
- /*
- * the revb memory map has 0x1100 through 0x1c00
- * free.
- */
-
- /*
- * align instance address to 256 bytes so that it's
- * shifted list address is aligned.
- * list address = (mem address >> 1) >> 7;
- */
- data_bytes = (data_bytes + 255) & ~255;
- address = 0x1100 + ((data_bytes/2) * index);
-
- if((address + (data_bytes/2)) >= 0x1c00) {
- printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n",
- data_bytes, index, address);
- return -1;
- }
-
- for(i = 0; i < data_bytes/2 ; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- address + i, 0);
-
- inst->code = 0x400;
- inst->data = address;
-
- return 0;
-}
-
-static int m3_assp_client_init(struct m3_state *s)
-{
- setup_msrc(s->card, &(s->dac_inst), s->index * 2);
- setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1);
-
- return 0;
-}
-
-static void m3_amp_enable(struct m3_card *card, int enable)
-{
- /*
- * this works for the reference board, have to find
- * out about others
- *
- * this needs more magic for 4 speaker, but..
- */
- int io = card->iobase;
- u16 gpo, polarity_port, polarity;
-
- if(!external_amp)
- return;
-
- if (gpio_pin >= 0 && gpio_pin <= 15) {
- polarity_port = 0x1000 + (0x100 * gpio_pin);
- } else {
- switch (card->card_type) {
- case ESS_ALLEGRO:
- polarity_port = 0x1800;
- break;
- default:
- polarity_port = 0x1100;
- /* Panasonic toughbook CF72 has to be different... */
- if(card->pcidev->subsystem_vendor == 0x10F7 && card->pcidev->subsystem_device == 0x833D)
- polarity_port = 0x1D00;
- break;
- }
- }
-
- gpo = (polarity_port >> 8) & 0x0F;
- polarity = polarity_port >> 12;
- if ( enable )
- polarity = !polarity;
- polarity = polarity << gpo;
- gpo = 1 << gpo;
-
- outw(~gpo , io + GPIO_MASK);
-
- outw( inw(io + GPIO_DIRECTION) | gpo ,
- io + GPIO_DIRECTION);
-
- outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) ,
- io + GPIO_DATA);
-
- outw(0xffff , io + GPIO_MASK);
-}
-
-static int
-maestro_config(struct m3_card *card)
-{
- struct pci_dev *pcidev = card->pcidev;
- u32 n;
- u8 t; /* makes as much sense as 'n', no? */
-
- pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
- n &= REDUCED_DEBOUNCE;
- n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
- pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
-
- outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B);
- pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
- n &= ~INT_CLK_SELECT;
- if(card->card_type >= ESS_MAESTRO3) {
- n &= ~INT_CLK_MULT_ENABLE;
- n |= INT_CLK_SRC_NOT_PCI;
- }
- n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 );
- pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
-
- if(card->card_type <= ESS_ALLEGRO) {
- pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n);
- n |= IN_CLK_12MHZ_SELECT;
- pci_write_config_dword(pcidev, PCI_USER_CONFIG, n);
- }
-
- t = inb(card->iobase + ASSP_CONTROL_A);
- t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT);
- t |= ASSP_CLK_49MHZ_SELECT;
- t |= ASSP_0_WS_ENABLE;
- outb(t, card->iobase + ASSP_CONTROL_A);
-
- outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B);
-
- return 0;
-}
-
-static void m3_enable_ints(struct m3_card *card)
-{
- unsigned long io = card->iobase;
-
- outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL);
- outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
- io + ASSP_CONTROL_C);
-}
-
-static struct file_operations m3_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = m3_read,
- .write = m3_write,
- .poll = m3_poll,
- .ioctl = m3_ioctl,
- .mmap = m3_mmap,
- .open = m3_open,
- .release = m3_release,
-};
-
-#ifdef CONFIG_PM
-static int alloc_dsp_suspendmem(struct m3_card *card)
-{
- int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
-
- if( (card->suspend_mem = vmalloc(len)) == NULL)
- return 1;
-
- return 0;
-}
-
-#else
-#define alloc_dsp_suspendmem(args...) 0
-#endif
-
-/*
- * great day! this function is ugly as hell.
- */
-static int __devinit m3_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- u32 n;
- int i;
- struct m3_card *card = NULL;
- int ret = 0;
- int card_type = pci_id->driver_data;
-
- DPRINTK(DPMOD, "in maestro_install\n");
-
- if (pci_enable_device(pci_dev))
- return -EIO;
-
- if (pci_set_dma_mask(pci_dev, M3_PCI_DMA_MASK)) {
- printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n");
- return -ENODEV;
- }
-
- pci_set_master(pci_dev);
-
- if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING PFX "out of memory\n");
- return -ENOMEM;
- }
- memset(card, 0, sizeof(struct m3_card));
- card->pcidev = pci_dev;
- init_waitqueue_head(&card->suspend_queue);
-
- if ( ! request_region(pci_resource_start(pci_dev, 0),
- pci_resource_len (pci_dev, 0), M3_MODULE_NAME)) {
-
- printk(KERN_WARNING PFX "unable to reserve I/O space.\n");
- ret = -EBUSY;
- goto out;
- }
-
- card->iobase = pci_resource_start(pci_dev, 0);
-
- if(alloc_dsp_suspendmem(card)) {
- printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n",
- REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
- ret = -ENOMEM;
- goto out;
- }
-
- card->card_type = card_type;
- card->irq = pci_dev->irq;
- card->next = devs;
- card->magic = M3_CARD_MAGIC;
- spin_lock_init(&card->lock);
- spin_lock_init(&card->ac97_lock);
- devs = card;
- for(i = 0; i<NR_DSPS; i++) {
- struct m3_state *s = &(card->channels[i]);
- s->dev_audio = -1;
- }
-
- printk(KERN_INFO PFX "Configuring ESS %s found at IO 0x%04X IRQ %d\n",
- card_names[card->card_type], card->iobase, card->irq);
-
- pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &n);
- printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n);
-
- maestro_config(card);
- m3_assp_halt(card);
-
- m3_codec_reset(card, 0);
-
- if(m3_codec_install(card)) {
- ret = -EIO;
- goto out;
- }
-
- m3_assp_init(card);
- m3_amp_enable(card, 1);
-
- for(i=0;i<NR_DSPS;i++) {
- struct m3_state *s=&card->channels[i];
-
- s->index = i;
-
- s->card = card;
- 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));
- s->magic = M3_STATE_MAGIC;
-
- m3_assp_client_init(s);
-
- if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
- printk(KERN_WARNING PFX "initing a dsp device that is already in use?\n");
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&m3_audio_fops, -1)) < 0) {
- break;
- }
-
- if( allocate_dmabuf(card->pcidev, &(s->dma_adc)) ||
- allocate_dmabuf(card->pcidev, &(s->dma_dac))) {
- ret = -ENOMEM;
- goto out;
- }
- }
-
- if(request_irq(card->irq, m3_interrupt, IRQF_SHARED, card_names[card->card_type], card)) {
-
- printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq);
-
- ret = -EIO;
- goto out;
- }
-
- pci_set_drvdata(pci_dev, card);
-
- m3_enable_ints(card);
- m3_assp_continue(card);
-
-out:
- if(ret) {
- if(card->iobase)
- release_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
- vfree(card->suspend_mem);
- if(card->ac97) {
- unregister_sound_mixer(card->ac97->dev_mixer);
- kfree(card->ac97);
- }
- for(i=0;i<NR_DSPS;i++)
- {
- struct m3_state *s = &card->channels[i];
- if(s->dev_audio != -1)
- unregister_sound_dsp(s->dev_audio);
- }
- kfree(card);
- }
-
- return ret;
-}
-
-static void m3_remove(struct pci_dev *pci_dev)
-{
- struct m3_card *card;
-
- unregister_reboot_notifier(&m3_reboot_nb);
-
- while ((card = devs)) {
- int i;
- devs = devs->next;
-
- free_irq(card->irq, card);
- unregister_sound_mixer(card->ac97->dev_mixer);
- kfree(card->ac97);
-
- for(i=0;i<NR_DSPS;i++)
- {
- struct m3_state *s = &card->channels[i];
- if(s->dev_audio < 0)
- continue;
-
- unregister_sound_dsp(s->dev_audio);
- free_dmabuf(card->pcidev, &s->dma_adc);
- free_dmabuf(card->pcidev, &s->dma_dac);
- }
-
- release_region(card->iobase, 256);
- vfree(card->suspend_mem);
- kfree(card);
- }
- devs = NULL;
-}
-
-/*
- * some bioses like the sound chip to be powered down
- * at shutdown. We're just calling _suspend to
- * achieve that..
- */
-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf)
-{
- struct m3_card *card;
-
- DPRINTK(DPMOD, "notifier suspending all cards\n");
-
- for(card = devs; card != NULL; card = card->next) {
- if(!card->in_suspend)
- m3_suspend(card->pcidev, PMSG_SUSPEND); /* XXX legal? */
- }
- return 0;
-}
-
-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state)
-{
- unsigned long flags;
- int i;
- struct m3_card *card = pci_get_drvdata(pci_dev);
-
- /* must be a better way.. */
- spin_lock_irqsave(&card->lock, flags);
-
- DPRINTK(DPMOD, "pm in dev %p\n",card);
-
- for(i=0;i<NR_DSPS;i++) {
- struct m3_state *s = &card->channels[i];
-
- if(s->dev_audio == -1)
- continue;
-
- DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i);
- stop_dac(s);
- stop_adc(s);
- }
-
- mdelay(10); /* give the assp a chance to idle.. */
-
- m3_assp_halt(card);
-
- if(card->suspend_mem) {
- int index = 0;
-
- DPRINTK(DPMOD, "saving code\n");
- for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
- card->suspend_mem[index++] =
- m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i);
- DPRINTK(DPMOD, "saving data\n");
- for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
- card->suspend_mem[index++] =
- m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i);
- }
-
- DPRINTK(DPMOD, "powering down apci regs\n");
- m3_outw(card, 0xffff, 0x54);
- m3_outw(card, 0xffff, 0x56);
-
- card->in_suspend = 1;
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return 0;
-}
-
-static int m3_resume(struct pci_dev *pci_dev)
-{
- unsigned long flags;
- int index;
- int i;
- struct m3_card *card = pci_get_drvdata(pci_dev);
-
- spin_lock_irqsave(&card->lock, flags);
- card->in_suspend = 0;
-
- DPRINTK(DPMOD, "resuming\n");
-
- /* first lets just bring everything back. .*/
-
- DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card);
- m3_outw(card, 0, 0x54);
- m3_outw(card, 0, 0x56);
-
- DPRINTK(DPMOD, "restoring pci configs and reseting codec\n");
- maestro_config(card);
- m3_assp_halt(card);
- m3_codec_reset(card, 1);
-
- DPRINTK(DPMOD, "restoring dsp code card\n");
- index = 0;
- for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i,
- card->suspend_mem[index++]);
- for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i,
- card->suspend_mem[index++]);
-
- /* tell the dma engine to restart itself */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_DMA_ACTIVE, 0);
-
- DPRINTK(DPMOD, "resuming dsp\n");
- m3_assp_continue(card);
-
- DPRINTK(DPMOD, "enabling ints\n");
- m3_enable_ints(card);
-
- /* bring back the old school flavor */
- for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) {
- int state = card->ac97->mixer_state[i];
- if (!supported_mixer(card->ac97, i))
- continue;
-
- card->ac97->write_mixer(card->ac97, i,
- state & 0xff, (state >> 8) & 0xff);
- }
-
- m3_amp_enable(card, 1);
-
- /*
- * now we flip on the music
- */
- for(i=0;i<NR_DSPS;i++) {
- struct m3_state *s = &card->channels[i];
- if(s->dev_audio == -1)
- continue;
- /*
- * db->ready makes it so these guys can be
- * called unconditionally..
- */
- DPRINTK(DPMOD, "turning on dacs ind %d\n",i);
- start_dac(s);
- start_adc(s);
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- /*
- * all right, we think things are ready,
- * wake up people who were using the device
- * when we suspended
- */
- wake_up(&card->suspend_queue);
-
- return 0;
-}
-
-MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
-MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver");
-MODULE_LICENSE("GPL");
-
-#ifdef M_DEBUG
-module_param(debug, int, 0);
-#endif
-module_param(external_amp, int, 0);
-module_param(gpio_pin, int, 0);
-
-static struct pci_driver m3_pci_driver = {
- .name = "ess_m3_audio",
- .id_table = m3_id_table,
- .probe = m3_probe,
- .remove = m3_remove,
- .suspend = m3_suspend,
- .resume = m3_resume,
-};
-
-static int __init m3_init_module(void)
-{
- printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n");
-
- if (register_reboot_notifier(&m3_reboot_nb)) {
- printk(KERN_WARNING PFX "reboot notifier registration failed\n");
- return -ENODEV; /* ? */
- }
-
- if (pci_register_driver(&m3_pci_driver)) {
- unregister_reboot_notifier(&m3_reboot_nb);
- return -ENODEV;
- }
- return 0;
-}
-
-static void __exit m3_cleanup_module(void)
-{
- pci_unregister_driver(&m3_pci_driver);
-}
-
-module_init(m3_init_module);
-module_exit(m3_cleanup_module);
-
-void check_suspend(struct m3_card *card)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- if(!card->in_suspend)
- return;
-
- card->in_suspend++;
- add_wait_queue(&card->suspend_queue, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
- remove_wait_queue(&card->suspend_queue, &wait);
- set_current_state(TASK_RUNNING);
-}
diff --git a/sound/oss/maestro3.h b/sound/oss/maestro3.h
deleted file mode 100644
index dde2986..0000000
--- a/sound/oss/maestro3.h
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
- * ESS Technology allegro audio driver.
- *
- * Copyright (C) 1992-2000 Don Kim (don.kim@esstech.com)
- *
- * 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.
- *
- * Hacked for the maestro3 driver by zab
- */
-
-// Allegro PCI configuration registers
-#define PCI_LEGACY_AUDIO_CTRL 0x40
-#define SOUND_BLASTER_ENABLE 0x00000001
-#define FM_SYNTHESIS_ENABLE 0x00000002
-#define GAME_PORT_ENABLE 0x00000004
-#define MPU401_IO_ENABLE 0x00000008
-#define MPU401_IRQ_ENABLE 0x00000010
-#define ALIAS_10BIT_IO 0x00000020
-#define SB_DMA_MASK 0x000000C0
-#define SB_DMA_0 0x00000040
-#define SB_DMA_1 0x00000040
-#define SB_DMA_R 0x00000080
-#define SB_DMA_3 0x000000C0
-#define SB_IRQ_MASK 0x00000700
-#define SB_IRQ_5 0x00000000
-#define SB_IRQ_7 0x00000100
-#define SB_IRQ_9 0x00000200
-#define SB_IRQ_10 0x00000300
-#define MIDI_IRQ_MASK 0x00003800
-#define SERIAL_IRQ_ENABLE 0x00004000
-#define DISABLE_LEGACY 0x00008000
-
-#define PCI_ALLEGRO_CONFIG 0x50
-#define SB_ADDR_240 0x00000004
-#define MPU_ADDR_MASK 0x00000018
-#define MPU_ADDR_330 0x00000000
-#define MPU_ADDR_300 0x00000008
-#define MPU_ADDR_320 0x00000010
-#define MPU_ADDR_340 0x00000018
-#define USE_PCI_TIMING 0x00000040
-#define POSTED_WRITE_ENABLE 0x00000080
-#define DMA_POLICY_MASK 0x00000700
-#define DMA_DDMA 0x00000000
-#define DMA_TDMA 0x00000100
-#define DMA_PCPCI 0x00000200
-#define DMA_WBDMA16 0x00000400
-#define DMA_WBDMA4 0x00000500
-#define DMA_WBDMA2 0x00000600
-#define DMA_WBDMA1 0x00000700
-#define DMA_SAFE_GUARD 0x00000800
-#define HI_PERF_GP_ENABLE 0x00001000
-#define PIC_SNOOP_MODE_0 0x00002000
-#define PIC_SNOOP_MODE_1 0x00004000
-#define SOUNDBLASTER_IRQ_MASK 0x00008000
-#define RING_IN_ENABLE 0x00010000
-#define SPDIF_TEST_MODE 0x00020000
-#define CLK_MULT_MODE_SELECT_2 0x00040000
-#define EEPROM_WRITE_ENABLE 0x00080000
-#define CODEC_DIR_IN 0x00100000
-#define HV_BUTTON_FROM_GD 0x00200000
-#define REDUCED_DEBOUNCE 0x00400000
-#define HV_CTRL_ENABLE 0x00800000
-#define SPDIF_ENABLE 0x01000000
-#define CLK_DIV_SELECT 0x06000000
-#define CLK_DIV_BY_48 0x00000000
-#define CLK_DIV_BY_49 0x02000000
-#define CLK_DIV_BY_50 0x04000000
-#define CLK_DIV_RESERVED 0x06000000
-#define PM_CTRL_ENABLE 0x08000000
-#define CLK_MULT_MODE_SELECT 0x30000000
-#define CLK_MULT_MODE_SHIFT 28
-#define CLK_MULT_MODE_0 0x00000000
-#define CLK_MULT_MODE_1 0x10000000
-#define CLK_MULT_MODE_2 0x20000000
-#define CLK_MULT_MODE_3 0x30000000
-#define INT_CLK_SELECT 0x40000000
-#define INT_CLK_MULT_RESET 0x80000000
-
-// M3
-#define INT_CLK_SRC_NOT_PCI 0x00100000
-#define INT_CLK_MULT_ENABLE 0x80000000
-
-#define PCI_ACPI_CONTROL 0x54
-#define PCI_ACPI_D0 0x00000000
-#define PCI_ACPI_D1 0xB4F70000
-#define PCI_ACPI_D2 0xB4F7B4F7
-
-#define PCI_USER_CONFIG 0x58
-#define EXT_PCI_MASTER_ENABLE 0x00000001
-#define SPDIF_OUT_SELECT 0x00000002
-#define TEST_PIN_DIR_CTRL 0x00000004
-#define AC97_CODEC_TEST 0x00000020
-#define TRI_STATE_BUFFER 0x00000080
-#define IN_CLK_12MHZ_SELECT 0x00000100
-#define MULTI_FUNC_DISABLE 0x00000200
-#define EXT_MASTER_PAIR_SEL 0x00000400
-#define PCI_MASTER_SUPPORT 0x00000800
-#define STOP_CLOCK_ENABLE 0x00001000
-#define EAPD_DRIVE_ENABLE 0x00002000
-#define REQ_TRI_STATE_ENABLE 0x00004000
-#define REQ_LOW_ENABLE 0x00008000
-#define MIDI_1_ENABLE 0x00010000
-#define MIDI_2_ENABLE 0x00020000
-#define SB_AUDIO_SYNC 0x00040000
-#define HV_CTRL_TEST 0x00100000
-#define SOUNDBLASTER_TEST 0x00400000
-
-#define PCI_USER_CONFIG_C 0x5C
-
-#define PCI_DDMA_CTRL 0x60
-#define DDMA_ENABLE 0x00000001
-
-
-// Allegro registers
-#define HOST_INT_CTRL 0x18
-#define SB_INT_ENABLE 0x0001
-#define MPU401_INT_ENABLE 0x0002
-#define ASSP_INT_ENABLE 0x0010
-#define RING_INT_ENABLE 0x0020
-#define HV_INT_ENABLE 0x0040
-#define CLKRUN_GEN_ENABLE 0x0100
-#define HV_CTRL_TO_PME 0x0400
-#define SOFTWARE_RESET_ENABLE 0x8000
-
-/*
- * should be using the above defines, probably.
- */
-#define REGB_ENABLE_RESET 0x01
-#define REGB_STOP_CLOCK 0x10
-
-#define HOST_INT_STATUS 0x1A
-#define SB_INT_PENDING 0x01
-#define MPU401_INT_PENDING 0x02
-#define ASSP_INT_PENDING 0x10
-#define RING_INT_PENDING 0x20
-#define HV_INT_PENDING 0x40
-
-#define HARDWARE_VOL_CTRL 0x1B
-#define SHADOW_MIX_REG_VOICE 0x1C
-#define HW_VOL_COUNTER_VOICE 0x1D
-#define SHADOW_MIX_REG_MASTER 0x1E
-#define HW_VOL_COUNTER_MASTER 0x1F
-
-#define CODEC_COMMAND 0x30
-#define CODEC_READ_B 0x80
-
-#define CODEC_STATUS 0x30
-#define CODEC_BUSY_B 0x01
-
-#define CODEC_DATA 0x32
-
-#define RING_BUS_CTRL_A 0x36
-#define RAC_PME_ENABLE 0x0100
-#define RAC_SDFS_ENABLE 0x0200
-#define LAC_PME_ENABLE 0x0400
-#define LAC_SDFS_ENABLE 0x0800
-#define SERIAL_AC_LINK_ENABLE 0x1000
-#define IO_SRAM_ENABLE 0x2000
-#define IIS_INPUT_ENABLE 0x8000
-
-#define RING_BUS_CTRL_B 0x38
-#define SECOND_CODEC_ID_MASK 0x0003
-#define SPDIF_FUNC_ENABLE 0x0010
-#define SECOND_AC_ENABLE 0x0020
-#define SB_MODULE_INTF_ENABLE 0x0040
-#define SSPE_ENABLE 0x0040
-#define M3I_DOCK_ENABLE 0x0080
-
-#define SDO_OUT_DEST_CTRL 0x3A
-#define COMMAND_ADDR_OUT 0x0003
-#define PCM_LR_OUT_LOCAL 0x0000
-#define PCM_LR_OUT_REMOTE 0x0004
-#define PCM_LR_OUT_MUTE 0x0008
-#define PCM_LR_OUT_BOTH 0x000C
-#define LINE1_DAC_OUT_LOCAL 0x0000
-#define LINE1_DAC_OUT_REMOTE 0x0010
-#define LINE1_DAC_OUT_MUTE 0x0020
-#define LINE1_DAC_OUT_BOTH 0x0030
-#define PCM_CLS_OUT_LOCAL 0x0000
-#define PCM_CLS_OUT_REMOTE 0x0040
-#define PCM_CLS_OUT_MUTE 0x0080
-#define PCM_CLS_OUT_BOTH 0x00C0
-#define PCM_RLF_OUT_LOCAL 0x0000
-#define PCM_RLF_OUT_REMOTE 0x0100
-#define PCM_RLF_OUT_MUTE 0x0200
-#define PCM_RLF_OUT_BOTH 0x0300
-#define LINE2_DAC_OUT_LOCAL 0x0000
-#define LINE2_DAC_OUT_REMOTE 0x0400
-#define LINE2_DAC_OUT_MUTE 0x0800
-#define LINE2_DAC_OUT_BOTH 0x0C00
-#define HANDSET_OUT_LOCAL 0x0000
-#define HANDSET_OUT_REMOTE 0x1000
-#define HANDSET_OUT_MUTE 0x2000
-#define HANDSET_OUT_BOTH 0x3000
-#define IO_CTRL_OUT_LOCAL 0x0000
-#define IO_CTRL_OUT_REMOTE 0x4000
-#define IO_CTRL_OUT_MUTE 0x8000
-#define IO_CTRL_OUT_BOTH 0xC000
-
-#define SDO_IN_DEST_CTRL 0x3C
-#define STATUS_ADDR_IN 0x0003
-#define PCM_LR_IN_LOCAL 0x0000
-#define PCM_LR_IN_REMOTE 0x0004
-#define PCM_LR_RESERVED 0x0008
-#define PCM_LR_IN_BOTH 0x000C
-#define LINE1_ADC_IN_LOCAL 0x0000
-#define LINE1_ADC_IN_REMOTE 0x0010
-#define LINE1_ADC_IN_MUTE 0x0020
-#define MIC_ADC_IN_LOCAL 0x0000
-#define MIC_ADC_IN_REMOTE 0x0040
-#define MIC_ADC_IN_MUTE 0x0080
-#define LINE2_DAC_IN_LOCAL 0x0000
-#define LINE2_DAC_IN_REMOTE 0x0400
-#define LINE2_DAC_IN_MUTE 0x0800
-#define HANDSET_IN_LOCAL 0x0000
-#define HANDSET_IN_REMOTE 0x1000
-#define HANDSET_IN_MUTE 0x2000
-#define IO_STATUS_IN_LOCAL 0x0000
-#define IO_STATUS_IN_REMOTE 0x4000
-
-#define SPDIF_IN_CTRL 0x3E
-#define SPDIF_IN_ENABLE 0x0001
-
-#define GPIO_DATA 0x60
-#define GPIO_DATA_MASK 0x0FFF
-#define GPIO_HV_STATUS 0x3000
-#define GPIO_PME_STATUS 0x4000
-
-#define GPIO_MASK 0x64
-#define GPIO_DIRECTION 0x68
-#define GPO_PRIMARY_AC97 0x0001
-#define GPI_LINEOUT_SENSE 0x0004
-#define GPO_SECONDARY_AC97 0x0008
-#define GPI_VOL_DOWN 0x0010
-#define GPI_VOL_UP 0x0020
-#define GPI_IIS_CLK 0x0040
-#define GPI_IIS_LRCLK 0x0080
-#define GPI_IIS_DATA 0x0100
-#define GPI_DOCKING_STATUS 0x0100
-#define GPI_HEADPHONE_SENSE 0x0200
-#define GPO_EXT_AMP_SHUTDOWN 0x1000
-
-// M3
-#define GPO_M3_EXT_AMP_SHUTDN 0x0002
-
-#define ASSP_INDEX_PORT 0x80
-#define ASSP_MEMORY_PORT 0x82
-#define ASSP_DATA_PORT 0x84
-
-#define MPU401_DATA_PORT 0x98
-#define MPU401_STATUS_PORT 0x99
-
-#define CLK_MULT_DATA_PORT 0x9C
-
-#define ASSP_CONTROL_A 0xA2
-#define ASSP_0_WS_ENABLE 0x01
-#define ASSP_CTRL_A_RESERVED1 0x02
-#define ASSP_CTRL_A_RESERVED2 0x04
-#define ASSP_CLK_49MHZ_SELECT 0x08
-#define FAST_PLU_ENABLE 0x10
-#define ASSP_CTRL_A_RESERVED3 0x20
-#define DSP_CLK_36MHZ_SELECT 0x40
-
-#define ASSP_CONTROL_B 0xA4
-#define RESET_ASSP 0x00
-#define RUN_ASSP 0x01
-#define ENABLE_ASSP_CLOCK 0x00
-#define STOP_ASSP_CLOCK 0x10
-#define RESET_TOGGLE 0x40
-
-#define ASSP_CONTROL_C 0xA6
-#define ASSP_HOST_INT_ENABLE 0x01
-#define FM_ADDR_REMAP_DISABLE 0x02
-#define HOST_WRITE_PORT_ENABLE 0x08
-
-#define ASSP_HOST_INT_STATUS 0xAC
-#define DSP2HOST_REQ_PIORECORD 0x01
-#define DSP2HOST_REQ_I2SRATE 0x02
-#define DSP2HOST_REQ_TIMER 0x04
-
-// AC97 registers
-// XXX fix this crap up
-/*#define AC97_RESET 0x00*/
-
-#define AC97_VOL_MUTE_B 0x8000
-#define AC97_VOL_M 0x1F
-#define AC97_LEFT_VOL_S 8
-
-#define AC97_MASTER_VOL 0x02
-#define AC97_LINE_LEVEL_VOL 0x04
-#define AC97_MASTER_MONO_VOL 0x06
-#define AC97_PC_BEEP_VOL 0x0A
-#define AC97_PC_BEEP_VOL_M 0x0F
-#define AC97_SROUND_MASTER_VOL 0x38
-#define AC97_PC_BEEP_VOL_S 1
-
-/*#define AC97_PHONE_VOL 0x0C
-#define AC97_MIC_VOL 0x0E*/
-#define AC97_MIC_20DB_ENABLE 0x40
-
-/*#define AC97_LINEIN_VOL 0x10
-#define AC97_CD_VOL 0x12
-#define AC97_VIDEO_VOL 0x14
-#define AC97_AUX_VOL 0x16*/
-#define AC97_PCM_OUT_VOL 0x18
-/*#define AC97_RECORD_SELECT 0x1A*/
-#define AC97_RECORD_MIC 0x00
-#define AC97_RECORD_CD 0x01
-#define AC97_RECORD_VIDEO 0x02
-#define AC97_RECORD_AUX 0x03
-#define AC97_RECORD_MONO_MUX 0x02
-#define AC97_RECORD_DIGITAL 0x03
-#define AC97_RECORD_LINE 0x04
-#define AC97_RECORD_STEREO 0x05
-#define AC97_RECORD_MONO 0x06
-#define AC97_RECORD_PHONE 0x07
-
-/*#define AC97_RECORD_GAIN 0x1C*/
-#define AC97_RECORD_VOL_M 0x0F
-
-/*#define AC97_GENERAL_PURPOSE 0x20*/
-#define AC97_POWER_DOWN_CTRL 0x26
-#define AC97_ADC_READY 0x0001
-#define AC97_DAC_READY 0x0002
-#define AC97_ANALOG_READY 0x0004
-#define AC97_VREF_ON 0x0008
-#define AC97_PR0 0x0100
-#define AC97_PR1 0x0200
-#define AC97_PR2 0x0400
-#define AC97_PR3 0x0800
-#define AC97_PR4 0x1000
-
-#define AC97_RESERVED1 0x28
-
-#define AC97_VENDOR_TEST 0x5A
-
-#define AC97_CLOCK_DELAY 0x5C
-#define AC97_LINEOUT_MUX_SEL 0x0001
-#define AC97_MONO_MUX_SEL 0x0002
-#define AC97_CLOCK_DELAY_SEL 0x1F
-#define AC97_DAC_CDS_SHIFT 6
-#define AC97_ADC_CDS_SHIFT 11
-
-#define AC97_MULTI_CHANNEL_SEL 0x74
-
-/*#define AC97_VENDOR_ID1 0x7C
-#define AC97_VENDOR_ID2 0x7E*/
-
-/*
- * ASSP control regs
- */
-#define DSP_PORT_TIMER_COUNT 0x06
-
-#define DSP_PORT_MEMORY_INDEX 0x80
-
-#define DSP_PORT_MEMORY_TYPE 0x82
-#define MEMTYPE_INTERNAL_CODE 0x0002
-#define MEMTYPE_INTERNAL_DATA 0x0003
-#define MEMTYPE_MASK 0x0003
-
-#define DSP_PORT_MEMORY_DATA 0x84
-
-#define DSP_PORT_CONTROL_REG_A 0xA2
-#define DSP_PORT_CONTROL_REG_B 0xA4
-#define DSP_PORT_CONTROL_REG_C 0xA6
-
-#define REV_A_CODE_MEMORY_BEGIN 0x0000
-#define REV_A_CODE_MEMORY_END 0x0FFF
-#define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040
-#define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1)
-
-#define REV_B_CODE_MEMORY_BEGIN 0x0000
-#define REV_B_CODE_MEMORY_END 0x0BFF
-#define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040
-#define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
-
-#define REV_A_DATA_MEMORY_BEGIN 0x1000
-#define REV_A_DATA_MEMORY_END 0x2FFF
-#define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080
-#define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
-
-#define REV_B_DATA_MEMORY_BEGIN 0x1000
-#define REV_B_DATA_MEMORY_END 0x2BFF
-#define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080
-#define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
-
-
-#define NUM_UNITS_KERNEL_CODE 16
-#define NUM_UNITS_KERNEL_DATA 2
-
-#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
-#define NUM_UNITS_KERNEL_DATA_WITH_HSP 5
-
-/*
- * Kernel data layout
- */
-
-#define DP_SHIFT_COUNT 7
-
-#define KDATA_BASE_ADDR 0x1000
-#define KDATA_BASE_ADDR2 0x1080
-
-#define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000)
-#define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001)
-#define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002)
-#define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003)
-#define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004)
-#define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005)
-#define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006)
-#define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007)
-#define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008)
-
-#define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009)
-#define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A)
-
-#define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B)
-#define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C)
-#define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D)
-#define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E)
-#define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F)
-#define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010)
-#define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011)
-#define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012)
-#define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013)
-#define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014)
-
-#define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015)
-#define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016)
-
-#define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017)
-#define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018)
-
-#define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019)
-#define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A)
-
-#define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B)
-#define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C)
-#define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D)
-
-#define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E)
-#define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F)
-#define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020)
-#define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021)
-#define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022)
-
-#define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023)
-#define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024)
-#define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025)
-
-#define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026)
-#define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027)
-#define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028)
-
-#define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029)
-#define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A)
-#define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B)
-#define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C)
-#define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D)
-#define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E)
-#define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F)
-#define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030)
-#define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031)
-#define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032)
-
-#define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033)
-#define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034)
-#define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035)
-
-#define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036)
-#define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037)
-
-#define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038)
-#define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039)
-#define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A)
-
-#define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B)
-#define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C)
-#define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D)
-#define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E)
-#define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F)
-#define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040)
-
-#define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041)
-#define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042)
-#define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043)
-#define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044)
-#define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045)
-#define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046)
-
-#define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047)
-#define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048)
-#define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049)
-#define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A)
-#define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B)
-#define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C)
-
-#define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D)
-#define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E)
-#define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F)
-#define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050)
-
-#define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051)
-#define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052)
-
-#define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053)
-#define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054)
-
-#define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055)
-#define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056)
-#define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057)
-#define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058)
-#define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059)
-
-#define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A)
-#define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B)
-
-#define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C)
-#define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D)
-#define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E)
-
-#define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F)
-#define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060)
-
-#define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061)
-
-#define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062)
-#define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063)
-#define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064)
-#define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065)
-#define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066)
-#define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067)
-#define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068)
-#define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069)
-#define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A)
-#define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B)
-#define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C)
-#define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D)
-
-#define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E)
-#define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F)
-#define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070)
-#define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071)
-
-#define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072)
-#define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073)
-
-#define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074)
-#define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075)
-#define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076)
-#define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077)
-
-#define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078)
-#define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079)
-#define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A)
-#define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B)
-#define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C)
-
-/*
- * second 'segment' (?) reserved for mixer
- * buffers..
- */
-
-#define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000)
-#define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001)
-#define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002)
-#define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003)
-#define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004)
-#define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005)
-#define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006)
-#define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007)
-#define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008)
-#define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009)
-#define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A)
-#define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B)
-#define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C)
-#define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D)
-#define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E)
-#define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F)
-
-#define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010)
-#define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011)
-#define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012)
-#define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013)
-#define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014)
-#define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015)
-#define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016)
-#define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017)
-#define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018)
-#define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019)
-#define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A)
-
-#define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B)
-#define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C)
-#define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D)
-#define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E)
-#define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F)
-#define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020)
-
-#define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
-#define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
-#define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
-#define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
-
-/*
- * client data area offsets
- */
-#define CDATA_INSTANCE_READY 0x00
-
-#define CDATA_HOST_SRC_ADDRL 0x01
-#define CDATA_HOST_SRC_ADDRH 0x02
-#define CDATA_HOST_SRC_END_PLUS_1L 0x03
-#define CDATA_HOST_SRC_END_PLUS_1H 0x04
-#define CDATA_HOST_SRC_CURRENTL 0x05
-#define CDATA_HOST_SRC_CURRENTH 0x06
-
-#define CDATA_IN_BUF_CONNECT 0x07
-#define CDATA_OUT_BUF_CONNECT 0x08
-
-#define CDATA_IN_BUF_BEGIN 0x09
-#define CDATA_IN_BUF_END_PLUS_1 0x0A
-#define CDATA_IN_BUF_HEAD 0x0B
-#define CDATA_IN_BUF_TAIL 0x0C
-#define CDATA_OUT_BUF_BEGIN 0x0D
-#define CDATA_OUT_BUF_END_PLUS_1 0x0E
-#define CDATA_OUT_BUF_HEAD 0x0F
-#define CDATA_OUT_BUF_TAIL 0x10
-
-#define CDATA_DMA_CONTROL 0x11
-#define CDATA_RESERVED 0x12
-
-#define CDATA_FREQUENCY 0x13
-#define CDATA_LEFT_VOLUME 0x14
-#define CDATA_RIGHT_VOLUME 0x15
-#define CDATA_LEFT_SUR_VOL 0x16
-#define CDATA_RIGHT_SUR_VOL 0x17
-
-#define CDATA_HEADER_LEN 0x18
-
-#define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN
-#define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1)
-#define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2)
-#define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3)
-#define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8)
-#define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10)
-#define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16)
-#define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17)
-
-#define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 )
-#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
-#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
-#define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
-#define MINISRC_BIQUAD_STAGE 2
-#define MINISRC_COEF_LOC 0X175
-
-#define DMACONTROL_BLOCK_MASK 0x000F
-#define DMAC_BLOCK0_SELECTOR 0x0000
-#define DMAC_BLOCK1_SELECTOR 0x0001
-#define DMAC_BLOCK2_SELECTOR 0x0002
-#define DMAC_BLOCK3_SELECTOR 0x0003
-#define DMAC_BLOCK4_SELECTOR 0x0004
-#define DMAC_BLOCK5_SELECTOR 0x0005
-#define DMAC_BLOCK6_SELECTOR 0x0006
-#define DMAC_BLOCK7_SELECTOR 0x0007
-#define DMAC_BLOCK8_SELECTOR 0x0008
-#define DMAC_BLOCK9_SELECTOR 0x0009
-#define DMAC_BLOCKA_SELECTOR 0x000A
-#define DMAC_BLOCKB_SELECTOR 0x000B
-#define DMAC_BLOCKC_SELECTOR 0x000C
-#define DMAC_BLOCKD_SELECTOR 0x000D
-#define DMAC_BLOCKE_SELECTOR 0x000E
-#define DMAC_BLOCKF_SELECTOR 0x000F
-#define DMACONTROL_PAGE_MASK 0x00F0
-#define DMAC_PAGE0_SELECTOR 0x0030
-#define DMAC_PAGE1_SELECTOR 0x0020
-#define DMAC_PAGE2_SELECTOR 0x0010
-#define DMAC_PAGE3_SELECTOR 0x0000
-#define DMACONTROL_AUTOREPEAT 0x1000
-#define DMACONTROL_STOPPED 0x2000
-#define DMACONTROL_DIRECTION 0x0100
-
-
-/*
- * DSP Code images
- */
-
-static u16 assp_kernel_image[] = {
- 0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4,
- 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
- 0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
- 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4,
- 0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08,
- 0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909,
- 0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41,
- 0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308,
- 0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910,
- 0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00,
- 0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026,
- 0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0,
- 0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012,
- 0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A,
- 0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000,
- 0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05,
- 0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26,
- 0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300,
- 0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88,
- 0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008,
- 0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80,
- 0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71,
- 0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A,
- 0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100,
- 0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900,
- 0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903,
- 0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309,
- 0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B,
- 0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540,
- 0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C,
- 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380,
- 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340,
- 0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041,
- 0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18,
- 0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40,
- 0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9,
- 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8,
- 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A,
- 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80,
- 0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40,
- 0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80,
- 0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A,
- 0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F,
- 0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1,
- 0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034,
- 0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E,
- 0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977,
- 0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B,
- 0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388,
- 0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80,
- 0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473,
- 0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473,
- 0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880,
- 0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80,
- 0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6,
- 0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909,
- 0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED,
- 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005,
- 0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388,
- 0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4,
- 0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100,
- 0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10,
- 0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070,
- 0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71,
- 0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A,
- 0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061,
- 0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A,
- 0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6,
- 0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A,
- 0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6,
- 0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358,
- 0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6,
- 0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9,
- 0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379,
- 0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6,
- 0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C,
- 0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166,
- 0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B,
- 0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A,
- 0xBE3A,
-};
-
-/*
- * Mini sample rate converter code image
- * that is to be loaded at 0x400 on the DSP.
- */
-static u16 assp_minisrc_image[] = {
-
- 0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412,
- 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41,
- 0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907,
- 0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01,
- 0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904,
- 0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D,
- 0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD,
- 0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22,
- 0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0,
- 0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9,
- 0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89,
- 0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0,
- 0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484,
- 0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80,
- 0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624,
- 0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4,
- 0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027,
- 0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903,
- 0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809,
- 0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46,
- 0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47,
- 0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0,
- 0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516,
- 0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E,
- 0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C,
- 0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180,
- 0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E,
- 0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0,
- 0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0,
- 0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0,
- 0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F,
- 0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-};
-
diff --git a/sound/oss/maui.c b/sound/oss/maui.c
deleted file mode 100644
index 317f225..0000000
--- a/sound/oss/maui.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * sound/oss/maui.c
- *
- * The low level driver for Turtle Beach Maui and Tropez.
- *
- *
- * 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.
- *
- * Changes:
- * Alan Cox General clean up, use kernel IRQ
- * system
- * Christoph Hellwig Adapted to module_init/module_exit
- * Bartlomiej Zolnierkiewicz
- * Added __init to download_code()
- *
- * Status:
- * Andrew J. Kroll Tested 06/01/1999 with:
- * * OSWF.MOT File Version: 1.15
- * * OSWF.MOT File Dated: 09/12/94
- * * Older versions will cause problems.
- */
-
-#include <linux/interrupt.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#define USE_SEQ_MACROS
-#define USE_SIMPLE_MACROS
-
-#include "sound_config.h"
-#include "sound_firmware.h"
-
-#include "mpu401.h"
-
-static int maui_base = 0x330;
-
-static volatile int irq_ok;
-static int *maui_osp;
-
-#define HOST_DATA_PORT (maui_base + 2)
-#define HOST_STAT_PORT (maui_base + 3)
-#define HOST_CTRL_PORT (maui_base + 3)
-
-#define STAT_TX_INTR 0x40
-#define STAT_TX_AVAIL 0x20
-#define STAT_TX_IENA 0x10
-#define STAT_RX_INTR 0x04
-#define STAT_RX_AVAIL 0x02
-#define STAT_RX_IENA 0x01
-
-static int (*orig_load_patch)(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag) = NULL;
-
-#include "maui_boot.h"
-
-static int maui_wait(int mask)
-{
- int i;
-
- /*
- * Perform a short initial wait without sleeping
- */
-
- for (i = 0; i < 100; i++)
- if (inb(HOST_STAT_PORT) & mask)
- return 1;
-
- /*
- * Wait up to 15 seconds with sleeping
- */
-
- for (i = 0; i < 150; i++) {
- if (inb(HOST_STAT_PORT) & mask)
- return 1;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ / 10);
- if (signal_pending(current))
- return 0;
- }
- return 0;
-}
-
-static int maui_read(void)
-{
- if (maui_wait(STAT_RX_AVAIL))
- return inb(HOST_DATA_PORT);
- return -1;
-}
-
-static int maui_write(unsigned char data)
-{
- if (maui_wait(STAT_TX_AVAIL)) {
- outb((data), HOST_DATA_PORT);
- return 1;
- }
- printk(KERN_WARNING "Maui: Write timeout\n");
- return 0;
-}
-
-static irqreturn_t mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
- irq_ok = 1;
- return IRQ_HANDLED;
-}
-
-static int __init download_code(void)
-{
- int i, lines = 0;
- int eol_seen = 0, done = 0;
- int skip = 1;
-
- printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
-
- for (i = 0; i < maui_osLen; i++) {
- if (maui_os[i] != '\r') {
- if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) {
- skip = 0;
-
- if (maui_os[i] == '\n')
- eol_seen = skip = 1;
- else if (maui_os[i] == 'S') {
- if (maui_os[i + 1] == '8')
- done = 1;
- if (!maui_write(0xF1))
- goto failure;
- if (!maui_write('S'))
- goto failure;
- } else {
- if (!maui_write(maui_os[i]))
- goto failure;
- }
-
- if (eol_seen) {
- int c = 0;
- int n;
-
- eol_seen = 0;
-
- for (n = 0; n < 2; n++) {
- if (maui_wait(STAT_RX_AVAIL)) {
- c = inb(HOST_DATA_PORT);
- break;
- }
- }
- if (c != 0x80) {
- printk("Download not acknowledged\n");
- return 0;
- }
- else if (!(lines++ % 10))
- printk(".");
-
- if (done) {
- printk("\n");
- printk(KERN_INFO "Download complete\n");
- return 1;
- }
- }
- }
- }
- }
-
-failure:
- printk("\n");
- printk(KERN_ERR "Download failed!!!\n");
- return 0;
-}
-
-static int __init maui_init(int irq)
-{
- unsigned char bits;
-
- switch (irq) {
- case 9:
- bits = 0x00;
- break;
- case 5:
- bits = 0x08;
- break;
- case 12:
- bits = 0x10;
- break;
- case 15:
- bits = 0x18;
- break;
-
- default:
- printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq);
- return 0;
- }
- outb((0x00), HOST_CTRL_PORT); /* Reset */
- outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */
- outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */
- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
- outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
-
-#ifdef CONFIG_SMP
- {
- int i;
- for (i = 0; i < 1000000 && !irq_ok; i++)
- ;
- if (!irq_ok)
- return 0;
- }
-#endif
- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
-
- printk(KERN_INFO "Turtle Beach Maui initialization\n");
-
- if (!download_code())
- return 0;
-
- outb((0xE0), HOST_CTRL_PORT); /* Normal operation */
-
- /* Select mpu401 mode */
-
- maui_write(0xf0);
- maui_write(1);
- if (maui_read() != 0x80) {
- maui_write(0xf0);
- maui_write(1);
- if (maui_read() != 0x80)
- printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n");
- }
- printk(KERN_INFO "Maui initialized OK\n");
- return 1;
-}
-
-static int maui_short_wait(int mask) {
- int i;
-
- for (i = 0; i < 1000; i++) {
- if (inb(HOST_STAT_PORT) & mask) {
- return 1;
- }
- }
- return 0;
-}
-
-static int maui_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
-
- struct sysex_info header;
- unsigned long left, src_offs;
- int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
- int i;
-
- if (format == SYSEX_PATCH) /* Handled by midi_synth.c */
- return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
-
- if (format != MAUI_PATCH)
- {
- printk(KERN_WARNING "Maui: Unknown patch format\n");
- }
- if (count < hdr_size) {
-/* printk("Maui 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.
- */
-
- if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
- return -EFAULT;
-
- if (count < header.len) {
- printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len);
- header.len = count;
- }
- left = header.len;
- src_offs = 0;
-
- for (i = 0; i < left; i++) {
- unsigned char data;
-
- if(get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i])))
- return -EFAULT;
- if (i == 0 && !(data & 0x80))
- return -EINVAL;
-
- if (maui_write(data) == -1)
- return -EIO;
- }
-
- if ((i = maui_read()) != 0x80) {
- if (i != -1)
- printk("Maui: Error status %02x\n", i);
- return -EIO;
- }
- return 0;
-}
-
-static int __init probe_maui(struct address_info *hw_config)
-{
- struct resource *ports;
- int this_dev;
- int i;
- int tmp1, tmp2, ret;
-
- ports = request_region(hw_config->io_base, 2, "mpu401");
- if (!ports)
- return 0;
-
- if (!request_region(hw_config->io_base + 2, 6, "Maui"))
- goto out;
-
- maui_base = hw_config->io_base;
- maui_osp = hw_config->osp;
-
- if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
- goto out2;
-
- /*
- * Initialize the processor if necessary
- */
-
- if (maui_osLen > 0) {
- if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
- !maui_write(0x9F) || /* Report firmware version */
- !maui_short_wait(STAT_RX_AVAIL) ||
- maui_read() == -1 || maui_read() == -1)
- if (!maui_init(hw_config->irq))
- goto out3;
- }
- if (!maui_write(0xCF)) /* Report hardware version */ {
- printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
- goto out3;
- }
- if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
- printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
- goto out3;
- }
- if (tmp1 == 0xff || tmp2 == 0xff)
- goto out3;
- printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
-
- if (!maui_write(0x9F)) /* Report firmware version */
- goto out3;
- if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
- goto out3;
-
- printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
-
- if (!maui_write(0x85)) /* Report free DRAM */
- goto out3;
- tmp1 = 0;
- for (i = 0; i < 4; i++) {
- tmp1 |= maui_read() << (7 * i);
- }
- printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
-
- for (i = 0; i < 1000; i++)
- if (probe_mpu401(hw_config, ports))
- break;
-
- ret = probe_mpu401(hw_config, ports);
- if (!ret)
- goto out3;
-
- conf_printf("Maui", hw_config);
-
- hw_config->irq *= -1;
- hw_config->name = "Maui";
- attach_mpu401(hw_config, THIS_MODULE);
-
- if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ {
- struct synth_operations *synth;
-
- this_dev = hw_config->slots[1];
-
- /*
- * Intercept patch loading calls so that they can be handled
- * by the Maui driver.
- */
-
- synth = midi_devs[this_dev]->converter;
- if (synth != NULL) {
- synth->id = "MAUI";
- orig_load_patch = synth->load_patch;
- synth->load_patch = &maui_load_patch;
- } else
- printk(KERN_ERR "Maui: Can't install patch loader\n");
- }
- return 1;
-
-out3:
- free_irq(hw_config->irq, NULL);
-out2:
- release_region(hw_config->io_base + 2, 6);
-out:
- release_region(hw_config->io_base, 2);
- return 0;
-}
-
-static void __exit unload_maui(struct address_info *hw_config)
-{
- int irq = hw_config->irq;
- release_region(hw_config->io_base + 2, 6);
- unload_mpu401(hw_config);
-
- if (irq < 0)
- irq = -irq;
- if (irq > 0)
- free_irq(irq, NULL);
-}
-
-static int fw_load;
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-
-/*
- * Install a Maui card. Needs mpu401 loaded already.
- */
-
-static int __init init_maui(void)
-{
- printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n");
-
- cfg.io_base = io;
- cfg.irq = irq;
-
- if (cfg.io_base == -1 || cfg.irq == -1) {
- printk(KERN_INFO "maui: irq and io must be set.\n");
- return -EINVAL;
- }
-
- if (maui_os == NULL) {
- fw_load = 1;
- maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
- }
- if (probe_maui(&cfg) == 0)
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit cleanup_maui(void)
-{
- if (fw_load && maui_os)
- vfree(maui_os);
- unload_maui(&cfg);
-}
-
-module_init(init_maui);
-module_exit(cleanup_maui);
-
-#ifndef MODULE
-static int __init setup_maui(char *str)
-{
- /* io, irq */
- int ints[3];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
-
- return 1;
-}
-
-__setup("maui=", setup_maui);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/midi_syms.c b/sound/oss/midi_syms.c
deleted file mode 100644
index 5b146dd..0000000
--- a/sound/oss/midi_syms.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Exported symbols for midi driver.
- */
-
-#include <linux/module.h>
-
-char midi_syms_symbol;
-
-#include "sound_config.h"
-#define _MIDI_SYNTH_C_
-#include "midi_synth.h"
-
-EXPORT_SYMBOL(do_midi_msg);
-EXPORT_SYMBOL(midi_synth_open);
-EXPORT_SYMBOL(midi_synth_close);
-EXPORT_SYMBOL(midi_synth_ioctl);
-EXPORT_SYMBOL(midi_synth_kill_note);
-EXPORT_SYMBOL(midi_synth_start_note);
-EXPORT_SYMBOL(midi_synth_set_instr);
-EXPORT_SYMBOL(midi_synth_reset);
-EXPORT_SYMBOL(midi_synth_hw_control);
-EXPORT_SYMBOL(midi_synth_aftertouch);
-EXPORT_SYMBOL(midi_synth_controller);
-EXPORT_SYMBOL(midi_synth_panning);
-EXPORT_SYMBOL(midi_synth_setup_voice);
-EXPORT_SYMBOL(midi_synth_send_sysex);
-EXPORT_SYMBOL(midi_synth_bender);
-EXPORT_SYMBOL(midi_synth_load_patch);
-EXPORT_SYMBOL(MIDIbuf_avail);
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c
index d2ab5c0..9e45098 100644
--- a/sound/oss/midi_synth.c
+++ b/sound/oss/midi_synth.c
@@ -84,6 +84,7 @@
;
}
}
+EXPORT_SYMBOL(do_midi_msg);
static void
midi_outc(int midi_dev, int data)
@@ -276,6 +277,7 @@
return -EINVAL;
}
}
+EXPORT_SYMBOL(midi_synth_ioctl);
int
midi_synth_kill_note(int dev, int channel, int note, int velocity)
@@ -342,6 +344,7 @@
return 0;
}
+EXPORT_SYMBOL(midi_synth_kill_note);
int
midi_synth_set_instr(int dev, int channel, int instr_no)
@@ -364,6 +367,7 @@
return 0;
}
+EXPORT_SYMBOL(midi_synth_set_instr);
int
midi_synth_start_note(int dev, int channel, int note, int velocity)
@@ -405,6 +409,7 @@
}
return 0;
}
+EXPORT_SYMBOL(midi_synth_start_note);
void
midi_synth_reset(int dev)
@@ -412,6 +417,7 @@
leave_sysex(dev);
}
+EXPORT_SYMBOL(midi_synth_reset);
int
midi_synth_open(int dev, int mode)
@@ -444,6 +450,7 @@
return 1;
}
+EXPORT_SYMBOL(midi_synth_open);
void
midi_synth_close(int dev)
@@ -459,11 +466,13 @@
midi_devs[orig_dev]->close(orig_dev);
}
+EXPORT_SYMBOL(midi_synth_close);
void
midi_synth_hw_control(int dev, unsigned char *event)
{
}
+EXPORT_SYMBOL(midi_synth_hw_control);
int
midi_synth_load_patch(int dev, int format, const char __user *addr,
@@ -542,11 +551,13 @@
midi_outc(orig_dev, 0xf7);
return 0;
}
-
+EXPORT_SYMBOL(midi_synth_load_patch);
+
void midi_synth_panning(int dev, int channel, int pressure)
{
}
-
+EXPORT_SYMBOL(midi_synth_panning);
+
void midi_synth_aftertouch(int dev, int channel, int pressure)
{
int orig_dev = synth_devs[dev]->midi_dev;
@@ -576,6 +587,7 @@
midi_outc(orig_dev, pressure);
}
+EXPORT_SYMBOL(midi_synth_aftertouch);
void
midi_synth_controller(int dev, int channel, int ctrl_num, int value)
@@ -604,6 +616,7 @@
midi_outc(orig_dev, ctrl_num);
midi_outc(orig_dev, value & 0x7f);
}
+EXPORT_SYMBOL(midi_synth_controller);
void
midi_synth_bender(int dev, int channel, int value)
@@ -635,11 +648,13 @@
midi_outc(orig_dev, value & 0x7f);
midi_outc(orig_dev, (value >> 7) & 0x7f);
}
+EXPORT_SYMBOL(midi_synth_bender);
void
midi_synth_setup_voice(int dev, int voice, int channel)
{
}
+EXPORT_SYMBOL(midi_synth_setup_voice);
int
midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
@@ -695,3 +710,5 @@
return 0;
}
+EXPORT_SYMBOL(midi_synth_send_sysex);
+
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
index c0e4bbc..a40be0c 100644
--- a/sound/oss/midibuf.c
+++ b/sound/oss/midibuf.c
@@ -414,18 +414,11 @@
}
-void MIDIbuf_init(void)
-{
- /* drag in midi_syms.o */
- {
- extern char midi_syms_symbol;
- midi_syms_symbol = 0;
- }
-}
-
int MIDIbuf_avail(int dev)
{
if (midi_in_buf[dev])
return DATA_AVAIL (midi_in_buf[dev]);
return 0;
}
+EXPORT_SYMBOL(MIDIbuf_avail);
+
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index 321f4c4..162d07c 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -432,16 +432,7 @@
devc->m_busy = 0;
}
-int intchk_mpu401(void *dev_id)
-{
- struct mpu_config *devc;
- int dev = (int) dev_id;
-
- devc = &dev_conf[dev];
- return input_avail(devc);
-}
-
-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
{
struct mpu_config *devc;
int dev = (int) dev_id;
@@ -1761,8 +1752,6 @@
EXPORT_SYMBOL(probe_mpu401);
EXPORT_SYMBOL(attach_mpu401);
EXPORT_SYMBOL(unload_mpu401);
-EXPORT_SYMBOL(intchk_mpu401);
-EXPORT_SYMBOL(mpuintr);
static struct address_info cfg;
diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h
index bdc5bde..84c0e95 100644
--- a/sound/oss/mpu401.h
+++ b/sound/oss/mpu401.h
@@ -10,5 +10,3 @@
int attach_mpu401(struct address_info * hw_config, struct module *owner);
void unload_mpu401(struct address_info *hw_info);
-int intchk_mpu401(void *dev_id);
-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs * dummy);
diff --git a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c
deleted file mode 100644
index 2535ed0..0000000
--- a/sound/oss/opl3sa.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * sound/oss/opl3sa.c
- *
- * Low level driver for Yamaha YMF701B aka OPL3-SA chip
- *
- *
- *
- * 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.
- *
- * Changes:
- * Alan Cox Modularisation
- * Christoph Hellwig Adapted to module_init/module_exit
- * Arnaldo C. de Melo got rid of attach_uart401
- *
- * FIXME:
- * Check for install of mpu etc is wrong, should check result of the mss stuff
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-
-#undef SB_OK
-
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#ifdef SB_OK
-#include "sb.h"
-static int sb_initialized;
-#endif
-
-static DEFINE_SPINLOCK(lock);
-
-static unsigned char opl3sa_read(int addr)
-{
- unsigned long flags;
- unsigned char tmp;
-
- spin_lock_irqsave(&lock,flags);
- outb((0x1d), 0xf86); /* password */
- outb(((unsigned char) addr), 0xf86); /* address */
- tmp = inb(0xf87); /* data */
- spin_unlock_irqrestore(&lock,flags);
-
- return tmp;
-}
-
-static void opl3sa_write(int addr, int data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
- outb((0x1d), 0xf86); /* password */
- outb(((unsigned char) addr), 0xf86); /* address */
- outb(((unsigned char) data), 0xf87); /* data */
- spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init opl3sa_detect(void)
-{
- int tmp;
-
- if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04)
- {
- DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01)));
- /* return 0; */
- }
-
- /*
- * Check that the password feature has any effect
- */
-
- if (inb(0xf87) == tmp)
- {
- DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87)));
- return 0;
- }
- tmp = (opl3sa_read(0x04) & 0xe0) >> 5;
-
- if (tmp != 0 && tmp != 1)
- {
- DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp));
- return 0;
- }
- DDB(printk("OPL3-SA mode %x detected\n", tmp));
-
- opl3sa_write(0x01, 0x00); /* Disable MSS */
- opl3sa_write(0x02, 0x00); /* Disable SB */
- opl3sa_write(0x03, 0x00); /* Disable MPU */
-
- return 1;
-}
-
-/*
- * Probe and attach routines for the Windows Sound System mode of
- * OPL3-SA
- */
-
-static int __init probe_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
-{
- unsigned char tmp = 0x24; /* WSS enable */
-
- /*
- * Check if the IO port returns valid signature. The original MS Sound
- * system returns 0x04 while some cards (OPL3-SA for example)
- * return 0x00.
- */
-
- if (!opl3sa_detect())
- {
- printk(KERN_ERR "OSS: OPL3-SA chip not found\n");
- return 0;
- }
-
- switch (hw_config->io_base)
- {
- case 0x530:
- tmp |= 0x00;
- break;
- case 0xe80:
- tmp |= 0x08;
- break;
- case 0xf40:
- tmp |= 0x10;
- break;
- case 0x604:
- tmp |= 0x18;
- break;
- default:
- printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base);
- return 0;
- }
-
- opl3sa_write(0x01, tmp); /* WSS setup register */
-
- return probe_ms_sound(hw_config, ports);
-}
-
-static void __init attach_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
-{
- int nm = num_mixers;
-
- /* FIXME */
- attach_ms_sound(hw_config, ports, THIS_MODULE);
- if (num_mixers > nm) /* A mixer was installed */
- {
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
- }
-}
-
-
-static int __init probe_opl3sa_mpu(struct address_info *hw_config)
-{
- unsigned char conf;
- static signed char irq_bits[] = {
- -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
- };
-
- if (hw_config->irq > 10)
- {
- printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
- return 0;
- }
- if (irq_bits[hw_config->irq] == -1)
- {
- printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
- return 0;
- }
- switch (hw_config->io_base)
- {
- case 0x330:
- conf = 0x00;
- break;
- case 0x332:
- conf = 0x20;
- break;
- case 0x334:
- conf = 0x40;
- break;
- case 0x300:
- conf = 0x60;
- break;
- default:
- return 0; /* Invalid port */
- }
-
- conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */
- conf |= irq_bits[hw_config->irq] << 2;
-
- opl3sa_write(0x03, conf);
-
- hw_config->name = "OPL3-SA (MPU401)";
-
- return probe_uart401(hw_config, THIS_MODULE);
-}
-
-static void __exit unload_opl3sa_wss(struct address_info *hw_config)
-{
- int dma2 = hw_config->dma2;
-
- if (dma2 == -1)
- dma2 = hw_config->dma;
-
- release_region(0xf86, 2);
- release_region(hw_config->io_base, 4);
-
- ad1848_unload(hw_config->io_base + 4,
- hw_config->irq,
- hw_config->dma,
- dma2,
- 0);
- sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config)
-{
- unload_uart401(hw_config);
-}
-
-#ifdef SB_OK
-static inline void __exit unload_opl3sa_sb(struct address_info *hw_config)
-{
- sb_dsp_unload(hw_config);
-}
-#endif
-
-static int found_mpu;
-
-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 mpu_io = -1;
-static int __initdata mpu_irq = -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma2, int, 0);
-module_param(mpu_io, int, 0);
-module_param(mpu_irq, int, 0);
-
-static int __init init_opl3sa(void)
-{
- struct resource *ports;
- if (io == -1 || irq == -1 || dma == -1) {
- printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n");
- return -EINVAL;
- }
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma2;
-
- cfg_mpu.io_base = mpu_io;
- cfg_mpu.irq = mpu_irq;
-
- ports = request_region(io + 4, 4, "ad1848");
- if (!ports)
- return -EBUSY;
-
- if (!request_region(0xf86, 2, "OPL3-SA"))/* Control port is busy */ {
- release_region(io + 4, 4);
- return 0;
- }
-
- if (!request_region(io, 4, "WSS config")) {
- release_region(0x86, 2);
- release_region(io + 4, 4);
- return 0;
- }
-
- if (probe_opl3sa_wss(&cfg, ports) == 0) {
- release_region(0xf86, 2);
- release_region(io, 4);
- release_region(io + 4, 4);
- return -ENODEV;
- }
-
- found_mpu=probe_opl3sa_mpu(&cfg_mpu);
-
- attach_opl3sa_wss(&cfg, ports);
- return 0;
-}
-
-static void __exit cleanup_opl3sa(void)
-{
- if(found_mpu)
- unload_opl3sa_mpu(&cfg_mpu);
- unload_opl3sa_wss(&cfg);
-}
-
-module_init(init_opl3sa);
-module_exit(cleanup_opl3sa);
-
-#ifndef MODULE
-static int __init setup_opl3sa(char *str)
-{
- /* io, irq, dma, dma2, mpu_io, mpu_irq */
- int ints[7];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- mpu_io = ints[5];
- mpu_irq = ints[6];
-
- return 1;
-}
-
-__setup("opl3sa=", setup_opl3sa);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c
deleted file mode 100644
index f17d25b..0000000
--- a/sound/oss/rme96xx.c
+++ /dev/null
@@ -1,1857 +0,0 @@
-/* (C) 2000 Guenter Geiger <geiger@debian.org>
- with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
- based on es1370.c
-
-
-
- * 10 Jan 2001: 0.1 initial version
- * 19 Jan 2001: 0.2 fixed bug in select()
- * 27 Apr 2001: 0.3 more than one card usable
- * 11 May 2001: 0.4 fixed for SMP, included into kernel source tree
- * 17 May 2001: 0.5 draining code didn't work on new cards
- * 18 May 2001: 0.6 remove synchronize_irq() call
- * 17 Jul 2001: 0.7 updated xrmectrl to make it work for newer cards
- * 2 feb 2002: 0.8 fixed pci device handling, see below for patches from Heiko (Thanks!)
- Marcus Meissner <Marcus.Meissner@caldera.de>
-
- Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
- HP20020108 fixed handling of "large" read()
- HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
- HP20020118 made mixer ioctl and handling of devices>1 more safe
- HP20020201 fixed handling of "large" read() properly
- added REV 1.5 S/P-DIF receiver support
- SNDCTL_DSP_SPEED now returns the actual speed
- * 10 Aug 2002: added synchronize_irq() again
-
-TODO:
- - test more than one card --- done
- - check for pci IOREGION (see es1370) in rme96xx_probe ??
- - error detection
- - mmap interface
- - mixer mmap interface
- - mixer ioctl
- - get rid of noise upon first open (why ??)
- - allow multiple open (at least for read)
- - allow multiple open for non overlapping regions
- - recheck the multiple devices part (offsets of different devices, etc)
- - do decent draining in _release --- done
- - SMP support
- - what about using fragstotal>2 for small fragsize? (HP20020118)
- - add support for AFMT_S32_LE
-*/
-
-#ifndef RMEVERSION
-#define RMEVERSION "0.8"
-#endif
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-#include <asm/dma.h>
-#include <asm/page.h>
-
-#include "rme96xx.h"
-
-#define NR_DEVICE 2
-
-static int devices = 1;
-module_param(devices, int, 0);
-MODULE_PARM_DESC(devices, "number of dsp devices allocated by the driver");
-
-
-MODULE_AUTHOR("Guenter Geiger, geiger@debian.org");
-MODULE_DESCRIPTION("RME9652/36 \"Hammerfall\" Driver");
-MODULE_LICENSE("GPL");
-
-
-#ifdef DEBUG
-#define DBG(x) printk("RME_DEBUG:");x
-#define COMM(x) printk("RME_COMM: " x "\n");
-#else
-#define DBG(x) while (0) {}
-#define COMM(x)
-#endif
-
-/*--------------------------------------------------------------------------
- Preporcessor Macros and Definitions
- --------------------------------------------------------------------------*/
-
-#define RME96xx_MAGIC 0x6473
-
-/* Registers-Space in offsets from base address with 16MByte size */
-
-#define RME96xx_IO_EXTENT 16l*1024l*1024l
-#define RME96xx_CHANNELS_PER_CARD 26
-
-/* Write - Register */
-
-/* 0,4,8,12,16,20,24,28 ... hardware init (erasing fifo-pointer intern) */
-#define RME96xx_num_of_init_regs 8
-
-#define RME96xx_init_buffer (0/4)
-#define RME96xx_play_buffer (32/4) /* pointer to 26x64kBit RAM from mainboard */
-#define RME96xx_rec_buffer (36/4) /* pointer to 26x64kBit RAM from mainboard */
-#define RME96xx_control_register (64/4) /* exact meaning see below */
-#define RME96xx_irq_clear (96/4) /* irq acknowledge */
-#define RME96xx_time_code (100/4) /* if used with alesis adat */
-#define RME96xx_thru_base (128/4) /* 132...228 Thru for 26 channels */
-#define RME96xx_thru_channels RME96xx_CHANNELS_PER_CARD
-
-/* Read Register */
-
-#define RME96xx_status_register 0 /* meaning see below */
-
-
-
-/* Status Register: */
-/* ------------------------------------------------------------------------ */
-#define RME96xx_IRQ 0x0000001 /* IRQ is High if not reset by RMExx_irq_clear */
-#define RME96xx_lock_2 0x0000002 /* ADAT 3-PLL: 1=locked, 0=unlocked */
-#define RME96xx_lock_1 0x0000004 /* ADAT 2-PLL: 1=locked, 0=unlocked */
-#define RME96xx_lock_0 0x0000008 /* ADAT 1-PLL: 1=locked, 0=unlocked */
-
-#define RME96xx_fs48 0x0000010 /* sample rate 0 ...44.1/88.2, 1 ... 48/96 Khz */
-#define RME96xx_wsel_rd 0x0000020 /* if Word-Clock is used and valid then 1 */
-#define RME96xx_buf_pos1 0x0000040 /* Bit 6..15 : Position of buffer-pointer in 64Bytes-blocks */
-#define RME96xx_buf_pos2 0x0000080 /* resolution +/- 1 64Byte/block (since 64Bytes bursts) */
-
-#define RME96xx_buf_pos3 0x0000100 /* 10 bits = 1024 values */
-#define RME96xx_buf_pos4 0x0000200 /* if we mask off the first 6 bits, we can take the status */
-#define RME96xx_buf_pos5 0x0000400 /* register as sample counter in the hardware buffer */
-#define RME96xx_buf_pos6 0x0000800
-
-#define RME96xx_buf_pos7 0x0001000
-#define RME96xx_buf_pos8 0x0002000
-#define RME96xx_buf_pos9 0x0004000
-#define RME96xx_buf_pos10 0x0008000
-
-#define RME96xx_sync_2 0x0010000 /* if ADAT-IN3 synced to system clock */
-#define RME96xx_sync_1 0x0020000 /* if ADAT-IN2 synced to system clock */
-#define RME96xx_sync_0 0x0040000 /* if ADAT-IN1 synced to system clock */
-#define RME96xx_DS_rd 0x0080000 /* 1=Double Speed, 0=Normal Speed */
-
-#define RME96xx_tc_busy 0x0100000 /* 1=time-code copy in progress (960ms) */
-#define RME96xx_tc_out 0x0200000 /* time-code out bit */
-#define RME96xx_F_0 0x0400000 /* 000=64kHz, 100=88.2kHz, 011=96kHz */
-#define RME96xx_F_1 0x0800000 /* 111=32kHz, 110=44.1kHz, 101=48kHz, */
-
-#define RME96xx_F_2 0x1000000 /* 001=Rev 1.5+ external Crystal Chip */
-#define RME96xx_ERF 0x2000000 /* Error-Flag of SDPIF Receiver (1=No Lock)*/
-#define RME96xx_buffer_id 0x4000000 /* toggles by each interrupt on rec/play */
-#define RME96xx_tc_valid 0x8000000 /* 1 = a signal is detected on time-code input */
-#define RME96xx_SPDIF_READ 0x10000000 /* byte available from Rev 1.5+ SPDIF interface */
-
-/* Status Register Fields */
-
-#define RME96xx_lock (RME96xx_lock_0|RME96xx_lock_1|RME96xx_lock_2)
-#define RME96xx_sync (RME96xx_sync_0|RME96xx_sync_1|RME96xx_sync_2)
-#define RME96xx_F (RME96xx_F_0|RME96xx_F_1|RME96xx_F_2)
-#define rme96xx_decode_spdif_rate(x) ((x)>>22)
-
-/* Bit 6..15 : h/w buffer pointer */
-#define RME96xx_buf_pos 0x000FFC0
-/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later
- Rev G EEPROMS and Rev 1.5 cards or later.
-*/
-#define RME96xx_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME96xx_buf_pos))
-
-
-/* Control-Register: */
-/*--------------------------------------------------------------------------------*/
-
-#define RME96xx_start_bit 0x0001 /* start record/play */
-#define RME96xx_latency0 0x0002 /* Buffer size / latency */
-#define RME96xx_latency1 0x0004 /* buffersize = 512Bytes * 2^n */
-#define RME96xx_latency2 0x0008 /* 0=64samples ... 7=8192samples */
-
-#define RME96xx_Master 0x0010 /* Clock Mode 1=Master, 0=Slave/Auto */
-#define RME96xx_IE 0x0020 /* Interupt Enable */
-#define RME96xx_freq 0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/
-#define RME96xx_freq1 0x0080 /* samplerate 0=32 kHz, 1=other rates ??? (from ALSA, but may be wrong) */
-#define RME96xx_DS 0x0100 /* double speed 0=44.1/48, 1=88.2/96 Khz */
-#define RME96xx_PRO 0x0200 /* SPDIF-OUT 0=consumer, 1=professional */
-#define RME96xx_EMP 0x0400 /* SPDIF-OUT emphasis 0=off, 1=on */
-#define RME96xx_Dolby 0x0800 /* SPDIF-OUT non-audio bit 1=set, 0=unset */
-
-#define RME96xx_opt_out 0x1000 /* use 1st optical OUT as SPDIF: 1=yes, 0=no */
-#define RME96xx_wsel 0x2000 /* use Wordclock as sync (overwrites master) */
-#define RME96xx_inp_0 0x4000 /* SPDIF-IN 00=optical (ADAT1), */
-#define RME96xx_inp_1 0x8000 /* 01=coaxial (Cinch), 10=internal CDROM */
-
-#define RME96xx_SyncRef0 0x10000 /* preferred sync-source in autosync */
-#define RME96xx_SyncRef1 0x20000 /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
-
-#define RME96xx_SPDIF_RESET (1<<18) /* Rev 1.5+: h/w SPDIF receiver */
-#define RME96xx_SPDIF_SELECT (1<<19)
-#define RME96xx_SPDIF_CLOCK (1<<20)
-#define RME96xx_SPDIF_WRITE (1<<21)
-#define RME96xx_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */
-
-
-#define RME96xx_ctrl_init (RME96xx_latency0 |\
- RME96xx_Master |\
- RME96xx_inp_1)
-
-
-
-/* Control register fields and shortcuts */
-
-#define RME96xx_latency (RME96xx_latency0|RME96xx_latency1|RME96xx_latency2)
-#define RME96xx_inp (RME96xx_inp_0|RME96xx_inp_1)
-#define RME96xx_SyncRef (RME96xx_SyncRef0|RME96xx_SyncRef1)
-#define RME96xx_mixer_allowed (RME96xx_Master|RME96xx_PRO|RME96xx_EMP|RME96xx_Dolby|RME96xx_opt_out|RME96xx_wsel|RME96xx_inp|RME96xx_SyncRef|RME96xx_ADAT1_INTERNAL)
-
-/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit1 (??? HP20020201) */
-
-#define RME96xx_SET_LATENCY(x) (((x)&0x7)<<1)
-#define RME96xx_GET_LATENCY(x) (((x)>>1)&0x7)
-#define RME96xx_SET_inp(x) (((x)&0x3)<<14)
-#define RME96xx_GET_inp(x) (((x)>>14)&0x3)
-#define RME96xx_SET_SyncRef(x) (((x)&0x3)<<17)
-#define RME96xx_GET_SyncRef(x) (((x)>>17)&0x3)
-
-
-/* buffer sizes */
-#define RME96xx_BYTES_PER_SAMPLE 4 /* sizeof(u32) */
-#define RME_16K 16*1024
-
-#define RME96xx_DMA_MAX_SAMPLES (RME_16K)
-#define RME96xx_DMA_MAX_SIZE (RME_16K * RME96xx_BYTES_PER_SAMPLE)
-#define RME96xx_DMA_MAX_SIZE_ALL (RME96xx_DMA_MAX_SIZE * RME96xx_CHANNELS_PER_CARD)
-
-#define RME96xx_NUM_OF_FRAGMENTS 2
-#define RME96xx_FRAGMENT_MAX_SIZE (RME96xx_DMA_MAX_SIZE/2)
-#define RME96xx_FRAGMENT_MAX_SAMPLES (RME96xx_DMA_MAX_SAMPLES/2)
-#define RME96xx_MAX_LATENCY 7 /* 16k samples */
-
-
-#define RME96xx_MAX_DEVS 4 /* we provide some OSS stereodevs */
-#define RME96xx_MASK_DEVS 0x3 /* RME96xx_MAX_DEVS-1 */
-
-#define RME_MESS "rme96xx:"
-/*------------------------------------------------------------------------
- Types, struct and function declarations
- ------------------------------------------------------------------------*/
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT RME_MESS" invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != RME96xx_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-
-static struct file_operations rme96xx_audio_fops;
-static struct file_operations rme96xx_mixer_fops;
-static int numcards;
-
-typedef int32_t raw_sample_t;
-
-typedef struct _rme96xx_info {
-
- /* hardware settings */
- int magic;
- struct pci_dev * pcidev; /* pci_dev structure */
- unsigned long __iomem *iobase;
- unsigned int irq;
-
- /* list of rme96xx devices */
- struct list_head devs;
-
- spinlock_t lock;
-
- u32 *recbuf; /* memory for rec buffer */
- u32 *playbuf; /* memory for play buffer */
-
- u32 control_register;
-
- u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */
-
- int hw_rev; /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */
- char *card_name; /* hammerfall or hammerfall light names */
-
- int open_count; /* unused ??? HP20020201 */
-
- int rate;
- int latency;
- unsigned int fragsize;
- int started;
-
- int hwptr; /* can be negativ because of pci burst offset */
- unsigned int hwbufid; /* set by interrupt, buffer which is written/read now */
-
- struct dmabuf {
-
- unsigned int format;
- int formatshift;
- int inchannels; /* number of channels for device */
- int outchannels; /* number of channels for device */
- int mono; /* if true, we play mono on 2 channels */
- int inoffset; /* which channel is considered the first one */
- int outoffset;
-
- /* state */
- int opened; /* open() made */
- int started; /* first write/read */
- int mmapped; /* mmap */
- int open_mode;
-
- struct _rme96xx_info *s;
-
- /* pointer to read/write position in buffer */
- unsigned readptr;
- unsigned writeptr;
-
- unsigned error; /* over/underruns cleared on sync again */
-
- /* waiting and locking */
- wait_queue_head_t wait;
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
-
- } dma[RME96xx_MAX_DEVS];
-
- int dspnum[RME96xx_MAX_DEVS]; /* register with sound subsystem */
- int mixer; /* register with sound subsystem */
-} rme96xx_info;
-
-
-/* fiddling with the card (first level hardware control) */
-
-static inline void rme96xx_set_ctrl(rme96xx_info* s,int mask)
-{
-
- s->control_register|=mask;
- writel(s->control_register,s->iobase + RME96xx_control_register);
-
-}
-
-static inline void rme96xx_unset_ctrl(rme96xx_info* s,int mask)
-{
-
- s->control_register&=(~mask);
- writel(s->control_register,s->iobase + RME96xx_control_register);
-
-}
-
-static inline int rme96xx_get_sample_rate_status(rme96xx_info* s)
-{
- int val;
- u32 status;
- status = readl(s->iobase + RME96xx_status_register);
- val = (status & RME96xx_fs48) ? 48000 : 44100;
- if (status & RME96xx_DS_rd)
- val *= 2;
- return val;
-}
-
-static inline int rme96xx_get_sample_rate_ctrl(rme96xx_info* s)
-{
- int val;
- val = (s->control_register & RME96xx_freq) ? 48000 : 44100;
- if (s->control_register & RME96xx_DS)
- val *= 2;
- return val;
-}
-
-
-/* code from ALSA card-rme9652.c for rev 1.5 SPDIF receiver HP 20020201 */
-
-static void rme96xx_spdif_set_bit (rme96xx_info* s, int mask, int onoff)
-{
- if (onoff)
- s->control_register |= mask;
- else
- s->control_register &= ~mask;
-
- writel(s->control_register,s->iobase + RME96xx_control_register);
-}
-
-static void rme96xx_spdif_write_byte (rme96xx_info* s, const int val)
-{
- long mask;
- long i;
-
- for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
- if (val & mask)
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 1);
- else
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 0);
-
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
- }
-}
-
-static int rme96xx_spdif_read_byte (rme96xx_info* s)
-{
- long mask;
- long val;
- long i;
-
- val = 0;
-
- for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
- if (readl(s->iobase + RME96xx_status_register) & RME96xx_SPDIF_READ)
- val |= mask;
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
- }
-
- return val;
-}
-
-static void rme96xx_write_spdif_codec (rme96xx_info* s, const int address, const int data)
-{
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
- rme96xx_spdif_write_byte (s, 0x20);
- rme96xx_spdif_write_byte (s, address);
- rme96xx_spdif_write_byte (s, data);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
-}
-
-
-static int rme96xx_spdif_read_codec (rme96xx_info* s, const int address)
-{
- int ret;
-
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
- rme96xx_spdif_write_byte (s, 0x20);
- rme96xx_spdif_write_byte (s, address);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
-
- rme96xx_spdif_write_byte (s, 0x21);
- ret = rme96xx_spdif_read_byte (s);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
-
- return ret;
-}
-
-static void rme96xx_initialize_spdif_receiver (rme96xx_info* s)
-{
- /* XXX what unsets this ? */
- /* no idea ??? HP 20020201 */
-
- s->control_register |= RME96xx_SPDIF_RESET;
-
- rme96xx_write_spdif_codec (s, 4, 0x40);
- rme96xx_write_spdif_codec (s, 17, 0x13);
- rme96xx_write_spdif_codec (s, 6, 0x02);
-}
-
-static inline int rme96xx_spdif_sample_rate (rme96xx_info *s, int *spdifrate)
-{
- unsigned int rate_bits;
-
- *spdifrate = 0x1;
- if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) {
- return -1; /* error condition */
- }
-
- if (s->hw_rev == 15) {
-
- int x, y, ret;
-
- x = rme96xx_spdif_read_codec (s, 30);
-
- if (x != 0)
- y = 48000 * 64 / x;
- else
- y = 0;
-
- if (y > 30400 && y < 33600) {ret = 32000; *spdifrate = 0x7;}
- else if (y > 41900 && y < 46000) {ret = 44100; *spdifrate = 0x6;}
- else if (y > 46000 && y < 50400) {ret = 48000; *spdifrate = 0x5;}
- else if (y > 60800 && y < 67200) {ret = 64000; *spdifrate = 0x0;}
- else if (y > 83700 && y < 92000) {ret = 88200; *spdifrate = 0x4;}
- else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;}
- else {ret = 0; *spdifrate = 0x1;}
- return ret;
- }
-
- rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F;
-
- switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) {
- case 0x7:
- return 32000;
- break;
-
- case 0x6:
- return 44100;
- break;
-
- case 0x5:
- return 48000;
- break;
-
- case 0x4:
- return 88200;
- break;
-
- case 0x3:
- return 96000;
- break;
-
- case 0x0:
- return 64000;
- break;
-
- default:
- /* was an ALSA warning ...
- snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n",
- s->card_name, rate_bits);
- */
- return 0;
- break;
- }
-}
-
-/* end of code from ALSA card-rme9652.c */
-
-
-
-/* the hwbuf in the status register seems to have some jitter, to get rid of
- it, we first only let the numbers grow, to be on the secure side we
- subtract a certain amount RME96xx_BURSTBYTES from the resulting number */
-
-/* the function returns the hardware pointer in bytes */
-#define RME96xx_BURSTBYTES -64 /* bytes by which hwptr could be off */
-
-static inline int rme96xx_gethwptr(rme96xx_info* s,int exact)
-{
- unsigned long flags;
- if (exact) {
- unsigned int hwp;
-/* the hwptr seems to be rather unreliable :(, so we don't use it */
- spin_lock_irqsave(&s->lock,flags);
-
- hwp = readl(s->iobase + RME96xx_status_register) & 0xffc0;
- s->hwptr = (hwp < s->hwptr) ? s->hwptr : hwp;
-// s->hwptr = hwp;
-
- spin_unlock_irqrestore(&s->lock,flags);
- return (s->hwptr+RME96xx_BURSTBYTES) & ((s->fragsize<<1)-1);
- }
- return (s->hwbufid ? s->fragsize : 0);
-}
-
-static inline void rme96xx_setlatency(rme96xx_info* s,int l)
-{
- s->latency = l;
- s->fragsize = 1<<(8+l);
- rme96xx_unset_ctrl(s,RME96xx_latency);
- rme96xx_set_ctrl(s,RME96xx_SET_LATENCY(l));
-}
-
-
-static void rme96xx_clearbufs(struct dmabuf* dma)
-{
- int i,j;
- unsigned long flags;
-
- /* clear dmabufs */
- for(i=0;i<devices;i++) {
- for (j=0;j<dma->outchannels + dma->mono;j++)
- memset(&dma->s->playbuf[(dma->outoffset + j)*RME96xx_DMA_MAX_SAMPLES],
- 0, RME96xx_DMA_MAX_SIZE);
- }
- spin_lock_irqsave(&dma->s->lock,flags);
- dma->writeptr = 0;
- dma->readptr = 0;
- spin_unlock_irqrestore(&dma->s->lock,flags);
-}
-
-static int rme96xx_startcard(rme96xx_info *s,int stop)
-{
- int i;
- unsigned long flags;
-
- COMM ("startcard");
- if(s->control_register & RME96xx_IE){
- /* disable interrupt first */
-
- rme96xx_unset_ctrl( s,RME96xx_start_bit );
- udelay(10);
- rme96xx_unset_ctrl( s,RME96xx_IE);
- spin_lock_irqsave(&s->lock,flags); /* timing is critical */
- s->started = 0;
- spin_unlock_irqrestore(&s->lock,flags);
- if (stop) {
- COMM("Sound card stopped");
- return 1;
- }
- }
- COMM ("interrupt disabled");
- /* first initialize all pointers on card */
- for(i=0;i<RME96xx_num_of_init_regs;i++){
- writel(0,s->iobase + i);
- udelay(10); /* ?? */
- }
- COMM ("regs cleaned");
-
- spin_lock_irqsave(&s->lock,flags); /* timing is critical */
- udelay(10);
- s->started = 1;
- s->hwptr = 0;
- spin_unlock_irqrestore(&s->lock,flags);
-
- rme96xx_set_ctrl( s, RME96xx_IE | RME96xx_start_bit);
-
-
- COMM("Sound card started");
-
- return 1;
-}
-
-
-static inline int rme96xx_getospace(struct dmabuf * dma, unsigned int hwp)
-{
- int cnt;
- int swptr;
- unsigned long flags;
-
- spin_lock_irqsave(&dma->s->lock,flags);
- swptr = dma->writeptr;
- cnt = (hwp - swptr);
-
- if (cnt < 0) {
- cnt = ((dma->s->fragsize<<1) - swptr);
- }
- spin_unlock_irqrestore(&dma->s->lock,flags);
- return cnt;
-}
-
-static inline int rme96xx_getispace(struct dmabuf * dma, unsigned int hwp)
-{
- int cnt;
- int swptr;
- unsigned long flags;
-
- spin_lock_irqsave(&dma->s->lock,flags);
- swptr = dma->readptr;
- cnt = (hwp - swptr);
-
- if (cnt < 0) {
- cnt = ((dma->s->fragsize<<1) - swptr);
- }
- spin_unlock_irqrestore(&dma->s->lock,flags);
- return cnt;
-}
-
-
-static inline int rme96xx_copyfromuser(struct dmabuf* dma,const char __user * buffer,int count,int hop)
-{
- int swptr = dma->writeptr;
- switch (dma->format) {
- case AFMT_S32_BLOCKED:
- {
- char __user * buf = (char __user *)buffer;
- int cnt = count/dma->outchannels;
- int i;
- for (i=0;i < dma->outchannels;i++) {
- char* hwbuf =(char*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=swptr;
-
- if (copy_from_user(hwbuf,buf, cnt))
- return -1;
- buf+=hop;
- }
- swptr+=cnt;
- break;
- }
- case AFMT_S16_LE:
- {
- int i,j;
- int cnt = count/dma->outchannels;
- for (i=0;i < dma->outchannels + dma->mono;i++) {
- short __user * sbuf = (short __user *)buffer + i*(!dma->mono);
- short* hwbuf =(short*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=(swptr>>1);
- for (j=0;j<(cnt>>1);j++) {
- hwbuf++; /* skip the low 16 bits */
- __get_user(*hwbuf++,sbuf++);
- sbuf+=(dma->outchannels-1);
- }
- }
- swptr += (cnt<<1);
- break;
- }
- default:
- printk(RME_MESS" unsupported format\n");
- return -1;
- } /* switch */
-
- swptr&=((dma->s->fragsize<<1) -1);
- dma->writeptr = swptr;
-
- return 0;
-}
-
-/* The count argument is the number of bytes */
-static inline int rme96xx_copytouser(struct dmabuf* dma,const char __user* buffer,int count,int hop)
-{
- int swptr = dma->readptr;
- switch (dma->format) {
- case AFMT_S32_BLOCKED:
- {
- char __user * buf = (char __user *)buffer;
- int cnt = count/dma->inchannels;
- int i;
-
- for (i=0;i < dma->inchannels;i++) {
- char* hwbuf =(char*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=swptr;
-
- if (copy_to_user(buf,hwbuf,cnt))
- return -1;
- buf+=hop;
- }
- swptr+=cnt;
- break;
- }
- case AFMT_S16_LE:
- {
- int i,j;
- int cnt = count/dma->inchannels;
- for (i=0;i < dma->inchannels;i++) {
- short __user * sbuf = (short __user *)buffer + i;
- short* hwbuf =(short*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=(swptr>>1);
- for (j=0;j<(cnt>>1);j++) {
- hwbuf++;
- __put_user(*hwbuf++,sbuf++);
- sbuf+=(dma->inchannels-1);
- }
- }
- swptr += (cnt<<1);
- break;
- }
- default:
- printk(RME_MESS" unsupported format\n");
- return -1;
- } /* switch */
-
- swptr&=((dma->s->fragsize<<1) -1);
- dma->readptr = swptr;
- return 0;
-}
-
-
-static irqreturn_t rme96xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- int i;
- rme96xx_info *s = (rme96xx_info *)dev_id;
- struct dmabuf *db;
- u32 status;
- unsigned long flags;
-
- status = readl(s->iobase + RME96xx_status_register);
- if (!(status & RME96xx_IRQ)) {
- return IRQ_NONE;
- }
-
- spin_lock_irqsave(&s->lock,flags);
- writel(0,s->iobase + RME96xx_irq_clear);
-
- s->hwbufid = (status & RME96xx_buffer_id)>>26;
- if ((status & 0xffc0) <= 256) s->hwptr = 0;
- for(i=0;i<devices;i++)
- {
- db = &(s->dma[i]);
- if(db->started > 0)
- wake_up(&(db->wait));
- }
- spin_unlock_irqrestore(&s->lock,flags);
- return IRQ_HANDLED;
-}
-
-
-
-/*----------------------------------------------------------------------------
- PCI detection and module initialization stuff
- ----------------------------------------------------------------------------*/
-
-static void* busmaster_malloc(int size) {
- int pg; /* 2 s exponent of memory size */
- char *buf;
-
- DBG(printk("kernel malloc pages ..\n"));
-
- for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-
- buf = (char *) __get_free_pages(GFP_KERNEL | GFP_DMA, pg);
-
- if (buf) {
- struct page* page, *last_page;
-
- page = virt_to_page(buf);
- last_page = page + (1 << pg);
- DBG(printk("setting reserved bit\n"));
- while (page < last_page) {
- SetPageReserved(page);
- page++;
- }
- return buf;
- }
- DBG(printk("allocated %ld",(long)buf));
- return NULL;
-}
-
-static void busmaster_free(void* ptr,int size) {
- int pg;
- struct page* page, *last_page;
-
- if (ptr == NULL)
- return;
-
- for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-
- page = virt_to_page(ptr);
- last_page = page + (1 << pg);
- while (page < last_page) {
- ClearPageReserved(page);
- page++;
- }
- DBG(printk("freeing pages\n"));
- free_pages((unsigned long) ptr, pg);
- DBG(printk("done\n"));
-}
-
-/* initialize those parts of the info structure which are not pci detectable resources */
-
-static int rme96xx_dmabuf_init(rme96xx_info * s,struct dmabuf* dma,int ioffset,int ooffset) {
-
- mutex_init(&dma->open_mutex);
- init_waitqueue_head(&dma->open_wait);
- init_waitqueue_head(&dma->wait);
- dma->s = s;
- dma->error = 0;
-
- dma->format = AFMT_S32_BLOCKED;
- dma->formatshift = 0;
- dma->inchannels = dma->outchannels = 1;
- dma->inoffset = ioffset;
- dma->outoffset = ooffset;
-
- dma->opened=0;
- dma->started=0;
- dma->mmapped=0;
- dma->open_mode=0;
- dma->mono=0;
-
- rme96xx_clearbufs(dma);
- return 0;
-}
-
-
-static int rme96xx_init(rme96xx_info* s)
-{
- int i;
- int status;
- unsigned short rev;
-
- DBG(printk("%s\n", __FUNCTION__));
- numcards++;
-
- s->magic = RME96xx_MAGIC;
-
- spin_lock_init(&s->lock);
-
- COMM ("setup busmaster memory")
- s->recbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
- s->playbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
-
- if (!s->recbuf || !s->playbuf) {
- printk(KERN_ERR RME_MESS" Unable to allocate busmaster memory\n");
- return -ENODEV;
- }
-
- COMM ("setting rec and playbuffers")
-
- writel((u32) virt_to_bus(s->recbuf),s->iobase + RME96xx_rec_buffer);
- writel((u32) virt_to_bus(s->playbuf),s->iobase + RME96xx_play_buffer);
-
- COMM ("initializing control register")
- rme96xx_unset_ctrl(s,0xffffffff);
- rme96xx_set_ctrl(s,RME96xx_ctrl_init);
-
-
- COMM ("setup devices")
- for (i=0;i < devices;i++) {
- struct dmabuf * dma = &s->dma[i];
- rme96xx_dmabuf_init(s,dma,2*i,2*i);
- }
-
- /* code from ALSA card-rme9652.c HP 20020201 */
- /* Determine the h/w rev level of the card. This seems like
- a particularly kludgy way to encode it, but its what RME
- chose to do, so we follow them ...
- */
-
- status = readl(s->iobase + RME96xx_status_register);
- if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) {
- s->hw_rev = 15;
- } else {
- s->hw_rev = 11;
- }
-
- /* Differentiate between the standard Hammerfall, and the
- "Light", which does not have the expansion board. This
- method comes from information received from Mathhias
- Clausen at RME. Display the EEPROM and h/w revID where
- relevant.
- */
-
- pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev);
- switch (rev & 0xff) {
- case 8: /* original eprom */
- if (s->hw_rev == 15) {
- s->card_name = "RME Digi9636 (Rev 1.5)";
- } else {
- s->card_name = "RME Digi9636";
- }
- break;
- case 9: /* W36_G EPROM */
- s->card_name = "RME Digi9636 (Rev G)";
- break;
- case 4: /* W52_G EPROM */
- s->card_name = "RME Digi9652 (Rev G)";
- break;
- default:
- case 3: /* original eprom */
- if (s->hw_rev == 15) {
- s->card_name = "RME Digi9652 (Rev 1.5)";
- } else {
- s->card_name = "RME Digi9652";
- }
- break;
- }
-
- printk(KERN_INFO RME_MESS" detected %s (hw_rev %d)\n",s->card_name,s->hw_rev);
-
- if (s->hw_rev == 15)
- rme96xx_initialize_spdif_receiver (s);
-
- s->started = 0;
- rme96xx_setlatency(s,7);
-
- printk(KERN_INFO RME_MESS" card %d initialized\n",numcards);
- return 0;
-}
-
-
-/* open uses this to figure out which device was opened .. this seems to be
- unnecessary complex */
-
-static LIST_HEAD(devs);
-
-static int __devinit rme96xx_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- int i;
- rme96xx_info *s;
-
- DBG(printk("%s\n", __FUNCTION__));
-
- if (pcidev->irq == 0)
- return -1;
- if (!pci_dma_supported(pcidev, 0xffffffff)) {
- printk(KERN_WARNING RME_MESS" architecture does not support 32bit PCI busmaster DMA\n");
- return -1;
- }
- if (!(s = kmalloc(sizeof(rme96xx_info), GFP_KERNEL))) {
- printk(KERN_WARNING RME_MESS" out of memory\n");
- return -1;
- }
- memset(s, 0, sizeof(rme96xx_info));
-
- s->pcidev = pcidev;
- s->iobase = ioremap(pci_resource_start(pcidev, 0),RME96xx_IO_EXTENT);
- s->irq = pcidev->irq;
-
- DBG(printk("remapped iobase: %lx irq %d\n",(long)s->iobase,s->irq));
-
- if (pci_enable_device(pcidev))
- goto err_irq;
- if (request_irq(s->irq, rme96xx_interrupt, IRQF_SHARED, "rme96xx", s)) {
- printk(KERN_ERR RME_MESS" irq %u in use\n", s->irq);
- goto err_irq;
- }
-
- /* initialize the card */
-
- i = 0;
- if (rme96xx_init(s) < 0) {
- printk(KERN_ERR RME_MESS" initialization failed\n");
- goto err_devices;
- }
- for (i=0;i<devices;i++) {
- if ((s->dspnum[i] = register_sound_dsp(&rme96xx_audio_fops, -1)) < 0)
- goto err_devices;
- }
-
- if ((s->mixer = register_sound_mixer(&rme96xx_mixer_fops, -1)) < 0)
- goto err_devices;
-
- pci_set_drvdata(pcidev, s);
- pcidev->dma_mask = 0xffffffff; /* ????? */
- /* put it into driver list */
- list_add_tail(&s->devs, &devs);
-
- DBG(printk("initialization successful\n"));
- return 0;
-
- /* error handler */
- err_devices:
- while (i--)
- unregister_sound_dsp(s->dspnum[i]);
- free_irq(s->irq,s);
- err_irq:
- kfree(s);
- return -1;
-}
-
-
-static void __devexit rme96xx_remove(struct pci_dev *dev)
-{
- int i;
- rme96xx_info *s = pci_get_drvdata(dev);
-
- if (!s) {
- printk(KERN_ERR"device structure not valid\n");
- return ;
- }
-
- if (s->started) rme96xx_startcard(s,0);
-
- i = devices;
- while (i) {
- i--;
- unregister_sound_dsp(s->dspnum[i]);
- }
-
- unregister_sound_mixer(s->mixer);
- synchronize_irq(s->irq);
- free_irq(s->irq,s);
- busmaster_free(s->recbuf,RME96xx_DMA_MAX_SIZE_ALL);
- busmaster_free(s->playbuf,RME96xx_DMA_MAX_SIZE_ALL);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-
-#ifndef PCI_VENDOR_ID_RME
-#define PCI_VENDOR_ID_RME 0x10ee
-#endif
-#ifndef PCI_DEVICE_ID_RME9652
-#define PCI_DEVICE_ID_RME9652 0x3fc4
-#endif
-#ifndef PCI_ANY_ID
-#define PCI_ANY_ID 0
-#endif
-
-static struct pci_device_id id_table[] = {
- {
- .vendor = PCI_VENDOR_ID_RME,
- .device = PCI_DEVICE_ID_RME9652,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver rme96xx_driver = {
- .name = "rme96xx",
- .id_table = id_table,
- .probe = rme96xx_probe,
- .remove = __devexit_p(rme96xx_remove),
-};
-
-static int __init init_rme96xx(void)
-{
- printk(KERN_INFO RME_MESS" version "RMEVERSION" time " __TIME__ " " __DATE__ "\n");
- devices = ((devices-1) & RME96xx_MASK_DEVS) + 1;
- printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices);
- numcards = 0;
- return pci_register_driver(&rme96xx_driver);
-}
-
-static void __exit cleanup_rme96xx(void)
-{
- printk(KERN_INFO RME_MESS" unloading\n");
- pci_unregister_driver(&rme96xx_driver);
-}
-
-module_init(init_rme96xx);
-module_exit(cleanup_rme96xx);
-
-
-
-
-
-/*--------------------------------------------------------------------------
- Implementation of file operations
----------------------------------------------------------------------------*/
-
-#define RME96xx_FMT (AFMT_S16_LE|AFMT_U8|AFMT_S32_BLOCKED)
-/* AFTM_U8 is not (yet?) supported ... HP20020201 */
-
-static int rme96xx_ioctl(struct inode *in, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct dmabuf * dma = (struct dmabuf *)file->private_data;
- rme96xx_info *s = dma->s;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val = 0;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
-
- DBG(printk("ioctl %ud\n",cmd));
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
-#if 0
- if (file->f_mode & FMODE_WRITE)
- return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
-#endif
- 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:
-// rme96xx_clearbufs(dma);
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
-/* generally it's not a problem if we change the speed
- if (dma->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
- return -EINVAL;
-*/
- spin_lock_irqsave(&s->lock, flags);
-
- switch (val) {
- case 44100:
- case 88200:
- rme96xx_unset_ctrl(s,RME96xx_freq);
- break;
- case 48000:
- case 96000:
- rme96xx_set_ctrl(s,RME96xx_freq);
- break;
- /* just report current rate as default
- e.g. use 0 to "select" current digital input rate
- default:
- rme96xx_unset_ctrl(s,RME96xx_freq);
- val = 44100;
- */
- }
- if (val > 50000)
- rme96xx_set_ctrl(s,RME96xx_DS);
- else
- rme96xx_unset_ctrl(s,RME96xx_DS);
- /* set val to actual value HP 20020201 */
- /* NOTE: if not "Sync Master", reported rate might be not yet "updated" ... but I don't want to insert a long udelay() here */
- if ((s->control_register & RME96xx_Master) && !(s->control_register & RME96xx_wsel))
- val = rme96xx_get_sample_rate_ctrl(s);
- else
- val = rme96xx_get_sample_rate_status(s);
- s->rate = val;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- DBG(printk("speed set to %d\n",val));
- return put_user(val, p);
-
- case SNDCTL_DSP_STEREO: /* this plays a mono file on two channels */
- if (get_user(val, p))
- return -EFAULT;
-
- if (!val) {
- DBG(printk("setting to mono\n"));
- dma->mono=1;
- dma->inchannels = 1;
- dma->outchannels = 1;
- }
- else {
- DBG(printk("setting to stereo\n"));
- dma->mono = 0;
- dma->inchannels = 2;
- dma->outchannels = 2;
- }
- return 0;
- case SNDCTL_DSP_CHANNELS:
- /* remember to check for resonable offset/channel pairs here */
- if (get_user(val, p))
- return -EFAULT;
-
- if (file->f_mode & FMODE_WRITE) {
- if (val > 0 && (dma->outoffset + val) <= RME96xx_CHANNELS_PER_CARD)
- dma->outchannels = val;
- else
- dma->outchannels = val = 2;
- DBG(printk("setting to outchannels %d\n",val));
- }
- if (file->f_mode & FMODE_READ) {
- if (val > 0 && (dma->inoffset + val) <= RME96xx_CHANNELS_PER_CARD)
- dma->inchannels = val;
- else
- dma->inchannels = val = 2;
- DBG(printk("setting to inchannels %d\n",val));
- }
-
- dma->mono=0;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(RME96xx_FMT, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- DBG(printk("setting to format %x\n",val));
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (val & RME96xx_FMT)
- dma->format = val;
- switch (dma->format) {
- case AFMT_S16_LE:
- dma->formatshift=1;
- break;
- case AFMT_S32_BLOCKED:
- dma->formatshift=0;
- break;
- }
- }
- return put_user(dma->format, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
-#if 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;
-#endif
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
-#if 0
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- start_adc(s);
- } else
- 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;
- start_dac2(s);
- } else
- stop_dac2(s);
- }
-#endif
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- val = rme96xx_gethwptr(dma->s,0);
-
-
- count = rme96xx_getospace(dma,val);
- if (!s->started) count = s->fragsize*2;
- abinfo.fragsize =(s->fragsize*dma->outchannels)>>dma->formatshift;
- abinfo.bytes = (count*dma->outchannels)>>dma->formatshift;
- abinfo.fragstotal = 2;
- abinfo.fragments = (count > s->fragsize);
-
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
-
- val = rme96xx_gethwptr(dma->s,0);
-
- count = rme96xx_getispace(dma,val);
-
- abinfo.fragsize = (s->fragsize*dma->inchannels)>>dma->formatshift;
- abinfo.bytes = (count*dma->inchannels)>>dma->formatshift;
- abinfo.fragstotal = 2;
- abinfo.fragments = count > s->fragsize;
- 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: /* What should this exactly do ? ,
- ATM it is just abinfo.bytes */
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- val = rme96xx_gethwptr(dma->s,0);
- count = val - dma->readptr;
- if (count < 0)
- count += s->fragsize<<1;
-
- return put_user(count, p);
-
-
-/* check out how to use mmaped mode (can only be blocked !!!) */
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- val = rme96xx_gethwptr(dma->s,0);
- spin_lock_irqsave(&s->lock,flags);
- cinfo.bytes = s->fragsize<<1;
- count = val - dma->readptr;
- if (count < 0)
- count += s->fragsize<<1;
-
- cinfo.blocks = (count > s->fragsize);
- cinfo.ptr = val;
- if (dma->mmapped)
- dma->readptr &= s->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_READ))
- return -EINVAL;
- val = rme96xx_gethwptr(dma->s,0);
- spin_lock_irqsave(&s->lock,flags);
- cinfo.bytes = s->fragsize<<1;
- count = val - dma->writeptr;
- if (count < 0)
- count += s->fragsize<<1;
-
- cinfo.blocks = (count > s->fragsize);
- cinfo.ptr = val;
- if (dma->mmapped)
- dma->writeptr &= s->fragsize<<1;
- spin_unlock_irqrestore(&s->lock,flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(s->fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- val&=0xffff;
- val -= 7;
- if (val < 0) val = 0;
- if (val > 7) val = 7;
- rme96xx_setlatency(s,val);
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
-#if 0
- 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;
-#endif
- return 0;
-
- case SOUND_PCM_READ_RATE:
- /* HP20020201 */
- s->rate = rme96xx_get_sample_rate_status(s);
- return put_user(s->rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user(dma->outchannels, p);
-
- case SOUND_PCM_READ_BITS:
- switch (dma->format) {
- case AFMT_S32_BLOCKED:
- val = 32;
- break;
- case AFMT_S16_LE:
- val = 16;
- break;
- }
- return put_user(val, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
-
-
- return -ENODEV;
-}
-
-
-
-static int rme96xx_open(struct inode *in, struct file *f)
-{
- int minor = iminor(in);
- struct list_head *list;
- int devnum;
- rme96xx_info *s;
- struct dmabuf* dma;
- DECLARE_WAITQUEUE(wait, current);
-
- DBG(printk("device num %d open\n",devnum));
-
- nonseekable_open(in, f);
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, rme96xx_info, devs);
- for (devnum=0; devnum<devices; devnum++)
- if (!((s->dspnum[devnum] ^ minor) & ~0xf))
- break;
- if (devnum<devices)
- break;
- }
- VALIDATE_STATE(s);
-
- dma = &s->dma[devnum];
- f->private_data = dma;
- /* wait for device to become free */
- mutex_lock(&dma->open_mutex);
- while (dma->open_mode & f->f_mode) {
- if (f->f_flags & O_NONBLOCK) {
- mutex_unlock(&dma->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&dma->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&dma->open_mutex);
- schedule();
- remove_wait_queue(&dma->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&dma->open_mutex);
- }
-
- COMM ("hardware open")
-
- if (!dma->opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset);
-
- dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE));
- dma->opened = 1;
- mutex_unlock(&dma->open_mutex);
-
- DBG(printk("device num %d open finished\n",devnum));
- return 0;
-}
-
-static int rme96xx_release(struct inode *in, struct file *file)
-{
- struct dmabuf * dma = (struct dmabuf*) file->private_data;
- /* int hwp; ... was unused HP20020201 */
- DBG(printk("%s\n", __FUNCTION__));
-
- COMM ("draining")
- if (dma->open_mode & FMODE_WRITE) {
-#if 0 /* Why doesn't this work with some cards ?? */
- hwp = rme96xx_gethwptr(dma->s,0);
- while (rme96xx_getospace(dma,hwp)) {
- interruptible_sleep_on(&(dma->wait));
- hwp = rme96xx_gethwptr(dma->s,0);
- }
-#endif
- rme96xx_clearbufs(dma);
- }
-
- dma->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
- if (!(dma->open_mode & (FMODE_READ|FMODE_WRITE))) {
- dma->opened = 0;
- if (dma->s->started) rme96xx_startcard(dma->s,1);
- }
-
- wake_up(&dma->open_wait);
- mutex_unlock(&dma->open_mutex);
-
- return 0;
-}
-
-
-static ssize_t rme96xx_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- ssize_t ret = 0;
- int cnt; /* number of bytes from "buffer" that will/can be used */
- int hop = count/dma->outchannels;
- int hwp;
- int exact = (file->f_flags & O_NONBLOCK);
-
-
- if(dma == NULL || (dma->s) == NULL)
- return -ENXIO;
-
- if (dma->mmapped || !dma->opened)
- return -ENXIO;
-
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-
- if (! (dma->open_mode & FMODE_WRITE))
- return -ENXIO;
-
- if (!dma->s->started) rme96xx_startcard(dma->s,exact);
- hwp = rme96xx_gethwptr(dma->s,0);
-
- if(!(dma->started)){
- COMM ("first write")
-
- dma->readptr = hwp;
- dma->writeptr = hwp;
- dma->started = 1;
- }
-
- while (count > 0) {
- cnt = rme96xx_getospace(dma,hwp);
- cnt>>=dma->formatshift;
- cnt*=dma->outchannels;
- if (cnt > count)
- cnt = count;
-
- if (cnt != 0) {
- if (rme96xx_copyfromuser(dma,buffer,cnt,hop))
- return ret ? ret : -EFAULT;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (count == 0) return ret;
- }
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
-
- if ((hwp - dma->writeptr) <= 0) {
- interruptible_sleep_on(&(dma->wait));
-
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- }
-
- hwp = rme96xx_gethwptr(dma->s,exact);
-
- }; /* count > 0 */
-
- return ret;
-}
-
-static ssize_t rme96xx_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- ssize_t ret = 0;
- int cnt; /* number of bytes from "buffer" that will/can be used */
- int hop = count/dma->inchannels;
- int hwp;
- int exact = (file->f_flags & O_NONBLOCK);
-
-
- if(dma == NULL || (dma->s) == NULL)
- return -ENXIO;
-
- if (dma->mmapped || !dma->opened)
- return -ENXIO;
-
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
-
- if (! (dma->open_mode & FMODE_READ))
- return -ENXIO;
-
- if (!dma->s->started) rme96xx_startcard(dma->s,exact);
- hwp = rme96xx_gethwptr(dma->s,0);
-
- if(!(dma->started)){
- COMM ("first read")
-
- dma->writeptr = hwp;
- dma->readptr = hwp;
- dma->started = 1;
- }
-
- while (count > 0) {
- cnt = rme96xx_getispace(dma,hwp);
- cnt>>=dma->formatshift;
- cnt*=dma->inchannels;
-
- if (cnt > count)
- cnt = count;
-
- if (cnt != 0) {
-
- if (rme96xx_copytouser(dma,buffer,cnt,hop))
- return ret ? ret : -EFAULT;
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (count == 0) return ret;
- }
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
-
- if ((hwp - dma->readptr) <= 0) {
- interruptible_sleep_on(&(dma->wait));
-
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- }
- hwp = rme96xx_gethwptr(dma->s,exact);
-
- }; /* count > 0 */
-
- return ret;
-}
-
-static int rm96xx_mmap(struct file *file, struct vm_area_struct *vma) {
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- rme96xx_info* s = dma->s;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
-
- if (vma->vm_pgoff != 0) {
- unlock_kernel();
- return -EINVAL;
- }
- size = vma->vm_end - vma->vm_start;
- if (size > RME96xx_DMA_MAX_SIZE) {
- unlock_kernel();
- return -EINVAL;
- }
-
-
- if (vma->vm_flags & VM_WRITE) {
- if (!s->started) rme96xx_startcard(s,1);
-
- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
- unlock_kernel();
- return -EAGAIN;
- }
- }
- else if (vma->vm_flags & VM_READ) {
- if (!s->started) rme96xx_startcard(s,1);
- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
- unlock_kernel();
- return -EAGAIN;
- }
- } else {
- unlock_kernel();
- return -EINVAL;
- }
-
-
-/* this is the mapping */
- vma->vm_flags &= ~VM_IO;
- dma->mmapped = 1;
- unlock_kernel();
- return 0;
-}
-
-static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- rme96xx_info* s = dma->s;
- unsigned int mask = 0;
- unsigned int hwp,cnt;
-
- DBG(printk("rme96xx poll_wait ...\n"));
- VALIDATE_STATE(s);
-
- if (!s->started) {
- mask |= POLLOUT | POLLWRNORM;
- }
- poll_wait(file, &dma->wait, wait);
-
- hwp = rme96xx_gethwptr(dma->s,0);
-
- DBG(printk("rme96xx poll: ..cnt %d > %d\n",cnt,s->fragsize));
-
- cnt = rme96xx_getispace(dma,hwp);
-
- if (file->f_mode & FMODE_READ)
- if (cnt > 0)
- mask |= POLLIN | POLLRDNORM;
-
-
-
- cnt = rme96xx_getospace(dma,hwp);
-
- if (file->f_mode & FMODE_WRITE)
- if (cnt > 0)
- mask |= POLLOUT | POLLWRNORM;
-
-
-// printk("rme96xx poll_wait ...%d > %d\n",rme96xx_getospace(dma,hwp),rme96xx_getispace(dma,hwp));
-
- return mask;
-}
-
-
-static struct file_operations rme96xx_audio_fops = {
- .owner = THIS_MODULE,
- .read = rme96xx_read,
- .write = rme96xx_write,
- .poll = rme96xx_poll,
- .ioctl = rme96xx_ioctl,
- .mmap = rm96xx_mmap,
- .open = rme96xx_open,
- .release = rme96xx_release
-};
-
-static int rme96xx_mixer_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- rme96xx_info *s;
-
- COMM ("mixer open");
-
- nonseekable_open(inode, file);
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, rme96xx_info, devs);
- if (s->mixer== minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
-
- COMM ("mixer opened")
- return 0;
-}
-
-static int rme96xx_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- rme96xx_info *s = (rme96xx_info *)file->private_data;
- u32 status;
- int spdifrate;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- status = readl(s->iobase + RME96xx_status_register);
- /* hack to convert rev 1.5 SPDIF rate to "crystalrate" format HP 20020201 */
- rme96xx_spdif_sample_rate(s,&spdifrate);
- status = (status & ~RME96xx_F) | ((spdifrate<<22) & RME96xx_F);
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_PRIVATE1) {
- rme_mixer mixer;
- if (copy_from_user(&mixer,argp,sizeof(mixer)))
- return -EFAULT;
-
- mixer.devnr &= RME96xx_MASK_DEVS;
- if (mixer.devnr >= devices)
- mixer.devnr = devices-1;
- if (file->f_mode & FMODE_WRITE && !s->dma[mixer.devnr].opened) {
- /* modify only if device not open */
- if (mixer.o_offset < 0)
- mixer.o_offset = 0;
- if (mixer.o_offset >= RME96xx_CHANNELS_PER_CARD)
- mixer.o_offset = RME96xx_CHANNELS_PER_CARD-1;
- if (mixer.i_offset < 0)
- mixer.i_offset = 0;
- if (mixer.i_offset >= RME96xx_CHANNELS_PER_CARD)
- mixer.i_offset = RME96xx_CHANNELS_PER_CARD-1;
- s->dma[mixer.devnr].outoffset = mixer.o_offset;
- s->dma[mixer.devnr].inoffset = mixer.i_offset;
- }
-
- mixer.o_offset = s->dma[mixer.devnr].outoffset;
- mixer.i_offset = s->dma[mixer.devnr].inoffset;
-
- return copy_to_user(argp, &mixer, sizeof(mixer)) ? -EFAULT : 0;
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- return put_user(status, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE3) {
- u32 control;
- if (copy_from_user(&control,argp,sizeof(control)))
- return -EFAULT;
- if (file->f_mode & FMODE_WRITE) {
- s->control_register &= ~RME96xx_mixer_allowed;
- s->control_register |= control & RME96xx_mixer_allowed;
- writel(control,s->iobase + RME96xx_control_register);
- }
-
- return put_user(s->control_register, p);
- }
- return -1;
-}
-
-
-
-static int rme96xx_mixer_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static /*const*/ struct file_operations rme96xx_mixer_fops = {
- .owner = THIS_MODULE,
- .ioctl = rme96xx_mixer_ioctl,
- .open = rme96xx_mixer_open,
- .release = rme96xx_mixer_release,
-};
diff --git a/sound/oss/rme96xx.h b/sound/oss/rme96xx.h
deleted file mode 100644
index 7a3c188..0000000
--- a/sound/oss/rme96xx.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* (C) 2000 Guenter Geiger <geiger@debian.org>
- with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
-
-Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
- HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
- HP20020201 completed?
-
-A text/graphic control panel (rmectrl/xrmectrl) is available from
- http://gige.xdv.org/pages/soft/pages/rme
-*/
-
-
-#ifndef AFMT_S32_BLOCKED
-#define AFMT_S32_BLOCKED 0x0000400
-#endif
-
-/* AFMT_S16_BLOCKED not yet supported */
-#ifndef AFMT_S16_BLOCKED
-#define AFMT_S16_BLOCKED 0x0000800
-#endif
-
-
-typedef struct rme_status {
- unsigned int irq:1;
- unsigned int lockmask:3; /* ADAT input PLLs locked */
- /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
- unsigned int sr48:1; /* sample rate: 0=44.1/88.2 1=48/96 kHz */
- unsigned int wclock:1; /* 1=wordclock used */
- unsigned int bufpoint:10;
- unsigned int syncmask:3; /* ADAT input in sync with system clock */
- /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
- unsigned int doublespeed:1; /* sample rate: 0=44.1/48 1=88.2/96 kHz */
- unsigned int tc_busy:1;
- unsigned int tc_out:1;
- unsigned int crystalrate:3; /* spdif input sample rate: */
- /* 000=64kHz, 100=88.2kHz, 011=96kHz */
- /* 111=32kHz, 110=44.1kHz, 101=48kHz */
- unsigned int spdif_error:1; /* 1=no spdif lock */
- unsigned int bufid:1;
- unsigned int tc_valid:1; /* 1=timecode input detected */
- unsigned int spdif_read:1;
-} rme_status_t;
-
-
-/* only fields marked W: can be modified by writing to SOUND_MIXER_PRIVATE3 */
-typedef struct rme_control {
- unsigned int start:1;
- unsigned int latency:3; /* buffer size / latency [samples]: */
- /* 0=64 ... 7=8192 */
- unsigned int master:1; /* W: clock mode: 1=master 0=slave/auto */
- unsigned int ie:1;
- unsigned int sr48:1; /* samplerate 0=44.1/88.2, 1=48/96 kHz */
- unsigned int spare:1;
- unsigned int doublespeed:1; /* double speed 0=44.1/48, 1=88.2/96 Khz */
- unsigned int pro:1; /* W: SPDIF-OUT 0=consumer, 1=professional */
- unsigned int emphasis:1; /* W: SPDIF-OUT emphasis 0=off, 1=on */
- unsigned int dolby:1; /* W: SPDIF-OUT non-audio bit 1=set, 0=unset */
- unsigned int opt_out:1; /* W: use 1st optical OUT as SPDIF: 1=yes, 0=no */
- unsigned int wordclock:1; /* W: use Wordclock as sync (overwrites master) */
- unsigned int spdif_in:2; /* W: SPDIF-IN: */
- /* 00=optical (ADAT1), 01=coaxial (Cinch), 10=internal CDROM */
- unsigned int sync_ref:2; /* W: preferred sync-source in autosync */
- /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
- unsigned int spdif_reset:1;
- unsigned int spdif_select:1;
- unsigned int spdif_clock:1;
- unsigned int spdif_write:1;
- unsigned int adat1_cd:1; /* W: Rev 1.5+: if set, internal CD connector carries ADAT */
-} rme_ctrl_t;
-
-
-typedef struct _rme_mixer {
- int i_offset;
- int o_offset;
- int devnr;
- int spare[8];
-} rme_mixer;
-
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
index 0ce4e4e..5c215f7 100644
--- a/sound/oss/sequencer.c
+++ b/sound/oss/sequencer.c
@@ -16,7 +16,6 @@
*/
#include <linux/kmod.h>
#include <linux/spinlock.h>
-#define SEQUENCER_C
#include "sound_config.h"
#include "midi_ctrl.h"
@@ -157,6 +156,7 @@
wake_up(&midi_sleeper);
spin_unlock_irqrestore(&lock,flags);
}
+EXPORT_SYMBOL(seq_copy_to_input);
static void sequencer_midi_input(int dev, unsigned char data)
{
@@ -206,6 +206,7 @@
}
seq_copy_to_input(event_rec, len);
}
+EXPORT_SYMBOL(seq_input_event);
int sequencer_write(int dev, struct file *file, const char __user *buf, int count)
{
@@ -1554,6 +1555,7 @@
{
seq_startplay();
}
+EXPORT_SYMBOL(sequencer_timer);
int note_to_freq(int note_num)
{
@@ -1587,6 +1589,7 @@
return note_freq;
}
+EXPORT_SYMBOL(note_to_freq);
unsigned long compute_finetune(unsigned long base_freq, int bend, int range,
int vibrato_cents)
@@ -1640,19 +1643,12 @@
else
return (base_freq * amount) / 10000; /* Bend up */
}
-
+EXPORT_SYMBOL(compute_finetune);
void sequencer_init(void)
{
- /* drag in sequencer_syms.o */
- {
- extern char sequencer_syms_symbol;
- sequencer_syms_symbol = 0;
- }
-
if (sequencer_ok)
return;
- MIDIbuf_init();
queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
if (queue == NULL)
{
@@ -1668,6 +1664,7 @@
}
sequencer_ok = 1;
}
+EXPORT_SYMBOL(sequencer_init);
void sequencer_unload(void)
{
diff --git a/sound/oss/sequencer_syms.c b/sound/oss/sequencer_syms.c
deleted file mode 100644
index 5d00879..0000000
--- a/sound/oss/sequencer_syms.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Exported symbols for sequencer driver.
- */
-
-#include <linux/module.h>
-
-char sequencer_syms_symbol;
-
-#include "sound_config.h"
-#include "sound_calls.h"
-
-EXPORT_SYMBOL(note_to_freq);
-EXPORT_SYMBOL(compute_finetune);
-EXPORT_SYMBOL(seq_copy_to_input);
-EXPORT_SYMBOL(seq_input_event);
-EXPORT_SYMBOL(sequencer_init);
-EXPORT_SYMBOL(sequencer_timer);
-
-EXPORT_SYMBOL(sound_timer_init);
-EXPORT_SYMBOL(sound_timer_interrupt);
-EXPORT_SYMBOL(sound_timer_syncinterval);
-
-/* Tuning */
-
-#define _SEQUENCER_C_
-#include "tuning.h"
-
-EXPORT_SYMBOL(cent_tuning);
-EXPORT_SYMBOL(semitone_tuning);
diff --git a/sound/oss/sgalaxy.c b/sound/oss/sgalaxy.c
deleted file mode 100644
index 0bcff67..0000000
--- a/sound/oss/sgalaxy.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * sound/oss/sgalaxy.c
- *
- * Low level driver for Aztech Sound Galaxy cards.
- * Copyright 1998 Artur Skawina <skawina@geocities.com>
- *
- * Supported cards:
- * Aztech Sound Galaxy Waverider Pro 32 - 3D
- * Aztech Sound Galaxy Washington 16
- *
- * Based on cs4232.c by Hannu Savolainen and Alan Cox.
- *
- *
- * 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.
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added __init to sb_rst() and sb_cmd()
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-#include "ad1848.h"
-
-static void sleep( unsigned howlong )
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(howlong);
-}
-
-#define DPORT 0x80
-
-/* Sound Blaster regs */
-
-#define SBDSP_RESET 0x6
-#define SBDSP_READ 0xA
-#define SBDSP_COMMAND 0xC
-#define SBDSP_STATUS SBDSP_COMMAND
-#define SBDSP_DATA_AVAIL 0xE
-
-static int __init sb_rst(int base)
-{
- int i;
-
- outb( 1, base+SBDSP_RESET ); /* reset the DSP */
- outb( 0, base+SBDSP_RESET );
-
- for ( i=0; i<500; i++ ) /* delay */
- inb(DPORT);
-
- for ( i=0; i<100000; i++ )
- {
- if ( inb( base+SBDSP_DATA_AVAIL )&0x80 )
- break;
- }
-
- if ( inb( base+SBDSP_READ )!=0xAA )
- return 0;
-
- return 1;
-}
-
-static int __init sb_cmd( int base, unsigned char val )
-{
- int i;
-
- for ( i=100000; i; i-- )
- {
- if ( (inb( base+SBDSP_STATUS )&0x80)==0 )
- {
- outb( val, base+SBDSP_COMMAND );
- break;
- }
- }
- return i; /* i>0 == success */
-}
-
-
-#define ai_sgbase driver_use_1
-
-static int __init probe_sgalaxy( struct address_info *ai )
-{
- struct resource *ports;
- int n;
-
- if (!request_region(ai->io_base, 4, "WSS config")) {
- printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
- return 0;
- }
-
- ports = request_region(ai->io_base + 4, 4, "ad1848");
- if (!ports) {
- printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
- release_region(ai->io_base, 4);
- return 0;
- }
-
- if (!request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB")) {
- printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
- release_region(ai->io_base + 4, 4);
- release_region(ai->io_base, 4);
- return 0;
- }
-
- if (ad1848_detect(ports, NULL, ai->osp))
- goto out; /* The card is already active, check irq etc... */
-
- /* switch to MSS/WSS mode */
-
- sb_rst( ai->ai_sgbase );
-
- sb_cmd( ai->ai_sgbase, 9 );
- sb_cmd( ai->ai_sgbase, 0 );
-
- sleep( HZ/10 );
-
-out:
- if (!probe_ms_sound(ai, ports)) {
- release_region(ai->io_base + 4, 4);
- release_region(ai->io_base, 4);
- release_region(ai->ai_sgbase, 0x10);
- return 0;
- }
-
- attach_ms_sound(ai, ports, THIS_MODULE);
- n=ai->slots[0];
-
- if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) {
- AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */
- AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/
- AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */
- }
- return 1;
-}
-
-static void __exit unload_sgalaxy( struct address_info *ai )
-{
- unload_ms_sound( ai );
- release_region( ai->ai_sgbase, 0x10 );
-}
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma2 = -1;
-static int __initdata sgbase = -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma2, int, 0);
-module_param(sgbase, int, 0);
-
-static int __init init_sgalaxy(void)
-{
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma2;
- cfg.ai_sgbase = sgbase;
-
- if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
- printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
- return -EINVAL;
- }
-
- if ( probe_sgalaxy(&cfg) == 0 )
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit cleanup_sgalaxy(void)
-{
- unload_sgalaxy(&cfg);
-}
-
-module_init(init_sgalaxy);
-module_exit(cleanup_sgalaxy);
-
-#ifndef MODULE
-static int __init setup_sgalaxy(char *str)
-{
- /* io, irq, dma, dma2, sgbase */
- int ints[6];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- sgbase = ints[5];
-
- return 1;
-}
-
-__setup("sgalaxy=", setup_sgalaxy);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
deleted file mode 100644
index 8ea532d..0000000
--- a/sound/oss/sonicvibes.c
+++ /dev/null
@@ -1,2792 +0,0 @@
-/*****************************************************************************/
-
-/*
- * sonicvibes.c -- S3 Sonic Vibes audio driver.
- *
- * 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 David C. Niemi
- *
- *
- * Module command line parameters:
- * none so far
- *
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * The card has both an FM and a Wavetable synth, but I have to figure
- * out first how to drive them...
- *
- * Revision history
- * 06.05.1998 0.1 Initial release
- * 10.05.1998 0.2 Fixed many bugs, esp. ADC rate calculation
- * First stab at a simple midi interface (no bells&whistles)
- * 13.05.1998 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
- * set_dac_rate in the FMODE_WRITE case in sv_open
- * Fix hwptr out of bounds (now mpg123 works)
- * 14.05.1998 0.4 Don't allow excessive interrupt rates
- * 08.06.1998 0.5 First release using Alan Cox' soundcore instead of miscdevice
- * 03.08.1998 0.6 Do not include modversions.h
- * Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * 31.08.1998 0.7 Fix realplayer problems - dac.count issues
- * 10.12.1998 0.8 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.1998 0.9 Fix a few f_file & FMODE_ bugs
- * 06.01.1999 0.10 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.1999 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.1999 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 05.04.1999 0.13 added code to sv_read and sv_write which should detect
- * lockups of the sound chip and revive it. This is basically
- * an ugly hack, but at least applications using this driver
- * won't hang forever. I don't know why these lockups happen,
- * it might well be the motherboard chipset (an early 486 PCI
- * board with ALI chipset), since every busmastering 100MB
- * ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
- * exhibit similar behaviour (they work for a couple of packets
- * and then lock up and can be revived by ifconfig down/up).
- * 07.04.1999 0.14 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>
- * Note: dmaio hack might still be wrong on archs other than i386
- * 15.06.1999 0.15 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.1999 0.16 Add pci_set_master
- * 03.08.1999 0.17 adapt to Linus' new __setup/__initcall
- * added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
- * 12.08.1999 0.18 module_init/__setup fixes
- * 24.08.1999 0.19 get rid of the dmaio kludge, replace with allocate_resource
- * 31.08.1999 0.20 add spin_lock_init
- * use new resource allocation to allocate DDMA IO space
- * replaced current->state = x with set_current_state(x)
- * 03.09.1999 0.21 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 28.10.1999 0.22 More waitqueue races fixed
- * 01.12.1999 0.23 New argument to allocate_resource
- * 07.12.1999 0.24 More allocate_resource semantics change
- * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun;
- * Tim Janik's BSE (Bedevilled Sound Engine) found this
- * use Martin Mares' pci_assign_resource
- * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver
- * 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>
- * 31.01.2001 0.29 Register/Unregister gameport
- * Fix SETTRIGGER non OSS API conformity
- * 18.05.2001 0.30 PCI probing and error values cleaned up by Marcus
- * Meissner <mm@caldera.de>
- * 03.01.2003 0.31 open_mode fixes from Georg Acher <acher@in.tum.de>
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/mm.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/smp_lock.h>
-#include <linux/gameport.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "dm.h"
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_S3
-#define PCI_VENDOR_ID_S3 0x5333
-#endif
-#ifndef PCI_DEVICE_ID_S3_SONICVIBES
-#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
-#endif
-
-#define SV_MAGIC ((PCI_VENDOR_ID_S3<<16)|PCI_DEVICE_ID_S3_SONICVIBES)
-
-#define SV_EXTENT_SB 0x10
-#define SV_EXTENT_ENH 0x10
-#define SV_EXTENT_SYNTH 0x4
-#define SV_EXTENT_MIDI 0x4
-#define SV_EXTENT_GAME 0x8
-#define SV_EXTENT_DMA 0x10
-
-/*
- * we are not a bridge and thus use a resource for DDMA that is used for bridges but
- * left empty for normal devices
- */
-#define RESOURCE_SB 0
-#define RESOURCE_ENH 1
-#define RESOURCE_SYNTH 2
-#define RESOURCE_MIDI 3
-#define RESOURCE_GAME 4
-#define RESOURCE_DDMA 7
-
-#define SV_MIDI_DATA 0
-#define SV_MIDI_COMMAND 1
-#define SV_MIDI_STATUS 1
-
-#define SV_DMA_ADDR0 0
-#define SV_DMA_ADDR1 1
-#define SV_DMA_ADDR2 2
-#define SV_DMA_ADDR3 3
-#define SV_DMA_COUNT0 4
-#define SV_DMA_COUNT1 5
-#define SV_DMA_COUNT2 6
-#define SV_DMA_MODE 0xb
-#define SV_DMA_RESET 0xd
-#define SV_DMA_MASK 0xf
-
-/*
- * DONT reset the DMA controllers unless you understand
- * the reset semantics. Assuming reset semantics as in
- * the 8237 does not work.
- */
-
-#define DMA_MODE_AUTOINIT 0x10
-#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
-
-#define SV_CODEC_CONTROL 0
-#define SV_CODEC_INTMASK 1
-#define SV_CODEC_STATUS 2
-#define SV_CODEC_IADDR 4
-#define SV_CODEC_IDATA 5
-
-#define SV_CCTRL_RESET 0x80
-#define SV_CCTRL_INTADRIVE 0x20
-#define SV_CCTRL_WAVETABLE 0x08
-#define SV_CCTRL_REVERB 0x04
-#define SV_CCTRL_ENHANCED 0x01
-
-#define SV_CINTMASK_DMAA 0x01
-#define SV_CINTMASK_DMAC 0x04
-#define SV_CINTMASK_SPECIAL 0x08
-#define SV_CINTMASK_UPDOWN 0x40
-#define SV_CINTMASK_MIDI 0x80
-
-#define SV_CSTAT_DMAA 0x01
-#define SV_CSTAT_DMAC 0x04
-#define SV_CSTAT_SPECIAL 0x08
-#define SV_CSTAT_UPDOWN 0x40
-#define SV_CSTAT_MIDI 0x80
-
-#define SV_CIADDR_TRD 0x80
-#define SV_CIADDR_MCE 0x40
-
-/* codec indirect registers */
-#define SV_CIMIX_ADCINL 0x00
-#define SV_CIMIX_ADCINR 0x01
-#define SV_CIMIX_AUX1INL 0x02
-#define SV_CIMIX_AUX1INR 0x03
-#define SV_CIMIX_CDINL 0x04
-#define SV_CIMIX_CDINR 0x05
-#define SV_CIMIX_LINEINL 0x06
-#define SV_CIMIX_LINEINR 0x07
-#define SV_CIMIX_MICIN 0x08
-#define SV_CIMIX_SYNTHINL 0x0A
-#define SV_CIMIX_SYNTHINR 0x0B
-#define SV_CIMIX_AUX2INL 0x0C
-#define SV_CIMIX_AUX2INR 0x0D
-#define SV_CIMIX_ANALOGINL 0x0E
-#define SV_CIMIX_ANALOGINR 0x0F
-#define SV_CIMIX_PCMINL 0x10
-#define SV_CIMIX_PCMINR 0x11
-
-#define SV_CIGAMECONTROL 0x09
-#define SV_CIDATAFMT 0x12
-#define SV_CIENABLE 0x13
-#define SV_CIUPDOWN 0x14
-#define SV_CIREVISION 0x15
-#define SV_CIADCOUTPUT 0x16
-#define SV_CIDMAABASECOUNT1 0x18
-#define SV_CIDMAABASECOUNT0 0x19
-#define SV_CIDMACBASECOUNT1 0x1c
-#define SV_CIDMACBASECOUNT0 0x1d
-#define SV_CIPCMSR0 0x1e
-#define SV_CIPCMSR1 0x1f
-#define SV_CISYNTHSR0 0x20
-#define SV_CISYNTHSR1 0x21
-#define SV_CIADCCLKSOURCE 0x22
-#define SV_CIADCALTSR 0x23
-#define SV_CIADCPLLM 0x24
-#define SV_CIADCPLLN 0x25
-#define SV_CISYNTHPLLM 0x26
-#define SV_CISYNTHPLLN 0x27
-#define SV_CIUARTCONTROL 0x2a
-#define SV_CIDRIVECONTROL 0x2b
-#define SV_CISRSSPACE 0x2c
-#define SV_CISRSCENTER 0x2d
-#define SV_CIWAVETABLESRC 0x2e
-#define SV_CIANALOGPWRDOWN 0x30
-#define SV_CIDIGITALPWRDOWN 0x31
-
-
-#define SV_CIMIX_ADCSRC_CD 0x20
-#define SV_CIMIX_ADCSRC_DAC 0x40
-#define SV_CIMIX_ADCSRC_AUX2 0x60
-#define SV_CIMIX_ADCSRC_LINE 0x80
-#define SV_CIMIX_ADCSRC_AUX1 0xa0
-#define SV_CIMIX_ADCSRC_MIC 0xc0
-#define SV_CIMIX_ADCSRC_MIXOUT 0xe0
-#define SV_CIMIX_ADCSRC_MASK 0xe0
-
-#define SV_CFMT_STEREO 0x01
-#define SV_CFMT_16BIT 0x02
-#define SV_CFMT_MASK 0x03
-#define SV_CFMT_ASHIFT 0
-#define SV_CFMT_CSHIFT 4
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-#define SV_CENABLE_PPE 0x4
-#define SV_CENABLE_RE 0x2
-#define SV_CENABLE_PE 0x1
-
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF 256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 2
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define FMODE_DMFM 0x10
-
-/* --------------------------------------------------------------------- */
-
-struct sv_state {
- /* magic */
- unsigned int magic;
-
- /* list of sonicvibes devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
- int dev_mixer;
- int dev_midi;
- int dev_dmfm;
-
- /* hardware resources */
- unsigned long iosb, ioenh, iosynth, iomidi; /* long for SPARC */
- unsigned int iodmaa, iodmac, irq;
-
- /* mixer stuff */
- struct {
- unsigned int modcnt;
-#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS
- unsigned short vol[13];
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- } mix;
-
- /* wave stuff */
- unsigned int rateadc, ratedac;
- unsigned char fmt, enable;
-
- 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_dac, dma_adc;
-
- /* midi stuff */
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- struct timer_list timer;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
-#if SUPPORT_JOYSTICK
- struct gameport *gameport;
-#endif
-};
-
-/* --------------------------------------------------------------------- */
-
-static LIST_HEAD(devs);
-static unsigned long wavetable_mem;
-
-/* --------------------------------------------------------------------- */
-
-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;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver.
- */
-
-#undef DMABYTEIO
-
-static void set_dmaa(struct sv_state *s, unsigned int addr, unsigned int count)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmaa, u;
-
- count--;
- for (u = 4; u > 0; u--, addr >>= 8, io++)
- outb(addr & 0xff, io);
- for (u = 3; u > 0; u--, count >>= 8, io++)
- outb(count & 0xff, io);
-#else /* DMABYTEIO */
- count--;
- outl(addr, s->iodmaa + SV_DMA_ADDR0);
- outl(count, s->iodmaa + SV_DMA_COUNT0);
-#endif /* DMABYTEIO */
- outb(0x18, s->iodmaa + SV_DMA_MODE);
-}
-
-static void set_dmac(struct sv_state *s, unsigned int addr, unsigned int count)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmac, u;
-
- count >>= 1;
- count--;
- for (u = 4; u > 0; u--, addr >>= 8, io++)
- outb(addr & 0xff, io);
- for (u = 3; u > 0; u--, count >>= 8, io++)
- outb(count & 0xff, io);
-#else /* DMABYTEIO */
- count >>= 1;
- count--;
- outl(addr, s->iodmac + SV_DMA_ADDR0);
- outl(count, s->iodmac + SV_DMA_COUNT0);
-#endif /* DMABYTEIO */
- outb(0x14, s->iodmac + SV_DMA_MODE);
-}
-
-static inline unsigned get_dmaa(struct sv_state *s)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmaa+6, v = 0, u;
-
- for (u = 3; u > 0; u--, io--) {
- v <<= 8;
- v |= inb(io);
- }
- return v + 1;
-#else /* DMABYTEIO */
- return (inl(s->iodmaa + SV_DMA_COUNT0) & 0xffffff) + 1;
-#endif /* DMABYTEIO */
-}
-
-static inline unsigned get_dmac(struct sv_state *s)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmac+6, v = 0, u;
-
- for (u = 3; u > 0; u--, io--) {
- v <<= 8;
- v |= inb(io);
- }
- return (v + 1) << 1;
-#else /* DMABYTEIO */
- return ((inl(s->iodmac + SV_DMA_COUNT0) & 0xffffff) + 1) << 1;
-#endif /* DMABYTEIO */
-}
-
-static void wrindir(struct sv_state *s, unsigned char idx, unsigned char data)
-{
- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb(data, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
-}
-
-static unsigned char rdindir(struct sv_state *s, unsigned char idx)
-{
- unsigned char v;
-
- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- v = inb(s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- return v;
-}
-
-static void set_fmt(struct sv_state *s, unsigned char mask, unsigned char data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- outb(SV_CIDATAFMT | SV_CIADDR_MCE, s->ioenh + SV_CODEC_IADDR);
- if (mask) {
- s->fmt = inb(s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- }
- s->fmt = (s->fmt & mask) | data;
- outb(s->fmt, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- outb(0, s->ioenh + SV_CODEC_IADDR);
- spin_unlock_irqrestore(&s->lock, flags);
- udelay(10);
-}
-
-static void frobindir(struct sv_state *s, unsigned char idx, unsigned char mask, unsigned char data)
-{
- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb((inb(s->ioenh + SV_CODEC_IDATA) & mask) ^ data, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
-}
-
-#define REFFREQUENCY 24576000
-#define ADCMULT 512
-#define FULLRATE 48000
-
-static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate)
-{
- unsigned long flags;
- unsigned char r, m=0, n=0;
- unsigned xm, xn, xr, xd, metric = ~0U;
- /* the warnings about m and n used uninitialized are bogus and may safely be ignored */
-
- if (rate < 625000/ADCMULT)
- rate = 625000/ADCMULT;
- if (rate > 150000000/ADCMULT)
- rate = 150000000/ADCMULT;
- /* slight violation of specs, needed for continuous sampling rates */
- for (r = 0; rate < 75000000/ADCMULT; r += 0x20, rate <<= 1);
- for (xn = 3; xn < 35; xn++)
- for (xm = 3; xm < 130; xm++) {
- xr = REFFREQUENCY/ADCMULT * xm / xn;
- xd = abs((signed)(xr - rate));
- if (xd < metric) {
- metric = xd;
- m = xm - 2;
- n = xn - 2;
- }
- }
- reg &= 0x3f;
- spin_lock_irqsave(&s->lock, flags);
- outb(reg, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb(m, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- outb(reg+1, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb(r | n, s->ioenh + SV_CODEC_IDATA);
- spin_unlock_irqrestore(&s->lock, flags);
- udelay(10);
- return (REFFREQUENCY/ADCMULT * (m + 2) / (n + 2)) >> ((r >> 5) & 7);
-}
-
-#if 0
-
-static unsigned getpll(struct sv_state *s, unsigned char reg)
-{
- unsigned long flags;
- unsigned char m, n;
-
- reg &= 0x3f;
- spin_lock_irqsave(&s->lock, flags);
- outb(reg, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- m = inb(s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- outb(reg+1, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- n = inb(s->ioenh + SV_CODEC_IDATA);
- spin_unlock_irqrestore(&s->lock, flags);
- udelay(10);
- return (REFFREQUENCY/ADCMULT * (m + 2) / ((n & 0x1f) + 2)) >> ((n >> 5) & 7);
-}
-
-#endif
-
-static void set_dac_rate(struct sv_state *s, unsigned rate)
-{
- unsigned div;
- unsigned long flags;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
- div = (rate * 65536 + FULLRATE/2) / FULLRATE;
- if (div > 65535)
- div = 65535;
- spin_lock_irqsave(&s->lock, flags);
- wrindir(s, SV_CIPCMSR1, div >> 8);
- wrindir(s, SV_CIPCMSR0, div);
- spin_unlock_irqrestore(&s->lock, flags);
- s->ratedac = (div * FULLRATE + 32768) / 65536;
-}
-
-static void set_adc_rate(struct sv_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned rate1, rate2, div;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
- rate1 = setpll(s, SV_CIADCPLLM, rate);
- div = (48000 + rate/2) / rate;
- if (div > 8)
- div = 8;
- rate2 = (48000 + div/2) / div;
- spin_lock_irqsave(&s->lock, flags);
- wrindir(s, SV_CIADCALTSR, (div-1) << 4);
- if (abs((signed)(rate-rate2)) <= abs((signed)(rate-rate1))) {
- wrindir(s, SV_CIADCCLKSOURCE, 0x10);
- s->rateadc = rate2;
- } else {
- wrindir(s, SV_CIADCCLKSOURCE, 0x00);
- s->rateadc = rate1;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->enable &= ~SV_CENABLE_RE;
- wrindir(s, SV_CIENABLE, s->enable);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->enable &= ~(SV_CENABLE_PPE | SV_CENABLE_PE);
- wrindir(s, SV_CIENABLE, s->enable);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
- s->enable = (s->enable & ~SV_CENABLE_PPE) | SV_CENABLE_PE;
- wrindir(s, SV_CIENABLE, s->enable);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- s->enable |= SV_CENABLE_RE;
- wrindir(s, SV_CIENABLE, s->enable);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static void dealloc_dmabuf(struct sv_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;
-}
-
-
-/* DMAA is used for playback, DMAC is used for recording */
-
-static int prog_dmabuf(struct sv_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- int order;
- unsigned bytepersec;
- unsigned bufs;
- struct page *page, *pend;
- unsigned char fmt;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- fmt = s->fmt;
- if (rec) {
- s->enable &= ~SV_CENABLE_RE;
- fmt >>= SV_CFMT_CSHIFT;
- } else {
- s->enable &= ~SV_CENABLE_PE;
- fmt >>= SV_CFMT_ASHIFT;
- }
- wrindir(s, SV_CIENABLE, s->enable);
- spin_unlock_irqrestore(&s->lock, flags);
- fmt &= SV_CFMT_MASK;
- 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;
- if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
- printk(KERN_DEBUG "sv: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
- if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
- printk(KERN_DEBUG "sv: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
- /* 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);
- }
- 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 & SV_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
- spin_lock_irqsave(&s->lock, flags);
- if (rec) {
- set_dmac(s, db->dmaaddr, db->numfrag << db->fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMACBASECOUNT1, (db->fragsamples-1) >> 8);
- wrindir(s, SV_CIDMACBASECOUNT0, db->fragsamples-1);
- } else {
- set_dmaa(s, db->dmaaddr, db->numfrag << db->fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMAABASECOUNT1, (db->fragsamples-1) >> 8);
- wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- db->enabled = 1;
- db->ready = 1;
- return 0;
-}
-
-static inline void clear_advance(struct sv_state *s)
-{
- unsigned char c = (s->fmt & (SV_CFMT_16BIT << SV_CFMT_ASHIFT)) ? 0 : 0x80;
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void sv_update_ptr(struct sv_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- hwptr = (s->dma_adc.dmasize - get_dmac(s)) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- 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->enable &= ~SV_CENABLE_RE;
- wrindir(s, SV_CIENABLE, s->enable);
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- wake_up(&s->dma_dac.wait);
- } else {
- s->dma_dac.count -= diff;
- if (s->dma_dac.count <= 0) {
- s->enable &= ~SV_CENABLE_PE;
- wrindir(s, SV_CIENABLE, s->enable);
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
- wake_up(&s->dma_dac.wait);
- }
- }
-}
-
-/* hold spinlock for the following! */
-static void sv_handle_midi(struct sv_state *s)
-{
- unsigned char ch;
- int wake;
-
- wake = 0;
- while (!(inb(s->iomidi+1) & 0x80)) {
- ch = inb(s->iomidi);
- 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->iomidi+1) & 0x40) && s->midi.ocnt > 0) {
- outb(s->midi.obuf[s->midi.ord], s->iomidi);
- 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);
-}
-
-static irqreturn_t sv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct sv_state *s = (struct sv_state *)dev_id;
- unsigned int intsrc;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inb(s->ioenh + SV_CODEC_STATUS);
- if (!(intsrc & (SV_CSTAT_DMAA | SV_CSTAT_DMAC | SV_CSTAT_MIDI)))
- return IRQ_NONE;
- spin_lock(&s->lock);
- sv_update_ptr(s);
- sv_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-static void sv_midi_timer(unsigned long data)
-{
- struct sv_state *s = (struct sv_state *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- sv_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->midi.timer.expires = jiffies+1;
- add_timer(&s->midi.timer);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "sv: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != SV_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-#define MT_4 1
-#define MT_5MUTE 2
-#define MT_4MUTEMONO 3
-#define MT_6MUTE 4
-
-static const struct {
- unsigned left:5;
- unsigned right:5;
- unsigned type:3;
- unsigned rec:3;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 },
- [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 },
- [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 },
- [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 },
- [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 },
- [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 },
- [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 },
- [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 },
- [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 }
-};
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-static int return_mixval(struct sv_state *s, unsigned i, int *arg)
-{
- unsigned long flags;
- unsigned char l, r, rl, rr;
-
- spin_lock_irqsave(&s->lock, flags);
- l = rdindir(s, mixtable[i].left);
- r = rdindir(s, mixtable[i].right);
- spin_unlock_irqrestore(&s->lock, flags);
- switch (mixtable[i].type) {
- case MT_4:
- r &= 0xf;
- l &= 0xf;
- rl = 10 + 6 * (l & 15);
- rr = 10 + 6 * (r & 15);
- break;
-
- case MT_4MUTEMONO:
- rl = 55 - 3 * (l & 15);
- if (r & 0x10)
- rl += 45;
- rr = rl;
- r = l;
- break;
-
- case MT_5MUTE:
- default:
- rl = 100 - 3 * (l & 31);
- rr = 100 - 3 * (r & 31);
- break;
-
- case MT_6MUTE:
- rl = 100 - 3 * (l & 63) / 2;
- rr = 100 - 3 * (r & 63) / 2;
- break;
- }
- if (l & 0x80)
- rl = 0;
- if (r & 0x80)
- rr = 0;
- return put_user((rr << 8) | rl, arg);
-}
-
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
-{
- [SOUND_MIXER_RECLEV] = 1,
- [SOUND_MIXER_LINE1] = 2,
- [SOUND_MIXER_CD] = 3,
- [SOUND_MIXER_LINE] = 4,
- [SOUND_MIXER_MIC] = 5,
- [SOUND_MIXER_SYNTH] = 6,
- [SOUND_MIXER_LINE2] = 7,
- [SOUND_MIXER_VOLUME] = 8,
- [SOUND_MIXER_PCM] = 9
-};
-
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static unsigned mixer_recmask(struct sv_state *s)
-{
- unsigned long flags;
- int i, j;
-
- spin_lock_irqsave(&s->lock, flags);
- j = rdindir(s, SV_CIMIX_ADCINL) >> 5;
- spin_unlock_irqrestore(&s->lock, flags);
- j &= 7;
- for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++);
- return 1 << i;
-}
-
-static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
-{
- unsigned long flags;
- int i, val;
- unsigned char l, r, rl, rr;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, "SonicVibes", sizeof(info.id));
- strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
- info.modify_counter = s->mix.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, "SonicVibes", sizeof(info.id));
- strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */
- if (get_user(val, p))
- return -EFAULT;
- spin_lock_irqsave(&s->lock, flags);
- if (val & 1) {
- if (val & 2) {
- l = 4 - ((val >> 2) & 7);
- if (l & ~3)
- l = 4;
- r = 4 - ((val >> 5) & 7);
- if (r & ~3)
- r = 4;
- wrindir(s, SV_CISRSSPACE, l);
- wrindir(s, SV_CISRSCENTER, r);
- } else
- wrindir(s, SV_CISRSSPACE, 0x80);
- }
- l = rdindir(s, SV_CISRSSPACE);
- r = rdindir(s, SV_CISRSCENTER);
- spin_unlock_irqrestore(&s->lock, flags);
- if (l & 0x80)
- return put_user(0, p);
- return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, p);
- }
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(mixer_recmask(s), p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].rec)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- return return_mixval(s, i, p);
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- if (!volidx[i])
- return -EINVAL;
- return put_user(s->mix.vol[volidx[i]-1], p);
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- i = hweight32(val);
- if (i == 0)
- return 0; /*val = mixer_recmask(s);*/
- else if (i > 1)
- val &= ~mixer_recmask(s);
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (mixtable[i].rec)
- break;
- }
- if (i == SOUND_MIXER_NRDEVICES)
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5);
- frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5);
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- r = (val >> 8) & 0xff;
- if (mixtable[i].type == MT_4MUTEMONO)
- l = (r + l) / 2;
- if (l > 100)
- l = 100;
- if (r > 100)
- r = 100;
- spin_lock_irqsave(&s->lock, flags);
- switch (mixtable[i].type) {
- case MT_4:
- if (l >= 10)
- l -= 10;
- if (r >= 10)
- r -= 10;
- frobindir(s, mixtable[i].left, 0xf0, l / 6);
- frobindir(s, mixtable[i].right, 0xf0, l / 6);
- break;
-
- case MT_4MUTEMONO:
- rr = 0;
- if (l < 10)
- rl = 0x80;
- else {
- if (l >= 55) {
- rr = 0x10;
- l -= 45;
- }
- rl = (55 - l) / 3;
- }
- wrindir(s, mixtable[i].left, rl);
- frobindir(s, mixtable[i].right, ~0x10, rr);
- break;
-
- case MT_5MUTE:
- if (l < 7)
- rl = 0x80;
- else
- rl = (100 - l) / 3;
- if (r < 7)
- rr = 0x80;
- else
- rr = (100 - r) / 3;
- wrindir(s, mixtable[i].left, rl);
- wrindir(s, mixtable[i].right, rr);
- break;
-
- case MT_6MUTE:
- if (l < 6)
- rl = 0x80;
- else
- rl = (100 - l) * 2 / 3;
- if (r < 6)
- rr = 0x80;
- else
- rr = (100 - r) * 2 / 3;
- wrindir(s, mixtable[i].left, rl);
- wrindir(s, mixtable[i].right, rr);
- break;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- return return_mixval(s, i, p);
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- if (!volidx[i])
- return -EINVAL;
- s->mix.vol[volidx[i]-1] = val;
- return put_user(s->mix.vol[volidx[i]-1], p);
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int sv_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_state, devs);
- if (s->dev_mixer == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int sv_release_mixdev(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int sv_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct sv_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations sv_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = sv_ioctl_mixdev,
- .open = sv_open_mixdev,
- .release = sv_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct sv_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "sv: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t sv_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-#if 0
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- spin_unlock_irqrestore(&s->lock, flags);
-#endif
- 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;
- break;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- 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);
- }
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t sv_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-#if 0
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- spin_unlock_irqrestore(&s->lock, flags);
-#endif
- add_wait_queue(&s->dma_dac.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize-swptr;
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.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_dac.enabled)
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- stop_dac(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac.enabled)
- start_dac(s);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf(s, 1))
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf(s, 0))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- sv_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_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int sv_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- goto out;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.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_dac(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_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.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_dac(s);
- s->dma_dac.ready = 0;
- set_dac_rate(s, val);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT)
- : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 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) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
- else
- fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_CSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
- else
- fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_ASHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT)
- : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 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->enable & SV_CENABLE_RE)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & SV_CENABLE_PE)
- 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(s, 1)))
- 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_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- s->dma_dac.enabled = 1;
- start_dac(s);
- } else {
- s->dma_dac.enabled = 0;
- stop_dac(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac.dmasize - count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.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(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_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_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- count = s->dma_dac.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(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_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_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.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(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- 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_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;
- }
- 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, 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_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT)
- : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT)
- : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int sv_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned char fmtm = ~0, fmts = 0;
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_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) {
- fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_CSHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
- 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) {
- fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_ASHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- s->dma_dac.enabled = 1;
- set_dac_rate(s, 8000);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int sv_release(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- dealloc_dmabuf(s, &s->dma_dac);
- }
- 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));
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations sv_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = sv_read,
- .write = sv_write,
- .poll = sv_poll,
- .ioctl = sv_ioctl,
- .mmap = sv_mmap,
- .open = sv_open,
- .release = sv_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t sv_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_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 sv_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_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);
- sv_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);
- sv_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 sv_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct sv_state *s = (struct sv_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 sv_midi_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_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(inb(s->ioenh + SV_CODEC_CONTROL) | SV_CCTRL_WAVETABLE, s->ioenh + SV_CODEC_CONTROL);
- outb(inb(s->ioenh + SV_CODEC_INTMASK) | SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
- wrindir(s, SV_CIUARTCONTROL, 5); /* output MIDI data to external and internal synth */
- wrindir(s, SV_CIWAVETABLESRC, 1); /* Wavetable in PC RAM */
- outb(0xff, s->iomidi+1); /* reset command */
- outb(0x3f, s->iomidi+1); /* uart command */
- if (!(inb(s->iomidi+1) & 0x80))
- inb(s->iomidi);
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- init_timer(&s->midi.timer);
- s->midi.timer.expires = jiffies+1;
- s->midi.timer.data = (unsigned long)s;
- s->midi.timer.function = sv_midi_timer;
- add_timer(&s->midi.timer);
- }
- 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;
- }
- 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 sv_midi_release(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_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) {
- remove_wait_queue(&s->midi.owait, &wait);
- set_current_state(TASK_RUNNING);
- unlock_kernel();
- return -EBUSY;
- }
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "sv: 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))) {
- outb(inb(s->ioenh + SV_CODEC_INTMASK) & ~SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
- del_timer(&s->midi.timer);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations sv_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = sv_midi_read,
- .write = sv_midi_write,
- .poll = sv_midi_poll,
- .open = sv_midi_open,
- .release = sv_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int sv_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- static const unsigned char op_offset[18] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
- };
- struct sv_state *s = (struct sv_state *)file->private_data;
- struct dm_fm_voice v;
- struct dm_fm_note n;
- struct dm_fm_params p;
- unsigned int io;
- unsigned int regb;
-
- switch (cmd) {
- case FM_IOCTL_RESET:
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->iosynth);
- outb(0, s->iosynth+1);
- outb(regb, s->iosynth+2);
- outb(0, s->iosynth+3);
- }
- return 0;
-
- case FM_IOCTL_PLAY_NOTE:
- if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
- return -EFAULT;
- if (n.voice >= 18)
- return -EINVAL;
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->iosynth+2;
- } else {
- regb = n.voice;
- io = s->iosynth;
- }
- outb(0xa0 + regb, io);
- outb(n.fnum & 0xff, io+1);
- outb(0xb0 + regb, io);
- outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
- return 0;
-
- case FM_IOCTL_SET_VOICE:
- if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
- return -EFAULT;
- if (v.voice >= 18)
- return -EINVAL;
- regb = op_offset[v.voice];
- io = s->iosynth + ((v.op & 1) << 1);
- outb(0x20 + regb, io);
- outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) |
- ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
- outb(0x40 + regb, io);
- outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
- outb(0x60 + regb, io);
- outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
- outb(0x80 + regb, io);
- outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
- outb(0xe0 + regb, io);
- outb(v.waveform & 0x7, io+1);
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->iosynth+2;
- } else {
- regb = n.voice;
- io = s->iosynth;
- }
- outb(0xc0 + regb, io);
- outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
- (v.connection & 1), io+1);
- return 0;
-
- case FM_IOCTL_SET_PARAMS:
- if (copy_from_user(&p, (void *__user )arg, sizeof(p)))
- return -EFAULT;
- outb(0x08, s->iosynth);
- outb((p.kbd_split & 1) << 6, s->iosynth+1);
- outb(0xbd, s->iosynth);
- outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
- ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->iosynth+1);
- return 0;
-
- case FM_IOCTL_SET_OPL:
- outb(4, s->iosynth+2);
- outb(arg, s->iosynth+3);
- return 0;
-
- case FM_IOCTL_SET_MODE:
- outb(5, s->iosynth+2);
- outb(arg & 1, s->iosynth+3);
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-static int sv_dmfm_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_state, devs);
- if (s->dev_dmfm == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & FMODE_DMFM) {
- 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);
- }
- /* init the stuff */
- outb(1, s->iosynth);
- outb(0x20, s->iosynth+1); /* enable waveforms */
- outb(4, s->iosynth+2);
- outb(0, s->iosynth+3); /* no 4op enabled */
- outb(5, s->iosynth+2);
- outb(1, s->iosynth+3); /* enable OPL3 */
- s->open_mode |= FMODE_DMFM;
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int sv_dmfm_release(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- unsigned int regb;
-
- VALIDATE_STATE(s);
- lock_kernel();
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~FMODE_DMFM;
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->iosynth);
- outb(0, s->iosynth+1);
- outb(regb, s->iosynth+2);
- outb(0, s->iosynth+3);
- }
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations sv_dmfm_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = sv_dmfm_ioctl,
- .open = sv_dmfm_open,
- .release = sv_dmfm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int reverb[NR_DEVICE];
-
-#if 0
-static int wavetable[NR_DEVICE];
-#endif
-
-static unsigned int devindex;
-
-module_param_array(reverb, bool, NULL, 0);
-MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
-#if 0
-MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i");
-MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled");
-#endif
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("S3 SonicVibes Driver");
-MODULE_LICENSE("GPL");
-
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 }
-};
-
-#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
- (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
-
-#ifdef SUPPORT_JOYSTICK
-static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
-{
- struct gameport *gp;
-
- if (!request_region(io_port, SV_EXTENT_GAME, "S3 SonicVibes Gameport")) {
- printk(KERN_ERR "sv: gameport io ports are in use\n");
- return -EBUSY;
- }
-
- s->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR "sv: can not allocate memory for gameport\n");
- release_region(io_port, SV_EXTENT_GAME);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "S3 SonicVibes Gameport");
- gameport_set_phys(gp, "isa%04x/gameport0", io_port);
- gp->dev.parent = &s->dev->dev;
- gp->io = io_port;
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void sv_unregister_gameport(struct sv_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, SV_EXTENT_GAME);
- }
-}
-#else
-static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; }
-static inline void sv_unregister_gameport(struct sv_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
- struct sv_state *s;
- mm_segment_t fs;
- int i, val, ret;
- int gpio;
- char *ddmaname;
- unsigned ddmanamelen;
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
-
- if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
- !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
- !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
- !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
- !RSRCISIOREGION(pcidev, RESOURCE_GAME))
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
- if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK)) {
- printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
- return -ENODEV;
- }
- /* try to allocate a DDMA resource if not already available */
- if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
- pcidev->resource[RESOURCE_DDMA].start = 0;
- pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1;
- pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
- ddmanamelen = strlen(sv_ddma_name)+1;
- if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
- return -1;
- memcpy(ddmaname, sv_ddma_name, ddmanamelen);
- pcidev->resource[RESOURCE_DDMA].name = ddmaname;
- if (pci_assign_resource(pcidev, RESOURCE_DDMA)) {
- pcidev->resource[RESOURCE_DDMA].name = NULL;
- kfree(ddmaname);
- printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
- return -EBUSY;
- }
- }
- if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
- printk(KERN_WARNING "sv: out of memory\n");
- return -ENOMEM;
- }
- memset(s, 0, sizeof(struct sv_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.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 = SV_MAGIC;
- s->dev = pcidev;
- s->iosb = pci_resource_start(pcidev, RESOURCE_SB);
- s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH);
- s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH);
- s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI);
- s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA);
- s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
- gpio = pci_resource_start(pcidev, RESOURCE_GAME);
- pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */
- pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */
- printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n",
- s->iosb, s->ioenh, s->iosynth, s->iomidi, gpio, s->iodmaa, s->iodmac);
- s->irq = pcidev->irq;
-
- /* hack */
- pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */
-
- ret = -EBUSY;
- if (!request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM")) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1);
- goto err_region5;
- }
- if (!request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA")) {
- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1);
- goto err_region4;
- }
- if (!request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC")) {
- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1);
- goto err_region3;
- }
- if (!request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi")) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1);
- goto err_region2;
- }
- if (!request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth")) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
- goto err_region1;
- }
-
- /* initialize codec registers */
- outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
- udelay(50);
- outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */
- udelay(50);
- outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */
- | (reverb[devindex] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL);
- inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */
- wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */
- wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */
- outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
- /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
- /* outb(0xff, s->iodmac + SV_DMA_RESET); */
- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
- wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
- wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
- wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */
- setpll(s, SV_CIADCPLLM, 8000);
- wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */
- wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff);
- wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff);
- wrindir(s, SV_CIADCOUTPUT, 0);
- /* request irq */
- if ((ret=request_irq(s->irq,sv_interrupt,IRQF_SHARED,"S3 SonicVibes",s))) {
- printk(KERN_ERR "sv: irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n",
- s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION));
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0) {
- ret = s->dev_midi;
- goto err_dev3;
- }
- if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) {
- ret = s->dev_dmfm;
- goto err_dev4;
- }
- pci_set_master(pcidev); /* enable bus mastering */
- /* initialize the chips */
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- set_fs(fs);
- /* register gameport */
- sv_register_gameport(s, gpio);
- /* 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_dev4:
- unregister_sound_midi(s->dev_midi);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "sv: cannot register misc device\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->iosynth, SV_EXTENT_SYNTH);
- err_region1:
- release_region(s->iomidi, SV_EXTENT_MIDI);
- err_region2:
- release_region(s->iodmac, SV_EXTENT_DMA);
- err_region3:
- release_region(s->iodmaa, SV_EXTENT_DMA);
- err_region4:
- release_region(s->ioenh, SV_EXTENT_ENH);
- err_region5:
- kfree(s);
- return ret;
-}
-
-static void __devexit sv_remove(struct pci_dev *dev)
-{
- struct sv_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- list_del(&s->devs);
- outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */
- synchronize_irq(s->irq);
- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
- wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */
- /*outb(0, s->iodmaa + SV_DMA_RESET);*/
- /*outb(0, s->iodmac + SV_DMA_RESET);*/
- free_irq(s->irq, s);
- sv_unregister_gameport(s);
- release_region(s->iodmac, SV_EXTENT_DMA);
- release_region(s->iodmaa, SV_EXTENT_DMA);
- release_region(s->ioenh, SV_EXTENT_ENH);
- release_region(s->iomidi, SV_EXTENT_MIDI);
- release_region(s->iosynth, SV_EXTENT_SYNTH);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_midi(s->dev_midi);
- unregister_sound_special(s->dev_dmfm);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver sv_driver = {
- .name = "sonicvibes",
- .id_table = id_table,
- .probe = sv_probe,
- .remove = __devexit_p(sv_remove),
-};
-
-static int __init init_sonicvibes(void)
-{
- printk(KERN_INFO "sv: version v0.31 time " __TIME__ " " __DATE__ "\n");
-#if 0
- if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
- printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
-#endif
- return pci_register_driver(&sv_driver);
-}
-
-static void __exit cleanup_sonicvibes(void)
-{
- printk(KERN_INFO "sv: unloading\n");
- pci_unregister_driver(&sv_driver);
- if (wavetable_mem)
- free_pages(wavetable_mem, 20-PAGE_SHIFT);
-}
-
-module_init(init_sonicvibes);
-module_exit(cleanup_sonicvibes);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: sonicvibes=[reverb] sonicvibesdmaio=dmaioaddr */
-
-static int __init sonicvibes_setup(char *str)
-{
- static unsigned __initdata nr_dev = 0;
-
- if (nr_dev >= NR_DEVICE)
- return 0;
-#if 0
- if (get_option(&str, &reverb[nr_dev]) == 2)
- (void)get_option(&str, &wavetable[nr_dev]);
-#else
- (void)get_option(&str, &reverb[nr_dev]);
-#endif
-
- nr_dev++;
- return 1;
-}
-
-__setup("sonicvibes=", sonicvibes_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h
index 1ae0750..87d8ad4 100644
--- a/sound/oss/sound_calls.h
+++ b/sound/oss/sound_calls.h
@@ -13,8 +13,6 @@
void DMAbuf_init(int dev, int dma1, int dma2);
void DMAbuf_deinit(int dev);
int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
-int DMAbuf_open_dma (int dev);
-void DMAbuf_close_dma (int dev);
void DMAbuf_inputintr(int dev);
void DMAbuf_outputintr(int dev, int underflow_flag);
struct dma_buffparms;
@@ -73,7 +71,6 @@
int MIDIbuf_avail(int dev);
void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
-void MIDIbuf_init(void);
/* From soundcard.c */
diff --git a/sound/oss/sound_syms.c b/sound/oss/sound_syms.c
deleted file mode 100644
index cb7c33f..0000000
--- a/sound/oss/sound_syms.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * The sound core exports the following symbols to the rest of
- * modulespace.
- *
- * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL
- *
- * Thu May 27 1999 Andrew J. Kroll <ag784@freenet..buffalo..edu>
- * left out exported symbol... fixed
- */
-
-#include <linux/module.h>
-#include "sound_config.h"
-#include "sound_calls.h"
-
-char sound_syms_symbol;
-
-EXPORT_SYMBOL(mixer_devs);
-EXPORT_SYMBOL(audio_devs);
-EXPORT_SYMBOL(num_mixers);
-EXPORT_SYMBOL(num_audiodevs);
-
-EXPORT_SYMBOL(midi_devs);
-EXPORT_SYMBOL(num_midis);
-EXPORT_SYMBOL(synth_devs);
-
-EXPORT_SYMBOL(sound_timer_devs);
-
-EXPORT_SYMBOL(sound_install_audiodrv);
-EXPORT_SYMBOL(sound_install_mixer);
-EXPORT_SYMBOL(sound_alloc_dma);
-EXPORT_SYMBOL(sound_free_dma);
-EXPORT_SYMBOL(sound_open_dma);
-EXPORT_SYMBOL(sound_close_dma);
-EXPORT_SYMBOL(sound_alloc_mididev);
-EXPORT_SYMBOL(sound_alloc_mixerdev);
-EXPORT_SYMBOL(sound_alloc_timerdev);
-EXPORT_SYMBOL(sound_alloc_synthdev);
-EXPORT_SYMBOL(sound_unload_audiodev);
-EXPORT_SYMBOL(sound_unload_mididev);
-EXPORT_SYMBOL(sound_unload_mixerdev);
-EXPORT_SYMBOL(sound_unload_timerdev);
-EXPORT_SYMBOL(sound_unload_synthdev);
-
-EXPORT_SYMBOL(load_mixer_volumes);
-
-EXPORT_SYMBOL(conf_printf);
-EXPORT_SYMBOL(conf_printf2);
-
-MODULE_DESCRIPTION("OSS Sound subsystem");
-MODULE_AUTHOR("Hannu Savolainen, et al.");
diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c
index 146bf85..f0f0c19 100644
--- a/sound/oss/sound_timer.c
+++ b/sound/oss/sound_timer.c
@@ -76,6 +76,7 @@
tmr_ctr = 0;
usecs_per_tmr = new_usecs;
}
+EXPORT_SYMBOL(sound_timer_syncinterval);
static void tmr_reset(void)
{
@@ -300,6 +301,7 @@
}
spin_unlock_irqrestore(&lock,flags);
}
+EXPORT_SYMBOL(sound_timer_interrupt);
void sound_timer_init(struct sound_lowlev_timer *t, char *name)
{
@@ -321,3 +323,5 @@
strcpy(sound_timer.info.name, 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 683dc00..2344d09 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -107,6 +107,7 @@
mixer_vols[n].levels[i] = levels[i];
return mixer_vols[n].levels;
}
+EXPORT_SYMBOL(load_mixer_volumes);
static int set_mixer_levels(void __user * arg)
{
@@ -541,12 +542,6 @@
int err;
int i, j;
- /* drag in sound_syms.o */
- {
- extern char sound_syms_symbol;
- sound_syms_symbol = 0;
- }
-
#ifdef CONFIG_PCI
if(dmabug)
isa_dma_bridge_buggy = dmabug;
@@ -614,6 +609,8 @@
module_init(oss_init);
module_exit(oss_cleanup);
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OSS Sound subsystem");
+MODULE_AUTHOR("Hannu Savolainen, et al.");
int sound_alloc_dma(int chn, char *deviceID)
@@ -627,6 +624,7 @@
return 0;
}
+EXPORT_SYMBOL(sound_alloc_dma);
int sound_open_dma(int chn, char *deviceID)
{
@@ -642,6 +640,7 @@
dma_alloc_map[chn] = DMA_MAP_BUSY;
return 0;
}
+EXPORT_SYMBOL(sound_open_dma);
void sound_free_dma(int chn)
{
@@ -652,6 +651,7 @@
free_dma(chn);
dma_alloc_map[chn] = DMA_MAP_UNAVAIL;
}
+EXPORT_SYMBOL(sound_free_dma);
void sound_close_dma(int chn)
{
@@ -661,6 +661,7 @@
}
dma_alloc_map[chn] = DMA_MAP_FREE;
}
+EXPORT_SYMBOL(sound_close_dma);
static void do_sequencer_timer(unsigned long dummy)
{
@@ -714,6 +715,7 @@
printk("\n");
#endif
}
+EXPORT_SYMBOL(conf_printf);
void conf_printf2(char *name, int base, int irq, int dma, int dma2)
{
@@ -734,3 +736,5 @@
printk("\n");
#endif
}
+EXPORT_SYMBOL(conf_printf2);
+
diff --git a/sound/oss/tuning.h b/sound/oss/tuning.h
index 858e1fe6..a73e3dd 100644
--- a/sound/oss/tuning.h
+++ b/sound/oss/tuning.h
@@ -1,13 +1,11 @@
-#ifdef SEQUENCER_C
-
-unsigned short semitone_tuning[24] =
+static unsigned short semitone_tuning[24] =
{
/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
};
-unsigned short cent_tuning[100] =
+static unsigned short cent_tuning[100] =
{
/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
@@ -23,7 +21,3 @@
/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
/* 96 */ 10570, 10576, 10582, 10589
};
-#else
-extern unsigned short semitone_tuning[24];
-extern unsigned short cent_tuning[100];
-#endif
diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c
deleted file mode 100644
index 1dec395..0000000
--- a/sound/oss/wavfront.c
+++ /dev/null
@@ -1,3554 +0,0 @@
-/* -*- linux-c -*-
- *
- * sound/wavfront.c
- *
- * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus)
- *
- * This driver supports the onboard wavetable synthesizer (an ICS2115),
- * including patch, sample and program loading and unloading, conversion
- * of GUS patches during loading, and full user-level access to all
- * WaveFront commands. It tries to provide semi-intelligent patch and
- * sample management as well.
- *
- * It also provides support for the ICS emulation of an MPU-401. Full
- * support for the ICS emulation's "virtual MIDI mode" is provided in
- * wf_midi.c.
- *
- * Support is also provided for the Tropez Plus' onboard FX processor,
- * a Yamaha YSS225. Currently, code exists to configure the YSS225,
- * and there is an interface allowing tweaking of any of its memory
- * addresses. However, I have been unable to decipher the logical
- * positioning of the configuration info for various effects, so for
- * now, you just get the YSS225 in the same state as Turtle Beach's
- * "SETUPSND.EXE" utility leaves it.
- *
- * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co],
- * This chip also controls the configuration of the card: the wavefront
- * synth is logical unit 4.
- *
- *
- * Supported devices:
- *
- * /dev/dsp - using cs4232+ad1848 modules, OSS compatible
- * /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible
- * /dev/synth00 - raw synth interface
- *
- **********************************************************************
- *
- * Copyright (C) by Paul Barton-Davis 1998
- *
- * Some portions of this file are taken from work that is
- * copyright (C) by Hannu Savolainen 1993-1996
- *
- * Although the relevant code here is all new, the handling of
- * sample/alias/multi- samples is entirely based on a driver by Matt
- * Martin and Rutger Nijlunsing which demonstrated how to get things
- * to work correctly. The GUS patch loading code has been almost
- * unaltered by me, except to fit formatting and function names in the
- * rest of the file. Many thanks to them.
- *
- * Appreciation and thanks to Hannu Savolainen for his early work on the Maui
- * driver, and answering a few questions while this one was developed.
- *
- * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their
- * complete lack of help in developing this driver, and in particular
- * for their utter silence in response to questions about undocumented
- * aspects of configuring a WaveFront soundcard, particularly the
- * effects processor.
- *
- * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $
- *
- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added some __init and __initdata to entries in yss225.c
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/ptrace.h>
-#include <linux/fcntl.h>
-#include <linux/syscalls.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/config.h>
-
-#include <linux/delay.h>
-
-#include "sound_config.h"
-
-#include <linux/wavefront.h>
-
-#define _MIDI_SYNTH_C_
-#define MIDI_SYNTH_NAME "WaveFront MIDI"
-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-/* Compile-time control of the extent to which OSS is supported.
-
- I consider /dev/sequencer to be an anachronism, but given its
- widespread usage by various Linux MIDI software, it seems worth
- offering support to it if it's not too painful. Instead of using
- /dev/sequencer, I recommend:
-
- for synth programming and patch loading: /dev/synthNN
- for kernel-synchronized MIDI sequencing: the ALSA sequencer
- for direct MIDI control: /dev/midiNN
-
- I have never tried static compilation into the kernel. The #if's
- for this are really just notes to myself about what the code is
- for.
-*/
-
-#define OSS_SUPPORT_SEQ 0x1 /* use of /dev/sequencer */
-#define OSS_SUPPORT_STATIC_INSTALL 0x2 /* static compilation into kernel */
-
-#define OSS_SUPPORT_LEVEL 0x1 /* just /dev/sequencer for now */
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-static int (*midi_load_patch) (int devno, int format, const char __user *addr,
- int offs, int count, int pmgr_flag) = NULL;
-#endif /* OSS_SUPPORT_SEQ */
-
-/* if WF_DEBUG not defined, no run-time debugging messages will
- be available via the debug flag setting. Given the current
- beta state of the driver, this will remain set until a future
- version.
-*/
-
-#define WF_DEBUG 1
-
-#ifdef WF_DEBUG
-
-/* Thank goodness for gcc's preprocessor ... */
-
-#define DPRINT(cond, format, args...) \
- if ((dev.debug & (cond)) == (cond)) { \
- printk (KERN_DEBUG LOGNAME format, ## args); \
- }
-#else
-#define DPRINT(cond, format, args...)
-#endif
-
-#define LOGNAME "WaveFront: "
-
-/* bitmasks for WaveFront status port value */
-
-#define STAT_RINTR_ENABLED 0x01
-#define STAT_CAN_READ 0x02
-#define STAT_INTR_READ 0x04
-#define STAT_WINTR_ENABLED 0x10
-#define STAT_CAN_WRITE 0x20
-#define STAT_INTR_WRITE 0x40
-
-/*** Module-accessible parameters ***************************************/
-
-static int wf_raw; /* we normally check for "raw state" to firmware
- loading. if set, then during driver loading, the
- state of the board is ignored, and we reset the
- board and load the firmware anyway.
- */
-
-static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in
- whatever state it is when the driver is loaded.
- The default is to download the microprogram and
- associated coefficients to set it up for "default"
- operation, whatever that means.
- */
-
-static int debug_default; /* you can set this to control debugging
- during driver loading. it takes any combination
- of the WF_DEBUG_* flags defined in
- wavefront.h
- */
-
-/* XXX this needs to be made firmware and hardware version dependent */
-
-static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed
- version of the WaveFront OS
- */
-
-static int wait_polls = 2000; /* This is a number of tries we poll the
- status register before resorting to sleeping.
- WaveFront being an ISA card each poll takes
- about 1.2us. So before going to
- sleep we wait up to 2.4ms in a loop.
- */
-
-static int sleep_length = HZ/100; /* This says how long we're going to
- sleep between polls.
- 10ms sounds reasonable for fast response.
- */
-
-static int sleep_tries = 50; /* Wait for status 0.5 seconds total. */
-
-static int reset_time = 2; /* hundreths of a second we wait after a HW reset for
- the expected interrupt.
- */
-
-static int ramcheck_time = 20; /* time in seconds to wait while ROM code
- checks on-board RAM.
- */
-
-static int osrun_time = 10; /* time in seconds we wait for the OS to
- start running.
- */
-
-module_param(wf_raw, int, 0);
-module_param(fx_raw, int, 0);
-module_param(debug_default, int, 0);
-module_param(wait_polls, int, 0);
-module_param(sleep_length, int, 0);
-module_param(sleep_tries, int, 0);
-module_param(ospath, charp, 0);
-module_param(reset_time, int, 0);
-module_param(ramcheck_time, int, 0);
-module_param(osrun_time, int, 0);
-
-/***************************************************************************/
-
-/* Note: because this module doesn't export any symbols, this really isn't
- a global variable, even if it looks like one. I was quite confused by
- this when I started writing this as a (newer) module -- pbd.
-*/
-
-struct wf_config {
- int devno; /* device number from kernel */
- int irq; /* "you were one, one of the few ..." */
- int base; /* low i/o port address */
-
-#define mpu_data_port base
-#define mpu_command_port base + 1 /* write semantics */
-#define mpu_status_port base + 1 /* read semantics */
-#define data_port base + 2
-#define status_port base + 3 /* read semantics */
-#define control_port base + 3 /* write semantics */
-#define block_port base + 4 /* 16 bit, writeonly */
-#define last_block_port base + 6 /* 16 bit, writeonly */
-
- /* FX ports. These are mapped through the ICS2115 to the YS225.
- The ICS2115 takes care of flipping the relevant pins on the
- YS225 so that access to each of these ports does the right
- thing. Note: these are NOT documented by Turtle Beach.
- */
-
-#define fx_status base + 8
-#define fx_op base + 8
-#define fx_lcr base + 9
-#define fx_dsp_addr base + 0xa
-#define fx_dsp_page base + 0xb
-#define fx_dsp_lsb base + 0xc
-#define fx_dsp_msb base + 0xd
-#define fx_mod_addr base + 0xe
-#define fx_mod_data base + 0xf
-
- volatile int irq_ok; /* set by interrupt handler */
- volatile int irq_cnt; /* ditto */
- int opened; /* flag, holds open(2) mode */
- char debug; /* debugging flags */
- int freemem; /* installed RAM, in bytes */
-
- int synth_dev; /* devno for "raw" synth */
- int mididev; /* devno for internal MIDI */
- int ext_mididev; /* devno for external MIDI */
- int fx_mididev; /* devno for FX MIDI interface */
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- int oss_dev; /* devno for OSS sequencer synth */
-#endif /* OSS_SUPPORT_SEQ */
-
- char fw_version[2]; /* major = [0], minor = [1] */
- char hw_version[2]; /* major = [0], minor = [1] */
- char israw; /* needs Motorola microcode */
- char has_fx; /* has FX processor (Tropez+) */
- char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */
- char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */
- char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
- int samples_used; /* how many */
- char interrupts_on; /* h/w MPU interrupts enabled ? */
- char rom_samples_rdonly; /* can we write on ROM samples */
- wait_queue_head_t interrupt_sleeper;
-} dev;
-
-static DEFINE_SPINLOCK(lock);
-static int detect_wffx(void);
-static int wffx_ioctl (wavefront_fx_info *);
-static int wffx_init (void);
-
-static int wavefront_delete_sample (int sampnum);
-static int wavefront_find_free_sample (void);
-
-/* From wf_midi.c */
-
-extern int virtual_midi_enable (void);
-extern int virtual_midi_disable (void);
-extern int detect_wf_mpu (int, int);
-extern int install_wf_mpu (void);
-extern int uninstall_wf_mpu (void);
-
-typedef struct {
- int cmd;
- char *action;
- unsigned int read_cnt;
- unsigned int write_cnt;
- int need_ack;
-} wavefront_command;
-
-static struct {
- int errno;
- const char *errstr;
-} wavefront_errors[] = {
- { 0x01, "Bad sample number" },
- { 0x02, "Out of sample memory" },
- { 0x03, "Bad patch number" },
- { 0x04, "Error in number of voices" },
- { 0x06, "Sample load already in progress" },
- { 0x0B, "No sample load request pending" },
- { 0x0E, "Bad MIDI channel number" },
- { 0x10, "Download Record Error" },
- { 0x80, "Success" },
- { 0 }
-};
-
-#define NEEDS_ACK 1
-
-static wavefront_command wavefront_commands[] = {
- { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK },
- { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0},
- { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK },
- { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 },
- { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK },
- { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 },
- { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK },
- { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK },
- { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 },
- { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK },
- { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK },
- { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK },
- { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK },
- { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 },
- { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 },
- { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 },
- { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 },
- { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 },
- { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 },
- { WFC_DOWNLOAD_SAMPLE, "download sample",
- 0, WF_SAMPLE_BYTES, NEEDS_ACK },
- { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK},
- { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header",
- 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK },
- { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 },
-
- /* This command requires a variable number of bytes to be written.
- There is a hack in wavefront_cmd() to support this. The actual
- count is passed in as the read buffer ptr, cast appropriately.
- Ugh.
- */
-
- { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK },
-
- /* This one is a hack as well. We just read the first byte of the
- response, don't fetch an ACK, and leave the rest to the
- calling function. Ugly, ugly, ugly.
- */
-
- { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 },
- { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias",
- 0, WF_ALIAS_BYTES, NEEDS_ACK },
- { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0},
- { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK },
- { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 },
- { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" },
- { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 },
- { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK },
- { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 },
- { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK },
- { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 },
- { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9,
- NEEDS_ACK},
- { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0},
- { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel",
- 0, 1, NEEDS_ACK },
- { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK },
- { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers",
- 32, 0, 0 },
- { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK },
- { 0x00 }
-};
-
-static const char *
-wavefront_errorstr (int errnum)
-
-{
- int i;
-
- for (i = 0; wavefront_errors[i].errstr; i++) {
- if (wavefront_errors[i].errno == errnum) {
- return wavefront_errors[i].errstr;
- }
- }
-
- return "Unknown WaveFront error";
-}
-
-static wavefront_command *
-wavefront_get_command (int cmd)
-
-{
- int i;
-
- for (i = 0; wavefront_commands[i].cmd != 0; i++) {
- if (cmd == wavefront_commands[i].cmd) {
- return &wavefront_commands[i];
- }
- }
-
- return (wavefront_command *) 0;
-}
-
-static inline int
-wavefront_status (void)
-
-{
- return inb (dev.status_port);
-}
-
-static int
-wavefront_wait (int mask)
-
-{
- int i;
-
- for (i = 0; i < wait_polls; i++)
- if (wavefront_status() & mask)
- return 1;
-
- for (i = 0; i < sleep_tries; i++) {
-
- if (wavefront_status() & mask) {
- set_current_state(TASK_RUNNING);
- return 1;
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(sleep_length);
- if (signal_pending(current))
- break;
- }
-
- set_current_state(TASK_RUNNING);
- return 0;
-}
-
-static int
-wavefront_read (void)
-
-{
- if (wavefront_wait (STAT_CAN_READ))
- return inb (dev.data_port);
-
- DPRINT (WF_DEBUG_DATA, "read timeout.\n");
-
- return -1;
-}
-
-static int
-wavefront_write (unsigned char data)
-
-{
- if (wavefront_wait (STAT_CAN_WRITE)) {
- outb (data, dev.data_port);
- return 0;
- }
-
- DPRINT (WF_DEBUG_DATA, "write timeout.\n");
-
- return -1;
-}
-
-static int
-wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf)
-
-{
- int ack;
- int i;
- int c;
- wavefront_command *wfcmd;
-
- if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) {
- printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n",
- cmd);
- return 1;
- }
-
- /* Hack to handle the one variable-size write command. See
- wavefront_send_multisample() for the other half of this
- gross and ugly strategy.
- */
-
- if (cmd == WFC_DOWNLOAD_MULTISAMPLE) {
- wfcmd->write_cnt = (unsigned int) rbuf;
- rbuf = NULL;
- }
-
- DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n",
- cmd, wfcmd->action, wfcmd->read_cnt,
- wfcmd->write_cnt, wfcmd->need_ack);
-
- if (wavefront_write (cmd)) {
- DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request "
- "0x%x [%s].\n",
- cmd, wfcmd->action);
- return 1;
- }
-
- if (wfcmd->write_cnt > 0) {
- DPRINT (WF_DEBUG_DATA, "writing %d bytes "
- "for 0x%x\n",
- wfcmd->write_cnt, cmd);
-
- for (i = 0; i < wfcmd->write_cnt; i++) {
- if (wavefront_write (wbuf[i])) {
- DPRINT (WF_DEBUG_IO, "bad write for byte "
- "%d of 0x%x [%s].\n",
- i, cmd, wfcmd->action);
- return 1;
- }
-
- DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n",
- i, wbuf[i]);
- }
- }
-
- if (wfcmd->read_cnt > 0) {
- DPRINT (WF_DEBUG_DATA, "reading %d ints "
- "for 0x%x\n",
- wfcmd->read_cnt, cmd);
-
- for (i = 0; i < wfcmd->read_cnt; i++) {
-
- if ((c = wavefront_read()) == -1) {
- DPRINT (WF_DEBUG_IO, "bad read for byte "
- "%d of 0x%x [%s].\n",
- i, cmd, wfcmd->action);
- return 1;
- }
-
- /* Now handle errors. Lots of special cases here */
-
- if (c == 0xff) {
- if ((c = wavefront_read ()) == -1) {
- DPRINT (WF_DEBUG_IO, "bad read for "
- "error byte at "
- "read byte %d "
- "of 0x%x [%s].\n",
- i, cmd,
- wfcmd->action);
- return 1;
- }
-
- /* Can you believe this madness ? */
-
- if (c == 1 &&
- wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) {
- rbuf[0] = WF_ST_EMPTY;
- return (0);
-
- } else if (c == 3 &&
- wfcmd->cmd == WFC_UPLOAD_PATCH) {
-
- return 3;
-
- } else if (c == 1 &&
- wfcmd->cmd == WFC_UPLOAD_PROGRAM) {
-
- return 1;
-
- } else {
-
- DPRINT (WF_DEBUG_IO, "error %d (%s) "
- "during "
- "read for byte "
- "%d of 0x%x "
- "[%s].\n",
- c,
- wavefront_errorstr (c),
- i, cmd,
- wfcmd->action);
- return 1;
-
- }
-
- } else {
- rbuf[i] = c;
- }
-
- DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]);
- }
- }
-
- if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) {
-
- DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd);
-
- /* Some commands need an ACK, but return zero instead
- of the standard value.
- */
-
- if ((ack = wavefront_read()) == 0) {
- ack = WF_ACK;
- }
-
- if (ack != WF_ACK) {
- if (ack == -1) {
- DPRINT (WF_DEBUG_IO, "cannot read ack for "
- "0x%x [%s].\n",
- cmd, wfcmd->action);
- return 1;
-
- } else {
- int err = -1; /* something unknown */
-
- if (ack == 0xff) { /* explicit error */
-
- if ((err = wavefront_read ()) == -1) {
- DPRINT (WF_DEBUG_DATA,
- "cannot read err "
- "for 0x%x [%s].\n",
- cmd, wfcmd->action);
- }
- }
-
- DPRINT (WF_DEBUG_IO, "0x%x [%s] "
- "failed (0x%x, 0x%x, %s)\n",
- cmd, wfcmd->action, ack, err,
- wavefront_errorstr (err));
-
- return -err;
- }
- }
-
- DPRINT (WF_DEBUG_DATA, "ack received "
- "for 0x%x [%s]\n",
- cmd, wfcmd->action);
- } else {
-
- DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need "
- "ACK (%d,%d,%d)\n",
- cmd, wfcmd->action, wfcmd->read_cnt,
- wfcmd->write_cnt, wfcmd->need_ack);
- }
-
- return 0;
-
-}
-
-/***********************************************************************
-WaveFront: data munging
-
-Things here are weird. All data written to the board cannot
-have its most significant bit set. Any data item with values
-potentially > 0x7F (127) must be split across multiple bytes.
-
-Sometimes, we need to munge numeric values that are represented on
-the x86 side as 8-32 bit values. Sometimes, we need to munge data
-that is represented on the x86 side as an array of bytes. The most
-efficient approach to handling both cases seems to be to use 2
-different functions for munging and 2 for de-munging. This avoids
-weird casting and worrying about bit-level offsets.
-
-**********************************************************************/
-
-static
-unsigned char *
-munge_int32 (unsigned int src,
- unsigned char *dst,
- unsigned int dst_size)
-{
- int i;
-
- for (i = 0;i < dst_size; i++) {
- *dst = src & 0x7F; /* Mask high bit of LSB */
- src = src >> 7; /* Rotate Right 7 bits */
- /* Note: we leave the upper bits in place */
-
- dst++;
- };
- return dst;
-};
-
-static int
-demunge_int32 (unsigned char* src, int src_size)
-
-{
- int i;
- int outval = 0;
-
- for (i = src_size - 1; i >= 0; i--) {
- outval=(outval<<7)+src[i];
- }
-
- return outval;
-};
-
-static
-unsigned char *
-munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size)
-
-{
- int i;
- unsigned int last = dst_size / 2;
-
- for (i = 0; i < last; i++) {
- *dst++ = src[i] & 0x7f;
- *dst++ = src[i] >> 7;
- }
- return dst;
-}
-
-static
-unsigned char *
-demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes)
-
-{
- int i;
- unsigned char *end = src + src_bytes;
-
- end = src + src_bytes;
-
- /* NOTE: src and dst *CAN* point to the same address */
-
- for (i = 0; src != end; i++) {
- dst[i] = *src++;
- dst[i] |= (*src++)<<7;
- }
-
- return dst;
-}
-
-/***********************************************************************
-WaveFront: sample, patch and program management.
-***********************************************************************/
-
-static int
-wavefront_delete_sample (int sample_num)
-
-{
- unsigned char wbuf[2];
- int x;
-
- wbuf[0] = sample_num & 0x7f;
- wbuf[1] = sample_num >> 7;
-
- if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) {
- dev.sample_status[sample_num] = WF_ST_EMPTY;
- }
-
- return x;
-}
-
-static int
-wavefront_get_sample_status (int assume_rom)
-
-{
- int i;
- unsigned char rbuf[32], wbuf[32];
- unsigned int sc_real, sc_alias, sc_multi;
-
- /* check sample status */
-
- if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME "cannot request sample count.\n");
- return -1;
- }
-
- sc_real = sc_alias = sc_multi = dev.samples_used = 0;
-
- for (i = 0; i < WF_MAX_SAMPLE; i++) {
-
- wbuf[0] = i & 0x7f;
- wbuf[1] = i >> 7;
-
- if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "cannot identify sample "
- "type of slot %d\n", i);
- dev.sample_status[i] = WF_ST_EMPTY;
- continue;
- }
-
- dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]);
-
- if (assume_rom) {
- dev.sample_status[i] |= WF_SLOT_ROM;
- }
-
- switch (rbuf[0] & WF_ST_MASK) {
- case WF_ST_SAMPLE:
- sc_real++;
- break;
- case WF_ST_MULTISAMPLE:
- sc_multi++;
- break;
- case WF_ST_ALIAS:
- sc_alias++;
- break;
- case WF_ST_EMPTY:
- break;
-
- default:
- printk (KERN_WARNING LOGNAME "unknown sample type for "
- "slot %d (0x%x)\n",
- i, rbuf[0]);
- }
-
- if (rbuf[0] != WF_ST_EMPTY) {
- dev.samples_used++;
- }
- }
-
- printk (KERN_INFO LOGNAME
- "%d samples used (%d real, %d aliases, %d multi), "
- "%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi,
- WF_MAX_SAMPLE - dev.samples_used);
-
-
- return (0);
-
-}
-
-static int
-wavefront_get_patch_status (void)
-
-{
- unsigned char patchbuf[WF_PATCH_BYTES];
- unsigned char patchnum[2];
- wavefront_patch *p;
- int i, x, cnt, cnt2;
-
- for (i = 0; i < WF_MAX_PATCH; i++) {
- patchnum[0] = i & 0x7f;
- patchnum[1] = i >> 7;
-
- if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf,
- patchnum)) == 0) {
-
- dev.patch_status[i] |= WF_SLOT_FILLED;
- p = (wavefront_patch *) patchbuf;
- dev.sample_status
- [p->sample_number|(p->sample_msb<<7)] |=
- WF_SLOT_USED;
-
- } else if (x == 3) { /* Bad patch number */
- dev.patch_status[i] = 0;
- } else {
- printk (KERN_ERR LOGNAME "upload patch "
- "error 0x%x\n", x);
- dev.patch_status[i] = 0;
- return 1;
- }
- }
-
- /* program status has already filled in slot_used bits */
-
- for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) {
- if (dev.patch_status[i] & WF_SLOT_FILLED) {
- cnt++;
- }
- if (dev.patch_status[i] & WF_SLOT_USED) {
- cnt2++;
- }
-
- }
- printk (KERN_INFO LOGNAME
- "%d patch slots filled, %d in use\n", cnt, cnt2);
-
- return (0);
-}
-
-static int
-wavefront_get_program_status (void)
-
-{
- unsigned char progbuf[WF_PROGRAM_BYTES];
- wavefront_program prog;
- unsigned char prognum;
- int i, x, l, cnt;
-
- for (i = 0; i < WF_MAX_PROGRAM; i++) {
- prognum = i;
-
- if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf,
- &prognum)) == 0) {
-
- dev.prog_status[i] |= WF_SLOT_USED;
-
- demunge_buf (progbuf, (unsigned char *) &prog,
- WF_PROGRAM_BYTES);
-
- for (l = 0; l < WF_NUM_LAYERS; l++) {
- if (prog.layer[l].mute) {
- dev.patch_status
- [prog.layer[l].patch_number] |=
- WF_SLOT_USED;
- }
- }
- } else if (x == 1) { /* Bad program number */
- dev.prog_status[i] = 0;
- } else {
- printk (KERN_ERR LOGNAME "upload program "
- "error 0x%x\n", x);
- dev.prog_status[i] = 0;
- }
- }
-
- for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) {
- if (dev.prog_status[i]) {
- cnt++;
- }
- }
-
- printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt);
-
- return (0);
-}
-
-static int
-wavefront_send_patch (wavefront_patch_info *header)
-
-{
- unsigned char buf[WF_PATCH_BYTES+2];
- unsigned char *bptr;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n",
- header->number);
-
- dev.patch_status[header->number] |= WF_SLOT_FILLED;
-
- bptr = buf;
- bptr = munge_int32 (header->number, buf, 2);
- munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES);
-
- if (wavefront_cmd (WFC_DOWNLOAD_PATCH, NULL, buf)) {
- printk (KERN_ERR LOGNAME "download patch failed\n");
- return -(EIO);
- }
-
- return (0);
-}
-
-static int
-wavefront_send_program (wavefront_patch_info *header)
-
-{
- unsigned char buf[WF_PROGRAM_BYTES+1];
- int i;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n",
- header->number);
-
- dev.prog_status[header->number] = WF_SLOT_USED;
-
- /* XXX need to zero existing SLOT_USED bit for program_status[i]
- where `i' is the program that's being (potentially) overwritten.
- */
-
- for (i = 0; i < WF_NUM_LAYERS; i++) {
- if (header->hdr.pr.layer[i].mute) {
- dev.patch_status[header->hdr.pr.layer[i].patch_number] |=
- WF_SLOT_USED;
-
- /* XXX need to mark SLOT_USED for sample used by
- patch_number, but this means we have to load it. Ick.
- */
- }
- }
-
- buf[0] = header->number;
- munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES);
-
- if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, NULL, buf)) {
- printk (KERN_WARNING LOGNAME "download patch failed\n");
- return -(EIO);
- }
-
- return (0);
-}
-
-static int
-wavefront_freemem (void)
-
-{
- char rbuf[8];
-
- if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, NULL)) {
- printk (KERN_WARNING LOGNAME "can't get memory stats.\n");
- return -1;
- } else {
- return demunge_int32 (rbuf, 4);
- }
-}
-
-static int
-wavefront_send_sample (wavefront_patch_info *header,
- UINT16 __user *dataptr,
- int data_is_unsigned)
-
-{
- /* samples are downloaded via a 16-bit wide i/o port
- (you could think of it as 2 adjacent 8-bit wide ports
- but its less efficient that way). therefore, all
- the blocksizes and so forth listed in the documentation,
- and used conventionally to refer to sample sizes,
- which are given in 8-bit units (bytes), need to be
- divided by 2.
- */
-
- UINT16 sample_short;
- UINT32 length;
- UINT16 __user *data_end = NULL;
- unsigned int i;
- const int max_blksize = 4096/2;
- unsigned int written;
- unsigned int blocksize;
- int dma_ack;
- int blocknum;
- unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES];
- unsigned char *shptr;
- int skip = 0;
- int initial_skip = 0;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, "
- "type %d, %d bytes from %p\n",
- header->size ? "" : "header ",
- header->number, header->subkey,
- header->size,
- header->dataptr);
-
- if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) {
- int x;
-
- if ((x = wavefront_find_free_sample ()) < 0) {
- return -ENOMEM;
- }
- printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x);
- header->number = x;
- }
-
- if (header->size) {
-
- /* XXX it's a debatable point whether or not RDONLY semantics
- on the ROM samples should cover just the sample data or
- the sample header. For now, it only covers the sample data,
- so anyone is free at all times to rewrite sample headers.
-
- My reason for this is that we have the sample headers
- available in the WFB file for General MIDI, and so these
- can always be reset if needed. The sample data, however,
- cannot be recovered without a complete reset and firmware
- reload of the ICS2115, which is a very expensive operation.
-
- So, doing things this way allows us to honor the notion of
- "RESETSAMPLES" reasonably cheaply. Note however, that this
- is done purely at user level: there is no WFB parser in
- this driver, and so a complete reset (back to General MIDI,
- or theoretically some other configuration) is the
- responsibility of the user level library.
-
- To try to do this in the kernel would be a little
- crazy: we'd need 158K of kernel space just to hold
- a copy of the patch/program/sample header data.
- */
-
- if (dev.rom_samples_rdonly) {
- if (dev.sample_status[header->number] & WF_SLOT_ROM) {
- printk (KERN_ERR LOGNAME "sample slot %d "
- "write protected\n",
- header->number);
- return -EACCES;
- }
- }
-
- wavefront_delete_sample (header->number);
- }
-
- if (header->size) {
- dev.freemem = wavefront_freemem ();
-
- if (dev.freemem < header->size) {
- printk (KERN_ERR LOGNAME
- "insufficient memory to "
- "load %d byte sample.\n",
- header->size);
- return -ENOMEM;
- }
-
- }
-
- skip = WF_GET_CHANNEL(&header->hdr.s);
-
- if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
- printk (KERN_ERR LOGNAME "channel selection only "
- "possible on 16-bit samples");
- return -(EINVAL);
- }
-
- switch (skip) {
- case 0:
- initial_skip = 0;
- skip = 1;
- break;
- case 1:
- initial_skip = 0;
- skip = 2;
- break;
- case 2:
- initial_skip = 1;
- skip = 2;
- break;
- case 3:
- initial_skip = 2;
- skip = 3;
- break;
- case 4:
- initial_skip = 3;
- skip = 4;
- break;
- case 5:
- initial_skip = 4;
- skip = 5;
- break;
- case 6:
- initial_skip = 5;
- skip = 6;
- break;
- }
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => "
- "initial skip = %d, skip = %d\n",
- WF_GET_CHANNEL (&header->hdr.s),
- initial_skip, skip);
-
- /* Be safe, and zero the "Unused" bits ... */
-
- WF_SET_CHANNEL(&header->hdr.s, 0);
-
- /* adjust size for 16 bit samples by dividing by two. We always
- send 16 bits per write, even for 8 bit samples, so the length
- is always half the size of the sample data in bytes.
- */
-
- length = header->size / 2;
-
- /* the data we're sent has not been munged, and in fact, the
- header we have to send isn't just a munged copy either.
- so, build the sample header right here.
- */
-
- shptr = &sample_hdr[0];
-
- shptr = munge_int32 (header->number, shptr, 2);
-
- if (header->size) {
- shptr = munge_int32 (length, shptr, 4);
- }
-
- /* Yes, a 4 byte result doesn't contain all of the offset bits,
- but the offset only uses 24 bits.
- */
-
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset),
- shptr, 4);
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset),
- shptr, 4);
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset),
- shptr, 4);
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset),
- shptr, 4);
-
- /* This one is truly weird. What kind of weirdo decided that in
- a system dominated by 16 and 32 bit integers, they would use
- a just 12 bits ?
- */
-
- shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3);
-
- /* Why is this nybblified, when the MSB is *always* zero ?
- Anyway, we can't take address of bitfield, so make a
- good-faith guess at where it starts.
- */
-
- shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1),
- shptr, 2);
-
- if (wavefront_cmd (header->size ?
- WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER,
- NULL, sample_hdr)) {
- printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n",
- header->size ? "" : "header ");
- return -(EIO);
- }
-
- if (header->size == 0) {
- goto sent; /* Sorry. Just had to have one somewhere */
- }
-
- data_end = dataptr + length;
-
- /* Do any initial skip over an unused channel's data */
-
- dataptr += initial_skip;
-
- for (written = 0, blocknum = 0;
- written < length; written += max_blksize, blocknum++) {
-
- if ((length - written) > max_blksize) {
- blocksize = max_blksize;
- } else {
- /* round to nearest 16-byte value */
- blocksize = ((length-written+7)&~0x7);
- }
-
- if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
- printk (KERN_WARNING LOGNAME "download block "
- "request refused.\n");
- return -(EIO);
- }
-
- for (i = 0; i < blocksize; i++) {
-
- if (dataptr < data_end) {
-
- __get_user (sample_short, dataptr);
- dataptr += skip;
-
- if (data_is_unsigned) { /* GUS ? */
-
- if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) {
-
- /* 8 bit sample
- resolution, sign
- extend both bytes.
- */
-
- ((unsigned char*)
- &sample_short)[0] += 0x7f;
- ((unsigned char*)
- &sample_short)[1] += 0x7f;
-
- } else {
-
- /* 16 bit sample
- resolution, sign
- extend the MSB.
- */
-
- sample_short += 0x7fff;
- }
- }
-
- } else {
-
- /* In padding section of final block:
-
- Don't fetch unsupplied data from
- user space, just continue with
- whatever the final value was.
- */
- }
-
- if (i < blocksize - 1) {
- outw (sample_short, dev.block_port);
- } else {
- outw (sample_short, dev.last_block_port);
- }
- }
-
- /* Get "DMA page acknowledge", even though its really
- nothing to do with DMA at all.
- */
-
- if ((dma_ack = wavefront_read ()) != WF_DMA_ACK) {
- if (dma_ack == -1) {
- printk (KERN_ERR LOGNAME "upload sample "
- "DMA ack timeout\n");
- return -(EIO);
- } else {
- printk (KERN_ERR LOGNAME "upload sample "
- "DMA ack error 0x%x\n",
- dma_ack);
- return -(EIO);
- }
- }
- }
-
- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE);
-
- /* Note, label is here because sending the sample header shouldn't
- alter the sample_status info at all.
- */
-
- sent:
- return (0);
-}
-
-static int
-wavefront_send_alias (wavefront_patch_info *header)
-
-{
- unsigned char alias_hdr[WF_ALIAS_BYTES];
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is "
- "alias for %d\n",
- header->number,
- header->hdr.a.OriginalSample);
-
- munge_int32 (header->number, &alias_hdr[0], 2);
- munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2);
- munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset),
- &alias_hdr[4], 4);
- munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset),
- &alias_hdr[8], 4);
- munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset),
- &alias_hdr[12], 4);
- munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset),
- &alias_hdr[16], 4);
- munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3);
- munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2);
-
- if (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) {
- printk (KERN_ERR LOGNAME "download alias failed.\n");
- return -(EIO);
- }
-
- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
-
- return (0);
-}
-
-static int
-wavefront_send_multisample (wavefront_patch_info *header)
-{
- int i;
- int num_samples;
- unsigned char msample_hdr[WF_MSAMPLE_BYTES];
-
- munge_int32 (header->number, &msample_hdr[0], 2);
-
- /* You'll recall at this point that the "number of samples" value
- in a wavefront_multisample struct is actually the log2 of the
- real number of samples.
- */
-
- num_samples = (1<<(header->hdr.ms.NumberOfSamples&7));
- msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n",
- header->number,
- header->hdr.ms.NumberOfSamples,
- num_samples);
-
- for (i = 0; i < num_samples; i++) {
- DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n",
- i, header->hdr.ms.SampleNumber[i]);
- munge_int32 (header->hdr.ms.SampleNumber[i],
- &msample_hdr[3+(i*2)], 2);
- }
-
- /* Need a hack here to pass in the number of bytes
- to be written to the synth. This is ugly, and perhaps
- one day, I'll fix it.
- */
-
- if (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE,
- (unsigned char *) ((num_samples*2)+3),
- msample_hdr)) {
- printk (KERN_ERR LOGNAME "download of multisample failed.\n");
- return -(EIO);
- }
-
- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
-
- return (0);
-}
-
-static int
-wavefront_fetch_multisample (wavefront_patch_info *header)
-{
- int i;
- unsigned char log_ns[1];
- unsigned char number[2];
- int num_samples;
-
- munge_int32 (header->number, number, 2);
-
- if (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
- printk (KERN_ERR LOGNAME "upload multisample failed.\n");
- return -(EIO);
- }
-
- DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n",
- header->number, log_ns[0]);
-
- header->hdr.ms.NumberOfSamples = log_ns[0];
-
- /* get the number of samples ... */
-
- num_samples = (1 << log_ns[0]);
-
- for (i = 0; i < num_samples; i++) {
- s8 d[2];
-
- if ((d[0] = wavefront_read ()) == -1) {
- printk (KERN_ERR LOGNAME "upload multisample failed "
- "during sample loop.\n");
- return -(EIO);
- }
-
- if ((d[1] = wavefront_read ()) == -1) {
- printk (KERN_ERR LOGNAME "upload multisample failed "
- "during sample loop.\n");
- return -(EIO);
- }
-
- header->hdr.ms.SampleNumber[i] =
- demunge_int32 ((unsigned char *) d, 2);
-
- DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n",
- i, header->hdr.ms.SampleNumber[i]);
- }
-
- return (0);
-}
-
-
-static int
-wavefront_send_drum (wavefront_patch_info *header)
-
-{
- unsigned char drumbuf[WF_DRUM_BYTES];
- wavefront_drum *drum = &header->hdr.d;
- int i;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI "
- "note %d, patch = %d\n",
- header->number, drum->PatchNumber);
-
- drumbuf[0] = header->number & 0x7f;
-
- for (i = 0; i < 4; i++) {
- munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2);
- }
-
- if (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) {
- printk (KERN_ERR LOGNAME "download drum failed.\n");
- return -(EIO);
- }
-
- return (0);
-}
-
-static int
-wavefront_find_free_sample (void)
-
-{
- int i;
-
- for (i = 0; i < WF_MAX_SAMPLE; i++) {
- if (!(dev.sample_status[i] & WF_SLOT_FILLED)) {
- return i;
- }
- }
- printk (KERN_WARNING LOGNAME "no free sample slots!\n");
- return -1;
-}
-
-static int
-wavefront_find_free_patch (void)
-
-{
- int i;
-
- for (i = 0; i < WF_MAX_PATCH; i++) {
- if (!(dev.patch_status[i] & WF_SLOT_FILLED)) {
- return i;
- }
- }
- printk (KERN_WARNING LOGNAME "no free patch slots!\n");
- return -1;
-}
-
-static int
-log2_2048(int n)
-
-{
- int tbl[]={0, 0, 2048, 3246, 4096, 4755, 5294, 5749, 6143,
- 6492, 6803, 7084, 7342, 7578, 7797, 8001, 8192,
- 8371, 8540, 8699, 8851, 8995, 9132, 9264, 9390,
- 9510, 9626, 9738, 9845, 9949, 10049, 10146};
- int i;
-
- /* Returns 2048*log2(n) */
-
- /* FIXME: this is like doing integer math
- on quantum particles (RuN) */
-
- i=0;
- while(n>=32*256) {
- n>>=8;
- i+=2048*8;
- }
- while(n>=32) {
- n>>=1;
- i+=2048;
- }
- i+=tbl[n];
- return(i);
-}
-
-static int
-wavefront_load_gus_patch (int devno, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
- struct patch_info guspatch;
- wavefront_patch_info *samp, *pat, *prog;
- wavefront_patch *patp;
- wavefront_sample *sampp;
- wavefront_program *progp;
-
- int i,base_note;
- long sizeof_patch;
- int rc = -ENOMEM;
-
- samp = kmalloc(3 * sizeof(wavefront_patch_info), GFP_KERNEL);
- if (!samp)
- goto free_fail;
- pat = samp + 1;
- prog = pat + 1;
-
- /* Copy in the header of the GUS patch */
-
- sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch;
- if (copy_from_user(&((char *) &guspatch)[offs],
- &(addr)[offs], sizeof_patch - offs)) {
- rc = -EFAULT;
- goto free_fail;
- }
-
- if ((i = wavefront_find_free_patch ()) == -1) {
- rc = -EBUSY;
- goto free_fail;
- }
- pat->number = i;
- pat->subkey = WF_ST_PATCH;
- patp = &pat->hdr.p;
-
- if ((i = wavefront_find_free_sample ()) == -1) {
- rc = -EBUSY;
- goto free_fail;
- }
- samp->number = i;
- samp->subkey = WF_ST_SAMPLE;
- samp->size = guspatch.len;
- sampp = &samp->hdr.s;
-
- prog->number = guspatch.instr_no;
- progp = &prog->hdr.pr;
-
- /* Setup the patch structure */
-
- patp->amplitude_bias=guspatch.volume;
- patp->portamento=0;
- patp->sample_number= samp->number & 0xff;
- patp->sample_msb= samp->number >> 8;
- patp->pitch_bend= /*12*/ 0;
- patp->mono=1;
- patp->retrigger=1;
- patp->nohold=(guspatch.mode & WAVE_SUSTAIN_ON) ? 0:1;
- patp->frequency_bias=0;
- patp->restart=0;
- patp->reuse=0;
- patp->reset_lfo=1;
- patp->fm_src2=0;
- patp->fm_src1=WF_MOD_MOD_WHEEL;
- patp->am_src=WF_MOD_PRESSURE;
- patp->am_amount=127;
- patp->fc1_mod_amount=0;
- patp->fc2_mod_amount=0;
- patp->fm_amount1=0;
- patp->fm_amount2=0;
- patp->envelope1.attack_level=127;
- patp->envelope1.decay1_level=127;
- patp->envelope1.decay2_level=127;
- patp->envelope1.sustain_level=127;
- patp->envelope1.release_level=0;
- patp->envelope2.attack_velocity=127;
- patp->envelope2.attack_level=127;
- patp->envelope2.decay1_level=127;
- patp->envelope2.decay2_level=127;
- patp->envelope2.sustain_level=127;
- patp->envelope2.release_level=0;
- patp->envelope2.attack_velocity=127;
- patp->randomizer=0;
-
- /* Program for this patch */
-
- progp->layer[0].patch_number= pat->number; /* XXX is this right ? */
- progp->layer[0].mute=1;
- progp->layer[0].pan_or_mod=1;
- progp->layer[0].pan=7;
- progp->layer[0].mix_level=127 /* guspatch.volume */;
- progp->layer[0].split_type=0;
- progp->layer[0].split_point=0;
- progp->layer[0].play_below=0;
-
- for (i = 1; i < 4; i++) {
- progp->layer[i].mute=0;
- }
-
- /* Sample data */
-
- sampp->SampleResolution=((~guspatch.mode & WAVE_16_BITS)<<1);
-
- for (base_note=0;
- note_to_freq (base_note) < guspatch.base_note;
- base_note++);
-
- if ((guspatch.base_note-note_to_freq(base_note))
- >(note_to_freq(base_note)-guspatch.base_note))
- base_note++;
-
- printk(KERN_DEBUG "ref freq=%d,base note=%d\n",
- guspatch.base_freq,
- base_note);
-
- sampp->FrequencyBias = (29550 - log2_2048(guspatch.base_freq)
- + base_note*171);
- printk(KERN_DEBUG "Freq Bias is %d\n", sampp->FrequencyBias);
- sampp->Loop=(guspatch.mode & WAVE_LOOPING) ? 1:0;
- sampp->sampleStartOffset.Fraction=0;
- sampp->sampleStartOffset.Integer=0;
- sampp->loopStartOffset.Fraction=0;
- sampp->loopStartOffset.Integer=guspatch.loop_start
- >>((guspatch.mode&WAVE_16_BITS) ? 1:0);
- sampp->loopEndOffset.Fraction=0;
- sampp->loopEndOffset.Integer=guspatch.loop_end
- >>((guspatch.mode&WAVE_16_BITS) ? 1:0);
- sampp->sampleEndOffset.Fraction=0;
- sampp->sampleEndOffset.Integer=guspatch.len >> (guspatch.mode&1);
- sampp->Bidirectional=(guspatch.mode&WAVE_BIDIR_LOOP) ? 1:0;
- sampp->Reverse=(guspatch.mode&WAVE_LOOP_BACK) ? 1:0;
-
- /* Now ship it down */
-
- wavefront_send_sample (samp,
- (unsigned short __user *) &(addr)[sizeof_patch],
- (guspatch.mode & WAVE_UNSIGNED) ? 1:0);
- wavefront_send_patch (pat);
- wavefront_send_program (prog);
-
- /* Now pan as best we can ... use the slave/internal MIDI device
- number if it exists (since it talks to the WaveFront), or the
- master otherwise.
- */
-
- if (dev.mididev > 0) {
- midi_synth_controller (dev.mididev, guspatch.instr_no, 10,
- ((guspatch.panning << 4) > 127) ?
- 127 : (guspatch.panning << 4));
- }
- rc = 0;
-
-free_fail:
- kfree(samp);
- return rc;
-}
-
-static int
-wavefront_load_patch (const char __user *addr)
-
-
-{
- wavefront_patch_info header;
-
- if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) -
- sizeof(wavefront_any))) {
- printk (KERN_WARNING LOGNAME "bad address for load patch.\n");
- return -EFAULT;
- }
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "download "
- "Sample type: %d "
- "Sample number: %d "
- "Sample size: %d\n",
- header.subkey,
- header.number,
- header.size);
-
- switch (header.subkey) {
- case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */
-
- if (copy_from_user((unsigned char *) &header.hdr.s,
- (unsigned char __user *) header.hdrptr,
- sizeof (wavefront_sample)))
- return -EFAULT;
-
- return wavefront_send_sample (&header, header.dataptr, 0);
-
- case WF_ST_MULTISAMPLE:
-
- if (copy_from_user(&header.hdr.s, header.hdrptr,
- sizeof(wavefront_multisample)))
- return -EFAULT;
-
- return wavefront_send_multisample (&header);
-
-
- case WF_ST_ALIAS:
-
- if (copy_from_user(&header.hdr.a, header.hdrptr,
- sizeof (wavefront_alias)))
- return -EFAULT;
-
- return wavefront_send_alias (&header);
-
- case WF_ST_DRUM:
- if (copy_from_user(&header.hdr.d, header.hdrptr,
- sizeof (wavefront_drum)))
- return -EFAULT;
-
- return wavefront_send_drum (&header);
-
- case WF_ST_PATCH:
- if (copy_from_user(&header.hdr.p, header.hdrptr,
- sizeof (wavefront_patch)))
- return -EFAULT;
-
- return wavefront_send_patch (&header);
-
- case WF_ST_PROGRAM:
- if (copy_from_user(&header.hdr.pr, header.hdrptr,
- sizeof (wavefront_program)))
- return -EFAULT;
-
- return wavefront_send_program (&header);
-
- default:
- printk (KERN_ERR LOGNAME "unknown patch type %d.\n",
- header.subkey);
- return -(EINVAL);
- }
-
- return 0;
-}
-
-/***********************************************************************
-WaveFront: /dev/sequencer{,2} and other hardware-dependent interfaces
-***********************************************************************/
-
-static void
-process_sample_hdr (UCHAR8 *buf)
-
-{
- wavefront_sample s;
- UCHAR8 *ptr;
-
- ptr = buf;
-
- /* The board doesn't send us an exact copy of a "wavefront_sample"
- in response to an Upload Sample Header command. Instead, we
- have to convert the data format back into our data structure,
- just as in the Download Sample command, where we have to do
- something very similar in the reverse direction.
- */
-
- *((UINT32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3;
-
- s.SampleResolution = *ptr & 0x3;
- s.Loop = *ptr & 0x8;
- s.Bidirectional = *ptr & 0x10;
- s.Reverse = *ptr & 0x40;
-
- /* Now copy it back to where it came from */
-
- memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample));
-}
-
-static int
-wavefront_synth_control (int cmd, wavefront_control *wc)
-
-{
- unsigned char patchnumbuf[2];
- int i;
-
- DPRINT (WF_DEBUG_CMD, "synth control with "
- "cmd 0x%x\n", wc->cmd);
-
- /* Pre-handling of or for various commands */
-
- switch (wc->cmd) {
- case WFC_DISABLE_INTERRUPTS:
- printk (KERN_INFO LOGNAME "interrupts disabled.\n");
- outb (0x80|0x20, dev.control_port);
- dev.interrupts_on = 0;
- return 0;
-
- case WFC_ENABLE_INTERRUPTS:
- printk (KERN_INFO LOGNAME "interrupts enabled.\n");
- outb (0x80|0x40|0x20, dev.control_port);
- dev.interrupts_on = 1;
- return 0;
-
- case WFC_INTERRUPT_STATUS:
- wc->rbuf[0] = dev.interrupts_on;
- return 0;
-
- case WFC_ROMSAMPLES_RDONLY:
- dev.rom_samples_rdonly = wc->wbuf[0];
- wc->status = 0;
- return 0;
-
- case WFC_IDENTIFY_SLOT_TYPE:
- i = wc->wbuf[0] | (wc->wbuf[1] << 7);
- if (i <0 || i >= WF_MAX_SAMPLE) {
- printk (KERN_WARNING LOGNAME "invalid slot ID %d\n",
- i);
- wc->status = EINVAL;
- return 0;
- }
- wc->rbuf[0] = dev.sample_status[i];
- wc->status = 0;
- return 0;
-
- case WFC_DEBUG_DRIVER:
- dev.debug = wc->wbuf[0];
- printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug);
- return 0;
-
- case WFC_FX_IOCTL:
- wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]);
- return 0;
-
- case WFC_UPLOAD_PATCH:
- munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2);
- memcpy (wc->wbuf, patchnumbuf, 2);
- break;
-
- case WFC_UPLOAD_MULTISAMPLE:
- /* multisamples have to be handled differently, and
- cannot be dealt with properly by wavefront_cmd() alone.
- */
- wc->status = wavefront_fetch_multisample
- ((wavefront_patch_info *) wc->rbuf);
- return 0;
-
- case WFC_UPLOAD_SAMPLE_ALIAS:
- printk (KERN_INFO LOGNAME "support for sample alias upload "
- "being considered.\n");
- wc->status = EINVAL;
- return -EINVAL;
- }
-
- wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf);
-
- /* Post-handling of certain commands.
-
- In particular, if the command was an upload, demunge the data
- so that the user-level doesn't have to think about it.
- */
-
- if (wc->status == 0) {
- switch (wc->cmd) {
- /* intercept any freemem requests so that we know
- we are always current with the user-level view
- of things.
- */
-
- case WFC_REPORT_FREE_MEMORY:
- dev.freemem = demunge_int32 (wc->rbuf, 4);
- break;
-
- case WFC_UPLOAD_PATCH:
- demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES);
- break;
-
- case WFC_UPLOAD_PROGRAM:
- demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES);
- break;
-
- case WFC_UPLOAD_EDRUM_PROGRAM:
- demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1);
- break;
-
- case WFC_UPLOAD_SAMPLE_HEADER:
- process_sample_hdr (wc->rbuf);
- break;
-
- case WFC_UPLOAD_SAMPLE_ALIAS:
- printk (KERN_INFO LOGNAME "support for "
- "sample aliases still "
- "being considered.\n");
- break;
-
- case WFC_VMIDI_OFF:
- if (virtual_midi_disable () < 0) {
- return -(EIO);
- }
- break;
-
- case WFC_VMIDI_ON:
- if (virtual_midi_enable () < 0) {
- return -(EIO);
- }
- break;
- }
- }
-
- return 0;
-}
-
-
-/***********************************************************************/
-/* WaveFront: Linux file system interface (for access via raw synth) */
-/***********************************************************************/
-
-static int
-wavefront_open (struct inode *inode, struct file *file)
-{
- /* XXX fix me */
- dev.opened = file->f_flags;
- return 0;
-}
-
-static int
-wavefront_release(struct inode *inode, struct file *file)
-{
- lock_kernel();
- dev.opened = 0;
- dev.debug = 0;
- unlock_kernel();
- return 0;
-}
-
-static int
-wavefront_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- wavefront_control wc;
- int err;
-
- switch (cmd) {
-
- case WFCTL_WFCMD:
- if (copy_from_user(&wc, (void __user *) arg, sizeof (wc)))
- return -EFAULT;
-
- if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
- if (copy_to_user ((void __user *) arg, &wc, sizeof (wc)))
- return -EFAULT;
- }
-
- return err;
-
- case WFCTL_LOAD_SPP:
- return wavefront_load_patch ((const char __user *) arg);
-
- default:
- printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd);
- return -(EINVAL);
-
- }
- return 0;
-}
-
-static /*const*/ struct file_operations wavefront_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = wavefront_ioctl,
- .open = wavefront_open,
- .release = wavefront_release,
-};
-
-
-/***********************************************************************/
-/* WaveFront: OSS installation and support interface */
-/***********************************************************************/
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-
-static struct synth_info wavefront_info =
-{"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT,
- 0, 32, 0, 0, SYNTH_CAP_INPUT};
-
-static int
-wavefront_oss_open (int devno, int mode)
-
-{
- dev.opened = mode;
- return 0;
-}
-
-static void
-wavefront_oss_close (int devno)
-
-{
- dev.opened = 0;
- dev.debug = 0;
- return;
-}
-
-static int
-wavefront_oss_ioctl (int devno, unsigned int cmd, void __user * arg)
-
-{
- wavefront_control wc;
- int err;
-
- switch (cmd) {
- case SNDCTL_SYNTH_INFO:
- if(copy_to_user(arg, &wavefront_info, sizeof (wavefront_info)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_SEQ_RESETSAMPLES:
-// printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
- return 0; /* don't force an error */
-
- case SNDCTL_SEQ_PERCMODE:
- return 0; /* don't force an error */
-
- case SNDCTL_SYNTH_MEMAVL:
- if ((dev.freemem = wavefront_freemem ()) < 0) {
- printk (KERN_ERR LOGNAME "cannot get memory size\n");
- return -EIO;
- } else {
- return dev.freemem;
- }
- break;
-
- case SNDCTL_SYNTH_CONTROL:
- if(copy_from_user (&wc, arg, sizeof (wc)))
- err = -EFAULT;
- else if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
- if(copy_to_user (arg, &wc, sizeof (wc)))
- err = -EFAULT;
- }
-
- return err;
-
- default:
- return -(EINVAL);
- }
-}
-
-static int
-wavefront_oss_load_patch (int devno, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
-
- if (format == SYSEX_PATCH) { /* Handled by midi_synth.c */
- if (midi_load_patch == NULL) {
- printk (KERN_ERR LOGNAME
- "SYSEX not loadable: "
- "no midi patch loader!\n");
- return -(EINVAL);
- }
-
- return midi_load_patch (devno, format, addr,
- offs, count, pmgr_flag);
-
- } else if (format == GUS_PATCH) {
- return wavefront_load_gus_patch (devno, format,
- addr, offs, count, pmgr_flag);
-
- } else if (format != WAVEFRONT_PATCH) {
- printk (KERN_ERR LOGNAME "unknown patch format %d\n", format);
- return -(EINVAL);
- }
-
- if (count < sizeof (wavefront_patch_info)) {
- printk (KERN_ERR LOGNAME "sample header too short\n");
- return -(EINVAL);
- }
-
- /* "addr" points to a user-space wavefront_patch_info */
-
- return wavefront_load_patch (addr);
-}
-
-static struct synth_operations wavefront_operations =
-{
- .owner = THIS_MODULE,
- .id = "WaveFront",
- .info = &wavefront_info,
- .midi_dev = 0,
- .synth_type = SYNTH_TYPE_SAMPLE,
- .synth_subtype = SAMPLE_TYPE_WAVEFRONT,
- .open = wavefront_oss_open,
- .close = wavefront_oss_close,
- .ioctl = wavefront_oss_ioctl,
- .kill_note = midi_synth_kill_note,
- .start_note = midi_synth_start_note,
- .set_instr = midi_synth_set_instr,
- .reset = midi_synth_reset,
- .load_patch = midi_synth_load_patch,
- .aftertouch = midi_synth_aftertouch,
- .controller = midi_synth_controller,
- .panning = midi_synth_panning,
- .bender = midi_synth_bender,
- .setup_voice = midi_synth_setup_voice
-};
-#endif /* OSS_SUPPORT_SEQ */
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL
-
-static void __init attach_wavefront (struct address_info *hw_config)
-{
- (void) install_wavefront ();
-}
-
-static int __init probe_wavefront (struct address_info *hw_config)
-{
- return !detect_wavefront (hw_config->irq, hw_config->io_base);
-}
-
-static void __exit unload_wavefront (struct address_info *hw_config)
-{
- (void) uninstall_wavefront ();
-}
-
-#endif /* OSS_SUPPORT_STATIC_INSTALL */
-
-/***********************************************************************/
-/* WaveFront: Linux modular sound kernel installation interface */
-/***********************************************************************/
-
-static irqreturn_t
-wavefrontintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
- struct wf_config *hw = dev_id;
-
- /*
- Some comments on interrupts. I attempted a version of this
- driver that used interrupts throughout the code instead of
- doing busy and/or sleep-waiting. Alas, it appears that once
- the Motorola firmware is downloaded, the card *never*
- generates an RX interrupt. These are successfully generated
- during firmware loading, and after that wavefront_status()
- reports that an interrupt is pending on the card from time
- to time, but it never seems to be delivered to this
- driver. Note also that wavefront_status() continues to
- report that RX interrupts are enabled, suggesting that I
- didn't goof up and disable them by mistake.
-
- Thus, I stepped back to a prior version of
- wavefront_wait(), the only place where this really
- matters. Its sad, but I've looked through the code to check
- on things, and I really feel certain that the Motorola
- firmware prevents RX-ready interrupts.
- */
-
- if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) {
- return IRQ_NONE;
- }
-
- hw->irq_ok = 1;
- hw->irq_cnt++;
- wake_up_interruptible (&hw->interrupt_sleeper);
- return IRQ_HANDLED;
-}
-
-/* STATUS REGISTER
-
-0 Host Rx Interrupt Enable (1=Enabled)
-1 Host Rx Register Full (1=Full)
-2 Host Rx Interrupt Pending (1=Interrupt)
-3 Unused
-4 Host Tx Interrupt (1=Enabled)
-5 Host Tx Register empty (1=Empty)
-6 Host Tx Interrupt Pending (1=Interrupt)
-7 Unused
-*/
-
-static int
-wavefront_interrupt_bits (int irq)
-
-{
- int bits;
-
- switch (irq) {
- case 9:
- bits = 0x00;
- break;
- case 5:
- bits = 0x08;
- break;
- case 12:
- bits = 0x10;
- break;
- case 15:
- bits = 0x18;
- break;
-
- default:
- printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq);
- bits = -1;
- }
-
- return bits;
-}
-
-static void
-wavefront_should_cause_interrupt (int val, int port, int timeout)
-
-{
- unsigned long flags;
-
- /* this will not help on SMP - but at least it compiles */
- spin_lock_irqsave(&lock, flags);
- dev.irq_ok = 0;
- outb (val,port);
- interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout);
- spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init wavefront_hw_reset (void)
-{
- int bits;
- int hwv[2];
- unsigned long irq_mask;
- short reported_irq;
-
- /* IRQ already checked in init_module() */
-
- bits = wavefront_interrupt_bits (dev.irq);
-
- printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n");
-
- irq_mask = probe_irq_on ();
-
- outb (0x0, dev.control_port);
- outb (0x80 | 0x40 | bits, dev.data_port);
- wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
- dev.control_port,
- (reset_time*HZ)/100);
-
- reported_irq = probe_irq_off (irq_mask);
-
- if (reported_irq != dev.irq) {
- if (reported_irq == 0) {
- printk (KERN_ERR LOGNAME
- "No unassigned interrupts detected "
- "after h/w reset\n");
- } else if (reported_irq < 0) {
- printk (KERN_ERR LOGNAME
- "Multiple unassigned interrupts detected "
- "after h/w reset\n");
- } else {
- printk (KERN_ERR LOGNAME "autodetected IRQ %d not the "
- "value provided (%d)\n", reported_irq,
- dev.irq);
- }
- dev.irq = -1;
- return 1;
- } else {
- printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n",
- reported_irq);
- }
-
- if (request_irq (dev.irq, wavefrontintr,
- IRQF_DISABLED|IRQF_SHARED,
- "wavefront synth", &dev) < 0) {
- printk (KERN_WARNING LOGNAME "IRQ %d not available!\n",
- dev.irq);
- return 1;
- }
-
- /* try reset of port */
-
- outb (0x0, dev.control_port);
-
- /* At this point, the board is in reset, and the H/W initialization
- register is accessed at the same address as the data port.
-
- Bit 7 - Enable IRQ Driver
- 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs
- 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus.
-
- Bit 6 - MIDI Interface Select
-
- 0 - Use the MIDI Input from the 26-pin WaveBlaster
- compatible header as the serial MIDI source
- 1 - Use the MIDI Input from the 9-pin D connector as the
- serial MIDI source.
-
- Bits 5:3 - IRQ Selection
- 0 0 0 - IRQ 2/9
- 0 0 1 - IRQ 5
- 0 1 0 - IRQ 12
- 0 1 1 - IRQ 15
- 1 0 0 - Reserved
- 1 0 1 - Reserved
- 1 1 0 - Reserved
- 1 1 1 - Reserved
-
- Bits 2:1 - Reserved
- Bit 0 - Disable Boot ROM
- 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM
- 1 - memory accesses to 03FC30-03FFFFH are directed to external
- storage.
-
- */
-
- /* configure hardware: IRQ, enable interrupts,
- plus external 9-pin MIDI interface selected
- */
-
- outb (0x80 | 0x40 | bits, dev.data_port);
-
- /* CONTROL REGISTER
-
- 0 Host Rx Interrupt Enable (1=Enabled) 0x1
- 1 Unused 0x2
- 2 Unused 0x4
- 3 Unused 0x8
- 4 Host Tx Interrupt Enable 0x10
- 5 Mute (0=Mute; 1=Play) 0x20
- 6 Master Interrupt Enable (1=Enabled) 0x40
- 7 Master Reset (0=Reset; 1=Run) 0x80
-
- Take us out of reset, mute output, master + TX + RX interrupts on.
-
- We'll get an interrupt presumably to tell us that the TX
- register is clear.
- */
-
- wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
- dev.control_port,
- (reset_time*HZ)/100);
-
- /* Note: data port is now the data port, not the h/w initialization
- port.
- */
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "intr not received after h/w un-reset.\n");
- goto gone_bad;
- }
-
- dev.interrupts_on = 1;
-
- /* Note: data port is now the data port, not the h/w initialization
- port.
-
- At this point, only "HW VERSION" or "DOWNLOAD OS" commands
- will work. So, issue one of them, and wait for TX
- interrupt. This can take a *long* time after a cold boot,
- while the ISC ROM does its RAM test. The SDK says up to 4
- seconds - with 12MB of RAM on a Tropez+, it takes a lot
- longer than that (~16secs). Note that the card understands
- the difference between a warm and a cold boot, so
- subsequent ISC2115 reboots (say, caused by module
- reloading) will get through this much faster.
-
- XXX Interesting question: why is no RX interrupt received first ?
- */
-
- wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION,
- dev.data_port, ramcheck_time*HZ);
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "post-RAM-check interrupt not received.\n");
- goto gone_bad;
- }
-
- if (!wavefront_wait (STAT_CAN_READ)) {
- printk (KERN_WARNING LOGNAME
- "no response to HW version cmd.\n");
- goto gone_bad;
- }
-
- if ((hwv[0] = wavefront_read ()) == -1) {
- printk (KERN_WARNING LOGNAME
- "board not responding correctly.\n");
- goto gone_bad;
- }
-
- if (hwv[0] == 0xFF) { /* NAK */
-
- /* Board's RAM test failed. Try to read error code,
- and tell us about it either way.
- */
-
- if ((hwv[0] = wavefront_read ()) == -1) {
- printk (KERN_WARNING LOGNAME "on-board RAM test failed "
- "(bad error code).\n");
- } else {
- printk (KERN_WARNING LOGNAME "on-board RAM test failed "
- "(error code: 0x%x).\n",
- hwv[0]);
- }
- goto gone_bad;
- }
-
- /* We're OK, just get the next byte of the HW version response */
-
- if ((hwv[1] = wavefront_read ()) == -1) {
- printk (KERN_WARNING LOGNAME "incorrect h/w response.\n");
- goto gone_bad;
- }
-
- printk (KERN_INFO LOGNAME "hardware version %d.%d\n",
- hwv[0], hwv[1]);
-
- return 0;
-
-
- gone_bad:
- if (dev.irq >= 0) {
- free_irq (dev.irq, &dev);
- dev.irq = -1;
- }
- return (1);
-}
-
-static int __init detect_wavefront (int irq, int io_base)
-{
- unsigned char rbuf[4], wbuf[4];
-
- /* TB docs say the device takes up 8 ports, but we know that
- if there is an FX device present (i.e. a Tropez+) it really
- consumes 16.
- */
-
- if (!request_region (io_base, 16, "wavfront")) {
- printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x "
- "already in use - ignored\n", dev.base,
- dev.base+15);
- return -1;
- }
-
- dev.irq = irq;
- dev.base = io_base;
- dev.israw = 0;
- dev.debug = debug_default;
- dev.interrupts_on = 0;
- dev.irq_cnt = 0;
- dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */
-
- if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) {
-
- dev.fw_version[0] = rbuf[0];
- dev.fw_version[1] = rbuf[1];
- printk (KERN_INFO LOGNAME
- "firmware %d.%d already loaded.\n",
- rbuf[0], rbuf[1]);
-
- /* check that a command actually works */
-
- if (wavefront_cmd (WFC_HARDWARE_VERSION,
- rbuf, wbuf) == 0) {
- dev.hw_version[0] = rbuf[0];
- dev.hw_version[1] = rbuf[1];
- } else {
- printk (KERN_WARNING LOGNAME "not raw, but no "
- "hardware version!\n");
- release_region (io_base, 16);
- return 0;
- }
-
- if (!wf_raw) {
- /* will re-acquire region in install_wavefront() */
- release_region (io_base, 16);
- return 1;
- } else {
- printk (KERN_INFO LOGNAME
- "reloading firmware anyway.\n");
- dev.israw = 1;
- }
-
- } else {
-
- dev.israw = 1;
- printk (KERN_INFO LOGNAME
- "no response to firmware probe, assume raw.\n");
-
- }
-
- init_waitqueue_head (&dev.interrupt_sleeper);
-
- if (wavefront_hw_reset ()) {
- printk (KERN_WARNING LOGNAME "hardware reset failed\n");
- release_region (io_base, 16);
- return 0;
- }
-
- /* Check for FX device, present only on Tropez+ */
-
- dev.has_fx = (detect_wffx () == 0);
-
- /* will re-acquire region in install_wavefront() */
- release_region (io_base, 16);
- return 1;
-}
-
-#include "os.h"
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-
-
-static int
-wavefront_download_firmware (char *path)
-
-{
- unsigned char section[WF_SECTION_MAX];
- char section_length; /* yes, just a char; max value is WF_SECTION_MAX */
- int section_cnt_downloaded = 0;
- int fd;
- int c;
- int i;
- mm_segment_t fs;
-
- /* This tries to be a bit cleverer than the stuff Alan Cox did for
- the generic sound firmware, in that it actually knows
- something about the structure of the Motorola firmware. In
- particular, it uses a version that has been stripped of the
- 20K of useless header information, and had section lengths
- added, making it possible to load the entire OS without any
- [kv]malloc() activity, since the longest entity we ever read is
- 42 bytes (well, WF_SECTION_MAX) long.
- */
-
- fs = get_fs();
- set_fs (get_ds());
-
- if ((fd = sys_open (path, 0, 0)) < 0) {
- printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n",
- path);
- return 1;
- }
-
- while (1) {
- int x;
-
- if ((x = sys_read (fd, §ion_length, sizeof (section_length))) !=
- sizeof (section_length)) {
- printk (KERN_ERR LOGNAME "firmware read error.\n");
- goto failure;
- }
-
- if (section_length == 0) {
- break;
- }
-
- if (sys_read (fd, section, section_length) != section_length) {
- printk (KERN_ERR LOGNAME "firmware section "
- "read error.\n");
- goto failure;
- }
-
- /* Send command */
-
- if (wavefront_write (WFC_DOWNLOAD_OS)) {
- goto failure;
- }
-
- for (i = 0; i < section_length; i++) {
- if (wavefront_write (section[i])) {
- goto failure;
- }
- }
-
- /* get ACK */
-
- if (wavefront_wait (STAT_CAN_READ)) {
-
- if ((c = inb (dev.data_port)) != WF_ACK) {
-
- printk (KERN_ERR LOGNAME "download "
- "of section #%d not "
- "acknowledged, ack = 0x%x\n",
- section_cnt_downloaded + 1, c);
- goto failure;
-
- }
-
- } else {
- printk (KERN_ERR LOGNAME "time out for firmware ACK.\n");
- goto failure;
- }
-
- }
-
- sys_close (fd);
- set_fs (fs);
- return 0;
-
- failure:
- sys_close (fd);
- set_fs (fs);
- printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n");
- return 1;
-}
-
-static int __init wavefront_config_midi (void)
-{
- unsigned char rbuf[4], wbuf[4];
-
- if (detect_wf_mpu (dev.irq, dev.base) < 0) {
- printk (KERN_WARNING LOGNAME
- "could not find working MIDI device\n");
- return -1;
- }
-
- if ((dev.mididev = install_wf_mpu ()) < 0) {
- printk (KERN_WARNING LOGNAME
- "MIDI interfaces not configured\n");
- return -1;
- }
-
- /* Route external MIDI to WaveFront synth (by default) */
-
- if (wavefront_cmd (WFC_MISYNTH_ON, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "cannot enable MIDI-IN to synth routing.\n");
- /* XXX error ? */
- }
-
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- /* Get the regular MIDI patch loading function, so we can
- use it if we ever get handed a SYSEX patch. This is
- unlikely, because its so damn slow, but we may as well
- leave this functionality from maui.c behind, since it
- could be useful for sequencer applications that can
- only use MIDI to do patch loading.
- */
-
- if (midi_devs[dev.mididev]->converter != NULL) {
- midi_load_patch = midi_devs[dev.mididev]->converter->load_patch;
- midi_devs[dev.mididev]->converter->load_patch =
- &wavefront_oss_load_patch;
- }
-
-#endif /* OSS_SUPPORT_SEQ */
-
- /* Turn on Virtual MIDI, but first *always* turn it off,
- since otherwise consectutive reloads of the driver will
- never cause the hardware to generate the initial "internal" or
- "external" source bytes in the MIDI data stream. This
- is pretty important, since the internal hardware generally will
- be used to generate none or very little MIDI output, and
- thus the only source of MIDI data is actually external. Without
- the switch bytes, the driver will think it all comes from
- the internal interface. Duh.
- */
-
- if (wavefront_cmd (WFC_VMIDI_OFF, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "virtual MIDI mode not disabled\n");
- return 0; /* We're OK, but missing the external MIDI dev */
- }
-
- if ((dev.ext_mididev = virtual_midi_enable ()) < 0) {
- printk (KERN_WARNING LOGNAME "no virtual MIDI access.\n");
- } else {
- if (wavefront_cmd (WFC_VMIDI_ON, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "cannot enable virtual MIDI mode.\n");
- virtual_midi_disable ();
- }
- }
-
- return 0;
-}
-
-static int __init wavefront_do_reset (int atboot)
-{
- char voices[1];
-
- if (!atboot && wavefront_hw_reset ()) {
- printk (KERN_WARNING LOGNAME "hw reset failed.\n");
- goto gone_bad;
- }
-
- if (dev.israw) {
- if (wavefront_download_firmware (ospath)) {
- goto gone_bad;
- }
-
- dev.israw = 0;
-
- /* Wait for the OS to get running. The protocol for
- this is non-obvious, and was determined by
- using port-IO tracing in DOSemu and some
- experimentation here.
-
- Rather than using timed waits, use interrupts creatively.
- */
-
- wavefront_should_cause_interrupt (WFC_NOOP,
- dev.data_port,
- (osrun_time*HZ));
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "no post-OS interrupt.\n");
- goto gone_bad;
- }
-
- /* Now, do it again ! */
-
- wavefront_should_cause_interrupt (WFC_NOOP,
- dev.data_port, (10*HZ));
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "no post-OS interrupt(2).\n");
- goto gone_bad;
- }
-
- /* OK, no (RX/TX) interrupts any more, but leave mute
- in effect.
- */
-
- outb (0x80|0x40, dev.control_port);
-
- /* No need for the IRQ anymore */
-
- free_irq (dev.irq, &dev);
-
- }
-
- if (dev.has_fx && fx_raw) {
- wffx_init ();
- }
-
- /* SETUPSND.EXE asks for sample memory config here, but since i
- have no idea how to interpret the result, we'll forget
- about it.
- */
-
- if ((dev.freemem = wavefront_freemem ()) < 0) {
- goto gone_bad;
- }
-
- printk (KERN_INFO LOGNAME "available DRAM %dk\n", dev.freemem / 1024);
-
- if (wavefront_write (0xf0) ||
- wavefront_write (1) ||
- (wavefront_read () < 0)) {
- dev.debug = 0;
- printk (KERN_WARNING LOGNAME "MPU emulation mode not set.\n");
- goto gone_bad;
- }
-
- voices[0] = 32;
-
- if (wavefront_cmd (WFC_SET_NVOICES, NULL, voices)) {
- printk (KERN_WARNING LOGNAME
- "cannot set number of voices to 32.\n");
- goto gone_bad;
- }
-
-
- return 0;
-
- gone_bad:
- /* reset that sucker so that it doesn't bother us. */
-
- outb (0x0, dev.control_port);
- dev.interrupts_on = 0;
- if (dev.irq >= 0) {
- free_irq (dev.irq, &dev);
- }
- return 1;
-}
-
-static int __init wavefront_init (int atboot)
-{
- int samples_are_from_rom;
-
- if (dev.israw) {
- samples_are_from_rom = 1;
- } else {
- /* XXX is this always true ? */
- samples_are_from_rom = 0;
- }
-
- if (dev.israw || fx_raw) {
- if (wavefront_do_reset (atboot)) {
- return -1;
- }
- }
-
- wavefront_get_sample_status (samples_are_from_rom);
- wavefront_get_program_status ();
- wavefront_get_patch_status ();
-
- /* Start normal operation: unreset, master interrupt enabled, no mute
- */
-
- outb (0x80|0x40|0x20, dev.control_port);
-
- return (0);
-}
-
-static int __init install_wavefront (void)
-{
- if (!request_region (dev.base+2, 6, "wavefront synth"))
- return -1;
-
- if (dev.has_fx) {
- if (!request_region (dev.base+8, 8, "wavefront fx")) {
- release_region (dev.base+2, 6);
- return -1;
- }
- }
-
- if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) {
- printk (KERN_ERR LOGNAME "cannot register raw synth\n");
- goto err_out;
- }
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- if ((dev.oss_dev = sound_alloc_synthdev()) == -1) {
- printk (KERN_ERR LOGNAME "Too many sequencers\n");
- /* FIXME: leak: should unregister sound synth */
- goto err_out;
- } else {
- synth_devs[dev.oss_dev] = &wavefront_operations;
- }
-#endif /* OSS_SUPPORT_SEQ */
-
- if (wavefront_init (1) < 0) {
- printk (KERN_WARNING LOGNAME "initialization failed.\n");
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- sound_unload_synthdev (dev.oss_dev);
-#endif /* OSS_SUPPORT_SEQ */
-
- goto err_out;
- }
-
- if (wavefront_config_midi ()) {
- printk (KERN_WARNING LOGNAME "could not initialize MIDI.\n");
- }
-
- return dev.oss_dev;
-
-err_out:
- release_region (dev.base+2, 6);
- if (dev.has_fx)
- release_region (dev.base+8, 8);
- return -1;
-}
-
-static void __exit uninstall_wavefront (void)
-{
- /* the first two i/o addresses are freed by the wf_mpu code */
- release_region (dev.base+2, 6);
-
- if (dev.has_fx) {
- release_region (dev.base+8, 8);
- }
-
- unregister_sound_synth (dev.synth_dev);
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- sound_unload_synthdev (dev.oss_dev);
-#endif /* OSS_SUPPORT_SEQ */
- uninstall_wf_mpu ();
-}
-
-/***********************************************************************/
-/* WaveFront FX control */
-/***********************************************************************/
-
-#include "yss225.h"
-
-/* Control bits for the Load Control Register
- */
-
-#define FX_LSB_TRANSFER 0x01 /* transfer after DSP LSB byte written */
-#define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */
-#define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */
-
-static int
-wffx_idle (void)
-
-{
- int i;
- unsigned int x = 0x80;
-
- for (i = 0; i < 1000; i++) {
- x = inb (dev.fx_status);
- if ((x & 0x80) == 0) {
- break;
- }
- }
-
- if (x & 0x80) {
- printk (KERN_ERR LOGNAME "FX device never idle.\n");
- return 0;
- }
-
- return (1);
-}
-
-int __init detect_wffx (void)
-{
- /* This is a crude check, but its the best one I have for now.
- Certainly on the Maui and the Tropez, wffx_idle() will
- report "never idle", which suggests that this test should
- work OK.
- */
-
- if (inb (dev.fx_status) & 0x80) {
- printk (KERN_INFO LOGNAME "Hmm, probably a Maui or Tropez.\n");
- return -1;
- }
-
- return 0;
-}
-
-static void
-wffx_mute (int onoff)
-
-{
- if (!wffx_idle()) {
- return;
- }
-
- outb (onoff ? 0x02 : 0x00, dev.fx_op);
-}
-
-static int
-wffx_memset (int page,
- int addr, int cnt, unsigned short *data)
-{
- if (page < 0 || page > 7) {
- printk (KERN_ERR LOGNAME "FX memset: "
- "page must be >= 0 and <= 7\n");
- return -(EINVAL);
- }
-
- if (addr < 0 || addr > 0x7f) {
- printk (KERN_ERR LOGNAME "FX memset: "
- "addr must be >= 0 and <= 7f\n");
- return -(EINVAL);
- }
-
- if (cnt == 1) {
-
- outb (FX_LSB_TRANSFER, dev.fx_lcr);
- outb (page, dev.fx_dsp_page);
- outb (addr, dev.fx_dsp_addr);
- outb ((data[0] >> 8), dev.fx_dsp_msb);
- outb ((data[0] & 0xff), dev.fx_dsp_lsb);
-
- printk (KERN_INFO LOGNAME "FX: addr %d:%x set to 0x%x\n",
- page, addr, data[0]);
-
- } else {
- int i;
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (page, dev.fx_dsp_page);
- outb (addr, dev.fx_dsp_addr);
-
- for (i = 0; i < cnt; i++) {
- outb ((data[i] >> 8), dev.fx_dsp_msb);
- outb ((data[i] & 0xff), dev.fx_dsp_lsb);
- if (!wffx_idle ()) {
- break;
- }
- }
-
- if (i != cnt) {
- printk (KERN_WARNING LOGNAME
- "FX memset "
- "(0x%x, 0x%x, %p, %d) incomplete\n",
- page, addr, data, cnt);
- return -(EIO);
- }
- }
-
- return 0;
-}
-
-static int
-wffx_ioctl (wavefront_fx_info *r)
-
-{
- unsigned short page_data[256];
- unsigned short *pd;
-
- switch (r->request) {
- case WFFX_MUTE:
- wffx_mute (r->data[0]);
- return 0;
-
- case WFFX_MEMSET:
-
- if (r->data[2] <= 0) {
- printk (KERN_ERR LOGNAME "cannot write "
- "<= 0 bytes to FX\n");
- return -(EINVAL);
- } else if (r->data[2] == 1) {
- pd = (unsigned short *) &r->data[3];
- } else {
- if (r->data[2] > sizeof (page_data)) {
- printk (KERN_ERR LOGNAME "cannot write "
- "> 255 bytes to FX\n");
- return -(EINVAL);
- }
- if (copy_from_user(page_data,
- (unsigned char __user *)r->data[3],
- r->data[2]))
- return -EFAULT;
- pd = page_data;
- }
-
- return wffx_memset (r->data[0], /* page */
- r->data[1], /* addr */
- r->data[2], /* cnt */
- pd);
-
- default:
- printk (KERN_WARNING LOGNAME
- "FX: ioctl %d not yet supported\n",
- r->request);
- return -(EINVAL);
- }
-}
-
-/* YSS225 initialization.
-
- This code was developed using DOSEMU. The Turtle Beach SETUPSND
- utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
- of the port I/O done, using the Yamaha faxback document as a guide
- to add more logic to the code. Its really pretty weird.
-
- There was an alternative approach of just dumping the whole I/O
- sequence as a series of port/value pairs and a simple loop
- that output it. However, I hope that eventually I'll get more
- control over what this code does, and so I tried to stick with
- a somewhat "algorithmic" approach.
-*/
-
-static int __init wffx_init (void)
-{
- int i;
- int j;
-
- /* Set all bits for all channels on the MOD unit to zero */
- /* XXX But why do this twice ? */
-
- for (j = 0; j < 2; j++) {
- for (i = 0x10; i <= 0xff; i++) {
-
- if (!wffx_idle ()) {
- return (-1);
- }
-
- outb (i, dev.fx_mod_addr);
- outb (0x0, dev.fx_mod_data);
- }
- }
-
- if (!wffx_idle()) return (-1);
- outb (0x02, dev.fx_op); /* mute on */
-
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x44, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x42, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x43, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x7c, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x7e, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x46, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x49, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x47, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x4a, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
-
- /* either because of stupidity by TB's programmers, or because it
- actually does something, rezero the MOD page.
- */
- for (i = 0x10; i <= 0xff; i++) {
-
- if (!wffx_idle ()) {
- return (-1);
- }
-
- outb (i, dev.fx_mod_addr);
- outb (0x0, dev.fx_mod_data);
- }
- /* load page zero */
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x00, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_zero); i += 2) {
- outb (page_zero[i], dev.fx_dsp_msb);
- outb (page_zero[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Now load page one */
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x01, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_one); i += 2) {
- outb (page_one[i], dev.fx_dsp_msb);
- outb (page_one[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x02, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_two); i++) {
- outb (page_two[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x03, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_three); i++) {
- outb (page_three[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x04, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_four); i++) {
- outb (page_four[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Load memory area (page six) */
-
- outb (FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x06, dev.fx_dsp_page);
-
- for (i = 0; i < sizeof (page_six); i += 3) {
- outb (page_six[i], dev.fx_dsp_addr);
- outb (page_six[i+1], dev.fx_dsp_msb);
- outb (page_six[i+2], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x07, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_seven); i += 2) {
- outb (page_seven[i], dev.fx_dsp_msb);
- outb (page_seven[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Now setup the MOD area. We do this algorithmically in order to
- save a little data space. It could be done in the same fashion
- as the "pages".
- */
-
- for (i = 0x00; i <= 0x0f; i++) {
- outb (0x01, dev.fx_mod_addr);
- outb (i, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0x02, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0xb0; i <= 0xbf; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0xf0; i <= 0xff; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x10; i <= 0x1d; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0xff, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x1e, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x1f; i <= 0x2d; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0xff, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x2e, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x2f; i <= 0x3e; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x3f, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x40; i <= 0x4d; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x4e, dev.fx_mod_addr);
- outb (0x0e, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0x4f, dev.fx_mod_addr);
- outb (0x0e, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
-
- for (i = 0x50; i <= 0x6b; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x6c, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- outb (0x6d, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- outb (0x6e, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- outb (0x6f, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x70; i <= 0x7f; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0xc0, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x80; i <= 0xaf; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0xc0; i <= 0xdd; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0xde, dev.fx_mod_addr);
- outb (0x10, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0xdf, dev.fx_mod_addr);
- outb (0x10, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0xe0; i <= 0xef; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x00; i <= 0x0f; i++) {
- outb (0x01, dev.fx_mod_addr);
- outb (i, dev.fx_mod_data);
- outb (0x02, dev.fx_mod_addr);
- outb (0x01, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x02, dev.fx_op); /* mute on */
-
- /* Now set the coefficients and so forth for the programs above */
-
- for (i = 0; i < sizeof (coefficients); i += 4) {
- outb (coefficients[i], dev.fx_dsp_page);
- outb (coefficients[i+1], dev.fx_dsp_addr);
- outb (coefficients[i+2], dev.fx_dsp_msb);
- outb (coefficients[i+3], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Some settings (?) that are too small to bundle into loops */
-
- if (!wffx_idle()) return (-1);
- outb (0x1e, dev.fx_mod_addr);
- outb (0x14, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0xde, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0xdf, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
-
- /* some more coefficients */
-
- if (!wffx_idle()) return (-1);
- outb (0x06, dev.fx_dsp_page);
- outb (0x78, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x40, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x03, dev.fx_dsp_addr);
- outb (0x0f, dev.fx_dsp_msb);
- outb (0xff, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x0b, dev.fx_dsp_addr);
- outb (0x0f, dev.fx_dsp_msb);
- outb (0xff, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x02, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x0a, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x46, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x49, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
-
- /* Now, for some strange reason, lets reload every page
- and all the coefficients over again. I have *NO* idea
- why this is done. I do know that no sound is produced
- is this phase is omitted.
- */
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x00, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_zero_v2); i += 2) {
- outb (page_zero_v2[i], dev.fx_dsp_msb);
- outb (page_zero_v2[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x01, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_one_v2); i += 2) {
- outb (page_one_v2[i], dev.fx_dsp_msb);
- outb (page_one_v2[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- if (!wffx_idle()) return (-1);
- if (!wffx_idle()) return (-1);
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x02, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_two_v2); i++) {
- outb (page_two_v2[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x03, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_three_v2); i++) {
- outb (page_three_v2[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x04, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_four_v2); i++) {
- outb (page_four_v2[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x06, dev.fx_dsp_page);
-
- /* Page six v.2 is algorithmic */
-
- for (i = 0x10; i <= 0x3e; i += 2) {
- outb (i, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x07, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_seven_v2); i += 2) {
- outb (page_seven_v2[i], dev.fx_dsp_msb);
- outb (page_seven_v2[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x00; i < sizeof(mod_v2); i += 2) {
- outb (mod_v2[i], dev.fx_mod_addr);
- outb (mod_v2[i+1], dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0; i < sizeof (coefficients2); i += 4) {
- outb (coefficients2[i], dev.fx_dsp_page);
- outb (coefficients2[i+1], dev.fx_dsp_addr);
- outb (coefficients2[i+2], dev.fx_dsp_msb);
- outb (coefficients2[i+3], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0; i < sizeof (coefficients3); i += 2) {
- int x;
-
- outb (0x07, dev.fx_dsp_page);
- x = (i % 4) ? 0x4e : 0x4c;
- outb (x, dev.fx_dsp_addr);
- outb (coefficients3[i], dev.fx_dsp_msb);
- outb (coefficients3[i+1], dev.fx_dsp_lsb);
- }
-
- outb (0x00, dev.fx_op); /* mute off */
- if (!wffx_idle()) return (-1);
-
- return (0);
-}
-
-static int io = -1;
-static int irq = -1;
-
-MODULE_AUTHOR ("Paul Barton-Davis <pbd@op.net>");
-MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver");
-MODULE_LICENSE("GPL");
-module_param (io, int, 0);
-module_param (irq, int, 0);
-
-static int __init init_wavfront (void)
-{
- printk ("Turtle Beach WaveFront Driver\n"
- "Copyright (C) by Hannu Solvainen, "
- "Paul Barton-Davis 1993-1998.\n");
-
- /* XXX t'would be lovely to ask the CS4232 for these values, eh ? */
-
- if (io == -1 || irq == -1) {
- printk (KERN_INFO LOGNAME "irq and io options must be set.\n");
- return -EINVAL;
- }
-
- if (wavefront_interrupt_bits (irq) < 0) {
- printk (KERN_INFO LOGNAME
- "IRQ must be 9, 5, 12 or 15 (not %d)\n", irq);
- return -ENODEV;
- }
-
- if (detect_wavefront (irq, io) < 0) {
- return -ENODEV;
- }
-
- if (install_wavefront () < 0) {
- return -EIO;
- }
-
- return 0;
-}
-
-static void __exit cleanup_wavfront (void)
-{
- uninstall_wavefront ();
-}
-
-module_init(init_wavfront);
-module_exit(cleanup_wavfront);
diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c
deleted file mode 100644
index 75c0c14..0000000
--- a/sound/oss/wf_midi.c
+++ /dev/null
@@ -1,880 +0,0 @@
-/*
- * sound/oss/wf_midi.c
- *
- * The low level driver for the WaveFront ICS2115 MIDI interface(s)
- * Note that there is also an MPU-401 emulation (actually, a UART-401
- * emulation) on the CS4232 on the Tropez Plus. This code has nothing
- * to do with that interface at all.
- *
- * The interface is essentially just a UART-401, but is has the
- * interesting property of supporting what Turtle Beach called
- * "Virtual MIDI" mode. In this mode, there are effectively *two*
- * MIDI buses accessible via the interface, one that is routed
- * solely to/from the external WaveFront synthesizer and the other
- * corresponding to the pin/socket connector used to link external
- * MIDI devices to the board.
- *
- * This driver fully supports this mode, allowing two distinct
- * midi devices (/dev/midiNN and /dev/midiNN+1) to be used
- * completely independently, giving 32 channels of MIDI routing,
- * 16 to the WaveFront synth and 16 to the external MIDI bus.
- *
- * Switching between the two is accomplished externally by the driver
- * using the two otherwise unused MIDI bytes. See the code for more details.
- *
- * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see wavefront.c)
- *
- * The main reason to turn off Virtual MIDI mode is when you want to
- * tightly couple the WaveFront synth with an external MIDI
- * device. You won't be able to distinguish the source of any MIDI
- * data except via SysEx ID, but thats probably OK, since for the most
- * part, the WaveFront won't be sending any MIDI data at all.
- *
- * The main reason to turn on Virtual MIDI Mode is to provide two
- * completely independent 16-channel MIDI buses, one to the
- * WaveFront and one to any external MIDI devices. Given the 32
- * voice nature of the WaveFront, its pretty easy to find a use
- * for all 16 channels driving just that synth.
- *
- */
-
-/*
- * Copyright (C) by Paul Barton-Davis 1998
- * Some portions of this file are derived from work that is:
- *
- * CopyriGht (C) by Hannu Savolainen 1993-1996
- *
- * USS/Lite 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.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include <linux/wavefront.h>
-
-#ifdef MODULE
-
-struct wf_mpu_config {
- int base;
-#define DATAPORT(d) (d)->base
-#define COMDPORT(d) (d)->base+1
-#define STATPORT(d) (d)->base+1
-
- int irq;
- int opened;
- int devno;
- int synthno;
- int mode;
-#define MODE_MIDI 1
-#define MODE_SYNTH 2
-
- void (*inputintr) (int dev, unsigned char data);
- char isvirtual; /* do virtual I/O stuff */
-};
-
-static struct wf_mpu_config devs[2];
-static struct wf_mpu_config *phys_dev = &devs[0];
-static struct wf_mpu_config *virt_dev = &devs[1];
-
-static void start_uart_mode (void);
-static DEFINE_SPINLOCK(lock);
-
-#define OUTPUT_READY 0x40
-#define INPUT_AVAIL 0x80
-#define MPU_ACK 0xFE
-#define UART_MODE_ON 0x3F
-
-static inline int wf_mpu_status (void)
-{
- return inb (STATPORT (phys_dev));
-}
-
-static inline int input_avail (void)
-{
- return !(wf_mpu_status() & INPUT_AVAIL);
-}
-
-static inline int output_ready (void)
-{
- return !(wf_mpu_status() & OUTPUT_READY);
-}
-
-static inline int read_data (void)
-{
- return inb (DATAPORT (phys_dev));
-}
-
-static inline void write_data (unsigned char byte)
-{
- outb (byte, DATAPORT (phys_dev));
-}
-
-/*
- * States for the input scanner (should be in dev_table.h)
- */
-
-#define MST_SYSMSG 100 /* System message (sysx etc). */
-#define MST_MTC 102 /* Midi Time Code (MTC) qframe msg */
-#define MST_SONGSEL 103 /* Song select */
-#define MST_SONGPOS 104 /* Song position pointer */
-#define MST_TIMED 105 /* Leading timing byte rcvd */
-
-/* buffer space check for input scanner */
-
-#define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \
-{printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \
- mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;}
-
-static unsigned char len_tab[] = /* # of data bytes following a status
- */
-{
- 2, /* 8x */
- 2, /* 9x */
- 2, /* Ax */
- 2, /* Bx */
- 1, /* Cx */
- 1, /* Dx */
- 2, /* Ex */
- 0 /* Fx */
-};
-
-static int
-wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic)
-
-{
- struct midi_input_info *mi = &midi_devs[devno]->in_info;
-
- switch (mi->m_state) {
- case MST_INIT:
- switch (midic) {
- case 0xf8:
- /* Timer overflow */
- break;
-
- case 0xfc:
- break;
-
- case 0xfd:
- /* XXX do something useful with this. If there is
- an external MIDI timer (e.g. a hardware sequencer,
- a useful timer can be derived ...
-
- For now, no timer support.
- */
- break;
-
- case 0xfe:
- return MPU_ACK;
- break;
-
- case 0xf0:
- case 0xf1:
- case 0xf2:
- case 0xf3:
- case 0xf4:
- case 0xf5:
- case 0xf6:
- case 0xf7:
- break;
-
- case 0xf9:
- break;
-
- case 0xff:
- mi->m_state = MST_SYSMSG;
- break;
-
- default:
- if (midic <= 0xef) {
- mi->m_state = MST_TIMED;
- }
- else
- printk (KERN_ERR "<MPU: Unknown event %02x> ",
- midic);
- }
- break;
-
- case MST_TIMED:
- {
- int msg = ((int) (midic & 0xf0) >> 4);
-
- mi->m_state = MST_DATA;
-
- if (msg < 8) { /* Data byte */
-
- msg = ((int) (mi->m_prev_status & 0xf0) >> 4);
- msg -= 8;
- mi->m_left = len_tab[msg] - 1;
-
- mi->m_ptr = 2;
- mi->m_buf[0] = mi->m_prev_status;
- mi->m_buf[1] = midic;
-
- if (mi->m_left <= 0) {
- mi->m_state = MST_INIT;
- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
- mi->m_ptr = 0;
- }
- } else if (msg == 0xf) { /* MPU MARK */
-
- mi->m_state = MST_INIT;
-
- switch (midic) {
- case 0xf8:
- break;
-
- case 0xf9:
- break;
-
- case 0xfc:
- break;
-
- default:
- break;
- }
- } else {
- mi->m_prev_status = midic;
- msg -= 8;
- mi->m_left = len_tab[msg];
-
- mi->m_ptr = 1;
- mi->m_buf[0] = midic;
-
- if (mi->m_left <= 0) {
- mi->m_state = MST_INIT;
- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
- mi->m_ptr = 0;
- }
- }
- }
- break;
-
- case MST_SYSMSG:
- switch (midic) {
- case 0xf0:
- mi->m_state = MST_SYSEX;
- break;
-
- case 0xf1:
- mi->m_state = MST_MTC;
- break;
-
- case 0xf2:
- mi->m_state = MST_SONGPOS;
- mi->m_ptr = 0;
- break;
-
- case 0xf3:
- mi->m_state = MST_SONGSEL;
- break;
-
- case 0xf6:
- mi->m_state = MST_INIT;
-
- /*
- * Real time messages
- */
- case 0xf8:
- /* midi clock */
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xfA:
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xFB:
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xFC:
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xFE:
- /* active sensing */
- mi->m_state = MST_INIT;
- break;
-
- case 0xff:
- mi->m_state = MST_INIT;
- break;
-
- default:
- printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic);
- mi->m_state = MST_INIT;
- }
- break;
-
- case MST_MTC:
- mi->m_state = MST_INIT;
- break;
-
- case MST_SYSEX:
- if (midic == 0xf7) {
- mi->m_state = MST_INIT;
- } else {
- /* XXX fix me */
- }
- break;
-
- case MST_SONGPOS:
- BUFTEST (mi);
- mi->m_buf[mi->m_ptr++] = midic;
- if (mi->m_ptr == 2) {
- mi->m_state = MST_INIT;
- mi->m_ptr = 0;
- /* XXX need ext MIDI timer support */
- }
- break;
-
- case MST_DATA:
- BUFTEST (mi);
- mi->m_buf[mi->m_ptr++] = midic;
- if ((--mi->m_left) <= 0) {
- mi->m_state = MST_INIT;
- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
- mi->m_ptr = 0;
- }
- break;
-
- default:
- printk (KERN_ERR "Bad state %d ", mi->m_state);
- mi->m_state = MST_INIT;
- }
-
- return 1;
-}
-
-static irqreturn_t
-wf_mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
-
-{
- struct wf_mpu_config *physical_dev = dev_id;
- static struct wf_mpu_config *input_dev;
- struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
- int n;
-
- if (!input_avail()) { /* not for us */
- return IRQ_NONE;
- }
-
- if (mi->m_busy)
- return IRQ_HANDLED;
- spin_lock(&lock);
- mi->m_busy = 1;
-
- if (!input_dev) {
- input_dev = physical_dev;
- }
-
- n = 50; /* XXX why ? */
-
- do {
- unsigned char c = read_data ();
-
- if (phys_dev->isvirtual) {
-
- if (c == WF_EXTERNAL_SWITCH) {
- input_dev = virt_dev;
- continue;
- } else if (c == WF_INTERNAL_SWITCH) {
- input_dev = phys_dev;
- continue;
- } /* else just leave it as it is */
-
- } else {
- input_dev = phys_dev;
- }
-
- if (input_dev->mode == MODE_SYNTH) {
-
- wf_mpu_input_scanner (input_dev->devno,
- input_dev->synthno, c);
-
- } else if (input_dev->opened & OPEN_READ) {
-
- if (input_dev->inputintr) {
- input_dev->inputintr (input_dev->devno, c);
- }
- }
-
- } while (input_avail() && n-- > 0);
-
- mi->m_busy = 0;
- spin_unlock(&lock);
- return IRQ_HANDLED;
-}
-
-static int
-wf_mpu_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
- )
-{
- struct wf_mpu_config *devc;
-
- if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
- return -(ENXIO);
-
- if (phys_dev->devno == dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return -(EINVAL);
- }
-
- if (devc->opened) {
- return -(EBUSY);
- }
-
- devc->mode = MODE_MIDI;
- devc->opened = mode;
- devc->synthno = 0;
-
- devc->inputintr = input;
- return 0;
-}
-
-static void
-wf_mpu_close (int dev)
-{
- struct wf_mpu_config *devc;
-
- if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
- return;
-
- if (phys_dev->devno == dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return;
- }
-
- devc->mode = 0;
- devc->inputintr = NULL;
- devc->opened = 0;
-}
-
-static int
-wf_mpu_out (int dev, unsigned char midi_byte)
-{
- int timeout;
- unsigned long flags;
- static int lastoutdev = -1;
- unsigned char switchch;
-
- if (phys_dev->isvirtual && lastoutdev != dev) {
-
- if (dev == phys_dev->devno) {
- switchch = WF_INTERNAL_SWITCH;
- } else if (dev == virt_dev->devno) {
- switchch = WF_EXTERNAL_SWITCH;
- } else {
- printk (KERN_ERR "WF-MPU: bad device number %d", dev);
- return (0);
- }
-
- /* XXX fix me */
-
- for (timeout = 30000; timeout > 0 && !output_ready ();
- timeout--);
-
- spin_lock_irqsave(&lock,flags);
-
- if (!output_ready ()) {
- printk (KERN_WARNING "WF-MPU: Send switch "
- "byte timeout\n");
- spin_unlock_irqrestore(&lock,flags);
- return 0;
- }
-
- write_data (switchch);
- spin_unlock_irqrestore(&lock,flags);
- }
-
- lastoutdev = dev;
-
- /*
- * Sometimes it takes about 30000 loops before the output becomes ready
- * (After reset). Normally it takes just about 10 loops.
- */
-
- /* XXX fix me */
-
- for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
-
- spin_lock_irqsave(&lock,flags);
- if (!output_ready ()) {
- spin_unlock_irqrestore(&lock,flags);
- printk (KERN_WARNING "WF-MPU: Send data timeout\n");
- return 0;
- }
-
- write_data (midi_byte);
- spin_unlock_irqrestore(&lock,flags);
-
- return 1;
-}
-
-static inline int wf_mpu_start_read (int dev) {
- return 0;
-}
-
-static inline int wf_mpu_end_read (int dev) {
- return 0;
-}
-
-static int wf_mpu_ioctl (int dev, unsigned cmd, void __user *arg)
-{
- printk (KERN_WARNING
- "WF-MPU: Intelligent mode not supported by hardware.\n");
- return -(EINVAL);
-}
-
-static int wf_mpu_buffer_status (int dev)
-{
- return 0;
-}
-
-static struct synth_operations wf_mpu_synth_operations[2];
-static struct midi_operations wf_mpu_midi_operations[2];
-
-static struct midi_operations wf_mpu_midi_proto =
-{
- .owner = THIS_MODULE,
- .info = {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
- .in_info = {0}, /* in_info */
- .open = wf_mpu_open,
- .close = wf_mpu_close,
- .ioctl = wf_mpu_ioctl,
- .outputc = wf_mpu_out,
- .start_read = wf_mpu_start_read,
- .end_read = wf_mpu_end_read,
- .buffer_status = wf_mpu_buffer_status,
-};
-
-static struct synth_info wf_mpu_synth_info_proto =
-{"WaveFront MPU-401 interface", 0,
- SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
-
-static struct synth_info wf_mpu_synth_info[2];
-
-static int
-wf_mpu_synth_ioctl (int dev, unsigned int cmd, void __user *arg)
-{
- int midi_dev;
- int index;
-
- midi_dev = synth_devs[dev]->midi_dev;
-
- if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
- return -(ENXIO);
-
- if (midi_dev == phys_dev->devno) {
- index = 0;
- } else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
- index = 1;
- } else {
- return -(EINVAL);
- }
-
- switch (cmd) {
-
- case SNDCTL_SYNTH_INFO:
- if (copy_to_user(arg,
- &wf_mpu_synth_info[index],
- sizeof (struct synth_info)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
-
- default:
- return -EINVAL;
- }
-}
-
-static int
-wf_mpu_synth_open (int dev, int mode)
-{
- int midi_dev;
- struct wf_mpu_config *devc;
-
- midi_dev = synth_devs[dev]->midi_dev;
-
- if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) {
- return -(ENXIO);
- }
-
- if (phys_dev->devno == midi_dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return -(EINVAL);
- }
-
- if (devc->opened) {
- return -(EBUSY);
- }
-
- devc->mode = MODE_SYNTH;
- devc->synthno = dev;
- devc->opened = mode;
- devc->inputintr = NULL;
- return 0;
-}
-
-static void
-wf_mpu_synth_close (int dev)
-{
- int midi_dev;
- struct wf_mpu_config *devc;
-
- midi_dev = synth_devs[dev]->midi_dev;
-
- if (phys_dev->devno == midi_dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return;
- }
-
- devc->inputintr = NULL;
- devc->opened = 0;
- devc->mode = 0;
-}
-
-#define _MIDI_SYNTH_C_
-#define MIDI_SYNTH_NAME "WaveFront (MIDI)"
-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-static struct synth_operations wf_mpu_synth_proto =
-{
- .owner = THIS_MODULE,
- .id = "WaveFront (ICS2115)",
- .info = NULL, /* info field, filled in during configuration */
- .midi_dev = 0, /* MIDI dev XXX should this be -1 ? */
- .synth_type = SYNTH_TYPE_MIDI,
- .synth_subtype = SAMPLE_TYPE_WAVEFRONT,
- .open = wf_mpu_synth_open,
- .close = wf_mpu_synth_close,
- .ioctl = wf_mpu_synth_ioctl,
- .kill_note = midi_synth_kill_note,
- .start_note = midi_synth_start_note,
- .set_instr = midi_synth_set_instr,
- .reset = midi_synth_reset,
- .hw_control = midi_synth_hw_control,
- .load_patch = midi_synth_load_patch,
- .aftertouch = midi_synth_aftertouch,
- .controller = midi_synth_controller,
- .panning = midi_synth_panning,
- .bender = midi_synth_bender,
- .setup_voice = midi_synth_setup_voice,
- .send_sysex = midi_synth_send_sysex
-};
-
-static int
-config_wf_mpu (struct wf_mpu_config *dev)
-
-{
- int is_external;
- char *name;
- int index;
-
- if (dev == phys_dev) {
- name = "WaveFront internal MIDI";
- is_external = 0;
- index = 0;
- memcpy ((char *) &wf_mpu_synth_operations[index],
- (char *) &wf_mpu_synth_proto,
- sizeof (struct synth_operations));
- } else {
- name = "WaveFront external MIDI";
- is_external = 1;
- index = 1;
- /* no synth operations for an external MIDI interface */
- }
-
- memcpy ((char *) &wf_mpu_synth_info[dev->devno],
- (char *) &wf_mpu_synth_info_proto,
- sizeof (struct synth_info));
-
- strcpy (wf_mpu_synth_info[index].name, name);
-
- wf_mpu_synth_operations[index].midi_dev = dev->devno;
- wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
-
- memcpy ((char *) &wf_mpu_midi_operations[index],
- (char *) &wf_mpu_midi_proto,
- sizeof (struct midi_operations));
-
- if (is_external) {
- wf_mpu_midi_operations[index].converter = NULL;
- } else {
- wf_mpu_midi_operations[index].converter =
- &wf_mpu_synth_operations[index];
- }
-
- strcpy (wf_mpu_midi_operations[index].info.name, name);
-
- midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
- midi_devs[dev->devno]->in_info.m_busy = 0;
- midi_devs[dev->devno]->in_info.m_state = MST_INIT;
- midi_devs[dev->devno]->in_info.m_ptr = 0;
- midi_devs[dev->devno]->in_info.m_left = 0;
- midi_devs[dev->devno]->in_info.m_prev_status = 0;
-
- devs[index].opened = 0;
- devs[index].mode = 0;
-
- return (0);
-}
-
-int virtual_midi_enable (void)
-
-{
- if ((virt_dev->devno < 0) &&
- (virt_dev->devno = sound_alloc_mididev()) == -1) {
- printk (KERN_ERR
- "WF-MPU: too many midi devices detected\n");
- return -1;
- }
-
- config_wf_mpu (virt_dev);
-
- phys_dev->isvirtual = 1;
- return virt_dev->devno;
-}
-
-int
-virtual_midi_disable (void)
-
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
-
- wf_mpu_close (virt_dev->devno);
- /* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
- phys_dev->isvirtual = 0;
-
- spin_unlock_irqrestore(&lock,flags);
-
- return 0;
-}
-
-int __init detect_wf_mpu (int irq, int io_base)
-{
- if (!request_region(io_base, 2, "wavefront midi")) {
- printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
- io_base);
- return -1;
- }
-
- phys_dev->base = io_base;
- phys_dev->irq = irq;
- phys_dev->devno = -1;
- virt_dev->devno = -1;
-
- return 0;
-}
-
-int __init install_wf_mpu (void)
-{
- if ((phys_dev->devno = sound_alloc_mididev()) < 0){
-
- printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
- release_region(phys_dev->base, 2);
- return -1;
- }
-
- phys_dev->isvirtual = 0;
-
- if (config_wf_mpu (phys_dev)) {
-
- printk (KERN_WARNING
- "WF-MPU: configuration for MIDI device %d failed\n",
- phys_dev->devno);
- sound_unload_mididev (phys_dev->devno);
-
- }
-
- /* OK, now we're configured to handle an interrupt ... */
-
- if (request_irq (phys_dev->irq, wf_mpuintr, IRQF_DISABLED|IRQF_SHARED,
- "wavefront midi", phys_dev) < 0) {
-
- printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
- phys_dev->irq);
- return -1;
-
- }
-
- /* This being a WaveFront (ICS-2115) emulated MPU-401, we have
- to switch it into UART (dumb) mode, because otherwise, it
- won't do anything at all.
- */
-
- start_uart_mode ();
-
- return phys_dev->devno;
-}
-
-void
-uninstall_wf_mpu (void)
-
-{
- release_region (phys_dev->base, 2);
- free_irq (phys_dev->irq, phys_dev);
- sound_unload_mididev (phys_dev->devno);
-
- if (virt_dev->devno >= 0) {
- sound_unload_mididev (virt_dev->devno);
- }
-}
-
-static void
-start_uart_mode (void)
-
-{
- int ok, i;
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
-
- /* XXX fix me */
-
- for (i = 0; i < 30000 && !output_ready (); i++);
-
- outb (UART_MODE_ON, COMDPORT(phys_dev));
-
- for (ok = 0, i = 50000; i > 0 && !ok; i--) {
- if (input_avail ()) {
- if (read_data () == MPU_ACK) {
- ok = 1;
- }
- }
- }
-
- spin_unlock_irqrestore(&lock,flags);
-}
-#endif
diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c
deleted file mode 100644
index 6e22472..0000000
--- a/sound/oss/ymfpci.c
+++ /dev/null
@@ -1,2692 +0,0 @@
-/*
- * Copyright 1999 Jaroslav Kysela <perex@suse.cz>
- * Copyright 2000 Alan Cox <alan@redhat.com>
- * Copyright 2001 Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
- * Copyright 2002 Pete Zaitcev <zaitcev@yahoo.com>
- *
- * Yamaha YMF7xx driver.
- *
- * This code is a result of high-speed collision
- * between ymfpci.c of ALSA and cs46xx.c of Linux.
- * -- Pete Zaitcev <zaitcev@yahoo.com>; 2000/09/18
- *
- * 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.
- *
- * TODO:
- * - Use P44Slot for 44.1 playback (beware of idle buzzing in P44Slot).
- * - 96KHz playback for DVD - use pitch of 2.0.
- * - Retain DMA buffer on close, do not wait the end of frame.
- * - Resolve XXX tagged questions.
- * - Cannot play 5133Hz.
- * - 2001/01/07 Consider if we can remove voice_lock, like so:
- * : Allocate/deallocate voices in open/close under semafore.
- * : We access voices in interrupt, that only for pcms that open.
- * voice_lock around playback_prepare closes interrupts for insane duration.
- * - Revisit the way voice_alloc is done - too confusing, overcomplicated.
- * Should support various channel types, however.
- * - Remove prog_dmabuf from read/write, leave it in open.
- * - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
- * native synthesizer through a playback slot.
- * - 2001/11/29 ac97_save_state
- * Talk to Kai to remove ac97_save_state before it's too late!
- * - Second AC97
- * - Restore S/PDIF - Toshibas have it.
- *
- * Kai used pci_alloc_consistent for DMA buffer, which sounds a little
- * unconventional. However, given how small our fragments can be,
- * a little uncached access is perhaps better than endless flushing.
- * On i386 and other I/O-coherent architectures pci_alloc_consistent
- * is entirely harmless.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/sound.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-# include "sound_config.h"
-# include "mpu401.h"
-#endif
-#include "ymfpci.h"
-
-/*
- * I do not believe in debug levels as I never can guess what
- * part of the code is going to be problematic in the future.
- * Don't forget to run your klogd with -c 8.
- *
- * Example (do not remove):
- * #define YMFDBG(fmt, arg...) do{ printk(KERN_DEBUG fmt, ##arg); }while(0)
- */
-#define YMFDBGW(fmt, arg...) /* */ /* write counts */
-#define YMFDBGI(fmt, arg...) /* */ /* interrupts */
-#define YMFDBGX(fmt, arg...) /* */ /* ioctl */
-
-static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
-static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice);
-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank);
-static int ymf_playback_prepare(struct ymf_state *state);
-static int ymf_capture_prepare(struct ymf_state *state);
-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit);
-
-static void ymfpci_aclink_reset(struct pci_dev * pci);
-static void ymfpci_disable_dsp(ymfpci_t *unit);
-static void ymfpci_download_image(ymfpci_t *codec);
-static void ymf_memload(ymfpci_t *unit);
-
-static DEFINE_SPINLOCK(ymf_devs_lock);
-static LIST_HEAD(ymf_devs);
-
-/*
- * constants
- */
-
-static struct pci_device_id ymf_id_tbl[] = {
-#define DEV(dev, data) \
- { PCI_VENDOR_ID_YAMAHA, dev, PCI_ANY_ID, PCI_ANY_ID, 0, 0, \
- (unsigned long)data }
- DEV (PCI_DEVICE_ID_YAMAHA_724, "YMF724"),
- DEV (PCI_DEVICE_ID_YAMAHA_724F, "YMF724F"),
- DEV (PCI_DEVICE_ID_YAMAHA_740, "YMF740"),
- DEV (PCI_DEVICE_ID_YAMAHA_740C, "YMF740C"),
- DEV (PCI_DEVICE_ID_YAMAHA_744, "YMF744"),
- DEV (PCI_DEVICE_ID_YAMAHA_754, "YMF754"),
-#undef DEV
- { }
-};
-MODULE_DEVICE_TABLE(pci, ymf_id_tbl);
-
-/*
- * common I/O routines
- */
-
-static inline void ymfpci_writeb(ymfpci_t *codec, u32 offset, u8 val)
-{
- writeb(val, codec->reg_area_virt + offset);
-}
-
-static inline u16 ymfpci_readw(ymfpci_t *codec, u32 offset)
-{
- return readw(codec->reg_area_virt + offset);
-}
-
-static inline void ymfpci_writew(ymfpci_t *codec, u32 offset, u16 val)
-{
- writew(val, codec->reg_area_virt + offset);
-}
-
-static inline u32 ymfpci_readl(ymfpci_t *codec, u32 offset)
-{
- return readl(codec->reg_area_virt + offset);
-}
-
-static inline void ymfpci_writel(ymfpci_t *codec, u32 offset, u32 val)
-{
- writel(val, codec->reg_area_virt + offset);
-}
-
-static int ymfpci_codec_ready(ymfpci_t *codec, int secondary, int sched)
-{
- signed long end_time;
- u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
-
- end_time = jiffies + 3 * (HZ / 4);
- do {
- if ((ymfpci_readw(codec, reg) & 0x8000) == 0)
- return 0;
- if (sched) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
- } while (end_time - (signed long)jiffies >= 0);
- printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
- secondary, ymfpci_readw(codec, reg));
- return -EBUSY;
-}
-
-static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val)
-{
- ymfpci_t *codec = dev->private_data;
- u32 cmd;
-
- spin_lock(&codec->ac97_lock);
- /* XXX Do make use of dev->id */
- ymfpci_codec_ready(codec, 0, 0);
- cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val;
- ymfpci_writel(codec, YDSXGR_AC97CMDDATA, cmd);
- spin_unlock(&codec->ac97_lock);
-}
-
-static u16 _ymfpci_codec_read(ymfpci_t *unit, u8 reg)
-{
- int i;
-
- if (ymfpci_codec_ready(unit, 0, 0))
- return ~0;
- ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
- if (ymfpci_codec_ready(unit, 0, 0))
- return ~0;
- if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
- for (i = 0; i < 600; i++)
- ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
- }
- return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
-}
-
-static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
-{
- ymfpci_t *unit = dev->private_data;
- u16 ret;
-
- spin_lock(&unit->ac97_lock);
- ret = _ymfpci_codec_read(unit, reg);
- spin_unlock(&unit->ac97_lock);
-
- return ret;
-}
-
-/*
- * Misc routines
- */
-
-/*
- * Calculate the actual sampling rate relatetively to the base clock (48kHz).
- */
-static u32 ymfpci_calc_delta(u32 rate)
-{
- switch (rate) {
- case 8000: return 0x02aaab00;
- case 11025: return 0x03accd00;
- case 16000: return 0x05555500;
- case 22050: return 0x07599a00;
- case 32000: return 0x0aaaab00;
- case 44100: return 0x0eb33300;
- default: return ((rate << 16) / 48000) << 12;
- }
-}
-
-static u32 def_rate[8] = {
- 100, 2000, 8000, 11025, 16000, 22050, 32000, 48000
-};
-
-static u32 ymfpci_calc_lpfK(u32 rate)
-{
- u32 i;
- static u32 val[8] = {
- 0x00570000, 0x06AA0000, 0x18B20000, 0x20930000,
- 0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000
- };
-
- if (rate == 44100)
- return 0x40000000; /* FIXME: What's the right value? */
- for (i = 0; i < 8; i++)
- if (rate <= def_rate[i])
- return val[i];
- return val[0];
-}
-
-static u32 ymfpci_calc_lpfQ(u32 rate)
-{
- u32 i;
- static u32 val[8] = {
- 0x35280000, 0x34A70000, 0x32020000, 0x31770000,
- 0x31390000, 0x31C90000, 0x33D00000, 0x40000000
- };
-
- if (rate == 44100)
- return 0x370A0000;
- for (i = 0; i < 8; i++)
- if (rate <= def_rate[i])
- return val[i];
- return val[0];
-}
-
-static u32 ymf_calc_lend(u32 rate)
-{
- return (rate * YMF_SAMPF) / 48000;
-}
-
-/*
- * We ever allow only a few formats, but let's be generic, for smaller surprise.
- */
-static int ymf_pcm_format_width(int format)
-{
- static int mask16 = AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE;
-
- if ((format & (format-1)) != 0) {
- printk(KERN_ERR "ymfpci: format 0x%x is not a power of 2\n", format);
- return 8;
- }
-
- if (format == AFMT_IMA_ADPCM) return 4;
- if ((format & mask16) != 0) return 16;
- return 8;
-}
-
-static void ymf_pcm_update_shift(struct ymf_pcm_format *f)
-{
- f->shift = 0;
- if (f->voices == 2)
- f->shift++;
- if (ymf_pcm_format_width(f->format) == 16)
- f->shift++;
-}
-
-/* Are you sure 32K is not too much? See if mpg123 skips on loaded systems. */
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/*
- * Allocate DMA buffer
- */
-static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
-{
- void *rawbuf = NULL;
- dma_addr_t dma_addr;
- int order;
- struct page *map, *mapend;
-
- /* alloc as big a chunk as we can */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
- rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr);
- if (rawbuf)
- break;
- }
- if (!rawbuf)
- return -ENOMEM;
-
-#if 0
- printk(KERN_DEBUG "ymfpci: allocated %ld (order = %d) bytes at %p\n",
- PAGE_SIZE << order, order, rawbuf);
-#endif
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->rawbuf = rawbuf;
- dmabuf->dma_addr = dma_addr;
- dmabuf->buforder = order;
-
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- mapend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (map = virt_to_page(rawbuf); map <= mapend; map++)
- set_bit(PG_reserved, &map->flags);
-
- return 0;
-}
-
-/*
- * Free DMA buffer
- */
-static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
-{
- struct page *map, *mapend;
-
- if (dmabuf->rawbuf) {
- /* undo marking the pages as reserved */
- mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
- for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
- clear_bit(PG_reserved, &map->flags);
-
- pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder,
- dmabuf->rawbuf, dmabuf->dma_addr);
- }
- dmabuf->rawbuf = NULL;
- dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct ymf_state *state, int rec)
-{
- struct ymf_dmabuf *dmabuf;
- int w_16;
- unsigned bufsize;
- unsigned long flags;
- int redzone, redfrags;
- int ret;
-
- w_16 = ymf_pcm_format_width(state->format.format) == 16;
- dmabuf = rec ? &state->rpcm.dmabuf : &state->wpcm.dmabuf;
-
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->hwptr = dmabuf->swptr = 0;
- dmabuf->total_bytes = 0;
- dmabuf->count = 0;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-
- /* allocate DMA buffer if not allocated yet */
- if (!dmabuf->rawbuf)
- if ((ret = alloc_dmabuf(state->unit, dmabuf)))
- return ret;
-
- /*
- * Create fake fragment sizes and numbers for OSS ioctls.
- * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT.
- */
- bufsize = PAGE_SIZE << dmabuf->buforder;
- /* By default we give 4 big buffers. */
- dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2);
- if (dmabuf->ossfragshift > 3 &&
- dmabuf->ossfragshift < dmabuf->fragshift) {
- /* If OSS set smaller fragments, give more smaller buffers. */
- dmabuf->fragshift = dmabuf->ossfragshift;
- }
- dmabuf->fragsize = 1 << dmabuf->fragshift;
-
- dmabuf->numfrag = bufsize >> dmabuf->fragshift;
- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
-
- if (dmabuf->ossmaxfrags >= 2) {
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= state->format.shift;
- redzone *= 3;
- redfrags = (redzone + dmabuf->fragsize-1) >> dmabuf->fragshift;
-
- if (dmabuf->ossmaxfrags + redfrags < dmabuf->numfrag) {
- dmabuf->numfrag = dmabuf->ossmaxfrags + redfrags;
- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
- }
- }
-
- memset(dmabuf->rawbuf, w_16 ? 0 : 0x80, dmabuf->dmasize);
-
- /*
- * Now set up the ring
- */
-
- /* XXX ret = rec? cap_pre(): pbk_pre(); */
- spin_lock_irqsave(&state->unit->voice_lock, flags);
- if (rec) {
- if ((ret = ymf_capture_prepare(state)) != 0) {
- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
- return ret;
- }
- } else {
- if ((ret = ymf_playback_prepare(state)) != 0) {
- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
- return ret;
- }
- }
- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
-
- /* set the ready flag for the dma buffer (this comment is not stupid) */
- dmabuf->ready = 1;
-
-#if 0
- printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
- " numfrag %d fragsize %d dmasize %d\n",
- state->format.rate, state->format.format, dmabuf->numfrag,
- dmabuf->fragsize, dmabuf->dmasize);
-#endif
-
- return 0;
-}
-
-static void ymf_start_dac(struct ymf_state *state)
-{
- ymf_playback_trigger(state->unit, &state->wpcm, 1);
-}
-
-// static void ymf_start_adc(struct ymf_state *state)
-// {
-// ymf_capture_trigger(state->unit, &state->rpcm, 1);
-// }
-
-/*
- * Wait until output is drained.
- * This does not kill the hardware for the sake of ioctls.
- */
-static void ymf_wait_dac(struct ymf_state *state)
-{
- struct ymf_unit *unit = state->unit;
- struct ymf_pcm *ypcm = &state->wpcm;
- DECLARE_WAITQUEUE(waita, current);
- unsigned long flags;
-
- add_wait_queue(&ypcm->dmabuf.wait, &waita);
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (ypcm->dmabuf.count != 0 && !ypcm->running) {
- ymf_playback_trigger(unit, ypcm, 1);
- }
-
-#if 0
- if (file->f_flags & O_NONBLOCK) {
- /*
- * XXX Our mistake is to attach DMA buffer to state
- * rather than to some per-device structure.
- * Cannot skip waiting, can only make it shorter.
- */
- }
-#endif
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (ypcm->running) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- schedule();
- spin_lock_irqsave(&unit->reg_lock, flags);
- set_current_state(TASK_UNINTERRUPTIBLE);
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&ypcm->dmabuf.wait, &waita);
-
- /*
- * This function may take up to 4 seconds to reach this point
- * (32K circular buffer, 8000 Hz). User notices.
- */
-}
-
-/* Can just stop, without wait. Or can we? */
-static void ymf_stop_adc(struct ymf_state *state)
-{
- struct ymf_unit *unit = state->unit;
- unsigned long flags;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- ymf_capture_trigger(unit, &state->rpcm, 0);
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-/*
- * Hardware start management
- */
-
-static void ymfpci_hw_start(ymfpci_t *unit)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->start_count++ == 0) {
- ymfpci_writel(unit, YDSXGR_MODE,
- ymfpci_readl(unit, YDSXGR_MODE) | 3);
- unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-static void ymfpci_hw_stop(ymfpci_t *unit)
-{
- unsigned long flags;
- long timeout = 1000;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (--unit->start_count == 0) {
- ymfpci_writel(unit, YDSXGR_MODE,
- ymfpci_readl(unit, YDSXGR_MODE) & ~3);
- while (timeout-- > 0) {
- if ((ymfpci_readl(unit, YDSXGR_STATUS) & 2) == 0)
- break;
- }
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-/*
- * Playback voice management
- */
-
-static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[])
-{
- ymfpci_voice_t *voice, *voice2;
- int idx;
-
- for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) {
- voice = &codec->voices[idx];
- voice2 = pair ? &codec->voices[idx+1] : NULL;
- if (voice->use || (voice2 && voice2->use))
- continue;
- voice->use = 1;
- if (voice2)
- voice2->use = 1;
- switch (type) {
- case YMFPCI_PCM:
- voice->pcm = 1;
- if (voice2)
- voice2->pcm = 1;
- break;
- case YMFPCI_SYNTH:
- voice->synth = 1;
- break;
- case YMFPCI_MIDI:
- voice->midi = 1;
- break;
- }
- ymfpci_hw_start(codec);
- rvoice[0] = voice;
- if (voice2) {
- ymfpci_hw_start(codec);
- rvoice[1] = voice2;
- }
- return 0;
- }
- return -EBUSY; /* Your audio channel is open by someone else. */
-}
-
-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice)
-{
- ymfpci_hw_stop(unit);
- pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
- pvoice->ypcm = NULL;
-}
-
-/*
- */
-
-static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
-{
- struct ymf_pcm *ypcm;
- int redzone;
- int pos, delta, swptr;
- int played, distance;
- struct ymf_state *state;
- struct ymf_dmabuf *dmabuf;
- char silence;
-
- if ((ypcm = voice->ypcm) == NULL) {
- return;
- }
- if ((state = ypcm->state) == NULL) {
- ypcm->running = 0; // lock it
- return;
- }
- dmabuf = &ypcm->dmabuf;
- spin_lock(&codec->reg_lock);
- if (ypcm->running) {
- YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
- voice->number, codec->active_bank, dmabuf->count,
- le32_to_cpu(voice->bank[0].start),
- le32_to_cpu(voice->bank[1].start));
- silence = (ymf_pcm_format_width(state->format.format) == 16) ?
- 0 : 0x80;
- /* We need actual left-hand-side redzone size here. */
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= (state->format.shift + 1);
- swptr = dmabuf->swptr;
-
- pos = le32_to_cpu(voice->bank[codec->active_bank].start);
- pos <<= state->format.shift;
- if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
- printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
- codec->dev_audio, voice->number,
- dmabuf->hwptr, pos, dmabuf->dmasize);
- pos = 0;
- }
- if (pos < dmabuf->hwptr) {
- delta = dmabuf->dmasize - dmabuf->hwptr;
- memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
- delta += pos;
- memset(dmabuf->rawbuf, silence, pos);
- } else {
- delta = pos - dmabuf->hwptr;
- memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
- }
- dmabuf->hwptr = pos;
-
- if (dmabuf->count == 0) {
- printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
- codec->dev_audio, voice->number, dmabuf->hwptr);
- ymf_playback_trigger(codec, ypcm, 0);
- }
-
- if (swptr <= pos) {
- distance = pos - swptr;
- } else {
- distance = dmabuf->dmasize - (swptr - pos);
- }
- if (distance < redzone) {
- /*
- * hwptr inside redzone => DMA ran out of samples.
- */
- if (delta < dmabuf->count) {
- /*
- * Lost interrupt or other screwage.
- */
- printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
- " hwptr %d swptr %d distance %d count %d\n",
- codec->dev_audio, voice->number, delta,
- dmabuf->hwptr, swptr, distance, dmabuf->count);
- } else {
- /*
- * Normal end of DMA.
- */
- YMFDBGI("ymfpci%d: %d: done: delta %d"
- " hwptr %d swptr %d distance %d count %d\n",
- codec->dev_audio, voice->number, delta,
- dmabuf->hwptr, swptr, distance, dmabuf->count);
- }
- played = dmabuf->count;
- if (ypcm->running) {
- ymf_playback_trigger(codec, ypcm, 0);
- }
- } else {
- /*
- * hwptr is chipping away towards a remote swptr.
- * Calculate other distance and apply it to count.
- */
- if (swptr >= pos) {
- distance = swptr - pos;
- } else {
- distance = dmabuf->dmasize - (pos - swptr);
- }
- if (distance < dmabuf->count) {
- played = dmabuf->count - distance;
- } else {
- played = 0;
- }
- }
-
- dmabuf->total_bytes += played;
- dmabuf->count -= played;
- if (dmabuf->count < dmabuf->dmasize / 2) {
- wake_up(&dmabuf->wait);
- }
- }
- spin_unlock(&codec->reg_lock);
-}
-
-static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap)
-{
- struct ymf_pcm *ypcm;
- int redzone;
- struct ymf_state *state;
- struct ymf_dmabuf *dmabuf;
- int pos, delta;
- int cnt;
-
- if ((ypcm = cap->ypcm) == NULL) {
- return;
- }
- if ((state = ypcm->state) == NULL) {
- ypcm->running = 0; // lock it
- return;
- }
- dmabuf = &ypcm->dmabuf;
- spin_lock(&unit->reg_lock);
- if (ypcm->running) {
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= (state->format.shift + 1);
-
- pos = le32_to_cpu(cap->bank[unit->active_bank].start);
- // pos <<= state->format.shift;
- if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
- printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
- unit->dev_audio, ypcm->capture_bank_number,
- dmabuf->hwptr, pos, dmabuf->dmasize);
- pos = 0;
- }
- if (pos < dmabuf->hwptr) {
- delta = dmabuf->dmasize - dmabuf->hwptr;
- delta += pos;
- } else {
- delta = pos - dmabuf->hwptr;
- }
- dmabuf->hwptr = pos;
-
- cnt = dmabuf->count;
- cnt += delta;
- if (cnt + redzone > dmabuf->dmasize) {
- /* Overflow - bump swptr */
- dmabuf->count = dmabuf->dmasize - redzone;
- dmabuf->swptr = dmabuf->hwptr + redzone;
- if (dmabuf->swptr >= dmabuf->dmasize) {
- dmabuf->swptr -= dmabuf->dmasize;
- }
- } else {
- dmabuf->count = cnt;
- }
-
- dmabuf->total_bytes += delta;
- if (dmabuf->count) { /* && is_sleeping XXX */
- wake_up(&dmabuf->wait);
- }
- }
- spin_unlock(&unit->reg_lock);
-}
-
-static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
-{
-
- if (ypcm->voices[0] == NULL) {
- return -EINVAL;
- }
- if (cmd != 0) {
- codec->ctrl_playback[ypcm->voices[0]->number + 1] =
- cpu_to_le32(ypcm->voices[0]->bank_ba);
- if (ypcm->voices[1] != NULL)
- codec->ctrl_playback[ypcm->voices[1]->number + 1] =
- cpu_to_le32(ypcm->voices[1]->bank_ba);
- ypcm->running = 1;
- } else {
- codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
- if (ypcm->voices[1] != NULL)
- codec->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
- ypcm->running = 0;
- }
- return 0;
-}
-
-static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
-{
- u32 tmp;
-
- if (cmd != 0) {
- tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);
- ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
- ypcm->running = 1;
- } else {
- tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);
- ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
- ypcm->running = 0;
- }
-}
-
-static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices)
-{
- struct ymf_unit *unit;
- int err;
-
- unit = ypcm->state->unit;
- if (ypcm->voices[1] != NULL && voices < 2) {
- ymfpci_voice_free(unit, ypcm->voices[1]);
- ypcm->voices[1] = NULL;
- }
- if (voices == 1 && ypcm->voices[0] != NULL)
- return 0; /* already allocated */
- if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL)
- return 0; /* already allocated */
- if (voices > 1) {
- if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {
- ymfpci_voice_free(unit, ypcm->voices[0]);
- ypcm->voices[0] = NULL;
- }
- if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0)
- return err;
- ypcm->voices[0]->ypcm = ypcm;
- ypcm->voices[1]->ypcm = ypcm;
- } else {
- if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0)
- return err;
- ypcm->voices[0]->ypcm = ypcm;
- }
- return 0;
-}
-
-static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
- int rate, int w_16, unsigned long addr, unsigned int end, int spdif)
-{
- u32 format;
- u32 delta = ymfpci_calc_delta(rate);
- u32 lpfQ = ymfpci_calc_lpfQ(rate);
- u32 lpfK = ymfpci_calc_lpfK(rate);
- ymfpci_playback_bank_t *bank;
- int nbank;
-
- /*
- * The gain is a floating point number. According to the manual,
- * bit 31 indicates a sign bit, bit 30 indicates an integer part,
- * and bits [29:15] indicate a decimal fraction part. Thus,
- * for a gain of 1.0 the constant of 0x40000000 is loaded.
- */
- unsigned default_gain = cpu_to_le32(0x40000000);
-
- format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
- if (stereo)
- end >>= 1;
- if (w_16)
- end >>= 1;
- for (nbank = 0; nbank < 2; nbank++) {
- bank = &voice->bank[nbank];
- bank->format = cpu_to_le32(format);
- bank->loop_default = 0; /* 0-loops forever, otherwise count */
- bank->base = cpu_to_le32(addr);
- bank->loop_start = 0;
- bank->loop_end = cpu_to_le32(end);
- bank->loop_frac = 0;
- bank->eg_gain_end = default_gain;
- bank->lpfQ = cpu_to_le32(lpfQ);
- bank->status = 0;
- bank->num_of_frames = 0;
- bank->loop_count = 0;
- bank->start = 0;
- bank->start_frac = 0;
- bank->delta =
- bank->delta_end = cpu_to_le32(delta);
- bank->lpfK =
- bank->lpfK_end = cpu_to_le32(lpfK);
- bank->eg_gain = default_gain;
- bank->lpfD1 =
- bank->lpfD2 = 0;
-
- bank->left_gain =
- bank->right_gain =
- bank->left_gain_end =
- bank->right_gain_end =
- bank->eff1_gain =
- bank->eff2_gain =
- bank->eff3_gain =
- bank->eff1_gain_end =
- bank->eff2_gain_end =
- bank->eff3_gain_end = 0;
-
- if (!stereo) {
- if (!spdif) {
- bank->left_gain =
- bank->right_gain =
- bank->left_gain_end =
- bank->right_gain_end = default_gain;
- } else {
- bank->eff2_gain =
- bank->eff2_gain_end =
- bank->eff3_gain =
- bank->eff3_gain_end = default_gain;
- }
- } else {
- if (!spdif) {
- if ((voice->number & 1) == 0) {
- bank->left_gain =
- bank->left_gain_end = default_gain;
- } else {
- bank->format |= cpu_to_le32(1);
- bank->right_gain =
- bank->right_gain_end = default_gain;
- }
- } else {
- if ((voice->number & 1) == 0) {
- bank->eff2_gain =
- bank->eff2_gain_end = default_gain;
- } else {
- bank->format |= cpu_to_le32(1);
- bank->eff3_gain =
- bank->eff3_gain_end = default_gain;
- }
- }
- }
- }
-}
-
-/*
- * XXX Capture channel allocation is entirely fake at the moment.
- * We use only one channel and mark it busy as required.
- */
-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank)
-{
- struct ymf_capture *cap;
- int cbank;
-
- cbank = 1; /* Only ADC slot is used for now. */
- cap = &unit->capture[cbank];
- if (cap->use)
- return -EBUSY;
- cap->use = 1;
- *pbank = cbank;
- return 0;
-}
-
-static int ymf_playback_prepare(struct ymf_state *state)
-{
- struct ymf_pcm *ypcm = &state->wpcm;
- int err, nvoice;
-
- if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
- /* Somebody started 32 mpg123's in parallel? */
- printk(KERN_INFO "ymfpci%d: cannot allocate voice\n",
- state->unit->dev_audio);
- return err;
- }
-
- for (nvoice = 0; nvoice < state->format.voices; nvoice++) {
- ymf_pcm_init_voice(ypcm->voices[nvoice],
- state->format.voices == 2, state->format.rate,
- ymf_pcm_format_width(state->format.format) == 16,
- ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize,
- ypcm->spdif);
- }
- return 0;
-}
-
-static int ymf_capture_prepare(struct ymf_state *state)
-{
- ymfpci_t *unit = state->unit;
- struct ymf_pcm *ypcm = &state->rpcm;
- ymfpci_capture_bank_t * bank;
- /* XXX This is confusing, gotta rename one of them banks... */
- int nbank; /* flip-flop bank */
- int cbank; /* input [super-]bank */
- struct ymf_capture *cap;
- u32 rate, format;
-
- if (ypcm->capture_bank_number == -1) {
- if (ymf_capture_alloc(unit, &cbank) != 0)
- return -EBUSY;
-
- ypcm->capture_bank_number = cbank;
-
- cap = &unit->capture[cbank];
- cap->bank = unit->bank_capture[cbank][0];
- cap->ypcm = ypcm;
- ymfpci_hw_start(unit);
- }
-
- // ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream);
- // frag_size is replaced with nonfragged byte-aligned rolling buffer
- rate = ((48000 * 4096) / state->format.rate) - 1;
- format = 0;
- if (state->format.voices == 2)
- format |= 2;
- if (ymf_pcm_format_width(state->format.format) == 8)
- format |= 1;
- switch (ypcm->capture_bank_number) {
- case 0:
- ymfpci_writel(unit, YDSXGR_RECFORMAT, format);
- ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate);
- break;
- case 1:
- ymfpci_writel(unit, YDSXGR_ADCFORMAT, format);
- ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate);
- break;
- }
- for (nbank = 0; nbank < 2; nbank++) {
- bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
- bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr);
- // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
- bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize);
- bank->start = 0;
- bank->num_of_loops = 0;
- }
-#if 0 /* s/pdif */
- if (state->digital.dig_valid)
- /*state->digital.type == SND_PCM_DIG_AES_IEC958*/
- ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS,
- state->digital.dig_status[0] | (state->digital.dig_status[1] << 8));
-#endif
- return 0;
-}
-
-static irqreturn_t ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- ymfpci_t *codec = dev_id;
- u32 status, nvoice, mode;
- struct ymf_voice *voice;
- struct ymf_capture *cap;
-
- status = ymfpci_readl(codec, YDSXGR_STATUS);
- if (status & 0x80000000) {
- codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1;
- spin_lock(&codec->voice_lock);
- for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
- voice = &codec->voices[nvoice];
- if (voice->use)
- ymf_pcm_interrupt(codec, voice);
- }
- for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
- cap = &codec->capture[nvoice];
- if (cap->use)
- ymf_cap_interrupt(codec, cap);
- }
- spin_unlock(&codec->voice_lock);
- spin_lock(&codec->reg_lock);
- ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000);
- mode = ymfpci_readl(codec, YDSXGR_MODE) | 2;
- ymfpci_writel(codec, YDSXGR_MODE, mode);
- spin_unlock(&codec->reg_lock);
- }
-
- status = ymfpci_readl(codec, YDSXGR_INTFLAG);
- if (status & 1) {
- /* timer handler */
- ymfpci_writel(codec, YDSXGR_INTFLAG, ~0);
- }
- return IRQ_HANDLED;
-}
-
-static void ymf_pcm_free_substream(struct ymf_pcm *ypcm)
-{
- unsigned long flags;
- struct ymf_unit *unit;
-
- unit = ypcm->state->unit;
-
- if (ypcm->type == PLAYBACK_VOICE) {
- spin_lock_irqsave(&unit->voice_lock, flags);
- if (ypcm->voices[1])
- ymfpci_voice_free(unit, ypcm->voices[1]);
- if (ypcm->voices[0])
- ymfpci_voice_free(unit, ypcm->voices[0]);
- spin_unlock_irqrestore(&unit->voice_lock, flags);
- } else {
- if (ypcm->capture_bank_number != -1) {
- unit->capture[ypcm->capture_bank_number].use = 0;
- ypcm->capture_bank_number = -1;
- ymfpci_hw_stop(unit);
- }
- }
-}
-
-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit)
-{
- struct ymf_pcm *ypcm;
- struct ymf_state *state;
-
- if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) {
- goto out0;
- }
- memset(state, 0, sizeof(struct ymf_state));
-
- ypcm = &state->wpcm;
- ypcm->state = state;
- ypcm->type = PLAYBACK_VOICE;
- ypcm->capture_bank_number = -1;
- init_waitqueue_head(&ypcm->dmabuf.wait);
-
- ypcm = &state->rpcm;
- ypcm->state = state;
- ypcm->type = CAPTURE_AC97;
- ypcm->capture_bank_number = -1;
- init_waitqueue_head(&ypcm->dmabuf.wait);
-
- state->unit = unit;
-
- state->format.format = AFMT_U8;
- state->format.rate = 8000;
- state->format.voices = 1;
- ymf_pcm_update_shift(&state->format);
-
- return state;
-
-out0:
- return NULL;
-}
-
-/* AES/IEC958 channel status bits */
-#define SND_PCM_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */
-#define SND_PCM_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */
-#define SND_PCM_AES0_PRO_EMPHASIS (7<<2) /* mask - emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_NOTID (0<<2) /* emphasis not indicated */
-#define SND_PCM_AES0_PRO_EMPHASIS_NONE (1<<2) /* none emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_5015 (3<<2) /* 50/15us emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_CCITT (7<<2) /* CCITT J.17 emphasis */
-#define SND_PCM_AES0_PRO_FREQ_UNLOCKED (1<<5) /* source sample frequency: 0 = locked, 1 = unlocked */
-#define SND_PCM_AES0_PRO_FS (3<<6) /* mask - sample frequency */
-#define SND_PCM_AES0_PRO_FS_NOTID (0<<6) /* fs not indicated */
-#define SND_PCM_AES0_PRO_FS_44100 (1<<6) /* 44.1kHz */
-#define SND_PCM_AES0_PRO_FS_48000 (2<<6) /* 48kHz */
-#define SND_PCM_AES0_PRO_FS_32000 (3<<6) /* 32kHz */
-#define SND_PCM_AES0_CON_NOT_COPYRIGHT (1<<2) /* 0 = copyright, 1 = not copyright */
-#define SND_PCM_AES0_CON_EMPHASIS (7<<3) /* mask - emphasis */
-#define SND_PCM_AES0_CON_EMPHASIS_NONE (0<<3) /* none emphasis */
-#define SND_PCM_AES0_CON_EMPHASIS_5015 (1<<3) /* 50/15us emphasis */
-#define SND_PCM_AES0_CON_MODE (3<<6) /* mask - mode */
-#define SND_PCM_AES1_PRO_MODE (15<<0) /* mask - channel mode */
-#define SND_PCM_AES1_PRO_MODE_NOTID (0<<0) /* not indicated */
-#define SND_PCM_AES1_PRO_MODE_STEREOPHONIC (2<<0) /* stereophonic - ch A is left */
-#define SND_PCM_AES1_PRO_MODE_SINGLE (4<<0) /* single channel */
-#define SND_PCM_AES1_PRO_MODE_TWO (8<<0) /* two channels */
-#define SND_PCM_AES1_PRO_MODE_PRIMARY (12<<0) /* primary/secondary */
-#define SND_PCM_AES1_PRO_MODE_BYTE3 (15<<0) /* vector to byte 3 */
-#define SND_PCM_AES1_PRO_USERBITS (15<<4) /* mask - user bits */
-#define SND_PCM_AES1_PRO_USERBITS_NOTID (0<<4) /* not indicated */
-#define SND_PCM_AES1_PRO_USERBITS_192 (8<<4) /* 192-bit structure */
-#define SND_PCM_AES1_PRO_USERBITS_UDEF (12<<4) /* user defined application */
-#define SND_PCM_AES1_CON_CATEGORY 0x7f
-#define SND_PCM_AES1_CON_GENERAL 0x00
-#define SND_PCM_AES1_CON_EXPERIMENTAL 0x40
-#define SND_PCM_AES1_CON_SOLIDMEM_MASK 0x0f
-#define SND_PCM_AES1_CON_SOLIDMEM_ID 0x08
-#define SND_PCM_AES1_CON_BROADCAST1_MASK 0x07
-#define SND_PCM_AES1_CON_BROADCAST1_ID 0x04
-#define SND_PCM_AES1_CON_DIGDIGCONV_MASK 0x07
-#define SND_PCM_AES1_CON_DIGDIGCONV_ID 0x02
-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_ID 0x06
-#define SND_PCM_AES1_CON_ADC_MASK 0x1f
-#define SND_PCM_AES1_CON_ADC_ID 0x16
-#define SND_PCM_AES1_CON_BROADCAST2_MASK 0x0f
-#define SND_PCM_AES1_CON_BROADCAST2_ID 0x0e
-#define SND_PCM_AES1_CON_LASEROPT_MASK 0x07
-#define SND_PCM_AES1_CON_LASEROPT_ID 0x01
-#define SND_PCM_AES1_CON_MUSICAL_MASK 0x07
-#define SND_PCM_AES1_CON_MUSICAL_ID 0x05
-#define SND_PCM_AES1_CON_MAGNETIC_MASK 0x07
-#define SND_PCM_AES1_CON_MAGNETIC_ID 0x03
-#define SND_PCM_AES1_CON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x00)
-#define SND_PCM_AES1_CON_NON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x08)
-#define SND_PCM_AES1_CON_PCM_CODER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x00)
-#define SND_PCM_AES1_CON_SAMPLER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x20)
-#define SND_PCM_AES1_CON_MIXER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x10)
-#define SND_PCM_AES1_CON_RATE_CONVERTER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x18)
-#define SND_PCM_AES1_CON_SYNTHESIZER (SND_PCM_AES1_CON_MUSICAL_ID|0x00)
-#define SND_PCM_AES1_CON_MICROPHONE (SND_PCM_AES1_CON_MUSICAL_ID|0x08)
-#define SND_PCM_AES1_CON_DAT (SND_PCM_AES1_CON_MAGNETIC_ID|0x00)
-#define SND_PCM_AES1_CON_VCR (SND_PCM_AES1_CON_MAGNETIC_ID|0x08)
-#define SND_PCM_AES1_CON_ORIGINAL (1<<7) /* this bits depends on the category code */
-#define SND_PCM_AES2_PRO_SBITS (7<<0) /* mask - sample bits */
-#define SND_PCM_AES2_PRO_SBITS_20 (2<<0) /* 20-bit - coordination */
-#define SND_PCM_AES2_PRO_SBITS_24 (4<<0) /* 24-bit - main audio */
-#define SND_PCM_AES2_PRO_SBITS_UDEF (6<<0) /* user defined application */
-#define SND_PCM_AES2_PRO_WORDLEN (7<<3) /* mask - source word length */
-#define SND_PCM_AES2_PRO_WORDLEN_NOTID (0<<3) /* not indicated */
-#define SND_PCM_AES2_PRO_WORDLEN_22_18 (2<<3) /* 22-bit or 18-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_23_19 (4<<3) /* 23-bit or 19-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_24_20 (5<<3) /* 24-bit or 20-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_20_16 (6<<3) /* 20-bit or 16-bit */
-#define SND_PCM_AES2_CON_SOURCE (15<<0) /* mask - source number */
-#define SND_PCM_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */
-#define SND_PCM_AES2_CON_CHANNEL (15<<4) /* mask - channel number */
-#define SND_PCM_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */
-#define SND_PCM_AES3_CON_FS (15<<0) /* mask - sample frequency */
-#define SND_PCM_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */
-#define SND_PCM_AES3_CON_FS_48000 (2<<0) /* 48kHz */
-#define SND_PCM_AES3_CON_FS_32000 (3<<0) /* 32kHz */
-#define SND_PCM_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */
-#define SND_PCM_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */
-#define SND_PCM_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */
-#define SND_PCM_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch */
-
-/*
- * User interface
- */
-
-/*
- * 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
-ymf_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf;
- struct ymf_unit *unit = state->unit;
- DECLARE_WAITQUEUE(waita, current);
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt; /* This many to go in this revolution */
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- ret = 0;
-
- add_wait_queue(&dmabuf->wait, &waita);
- set_current_state(TASK_INTERRUPTIBLE);
- while (count > 0) {
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
- swptr = dmabuf->swptr;
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count < cnt)
- cnt = dmabuf->count;
- spin_unlock_irqrestore(&unit->reg_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 */
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (!state->rpcm.running) {
- ymf_capture_trigger(state->unit, &state->rpcm, 1);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- /* This isnt strictly right for the 810 but it'll do */
- tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2);
- tmo >>= state->format.shift;
- /* 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. */
- tmo = schedule_timeout(tmo);
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tmo == 0 && dmabuf->count == 0) {
- printk(KERN_ERR "ymfpci%d: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- state->unit->dev_audio,
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
-
- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
- if (!ret) ret = -EFAULT;
- break;
- }
-
- swptr = (swptr + cnt) % dmabuf->dmasize;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- continue;
- }
-
- dmabuf->swptr = swptr;
- dmabuf->count -= cnt;
- // spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- // spin_lock_irqsave(&unit->reg_lock, flags);
- if (!state->rpcm.running) {
- ymf_capture_trigger(unit, &state->rpcm, 1);
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- return ret;
-}
-
-static ssize_t
-ymf_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
- struct ymf_unit *unit = state->unit;
- DECLARE_WAITQUEUE(waita, current);
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt; /* This many to go in this revolution */
- int redzone;
- int delay;
-
- YMFDBGW("ymf_write: count %d\n", count);
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- ret = 0;
-
- /*
- * Alan's cs46xx works without a red zone - marvel of ingenuity.
- * We are not so brilliant... Red zone does two things:
- * 1. allows for safe start after a pause as we have no way
- * to know what the actual, relentlessly advancing, hwptr is.
- * 2. makes computations in ymf_pcm_interrupt simpler.
- */
- redzone = ymf_calc_lend(state->format.rate) << state->format.shift;
- redzone *= 3; /* 2 redzone + 1 possible uncertainty reserve. */
-
- add_wait_queue(&dmabuf->wait, &waita);
- set_current_state(TASK_INTERRUPTIBLE);
- while (count > 0) {
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
- if (dmabuf->count < 0) {
- printk(KERN_ERR
- "ymf_write: count %d, was legal in cs46xx\n",
- dmabuf->count);
- dmabuf->count = 0;
- }
- if (dmabuf->count == 0) {
- swptr = dmabuf->hwptr;
- if (state->wpcm.running) {
- /*
- * Add uncertainty reserve.
- */
- cnt = ymf_calc_lend(state->format.rate);
- cnt <<= state->format.shift;
- if ((swptr += cnt) >= dmabuf->dmasize) {
- swptr -= dmabuf->dmasize;
- }
- }
- dmabuf->swptr = swptr;
- } else {
- /*
- * XXX This is not right if dmabuf->count is small -
- * about 2*x frame size or less. We cannot count on
- * on appending and not causing an artefact.
- * Should use a variation of the count==0 case above.
- */
- swptr = dmabuf->swptr;
- }
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count + cnt > dmabuf->dmasize - redzone)
- cnt = (dmabuf->dmasize - redzone) - dmabuf->count;
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- YMFDBGW("ymf_write: full, count %d swptr %d\n",
- dmabuf->count, dmabuf->swptr);
- /*
- * buffer is full, start the dma machine and
- * wait for data to be played
- */
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (!state->wpcm.running) {
- ymf_playback_trigger(unit, &state->wpcm, 1);
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
- break;
- }
-
- if ((swptr += cnt) >= dmabuf->dmasize) {
- swptr -= dmabuf->dmasize;
- }
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- continue;
- }
- dmabuf->swptr = swptr;
- dmabuf->count += cnt;
-
- /*
- * Start here is a bad idea - may cause startup click
- * in /bin/play when dmabuf is not full yet.
- * However, some broken applications do not make
- * any use of SNDCTL_DSP_SYNC (Doom is the worst).
- * One frame is about 5.3ms, Doom write size is 46ms.
- */
- delay = state->format.rate / 20; /* 50ms */
- delay <<= state->format.shift;
- if (dmabuf->count >= delay && !state->wpcm.running) {
- ymf_playback_trigger(unit, &state->wpcm, 1);
- }
-
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count);
- return ret;
-}
-
-static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf;
- int redzone;
- unsigned long flags;
- unsigned int mask = 0;
-
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &state->wpcm.dmabuf.wait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &state->rpcm.dmabuf.wait, wait);
-
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (file->f_mode & FMODE_READ) {
- dmabuf = &state->rpcm.dmabuf;
- if (dmabuf->count >= (signed)dmabuf->fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= state->format.shift;
- redzone *= 3;
-
- dmabuf = &state->wpcm.dmabuf;
- if (dmabuf->mapped) {
- if (dmabuf->count >= (signed)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- /*
- * Don't select unless a full fragment is available.
- * Otherwise artsd does GETOSPACE, sees 0, and loops.
- */
- if (dmabuf->count + redzone + dmabuf->fragsize
- <= dmabuf->dmasize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-
- return mask;
-}
-
-static int ymf_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
- int ret;
- unsigned long size;
-
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(state, 0)) != 0)
- return ret;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(state, 1)) != 0)
- return ret;
- } else
- return -EINVAL;
-
- if (vma->vm_pgoff != 0)
- return -EINVAL;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << dmabuf->buforder))
- return -EINVAL;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
- dmabuf->mapped = 1;
-
-/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");
- return 0;
-}
-
-static int ymf_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int redzone;
- int val;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- switch (cmd) {
- case OSS_GETVERSION:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_RESET:
- YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = dmabuf->total_bytes = 0;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = dmabuf->total_bytes = 0;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- return 0;
-
- case SNDCTL_DSP_SYNC:
- YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
- if (file->f_mode & FMODE_WRITE) {
- dmabuf = &state->wpcm.dmabuf;
- if (file->f_flags & O_NONBLOCK) {
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (dmabuf->count != 0 && !state->wpcm.running) {
- ymf_start_dac(state);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- } else {
- ymf_wait_dac(state);
- }
- }
- /* XXX What does this do for reading? dmabuf->count=0; ? */
- return 0;
-
- case SNDCTL_DSP_SPEED: /* set smaple rate */
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
- if (val >= 8000 && val <= 48000) {
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.rate = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.rate = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- return put_user(state->format.rate, p);
-
- /*
- * OSS manual does not mention SNDCTL_DSP_STEREO at all.
- * All channels are mono and if you want stereo, you
- * play into two channels with SNDCTL_DSP_CHANNELS.
- * However, mpg123 calls it. I wonder, why Michael Hipp used it.
- */
- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.voices = val ? 2 : 1;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.voices = val ? 2 : 1;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(state, 0)))
- return val;
- val = state->wpcm.dmabuf.fragsize;
- YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
- return put_user(val, p);
- }
- if (file->f_mode & FMODE_READ) {
- if ((val = prog_dmabuf(state, 1)))
- return val;
- val = state->rpcm.dmabuf.fragsize;
- YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
- return put_user(val, p);
- }
- return -EINVAL;
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Select sample format */
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
- if (val == AFMT_S16_LE || val == AFMT_U8) {
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.format = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.format = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- return put_user(state->format.format, p);
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
- if (val != 0) {
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- if (val == 1 || val == 2) {
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf = &state->wpcm.dmabuf;
- dmabuf->ready = 0;
- state->format.voices = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- if (val == 1 || val == 2) {
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf = &state->rpcm.dmabuf;
- dmabuf->ready = 0;
- state->format.voices = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- }
- return put_user(state->format.voices, p);
-
- case SNDCTL_DSP_POST:
- YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
- /*
- * Quoting OSS PG:
- * The ioctl SNDCTL_DSP_POST is a lightweight version of
- * SNDCTL_DSP_SYNC. It just tells to the driver that there
- * is likely to be a pause in the output. This makes it
- * possible for the device to handle the pause more
- * intelligently. This ioctl doesn't block the application.
- *
- * The paragraph above is a clumsy way to say "flush ioctl".
- * This ioctl is used by mpg123.
- */
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) {
- ymf_start_dac(state);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
- cmd,
- (val >> 16) & 0xFFFF, val & 0xFFFF,
- (val >> 16) & 0xFFFF, val & 0xFFFF);
- dmabuf = &state->wpcm.dmabuf;
- dmabuf->ossfragshift = val & 0xffff;
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- if (dmabuf->ossfragshift < 4)
- dmabuf->ossfragshift = 4;
- if (dmabuf->ossfragshift > 15)
- dmabuf->ossfragshift = 15;
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- dmabuf = &state->wpcm.dmabuf;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= state->format.shift;
- redzone *= 3;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
- abinfo.fragstotal = dmabuf->numfrag;
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- dmabuf = &state->rpcm.dmabuf;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
- return val;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->count;
- abinfo.fragstotal = dmabuf->numfrag;
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
- /* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
- p); */
- return put_user(0, p);
-
- case SNDCTL_DSP_GETIPTR:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
- cinfo.ptr = dmabuf->hwptr;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
- cinfo.ptr, cinfo.bytes);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
- cinfo.ptr = dmabuf->hwptr;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
- cinfo.ptr, cinfo.bytes);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
- return 0; /* Always duplex */
-
- case SOUND_PCM_READ_RATE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
- return put_user(state->format.rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
- return put_user(state->format.voices, p);
-
- case SOUND_PCM_READ_BITS:
- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd);
- return -ENOTTY;
-
- default:
- /*
- * Some programs mix up audio devices and ioctls
- * or perhaps they expect "universal" ioctls,
- * for instance we get SNDCTL_TMR_CONTINUE here.
- * (mpg123 -g 100 ends here too - to be fixed.)
- */
- YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
- break;
- }
- return -ENOTTY;
-}
-
-/*
- * open(2)
- * We use upper part of the minor to distinguish between soundcards.
- * Channels are opened with a clone open.
- */
-static int ymf_open(struct inode *inode, struct file *file)
-{
- struct list_head *list;
- ymfpci_t *unit = NULL;
- int minor;
- struct ymf_state *state;
- int err;
-
- minor = iminor(inode);
- if ((minor & 0x0F) == 3) { /* /dev/dspN */
- ;
- } else {
- return -ENXIO;
- }
-
- unit = NULL; /* gcc warns */
- spin_lock(&ymf_devs_lock);
- list_for_each(list, &ymf_devs) {
- unit = list_entry(list, ymfpci_t, ymf_devs);
- if (((unit->dev_audio ^ minor) & ~0x0F) == 0)
- break;
- }
- spin_unlock(&ymf_devs_lock);
- if (unit == NULL)
- return -ENODEV;
-
- mutex_lock(&unit->open_mutex);
-
- if ((state = ymf_state_alloc(unit)) == NULL) {
- mutex_unlock(&unit->open_mutex);
- return -ENOMEM;
- }
- list_add_tail(&state->chain, &unit->states);
-
- file->private_data = state;
-
- /*
- * ymf_read and ymf_write that we borrowed from cs46xx
- * allocate buffers with prog_dmabuf(). We call prog_dmabuf
- * here so that in case of DMA memory exhaustion open
- * fails rather than write.
- *
- * XXX prog_dmabuf allocates voice. Should allocate explicitly, above.
- */
- if (file->f_mode & FMODE_WRITE) {
- if (!state->wpcm.dmabuf.ready) {
- if ((err = prog_dmabuf(state, 0)) != 0) {
- goto out_nodma;
- }
- }
- }
- if (file->f_mode & FMODE_READ) {
- if (!state->rpcm.dmabuf.ready) {
- if ((err = prog_dmabuf(state, 1)) != 0) {
- goto out_nodma;
- }
- }
- }
-
-#if 0 /* test if interrupts work */
- ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
- ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
- (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
-#endif
- mutex_unlock(&unit->open_mutex);
-
- return nonseekable_open(inode, file);
-
-out_nodma:
- /*
- * XXX Broken custom: "goto out_xxx" in other place is
- * a nestable exception, but here it is not nestable due to semaphore.
- * XXX Doubtful technique of self-describing objects....
- */
- dealloc_dmabuf(unit, &state->wpcm.dmabuf);
- dealloc_dmabuf(unit, &state->rpcm.dmabuf);
- ymf_pcm_free_substream(&state->wpcm);
- ymf_pcm_free_substream(&state->rpcm);
-
- list_del(&state->chain);
- kfree(state);
-
- mutex_unlock(&unit->open_mutex);
- return err;
-}
-
-static int ymf_release(struct inode *inode, struct file *file)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- ymfpci_t *unit = state->unit;
-
-#if 0 /* test if interrupts work */
- ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
-#endif
-
- mutex_lock(&unit->open_mutex);
-
- /*
- * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
- * Deallocate when unloading the driver and we can wait.
- */
- ymf_wait_dac(state);
- ymf_stop_adc(state); /* fortunately, it's immediate */
- dealloc_dmabuf(unit, &state->wpcm.dmabuf);
- dealloc_dmabuf(unit, &state->rpcm.dmabuf);
- ymf_pcm_free_substream(&state->wpcm);
- ymf_pcm_free_substream(&state->rpcm);
-
- list_del(&state->chain);
- file->private_data = NULL; /* Can you tell I programmed Solaris */
- kfree(state);
-
- mutex_unlock(&unit->open_mutex);
-
- return 0;
-}
-
-/*
- * Mixer operations are based on cs46xx.
- */
-static int ymf_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- ymfpci_t *unit;
- int i;
-
- spin_lock(&ymf_devs_lock);
- list_for_each(list, &ymf_devs) {
- unit = list_entry(list, ymfpci_t, ymf_devs);
- for (i = 0; i < NR_AC97; i++) {
- if (unit->ac97_codec[i] != NULL &&
- unit->ac97_codec[i]->dev_mixer == minor) {
- spin_unlock(&ymf_devs_lock);
- goto match;
- }
- }
- }
- spin_unlock(&ymf_devs_lock);
- return -ENODEV;
-
- match:
- file->private_data = unit->ac97_codec[i];
-
- return nonseekable_open(inode, file);
-}
-
-static int ymf_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 int ymf_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static /*const*/ struct file_operations ymf_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ymf_read,
- .write = ymf_write,
- .poll = ymf_poll,
- .ioctl = ymf_ioctl,
- .mmap = ymf_mmap,
- .open = ymf_open,
- .release = ymf_release,
-};
-
-static /*const*/ struct file_operations ymf_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = ymf_ioctl_mixdev,
- .open = ymf_open_mixdev,
- .release = ymf_release_mixdev,
-};
-
-/*
- */
-
-static int ymf_suspend(struct pci_dev *pcidev, pm_message_t unused)
-{
- struct ymf_unit *unit = pci_get_drvdata(pcidev);
- unsigned long flags;
- struct ymf_dmabuf *dmabuf;
- struct list_head *p;
- struct ymf_state *state;
- struct ac97_codec *codec;
- int i;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
-
- unit->suspended = 1;
-
- for (i = 0; i < NR_AC97; i++) {
- if ((codec = unit->ac97_codec[i]) != NULL)
- ac97_save_state(codec);
- }
-
- list_for_each(p, &unit->states) {
- state = list_entry(p, struct ymf_state, chain);
-
- dmabuf = &state->wpcm.dmabuf;
- dmabuf->hwptr = dmabuf->swptr = 0;
- dmabuf->total_bytes = 0;
- dmabuf->count = 0;
-
- dmabuf = &state->rpcm.dmabuf;
- dmabuf->hwptr = dmabuf->swptr = 0;
- dmabuf->total_bytes = 0;
- dmabuf->count = 0;
- }
-
- ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0);
- ymfpci_disable_dsp(unit);
-
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- return 0;
-}
-
-static int ymf_resume(struct pci_dev *pcidev)
-{
- struct ymf_unit *unit = pci_get_drvdata(pcidev);
- unsigned long flags;
- struct list_head *p;
- struct ymf_state *state;
- struct ac97_codec *codec;
- int i;
-
- ymfpci_aclink_reset(unit->pci);
- ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- /* XXX At this time the legacy registers are probably deprogrammed. */
-#endif
-
- ymfpci_download_image(unit);
-
- ymf_memload(unit);
-
- spin_lock_irqsave(&unit->reg_lock, flags);
-
- if (unit->start_count) {
- ymfpci_writel(unit, YDSXGR_MODE, 3);
- unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
- }
-
- for (i = 0; i < NR_AC97; i++) {
- if ((codec = unit->ac97_codec[i]) != NULL)
- ac97_restore_state(codec);
- }
-
- unit->suspended = 0;
- list_for_each(p, &unit->states) {
- state = list_entry(p, struct ymf_state, chain);
- wake_up(&state->wpcm.dmabuf.wait);
- wake_up(&state->rpcm.dmabuf.wait);
- }
-
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- return 0;
-}
-
-/*
- * initialization routines
- */
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-
-static int ymfpci_setup_legacy(ymfpci_t *unit, struct pci_dev *pcidev)
-{
- int v;
- int mpuio = -1, oplio = -1;
-
- switch (unit->iomidi) {
- case 0x330:
- mpuio = 0;
- break;
- case 0x300:
- mpuio = 1;
- break;
- case 0x332:
- mpuio = 2;
- break;
- case 0x334:
- mpuio = 3;
- break;
- default: ;
- }
-
- switch (unit->iosynth) {
- case 0x388:
- oplio = 0;
- break;
- case 0x398:
- oplio = 1;
- break;
- case 0x3a0:
- oplio = 2;
- break;
- case 0x3a8:
- oplio = 3;
- break;
- default: ;
- }
-
- if (mpuio >= 0 || oplio >= 0) {
- /* 0x0020: 1 - 10 bits of I/O address decoded, 0 - 16 bits. */
- v = 0x001e;
- pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
-
- switch (pcidev->device) {
- case PCI_DEVICE_ID_YAMAHA_724:
- case PCI_DEVICE_ID_YAMAHA_740:
- case PCI_DEVICE_ID_YAMAHA_724F:
- case PCI_DEVICE_ID_YAMAHA_740C:
- v = 0x8800;
- if (mpuio >= 0) { v |= mpuio<<4; }
- if (oplio >= 0) { v |= oplio; }
- pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
- break;
-
- case PCI_DEVICE_ID_YAMAHA_744:
- case PCI_DEVICE_ID_YAMAHA_754:
- v = 0x8800;
- pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
- if (oplio >= 0) {
- pci_write_config_word(pcidev, PCIR_OPLADR, unit->iosynth);
- }
- if (mpuio >= 0) {
- pci_write_config_word(pcidev, PCIR_MPUADR, unit->iomidi);
- }
- break;
-
- default:
- printk(KERN_ERR "ymfpci: Unknown device ID: 0x%x\n",
- pcidev->device);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
-static void ymfpci_aclink_reset(struct pci_dev * pci)
-{
- u8 cmd;
-
- /*
- * In the 744, 754 only 0x01 exists, 0x02 is undefined.
- * It does not seem to hurt to trip both regardless of revision.
- */
- pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-
- pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
- pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
-}
-
-static void ymfpci_enable_dsp(ymfpci_t *codec)
-{
- ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000001);
-}
-
-static void ymfpci_disable_dsp(ymfpci_t *codec)
-{
- u32 val;
- int timeout = 1000;
-
- val = ymfpci_readl(codec, YDSXGR_CONFIG);
- if (val)
- ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000);
- while (timeout-- > 0) {
- val = ymfpci_readl(codec, YDSXGR_STATUS);
- if ((val & 0x00000002) == 0)
- break;
- }
-}
-
-#include "ymfpci_image.h"
-
-static void ymfpci_download_image(ymfpci_t *codec)
-{
- int i, ver_1e;
- u16 ctrl;
-
- ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
- ymfpci_disable_dsp(codec);
- ymfpci_writel(codec, YDSXGR_MODE, 0x00010000);
- ymfpci_writel(codec, YDSXGR_MODE, 0x00000000);
- ymfpci_writel(codec, YDSXGR_MAPOFREC, 0x00000000);
- ymfpci_writel(codec, YDSXGR_MAPOFEFFECT, 0x00000000);
- ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0x00000000);
- ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0x00000000);
- ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0x00000000);
- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
-
- /* setup DSP instruction code */
- for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
- ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
-
- switch (codec->pci->device) {
- case PCI_DEVICE_ID_YAMAHA_724F:
- case PCI_DEVICE_ID_YAMAHA_740C:
- case PCI_DEVICE_ID_YAMAHA_744:
- case PCI_DEVICE_ID_YAMAHA_754:
- ver_1e = 1;
- break;
- default:
- ver_1e = 0;
- }
-
- if (ver_1e) {
- /* setup control instruction code */
- for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
- ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]);
- } else {
- for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
- ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]);
- }
-
- ymfpci_enable_dsp(codec);
-
- /* 0.02s sounds not too bad, we may do schedule_timeout() later. */
- mdelay(20); /* seems we need some delay after downloading image.. */
-}
-
-static int ymfpci_memalloc(ymfpci_t *codec)
-{
- unsigned int playback_ctrl_size;
- unsigned int bank_size_playback;
- unsigned int bank_size_capture;
- unsigned int bank_size_effect;
- unsigned int size;
- unsigned int off;
- char *ptr;
- dma_addr_t pba;
- int voice, bank;
-
- playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
- bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
- bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
- bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
- codec->work_size = YDSXG_DEFAULT_WORK_SIZE;
-
- size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
- ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
- ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
- ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
- codec->work_size;
-
- ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba);
- if (ptr == NULL)
- return -ENOMEM;
- codec->dma_area_va = ptr;
- codec->dma_area_ba = pba;
- codec->dma_area_size = size + 0xff;
-
- off = (unsigned long)ptr & 0xff;
- if (off) {
- ptr += 0x100 - off;
- pba += 0x100 - off;
- }
-
- /*
- * Hardware requires only ptr[playback_ctrl_size] zeroed,
- * but in our judgement it is a wrong kind of savings, so clear it all.
- */
- memset(ptr, 0, size);
-
- codec->ctrl_playback = (u32 *)ptr;
- codec->ctrl_playback_ba = pba;
- codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
- ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
- pba += (playback_ctrl_size + 0x00ff) & ~0x00ff;
-
- off = 0;
- for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
- codec->voices[voice].number = voice;
- codec->voices[voice].bank =
- (ymfpci_playback_bank_t *) (ptr + off);
- codec->voices[voice].bank_ba = pba + off;
- off += 2 * bank_size_playback; /* 2 banks */
- }
- off = (off + 0xff) & ~0xff;
- ptr += off;
- pba += off;
-
- off = 0;
- codec->bank_base_capture = pba;
- for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
- for (bank = 0; bank < 2; bank++) {
- codec->bank_capture[voice][bank] =
- (ymfpci_capture_bank_t *) (ptr + off);
- off += bank_size_capture;
- }
- off = (off + 0xff) & ~0xff;
- ptr += off;
- pba += off;
-
- off = 0;
- codec->bank_base_effect = pba;
- for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
- for (bank = 0; bank < 2; bank++) {
- codec->bank_effect[voice][bank] =
- (ymfpci_effect_bank_t *) (ptr + off);
- off += bank_size_effect;
- }
- off = (off + 0xff) & ~0xff;
- ptr += off;
- pba += off;
-
- codec->work_base = pba;
-
- return 0;
-}
-
-static void ymfpci_memfree(ymfpci_t *codec)
-{
- ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0);
- ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0);
- ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);
- ymfpci_writel(codec, YDSXGR_WORKBASE, 0);
- ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);
- pci_free_consistent(codec->pci,
- codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba);
-}
-
-static void ymf_memload(ymfpci_t *unit)
-{
-
- ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba);
- ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture);
- ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect);
- ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base);
- ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
-
- /* S/PDIF output initialization */
- ymfpci_writew(unit, YDSXGR_SPDIFOUTCTRL, 0);
- ymfpci_writew(unit, YDSXGR_SPDIFOUTSTATUS,
- SND_PCM_AES0_CON_EMPHASIS_NONE |
- (SND_PCM_AES1_CON_ORIGINAL << 8) |
- (SND_PCM_AES1_CON_PCM_CODER << 8));
-
- /* S/PDIF input initialization */
- ymfpci_writew(unit, YDSXGR_SPDIFINCTRL, 0);
-
- /* move this volume setup to mixer */
- ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
- ymfpci_writel(unit, YDSXGR_BUF441OUTVOL, 0);
- ymfpci_writel(unit, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
- ymfpci_writel(unit, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
-}
-
-static int ymf_ac97_init(ymfpci_t *unit, int num_ac97)
-{
- struct ac97_codec *codec;
- u16 eid;
-
- 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 = unit;
- codec->id = num_ac97;
-
- codec->codec_read = ymfpci_codec_read;
- codec->codec_write = ymfpci_codec_write;
-
- if (ac97_probe_codec(codec) == 0) {
- printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
- goto out_kfree;
- }
-
- eid = ymfpci_codec_read(codec, AC97_EXTENDED_ID);
- if (eid==0xFFFF) {
- printk(KERN_WARNING "ymfpci: no codec attached ?\n");
- goto out_kfree;
- }
-
- unit->ac97_features = eid;
-
- if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "ymfpci: couldn't register mixer!\n");
- goto out_kfree;
- }
-
- unit->ac97_codec[num_ac97] = codec;
-
- return 0;
- out_kfree:
- ac97_release_codec(codec);
- return -ENODEV;
-}
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-# ifdef MODULE
-static int mpu_io;
-static int synth_io;
-module_param(mpu_io, int, 0);
-module_param(synth_io, int, 0);
-# else
-static int mpu_io = 0x330;
-static int synth_io = 0x388;
-# endif
-static int assigned;
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
-static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
-{
- u16 ctrl;
- unsigned long base;
- ymfpci_t *codec;
-
- int err;
-
- if ((err = pci_enable_device(pcidev)) != 0) {
- printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
- return err;
- }
- base = pci_resource_start(pcidev, 0);
-
- if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "ymfpci: no core\n");
- return -ENOMEM;
- }
- memset(codec, 0, sizeof(*codec));
-
- spin_lock_init(&codec->reg_lock);
- spin_lock_init(&codec->voice_lock);
- spin_lock_init(&codec->ac97_lock);
- mutex_init(&codec->open_mutex);
- INIT_LIST_HEAD(&codec->states);
- codec->pci = pcidev;
-
- pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
-
- if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
- printk(KERN_ERR "ymfpci: unable to request mem region\n");
- goto out_free;
- }
-
- if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
- printk(KERN_ERR "ymfpci: unable to map registers\n");
- goto out_release_region;
- }
-
- pci_set_master(pcidev);
-
- printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
- (char *)ent->driver_data, base, pcidev->irq);
-
- ymfpci_aclink_reset(pcidev);
- if (ymfpci_codec_ready(codec, 0, 1) < 0)
- goto out_unmap;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- if (assigned == 0) {
- codec->iomidi = mpu_io;
- codec->iosynth = synth_io;
- if (ymfpci_setup_legacy(codec, pcidev) < 0)
- goto out_unmap;
- assigned = 1;
- }
-#endif
-
- ymfpci_download_image(codec);
-
- if (ymfpci_memalloc(codec) < 0)
- goto out_disable_dsp;
- ymf_memload(codec);
-
- if (request_irq(pcidev->irq, ymf_interrupt, IRQF_SHARED, "ymfpci", codec) != 0) {
- printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
- pcidev->irq);
- goto out_memfree;
- }
-
- /* register /dev/dsp */
- if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
- printk(KERN_ERR "ymfpci: unable to register dsp\n");
- goto out_free_irq;
- }
-
- /*
- * Poke just the primary for the moment.
- */
- if ((err = ymf_ac97_init(codec, 0)) != 0)
- goto out_unregister_sound_dsp;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- codec->opl3_data.name = "ymfpci";
- codec->mpu_data.name = "ymfpci";
-
- codec->opl3_data.io_base = codec->iosynth;
- codec->opl3_data.irq = -1;
-
- codec->mpu_data.io_base = codec->iomidi;
- codec->mpu_data.irq = -1; /* May be different from our PCI IRQ. */
-
- if (codec->iomidi) {
- if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
- codec->iomidi = 0; /* XXX kludge */
- }
- }
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
- /* put it into driver list */
- spin_lock(&ymf_devs_lock);
- list_add_tail(&codec->ymf_devs, &ymf_devs);
- spin_unlock(&ymf_devs_lock);
- pci_set_drvdata(pcidev, codec);
-
- return 0;
-
- out_unregister_sound_dsp:
- unregister_sound_dsp(codec->dev_audio);
- out_free_irq:
- free_irq(pcidev->irq, codec);
- out_memfree:
- ymfpci_memfree(codec);
- out_disable_dsp:
- ymfpci_disable_dsp(codec);
- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
- ymfpci_writel(codec, YDSXGR_STATUS, ~0);
- out_unmap:
- iounmap(codec->reg_area_virt);
- out_release_region:
- release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
- out_free:
- if (codec->ac97_codec[0])
- ac97_release_codec(codec->ac97_codec[0]);
- return -ENODEV;
-}
-
-static void __devexit ymf_remove_one(struct pci_dev *pcidev)
-{
- __u16 ctrl;
- ymfpci_t *codec = pci_get_drvdata(pcidev);
-
- /* remove from list of devices */
- spin_lock(&ymf_devs_lock);
- list_del(&codec->ymf_devs);
- spin_unlock(&ymf_devs_lock);
-
- unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer);
- ac97_release_codec(codec->ac97_codec[0]);
- unregister_sound_dsp(codec->dev_audio);
- free_irq(pcidev->irq, codec);
- ymfpci_memfree(codec);
- ymfpci_writel(codec, YDSXGR_STATUS, ~0);
- ymfpci_disable_dsp(codec);
- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
- iounmap(codec->reg_area_virt);
- release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- if (codec->iomidi) {
- unload_uart401(&codec->mpu_data);
- }
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-}
-
-MODULE_AUTHOR("Jaroslav Kysela");
-MODULE_DESCRIPTION("Yamaha YMF7xx PCI Audio");
-MODULE_LICENSE("GPL");
-
-static struct pci_driver ymfpci_driver = {
- .name = "ymfpci",
- .id_table = ymf_id_tbl,
- .probe = ymf_probe_one,
- .remove = __devexit_p(ymf_remove_one),
- .suspend = ymf_suspend,
- .resume = ymf_resume
-};
-
-static int __init ymf_init_module(void)
-{
- return pci_register_driver(&ymfpci_driver);
-}
-
-static void __exit ymf_cleanup_module (void)
-{
- pci_unregister_driver(&ymfpci_driver);
-}
-
-module_init(ymf_init_module);
-module_exit(ymf_cleanup_module);
diff --git a/sound/oss/ymfpci.h b/sound/oss/ymfpci.h
deleted file mode 100644
index ac1785f..0000000
--- a/sound/oss/ymfpci.h
+++ /dev/null
@@ -1,361 +0,0 @@
-#ifndef __YMFPCI_H
-#define __YMFPCI_H
-
-/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- * Definitions for Yahama YMF724/740/744/754 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.
- *
- */
-#include <linux/config.h>
-#include <linux/mutex.h>
-
-/*
- * Direct registers
- */
-
-/* #define YMFREG(codec, reg) (codec->port + YDSXGR_##reg) */
-
-#define YDSXGR_INTFLAG 0x0004
-#define YDSXGR_ACTIVITY 0x0006
-#define YDSXGR_GLOBALCTRL 0x0008
-#define YDSXGR_ZVCTRL 0x000A
-#define YDSXGR_TIMERCTRL 0x0010
-#define YDSXGR_TIMERCTRL_TEN 0x0001
-#define YDSXGR_TIMERCTRL_TIEN 0x0002
-#define YDSXGR_TIMERCOUNT 0x0012
-#define YDSXGR_SPDIFOUTCTRL 0x0018
-#define YDSXGR_SPDIFOUTSTATUS 0x001C
-#define YDSXGR_EEPROMCTRL 0x0020
-#define YDSXGR_SPDIFINCTRL 0x0034
-#define YDSXGR_SPDIFINSTATUS 0x0038
-#define YDSXGR_DSPPROGRAMDL 0x0048
-#define YDSXGR_DLCNTRL 0x004C
-#define YDSXGR_GPIOININTFLAG 0x0050
-#define YDSXGR_GPIOININTENABLE 0x0052
-#define YDSXGR_GPIOINSTATUS 0x0054
-#define YDSXGR_GPIOOUTCTRL 0x0056
-#define YDSXGR_GPIOFUNCENABLE 0x0058
-#define YDSXGR_GPIOTYPECONFIG 0x005A
-#define YDSXGR_AC97CMDDATA 0x0060
-#define YDSXGR_AC97CMDADR 0x0062
-#define YDSXGR_PRISTATUSDATA 0x0064
-#define YDSXGR_PRISTATUSADR 0x0066
-#define YDSXGR_SECSTATUSDATA 0x0068
-#define YDSXGR_SECSTATUSADR 0x006A
-#define YDSXGR_SECCONFIG 0x0070
-#define YDSXGR_LEGACYOUTVOL 0x0080
-#define YDSXGR_LEGACYOUTVOLL 0x0080
-#define YDSXGR_LEGACYOUTVOLR 0x0082
-#define YDSXGR_NATIVEDACOUTVOL 0x0084
-#define YDSXGR_NATIVEDACOUTVOLL 0x0084
-#define YDSXGR_NATIVEDACOUTVOLR 0x0086
-#define YDSXGR_SPDIFOUTVOL 0x0088
-#define YDSXGR_SPDIFOUTVOLL 0x0088
-#define YDSXGR_SPDIFOUTVOLR 0x008A
-#define YDSXGR_AC3OUTVOL 0x008C
-#define YDSXGR_AC3OUTVOLL 0x008C
-#define YDSXGR_AC3OUTVOLR 0x008E
-#define YDSXGR_PRIADCOUTVOL 0x0090
-#define YDSXGR_PRIADCOUTVOLL 0x0090
-#define YDSXGR_PRIADCOUTVOLR 0x0092
-#define YDSXGR_LEGACYLOOPVOL 0x0094
-#define YDSXGR_LEGACYLOOPVOLL 0x0094
-#define YDSXGR_LEGACYLOOPVOLR 0x0096
-#define YDSXGR_NATIVEDACLOOPVOL 0x0098
-#define YDSXGR_NATIVEDACLOOPVOLL 0x0098
-#define YDSXGR_NATIVEDACLOOPVOLR 0x009A
-#define YDSXGR_SPDIFLOOPVOL 0x009C
-#define YDSXGR_SPDIFLOOPVOLL 0x009E
-#define YDSXGR_SPDIFLOOPVOLR 0x009E
-#define YDSXGR_AC3LOOPVOL 0x00A0
-#define YDSXGR_AC3LOOPVOLL 0x00A0
-#define YDSXGR_AC3LOOPVOLR 0x00A2
-#define YDSXGR_PRIADCLOOPVOL 0x00A4
-#define YDSXGR_PRIADCLOOPVOLL 0x00A4
-#define YDSXGR_PRIADCLOOPVOLR 0x00A6
-#define YDSXGR_NATIVEADCINVOL 0x00A8
-#define YDSXGR_NATIVEADCINVOLL 0x00A8
-#define YDSXGR_NATIVEADCINVOLR 0x00AA
-#define YDSXGR_NATIVEDACINVOL 0x00AC
-#define YDSXGR_NATIVEDACINVOLL 0x00AC
-#define YDSXGR_NATIVEDACINVOLR 0x00AE
-#define YDSXGR_BUF441OUTVOL 0x00B0
-#define YDSXGR_BUF441OUTVOLL 0x00B0
-#define YDSXGR_BUF441OUTVOLR 0x00B2
-#define YDSXGR_BUF441LOOPVOL 0x00B4
-#define YDSXGR_BUF441LOOPVOLL 0x00B4
-#define YDSXGR_BUF441LOOPVOLR 0x00B6
-#define YDSXGR_SPDIFOUTVOL2 0x00B8
-#define YDSXGR_SPDIFOUTVOL2L 0x00B8
-#define YDSXGR_SPDIFOUTVOL2R 0x00BA
-#define YDSXGR_SPDIFLOOPVOL2 0x00BC
-#define YDSXGR_SPDIFLOOPVOL2L 0x00BC
-#define YDSXGR_SPDIFLOOPVOL2R 0x00BE
-#define YDSXGR_ADCSLOTSR 0x00C0
-#define YDSXGR_RECSLOTSR 0x00C4
-#define YDSXGR_ADCFORMAT 0x00C8
-#define YDSXGR_RECFORMAT 0x00CC
-#define YDSXGR_P44SLOTSR 0x00D0
-#define YDSXGR_STATUS 0x0100
-#define YDSXGR_CTRLSELECT 0x0104
-#define YDSXGR_MODE 0x0108
-#define YDSXGR_SAMPLECOUNT 0x010C
-#define YDSXGR_NUMOFSAMPLES 0x0110
-#define YDSXGR_CONFIG 0x0114
-#define YDSXGR_PLAYCTRLSIZE 0x0140
-#define YDSXGR_RECCTRLSIZE 0x0144
-#define YDSXGR_EFFCTRLSIZE 0x0148
-#define YDSXGR_WORKSIZE 0x014C
-#define YDSXGR_MAPOFREC 0x0150
-#define YDSXGR_MAPOFEFFECT 0x0154
-#define YDSXGR_PLAYCTRLBASE 0x0158
-#define YDSXGR_RECCTRLBASE 0x015C
-#define YDSXGR_EFFCTRLBASE 0x0160
-#define YDSXGR_WORKBASE 0x0164
-#define YDSXGR_DSPINSTRAM 0x1000
-#define YDSXGR_CTRLINSTRAM 0x4000
-
-#define YDSXG_AC97READCMD 0x8000
-#define YDSXG_AC97WRITECMD 0x0000
-
-#define PCIR_LEGCTRL 0x40
-#define PCIR_ELEGCTRL 0x42
-#define PCIR_DSXGCTRL 0x48
-#define PCIR_DSXPWRCTRL1 0x4a
-#define PCIR_DSXPWRCTRL2 0x4e
-#define PCIR_OPLADR 0x60
-#define PCIR_SBADR 0x62
-#define PCIR_MPUADR 0x64
-
-#define YDSXG_DSPLENGTH 0x0080
-#define YDSXG_CTRLLENGTH 0x3000
-
-#define YDSXG_DEFAULT_WORK_SIZE 0x0400
-
-#define YDSXG_PLAYBACK_VOICES 64
-#define YDSXG_CAPTURE_VOICES 2
-#define YDSXG_EFFECT_VOICES 5
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 2
-
-#define YMF_SAMPF 256 /* Samples per frame @48000 */
-
-/*
- * The slot/voice control bank (2 of these per voice)
- */
-
-typedef struct stru_ymfpci_playback_bank {
- u32 format;
- u32 loop_default;
- u32 base; /* 32-bit address */
- u32 loop_start; /* 32-bit offset */
- u32 loop_end; /* 32-bit offset */
- u32 loop_frac; /* 8-bit fraction - loop_start */
- u32 delta_end; /* pitch delta end */
- u32 lpfK_end;
- u32 eg_gain_end;
- u32 left_gain_end;
- u32 right_gain_end;
- u32 eff1_gain_end;
- u32 eff2_gain_end;
- u32 eff3_gain_end;
- u32 lpfQ;
- u32 status; /* P3: Always 0 for some reason. */
- u32 num_of_frames;
- u32 loop_count;
- u32 start; /* P3: J. reads this to know where chip is. */
- u32 start_frac;
- u32 delta;
- u32 lpfK;
- u32 eg_gain;
- u32 left_gain;
- u32 right_gain;
- u32 eff1_gain;
- u32 eff2_gain;
- u32 eff3_gain;
- u32 lpfD1;
- u32 lpfD2;
-} ymfpci_playback_bank_t;
-
-typedef struct stru_ymfpci_capture_bank {
- u32 base; /* 32-bit address (aligned at 4) */
- u32 loop_end; /* size in BYTES (aligned at 4) */
- u32 start; /* 32-bit offset */
- u32 num_of_loops; /* counter */
-} ymfpci_capture_bank_t;
-
-typedef struct stru_ymfpci_effect_bank {
- u32 base; /* 32-bit address */
- u32 loop_end; /* 32-bit offset */
- u32 start; /* 32-bit offset */
- u32 temp;
-} ymfpci_effect_bank_t;
-
-typedef struct ymf_voice ymfpci_voice_t;
-/*
- * Throughout the code Yaroslav names YMF unit pointer "codec"
- * even though it does not correspond to any codec. Must be historic.
- * We replace it with "unit" over time.
- * AC97 parts use "codec" to denote a codec, naturally.
- */
-typedef struct ymf_unit ymfpci_t;
-
-typedef enum {
- YMFPCI_PCM,
- YMFPCI_SYNTH,
- YMFPCI_MIDI
-} ymfpci_voice_type_t;
-
-struct ymf_voice {
- // ymfpci_t *codec;
- int number;
- char use, pcm, synth, midi; // bool
- ymfpci_playback_bank_t *bank;
- struct ymf_pcm *ypcm;
- dma_addr_t bank_ba;
-};
-
-struct ymf_capture {
- // struct ymf_unit *unit;
- int use;
- ymfpci_capture_bank_t *bank;
- struct ymf_pcm *ypcm;
-};
-
-struct ymf_unit {
- u8 rev; /* PCI revision */
- void __iomem *reg_area_virt;
- void *dma_area_va;
- dma_addr_t dma_area_ba;
- unsigned int dma_area_size;
-
- dma_addr_t bank_base_capture;
- dma_addr_t bank_base_effect;
- dma_addr_t work_base;
- unsigned int work_size;
-
- u32 *ctrl_playback;
- dma_addr_t ctrl_playback_ba;
- ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
- ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2];
- ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
-
- int start_count;
- int suspended;
-
- u32 active_bank;
- struct ymf_voice voices[YDSXG_PLAYBACK_VOICES];
- struct ymf_capture capture[YDSXG_CAPTURE_VOICES];
-
- struct ac97_codec *ac97_codec[NR_AC97];
- u16 ac97_features;
-
- struct pci_dev *pci;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- /* legacy hardware resources */
- unsigned int iosynth, iomidi;
- struct address_info opl3_data, mpu_data;
-#endif
-
- spinlock_t reg_lock;
- spinlock_t voice_lock;
- spinlock_t ac97_lock;
-
- /* soundcore stuff */
- int dev_audio;
- struct mutex open_mutex;
-
- struct list_head ymf_devs;
- struct list_head states; /* List of states for this unit */
-};
-
-struct ymf_dmabuf {
- dma_addr_t dma_addr;
- void *rawbuf;
- unsigned buforder;
-
- /* OSS buffer management stuff */
- unsigned numfrag;
- unsigned fragshift;
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started */
- unsigned swptr; /* where driver last clear/filled */
- int count; /* fill count */
- unsigned total_bytes; /* total bytes dmaed by hardware */
-
- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize; /* Total rawbuf[] size */
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
-};
-
-struct ymf_pcm_format {
- int format; /* OSS format */
- int rate; /* rate in Hz */
- int voices; /* number of voices */
- int shift; /* redundant, computed from the above */
-};
-
-typedef enum {
- PLAYBACK_VOICE,
- CAPTURE_REC,
- CAPTURE_AC97,
- EFFECT_DRY_LEFT,
- EFFECT_DRY_RIGHT,
- EFFECT_EFF1,
- EFFECT_EFF2,
- EFFECT_EFF3
-} ymfpci_pcm_type_t;
-
-/* This is variant record, but we hate unions. Little waste on pointers []. */
-struct ymf_pcm {
- ymfpci_pcm_type_t type;
- struct ymf_state *state;
-
- ymfpci_voice_t *voices[2];
- int capture_bank_number;
-
- struct ymf_dmabuf dmabuf;
- int running;
- int spdif;
-};
-
-/*
- * "Software" or virtual channel, an instance of opened /dev/dsp.
- * It may have two physical channels (pcms) for duplex operations.
- */
-
-struct ymf_state {
- struct list_head chain;
- struct ymf_unit *unit; /* backpointer */
- struct ymf_pcm rpcm, wpcm;
- struct ymf_pcm_format format;
-};
-
-#endif /* __YMFPCI_H */
diff --git a/sound/oss/ymfpci_image.h b/sound/oss/ymfpci_image.h
deleted file mode 100644
index 112f2ff..0000000
--- a/sound/oss/ymfpci_image.h
+++ /dev/null
@@ -1,1565 +0,0 @@
-#ifndef _HWMCODE_
-#define _HWMCODE_
-
-static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
- 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
- 0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
- 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
- 0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-
-static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
- 0x000007, 0x240007, 0x0C0007, 0x1C0007,
- 0x060007, 0x700002, 0x000020, 0x030040,
- 0x007104, 0x004286, 0x030040, 0x000F0D,
- 0x000810, 0x20043A, 0x000282, 0x00020D,
- 0x000810, 0x20043A, 0x001282, 0x200E82,
- 0x001A82, 0x032D0D, 0x000810, 0x10043A,
- 0x02D38D, 0x000810, 0x18043A, 0x00010D,
- 0x020015, 0x0000FD, 0x000020, 0x038860,
- 0x039060, 0x038060, 0x038040, 0x038040,
- 0x038040, 0x018040, 0x000A7D, 0x038040,
- 0x038040, 0x018040, 0x200402, 0x000882,
- 0x08001A, 0x000904, 0x015986, 0x000007,
- 0x260007, 0x000007, 0x000007, 0x018A06,
- 0x000007, 0x030C8D, 0x000810, 0x18043A,
- 0x260007, 0x00087D, 0x018042, 0x00160A,
- 0x04A206, 0x000007, 0x00218D, 0x000810,
- 0x08043A, 0x21C206, 0x000007, 0x0007FD,
- 0x018042, 0x08000A, 0x000904, 0x029386,
- 0x000195, 0x090D04, 0x000007, 0x000820,
- 0x0000F5, 0x000B7D, 0x01F060, 0x0000FD,
- 0x032206, 0x018040, 0x000A7D, 0x038042,
- 0x13804A, 0x18000A, 0x001820, 0x059060,
- 0x058860, 0x018040, 0x0000FD, 0x018042,
- 0x70000A, 0x000115, 0x071144, 0x032386,
- 0x030000, 0x007020, 0x034A06, 0x018040,
- 0x00348D, 0x000810, 0x08043A, 0x21EA06,
- 0x000007, 0x02D38D, 0x000810, 0x18043A,
- 0x018206, 0x000007, 0x240007, 0x000F8D,
- 0x000810, 0x00163A, 0x002402, 0x005C02,
- 0x0028FD, 0x000020, 0x018040, 0x08000D,
- 0x000815, 0x510984, 0x000007, 0x00004D,
- 0x000E5D, 0x000E02, 0x00418D, 0x000810,
- 0x08043A, 0x2C8A06, 0x000007, 0x00008D,
- 0x000924, 0x000F02, 0x00458D, 0x000810,
- 0x08043A, 0x2C8A06, 0x000007, 0x00387D,
- 0x018042, 0x08000A, 0x001015, 0x010984,
- 0x018386, 0x000007, 0x01AA06, 0x000007,
- 0x0008FD, 0x018042, 0x18000A, 0x001904,
- 0x218086, 0x280007, 0x001810, 0x28043A,
- 0x280C02, 0x00000D, 0x000810, 0x28143A,
- 0x08808D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00020D, 0x189904, 0x000007,
- 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x055A86, 0x000007,
- 0x000100, 0x000A20, 0x00047D, 0x018040,
- 0x018042, 0x20000A, 0x003015, 0x012144,
- 0x034986, 0x000007, 0x002104, 0x034986,
- 0x000007, 0x000F8D, 0x000810, 0x280C3A,
- 0x023944, 0x06C986, 0x000007, 0x001810,
- 0x28043A, 0x08810D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x002810, 0x78003A,
- 0x00688D, 0x000810, 0x08043A, 0x288A06,
- 0x000007, 0x00400D, 0x001015, 0x189904,
- 0x292904, 0x393904, 0x000007, 0x060206,
- 0x000007, 0x0004F5, 0x00007D, 0x000020,
- 0x00008D, 0x010860, 0x018040, 0x00047D,
- 0x038042, 0x21804A, 0x18000A, 0x021944,
- 0x215886, 0x000007, 0x004075, 0x71F104,
- 0x000007, 0x010042, 0x28000A, 0x002904,
- 0x212086, 0x000007, 0x003C0D, 0x30A904,
- 0x000007, 0x00077D, 0x018042, 0x08000A,
- 0x000904, 0x07DA86, 0x00057D, 0x002820,
- 0x03B060, 0x07F206, 0x018040, 0x003020,
- 0x03A860, 0x018040, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x07FA86, 0x000007,
- 0x00057D, 0x018042, 0x28040A, 0x000E8D,
- 0x000810, 0x280C3A, 0x00000D, 0x000810,
- 0x28143A, 0x09000D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x003DFD, 0x000020,
- 0x018040, 0x00107D, 0x008D8D, 0x000810,
- 0x08043A, 0x288A06, 0x000007, 0x000815,
- 0x08001A, 0x010984, 0x095186, 0x00137D,
- 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
- 0x038A60, 0x018040, 0x007FBD, 0x383DC4,
- 0x000007, 0x001A7D, 0x001375, 0x018042,
- 0x09004A, 0x10000A, 0x0B8D04, 0x139504,
- 0x000007, 0x000820, 0x019060, 0x001104,
- 0x212086, 0x010040, 0x0017FD, 0x018042,
- 0x08000A, 0x000904, 0x212286, 0x000007,
- 0x00197D, 0x038042, 0x09804A, 0x10000A,
- 0x000924, 0x001664, 0x0011FD, 0x038042,
- 0x2B804A, 0x19804A, 0x00008D, 0x218944,
- 0x000007, 0x002244, 0x0AE186, 0x000007,
- 0x001A64, 0x002A24, 0x00197D, 0x080102,
- 0x100122, 0x000820, 0x039060, 0x018040,
- 0x003DFD, 0x00008D, 0x000820, 0x018040,
- 0x001375, 0x001A7D, 0x010042, 0x09804A,
- 0x10000A, 0x00021D, 0x0189E4, 0x2992E4,
- 0x309144, 0x000007, 0x00060D, 0x000A15,
- 0x000C1D, 0x001025, 0x00A9E4, 0x012BE4,
- 0x000464, 0x01B3E4, 0x0232E4, 0x000464,
- 0x000464, 0x000464, 0x000464, 0x00040D,
- 0x08B1C4, 0x000007, 0x000820, 0x000BF5,
- 0x030040, 0x00197D, 0x038042, 0x09804A,
- 0x000A24, 0x08000A, 0x080E64, 0x000007,
- 0x100122, 0x000820, 0x031060, 0x010040,
- 0x0064AC, 0x00027D, 0x000020, 0x018040,
- 0x00107D, 0x018042, 0x0011FD, 0x3B804A,
- 0x09804A, 0x20000A, 0x000095, 0x1A1144,
- 0x00A144, 0x0D2086, 0x00040D, 0x00B984,
- 0x0D2186, 0x0018FD, 0x018042, 0x0010FD,
- 0x09804A, 0x28000A, 0x000095, 0x010924,
- 0x002A64, 0x0D1186, 0x000007, 0x002904,
- 0x0D2286, 0x000007, 0x0D2A06, 0x080002,
- 0x00008D, 0x00387D, 0x000820, 0x018040,
- 0x00127D, 0x018042, 0x10000A, 0x003904,
- 0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984,
- 0x0DA186, 0x000025, 0x0E7A06, 0x00002D,
- 0x000015, 0x00082D, 0x02C78D, 0x000820,
- 0x0EC206, 0x00000D, 0x7F8035, 0x00B984,
- 0x0E7186, 0x400025, 0x00008D, 0x110944,
- 0x000007, 0x00018D, 0x109504, 0x000007,
- 0x009164, 0x000424, 0x000424, 0x000424,
- 0x100102, 0x280002, 0x02C68D, 0x000820,
- 0x0EC206, 0x00018D, 0x00042D, 0x00008D,
- 0x109504, 0x000007, 0x00020D, 0x109184,
- 0x000007, 0x02C70D, 0x000820, 0x00008D,
- 0x0038FD, 0x018040, 0x003BFD, 0x001020,
- 0x03A860, 0x000815, 0x313184, 0x212184,
- 0x000007, 0x03B060, 0x03A060, 0x018040,
- 0x0022FD, 0x000095, 0x010924, 0x000424,
- 0x000424, 0x001264, 0x100102, 0x000820,
- 0x039060, 0x018040, 0x001924, 0x00FB8D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x000424,
- 0x000424, 0x00117D, 0x018042, 0x08000A,
- 0x000A24, 0x280502, 0x280C02, 0x09800D,
- 0x000820, 0x0002FD, 0x018040, 0x200007,
- 0x0022FD, 0x018042, 0x08000A, 0x000095,
- 0x280DC4, 0x011924, 0x00197D, 0x018042,
- 0x0011FD, 0x09804A, 0x10000A, 0x0000B5,
- 0x113144, 0x0A8D04, 0x000007, 0x080A44,
- 0x129504, 0x000007, 0x0023FD, 0x001020,
- 0x038040, 0x101244, 0x000007, 0x000820,
- 0x039060, 0x018040, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x10FA86, 0x000007,
- 0x003BFD, 0x000100, 0x000A10, 0x0B807A,
- 0x13804A, 0x090984, 0x000007, 0x000095,
- 0x013D04, 0x118086, 0x10000A, 0x100002,
- 0x090984, 0x000007, 0x038042, 0x11804A,
- 0x090D04, 0x000007, 0x10000A, 0x090D84,
- 0x000007, 0x00257D, 0x000820, 0x018040,
- 0x00010D, 0x000810, 0x28143A, 0x00127D,
- 0x018042, 0x20000A, 0x00197D, 0x018042,
- 0x00117D, 0x31804A, 0x10000A, 0x003124,
- 0x01280D, 0x00397D, 0x000820, 0x058040,
- 0x038042, 0x09844A, 0x000606, 0x08040A,
- 0x300102, 0x003124, 0x000424, 0x000424,
- 0x001224, 0x280502, 0x001A4C, 0x130186,
- 0x700002, 0x00002D, 0x030000, 0x00387D,
- 0x018042, 0x10000A, 0x132A06, 0x002124,
- 0x0000AD, 0x100002, 0x00010D, 0x000924,
- 0x006B24, 0x01368D, 0x00397D, 0x000820,
- 0x058040, 0x038042, 0x09844A, 0x000606,
- 0x08040A, 0x003264, 0x00008D, 0x000A24,
- 0x001020, 0x00227D, 0x018040, 0x013C0D,
- 0x000810, 0x08043A, 0x29D206, 0x000007,
- 0x002820, 0x00207D, 0x018040, 0x00117D,
- 0x038042, 0x13804A, 0x33800A, 0x00387D,
- 0x018042, 0x08000A, 0x000904, 0x163A86,
- 0x000007, 0x00008D, 0x030964, 0x01478D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x380102,
- 0x000424, 0x000424, 0x001224, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x14A286,
- 0x000007, 0x280502, 0x001A4C, 0x163986,
- 0x000007, 0x032164, 0x00632C, 0x003DFD,
- 0x018042, 0x08000A, 0x000095, 0x090904,
- 0x000007, 0x000820, 0x001A4C, 0x156186,
- 0x018040, 0x030000, 0x157A06, 0x002124,
- 0x00010D, 0x000924, 0x006B24, 0x015B8D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x003A64,
- 0x000095, 0x001224, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x15DA86, 0x000007,
- 0x01628D, 0x000810, 0x08043A, 0x29D206,
- 0x000007, 0x14D206, 0x000007, 0x007020,
- 0x08010A, 0x10012A, 0x0020FD, 0x038860,
- 0x039060, 0x018040, 0x00227D, 0x018042,
- 0x003DFD, 0x08000A, 0x31844A, 0x000904,
- 0x16D886, 0x18008B, 0x00008D, 0x189904,
- 0x00312C, 0x17AA06, 0x000007, 0x00324C,
- 0x173386, 0x000007, 0x001904, 0x173086,
- 0x000007, 0x000095, 0x199144, 0x00222C,
- 0x003124, 0x00636C, 0x000E3D, 0x001375,
- 0x000BFD, 0x010042, 0x09804A, 0x10000A,
- 0x038AEC, 0x0393EC, 0x00224C, 0x17A986,
- 0x000007, 0x00008D, 0x189904, 0x00226C,
- 0x00322C, 0x30050A, 0x301DAB, 0x002083,
- 0x0018FD, 0x018042, 0x08000A, 0x018924,
- 0x300502, 0x001083, 0x001875, 0x010042,
- 0x10000A, 0x00008D, 0x010924, 0x001375,
- 0x330542, 0x330CCB, 0x332CCB, 0x3334CB,
- 0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB,
- 0x305C8B, 0x006083, 0x0002F5, 0x010042,
- 0x08000A, 0x000904, 0x187A86, 0x000007,
- 0x001E2D, 0x0005FD, 0x018042, 0x08000A,
- 0x028924, 0x280502, 0x00060D, 0x000810,
- 0x280C3A, 0x00008D, 0x000810, 0x28143A,
- 0x0A808D, 0x000820, 0x0002F5, 0x010040,
- 0x220007, 0x001275, 0x030042, 0x21004A,
- 0x00008D, 0x1A0944, 0x000007, 0x01980D,
- 0x000810, 0x08043A, 0x2B2206, 0x000007,
- 0x0001F5, 0x030042, 0x0D004A, 0x10000A,
- 0x089144, 0x000007, 0x000820, 0x010040,
- 0x0025F5, 0x0A3144, 0x000007, 0x000820,
- 0x032860, 0x030040, 0x00217D, 0x038042,
- 0x0B804A, 0x10000A, 0x000820, 0x031060,
- 0x030040, 0x00008D, 0x000124, 0x00012C,
- 0x000E64, 0x001A64, 0x00636C, 0x08010A,
- 0x10012A, 0x000820, 0x031060, 0x030040,
- 0x0020FD, 0x018042, 0x08000A, 0x00227D,
- 0x018042, 0x10000A, 0x000820, 0x031060,
- 0x030040, 0x00197D, 0x018042, 0x08000A,
- 0x0022FD, 0x038042, 0x10000A, 0x000820,
- 0x031060, 0x030040, 0x090D04, 0x000007,
- 0x000820, 0x030040, 0x038042, 0x0B804A,
- 0x10000A, 0x000820, 0x031060, 0x030040,
- 0x038042, 0x13804A, 0x19804A, 0x110D04,
- 0x198D04, 0x000007, 0x08000A, 0x001020,
- 0x031860, 0x030860, 0x030040, 0x00008D,
- 0x0B0944, 0x000007, 0x000820, 0x010040,
- 0x0005F5, 0x030042, 0x08000A, 0x000820,
- 0x010040, 0x0000F5, 0x010042, 0x08000A,
- 0x000904, 0x1C6086, 0x001E75, 0x030042,
- 0x01044A, 0x000C0A, 0x1C7206, 0x000007,
- 0x000402, 0x000C02, 0x00177D, 0x001AF5,
- 0x018042, 0x03144A, 0x031C4A, 0x03244A,
- 0x032C4A, 0x03344A, 0x033C4A, 0x03444A,
- 0x004C0A, 0x00043D, 0x0013F5, 0x001AFD,
- 0x030042, 0x0B004A, 0x1B804A, 0x13804A,
- 0x20000A, 0x089144, 0x19A144, 0x0389E4,
- 0x0399EC, 0x005502, 0x005D0A, 0x030042,
- 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
- 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
- 0x006502, 0x006D0A, 0x030042, 0x0B004A,
- 0x19004A, 0x2B804A, 0x13804A, 0x21804A,
- 0x30000A, 0x089144, 0x19A144, 0x2AB144,
- 0x0389E4, 0x0399EC, 0x007502, 0x007D0A,
- 0x03A9E4, 0x000702, 0x00107D, 0x000415,
- 0x018042, 0x08000A, 0x0109E4, 0x000F02,
- 0x002AF5, 0x0019FD, 0x010042, 0x09804A,
- 0x10000A, 0x000934, 0x001674, 0x0029F5,
- 0x010042, 0x10000A, 0x00917C, 0x002075,
- 0x010042, 0x08000A, 0x000904, 0x1ED286,
- 0x0026F5, 0x0027F5, 0x030042, 0x09004A,
- 0x10000A, 0x000A3C, 0x00167C, 0x001A75,
- 0x000BFD, 0x010042, 0x51804A, 0x48000A,
- 0x160007, 0x001075, 0x010042, 0x282C0A,
- 0x281D12, 0x282512, 0x001F32, 0x1E0007,
- 0x0E0007, 0x001975, 0x010042, 0x002DF5,
- 0x0D004A, 0x10000A, 0x009144, 0x1FB286,
- 0x010042, 0x28340A, 0x000E5D, 0x00008D,
- 0x000375, 0x000820, 0x010040, 0x05D2F4,
- 0x54D104, 0x00735C, 0x205386, 0x000007,
- 0x0C0007, 0x080007, 0x0A0007, 0x02040D,
- 0x000810, 0x08043A, 0x332206, 0x000007,
- 0x205A06, 0x000007, 0x080007, 0x002275,
- 0x010042, 0x20000A, 0x002104, 0x212086,
- 0x001E2D, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x209286, 0x000007, 0x002010,
- 0x30043A, 0x00057D, 0x0180C3, 0x08000A,
- 0x028924, 0x280502, 0x280C02, 0x0A810D,
- 0x000820, 0x0002F5, 0x010040, 0x220007,
- 0x0004FD, 0x018042, 0x70000A, 0x030000,
- 0x007020, 0x06FA06, 0x018040, 0x02180D,
- 0x000810, 0x08043A, 0x2B2206, 0x000007,
- 0x0002FD, 0x018042, 0x08000A, 0x000904,
- 0x218A86, 0x000007, 0x01F206, 0x000007,
- 0x000875, 0x0009FD, 0x00010D, 0x220A06,
- 0x000295, 0x000B75, 0x00097D, 0x00000D,
- 0x000515, 0x010042, 0x18000A, 0x001904,
- 0x287886, 0x0006F5, 0x001020, 0x010040,
- 0x0004F5, 0x000820, 0x010040, 0x000775,
- 0x010042, 0x09804A, 0x10000A, 0x001124,
- 0x000904, 0x22BA86, 0x000815, 0x080102,
- 0x101204, 0x22DA06, 0x000575, 0x081204,
- 0x000007, 0x100102, 0x000575, 0x000425,
- 0x021124, 0x100102, 0x000820, 0x031060,
- 0x010040, 0x001924, 0x287886, 0x00008D,
- 0x000464, 0x009D04, 0x278886, 0x180102,
- 0x000575, 0x010042, 0x28040A, 0x00018D,
- 0x000924, 0x280D02, 0x00000D, 0x000924,
- 0x281502, 0x10000D, 0x000820, 0x0002F5,
- 0x010040, 0x200007, 0x001175, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x23C286,
- 0x000007, 0x000100, 0x080B20, 0x130B60,
- 0x1B0B60, 0x030A60, 0x010040, 0x050042,
- 0x3D004A, 0x35004A, 0x2D004A, 0x20000A,
- 0x0006F5, 0x010042, 0x28140A, 0x0004F5,
- 0x010042, 0x08000A, 0x000315, 0x010D04,
- 0x24CA86, 0x004015, 0x000095, 0x010D04,
- 0x24B886, 0x100022, 0x10002A, 0x24E206,
- 0x000007, 0x333104, 0x2AA904, 0x000007,
- 0x032124, 0x280502, 0x001124, 0x000424,
- 0x000424, 0x003224, 0x00292C, 0x00636C,
- 0x25F386, 0x000007, 0x02B164, 0x000464,
- 0x000464, 0x00008D, 0x000A64, 0x280D02,
- 0x10008D, 0x000820, 0x0002F5, 0x010040,
- 0x220007, 0x00008D, 0x38B904, 0x000007,
- 0x03296C, 0x30010A, 0x0002F5, 0x010042,
- 0x08000A, 0x000904, 0x25BA86, 0x000007,
- 0x02312C, 0x28050A, 0x00008D, 0x01096C,
- 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x001124, 0x000424,
- 0x000424, 0x003224, 0x300102, 0x032944,
- 0x267A86, 0x000007, 0x300002, 0x0004F5,
- 0x010042, 0x08000A, 0x000315, 0x010D04,
- 0x26C086, 0x003124, 0x000464, 0x300102,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x26CA86, 0x000007, 0x003124, 0x300502,
- 0x003924, 0x300583, 0x000883, 0x0005F5,
- 0x010042, 0x28040A, 0x00008D, 0x008124,
- 0x280D02, 0x00008D, 0x008124, 0x281502,
- 0x10018D, 0x000820, 0x0002F5, 0x010040,
- 0x220007, 0x001025, 0x000575, 0x030042,
- 0x09004A, 0x10000A, 0x0A0904, 0x121104,
- 0x000007, 0x001020, 0x050860, 0x050040,
- 0x0006FD, 0x018042, 0x09004A, 0x10000A,
- 0x0000A5, 0x0A0904, 0x121104, 0x000007,
- 0x000820, 0x019060, 0x010040, 0x0002F5,
- 0x010042, 0x08000A, 0x000904, 0x284286,
- 0x000007, 0x230A06, 0x000007, 0x000606,
- 0x000007, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x289286, 0x000007, 0x000100,
- 0x080B20, 0x138B60, 0x1B8B60, 0x238B60,
- 0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60,
- 0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60,
- 0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60,
- 0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60,
- 0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60,
- 0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60,
- 0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60,
- 0x000606, 0x018040, 0x00008D, 0x000A64,
- 0x280D02, 0x000A24, 0x00027D, 0x018042,
- 0x10000A, 0x001224, 0x0003FD, 0x018042,
- 0x08000A, 0x000904, 0x2A8286, 0x000007,
- 0x00018D, 0x000A24, 0x000464, 0x000464,
- 0x080102, 0x000924, 0x000424, 0x000424,
- 0x100102, 0x02000D, 0x009144, 0x2AD986,
- 0x000007, 0x0001FD, 0x018042, 0x08000A,
- 0x000A44, 0x2ABB86, 0x018042, 0x0A000D,
- 0x000820, 0x0002FD, 0x018040, 0x200007,
- 0x00027D, 0x001020, 0x000606, 0x018040,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x2B2A86, 0x000007, 0x00037D, 0x018042,
- 0x08000A, 0x000904, 0x2B5A86, 0x000007,
- 0x000075, 0x002E7D, 0x010042, 0x0B804A,
- 0x000020, 0x000904, 0x000686, 0x010040,
- 0x31844A, 0x30048B, 0x000883, 0x00008D,
- 0x000810, 0x28143A, 0x00008D, 0x000810,
- 0x280C3A, 0x000675, 0x010042, 0x08000A,
- 0x003815, 0x010924, 0x280502, 0x0B000D,
- 0x000820, 0x0002F5, 0x010040, 0x000606,
- 0x220007, 0x000464, 0x000464, 0x000606,
- 0x000007, 0x000134, 0x007F8D, 0x00093C,
- 0x281D12, 0x282512, 0x001F32, 0x0E0007,
- 0x00010D, 0x00037D, 0x000820, 0x018040,
- 0x05D2F4, 0x000007, 0x080007, 0x00037D,
- 0x018042, 0x08000A, 0x000904, 0x2D0286,
- 0x000007, 0x000606, 0x000007, 0x000007,
- 0x000012, 0x100007, 0x320007, 0x600007,
- 0x100080, 0x48001A, 0x004904, 0x2D6186,
- 0x000007, 0x001210, 0x58003A, 0x000145,
- 0x5C5D04, 0x000007, 0x000080, 0x48001A,
- 0x004904, 0x2DB186, 0x000007, 0x001210,
- 0x50003A, 0x005904, 0x2E0886, 0x000045,
- 0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524,
- 0x004224, 0x500102, 0x200502, 0x000082,
- 0x40001A, 0x004104, 0x2E3986, 0x000007,
- 0x003865, 0x40001A, 0x004020, 0x00104D,
- 0x04C184, 0x301B86, 0x000040, 0x040007,
- 0x000165, 0x000145, 0x004020, 0x000040,
- 0x000765, 0x080080, 0x40001A, 0x004104,
- 0x2EC986, 0x000007, 0x001210, 0x40003A,
- 0x004104, 0x2F2286, 0x00004D, 0x0000CD,
- 0x004810, 0x20043A, 0x000882, 0x40001A,
- 0x004104, 0x2F3186, 0x000007, 0x004820,
- 0x005904, 0x300886, 0x000040, 0x0007E5,
- 0x200480, 0x2816A0, 0x3216E0, 0x3A16E0,
- 0x4216E0, 0x021260, 0x000040, 0x000032,
- 0x400075, 0x00007D, 0x07D574, 0x200512,
- 0x000082, 0x40001A, 0x004104, 0x2FE186,
- 0x000007, 0x037206, 0x640007, 0x060007,
- 0x0000E5, 0x000020, 0x000040, 0x000A65,
- 0x000020, 0x020040, 0x020040, 0x000040,
- 0x000165, 0x000042, 0x70000A, 0x007104,
- 0x30A286, 0x000007, 0x018206, 0x640007,
- 0x050000, 0x007020, 0x000040, 0x037206,
- 0x640007, 0x000007, 0x00306D, 0x028860,
- 0x029060, 0x08000A, 0x028860, 0x008040,
- 0x100012, 0x00100D, 0x009184, 0x314186,
- 0x000E0D, 0x009184, 0x325186, 0x000007,
- 0x300007, 0x001020, 0x003B6D, 0x008040,
- 0x000080, 0x08001A, 0x000904, 0x316186,
- 0x000007, 0x001220, 0x000DED, 0x008040,
- 0x008042, 0x10000A, 0x40000D, 0x109544,
- 0x000007, 0x001020, 0x000DED, 0x008040,
- 0x008042, 0x20040A, 0x000082, 0x08001A,
- 0x000904, 0x31F186, 0x000007, 0x003B6D,
- 0x008042, 0x08000A, 0x000E15, 0x010984,
- 0x329B86, 0x600007, 0x08001A, 0x000C15,
- 0x010984, 0x328386, 0x000020, 0x1A0007,
- 0x0002ED, 0x008040, 0x620007, 0x00306D,
- 0x028042, 0x0A804A, 0x000820, 0x0A804A,
- 0x000606, 0x10804A, 0x000007, 0x282512,
- 0x001F32, 0x05D2F4, 0x54D104, 0x00735C,
- 0x000786, 0x000007, 0x0C0007, 0x0A0007,
- 0x1C0007, 0x003465, 0x020040, 0x004820,
- 0x025060, 0x40000A, 0x024060, 0x000040,
- 0x454944, 0x000007, 0x004020, 0x003AE5,
- 0x000040, 0x0028E5, 0x000042, 0x48000A,
- 0x004904, 0x386886, 0x002C65, 0x000042,
- 0x40000A, 0x0000D5, 0x454104, 0x000007,
- 0x000655, 0x054504, 0x34F286, 0x0001D5,
- 0x054504, 0x34F086, 0x002B65, 0x000042,
- 0x003AE5, 0x50004A, 0x40000A, 0x45C3D4,
- 0x000007, 0x454504, 0x000007, 0x0000CD,
- 0x444944, 0x000007, 0x454504, 0x000007,
- 0x00014D, 0x554944, 0x000007, 0x045144,
- 0x34E986, 0x002C65, 0x000042, 0x48000A,
- 0x4CD104, 0x000007, 0x04C144, 0x34F386,
- 0x000007, 0x160007, 0x002CE5, 0x040042,
- 0x40000A, 0x004020, 0x000040, 0x002965,
- 0x000042, 0x40000A, 0x004104, 0x356086,
- 0x000007, 0x002402, 0x36A206, 0x005C02,
- 0x0025E5, 0x000042, 0x40000A, 0x004274,
- 0x002AE5, 0x000042, 0x40000A, 0x004274,
- 0x500112, 0x0029E5, 0x000042, 0x40000A,
- 0x004234, 0x454104, 0x000007, 0x004020,
- 0x000040, 0x003EE5, 0x000020, 0x000040,
- 0x002DE5, 0x400152, 0x50000A, 0x045144,
- 0x364A86, 0x0000C5, 0x003EE5, 0x004020,
- 0x000040, 0x002BE5, 0x000042, 0x40000A,
- 0x404254, 0x000007, 0x002AE5, 0x004020,
- 0x000040, 0x500132, 0x040134, 0x005674,
- 0x0029E5, 0x020042, 0x42000A, 0x000042,
- 0x50000A, 0x05417C, 0x0028E5, 0x000042,
- 0x48000A, 0x0000C5, 0x4CC144, 0x371086,
- 0x0026E5, 0x0027E5, 0x020042, 0x40004A,
- 0x50000A, 0x00423C, 0x00567C, 0x0028E5,
- 0x004820, 0x000040, 0x281D12, 0x282512,
- 0x001F72, 0x002965, 0x000042, 0x40000A,
- 0x004104, 0x37AA86, 0x0E0007, 0x160007,
- 0x1E0007, 0x003EE5, 0x000042, 0x40000A,
- 0x004104, 0x37E886, 0x002D65, 0x000042,
- 0x28340A, 0x003465, 0x020042, 0x42004A,
- 0x004020, 0x4A004A, 0x50004A, 0x05D2F4,
- 0x54D104, 0x00735C, 0x385186, 0x000007,
- 0x000606, 0x080007, 0x0C0007, 0x080007,
- 0x0A0007, 0x0001E5, 0x020045, 0x004020,
- 0x000060, 0x000365, 0x000040, 0x002E65,
- 0x001A20, 0x0A1A60, 0x000040, 0x003465,
- 0x020042, 0x42004A, 0x004020, 0x4A004A,
- 0x000606, 0x50004A, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000
-};
-
-// --------------------------------------------
-// DS-1E Controller InstructionRAM Code
-// 1999/06/21
-// Buf441 slot is Enabled.
-// --------------------------------------------
-// 04/09 creat
-// 04/12 stop nise fix
-// 06/21 WorkingOff timming
-static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
- 0x000007, 0x240007, 0x0C0007, 0x1C0007,
- 0x060007, 0x700002, 0x000020, 0x030040,
- 0x007104, 0x004286, 0x030040, 0x000F0D,
- 0x000810, 0x20043A, 0x000282, 0x00020D,
- 0x000810, 0x20043A, 0x001282, 0x200E82,
- 0x00800D, 0x000810, 0x20043A, 0x001A82,
- 0x03460D, 0x000810, 0x10043A, 0x02EC0D,
- 0x000810, 0x18043A, 0x00010D, 0x020015,
- 0x0000FD, 0x000020, 0x038860, 0x039060,
- 0x038060, 0x038040, 0x038040, 0x038040,
- 0x018040, 0x000A7D, 0x038040, 0x038040,
- 0x018040, 0x200402, 0x000882, 0x08001A,
- 0x000904, 0x017186, 0x000007, 0x260007,
- 0x400007, 0x000007, 0x03258D, 0x000810,
- 0x18043A, 0x260007, 0x284402, 0x00087D,
- 0x018042, 0x00160A, 0x05A206, 0x000007,
- 0x440007, 0x00230D, 0x000810, 0x08043A,
- 0x22FA06, 0x000007, 0x0007FD, 0x018042,
- 0x08000A, 0x000904, 0x02AB86, 0x000195,
- 0x090D04, 0x000007, 0x000820, 0x0000F5,
- 0x000B7D, 0x01F060, 0x0000FD, 0x033A06,
- 0x018040, 0x000A7D, 0x038042, 0x13804A,
- 0x18000A, 0x001820, 0x059060, 0x058860,
- 0x018040, 0x0000FD, 0x018042, 0x70000A,
- 0x000115, 0x071144, 0x033B86, 0x030000,
- 0x007020, 0x036206, 0x018040, 0x00360D,
- 0x000810, 0x08043A, 0x232206, 0x000007,
- 0x02EC0D, 0x000810, 0x18043A, 0x019A06,
- 0x000007, 0x240007, 0x000F8D, 0x000810,
- 0x00163A, 0x002402, 0x005C02, 0x0028FD,
- 0x000020, 0x018040, 0x08000D, 0x000815,
- 0x510984, 0x000007, 0x00004D, 0x000E5D,
- 0x000E02, 0x00430D, 0x000810, 0x08043A,
- 0x2E1206, 0x000007, 0x00008D, 0x000924,
- 0x000F02, 0x00470D, 0x000810, 0x08043A,
- 0x2E1206, 0x000007, 0x480480, 0x001210,
- 0x28043A, 0x00778D, 0x000810, 0x280C3A,
- 0x00068D, 0x000810, 0x28143A, 0x284402,
- 0x03258D, 0x000810, 0x18043A, 0x07FF8D,
- 0x000820, 0x0002FD, 0x018040, 0x260007,
- 0x200007, 0x0002FD, 0x018042, 0x08000A,
- 0x000904, 0x051286, 0x000007, 0x240007,
- 0x02EC0D, 0x000810, 0x18043A, 0x00387D,
- 0x018042, 0x08000A, 0x001015, 0x010984,
- 0x019B86, 0x000007, 0x01B206, 0x000007,
- 0x0008FD, 0x018042, 0x18000A, 0x001904,
- 0x22B886, 0x280007, 0x001810, 0x28043A,
- 0x280C02, 0x00000D, 0x000810, 0x28143A,
- 0x08808D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00020D, 0x189904, 0x000007,
- 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x065A86, 0x000007,
- 0x000100, 0x000A20, 0x00047D, 0x018040,
- 0x018042, 0x20000A, 0x003015, 0x012144,
- 0x036186, 0x000007, 0x002104, 0x036186,
- 0x000007, 0x000F8D, 0x000810, 0x280C3A,
- 0x023944, 0x07C986, 0x000007, 0x001810,
- 0x28043A, 0x08810D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x002810, 0x78003A,
- 0x00788D, 0x000810, 0x08043A, 0x2A1206,
- 0x000007, 0x00400D, 0x001015, 0x189904,
- 0x292904, 0x393904, 0x000007, 0x070206,
- 0x000007, 0x0004F5, 0x00007D, 0x000020,
- 0x00008D, 0x010860, 0x018040, 0x00047D,
- 0x038042, 0x21804A, 0x18000A, 0x021944,
- 0x229086, 0x000007, 0x004075, 0x71F104,
- 0x000007, 0x010042, 0x28000A, 0x002904,
- 0x225886, 0x000007, 0x003C0D, 0x30A904,
- 0x000007, 0x00077D, 0x018042, 0x08000A,
- 0x000904, 0x08DA86, 0x00057D, 0x002820,
- 0x03B060, 0x08F206, 0x018040, 0x003020,
- 0x03A860, 0x018040, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x08FA86, 0x000007,
- 0x00057D, 0x018042, 0x28040A, 0x000E8D,
- 0x000810, 0x280C3A, 0x00000D, 0x000810,
- 0x28143A, 0x09000D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x003DFD, 0x000020,
- 0x018040, 0x00107D, 0x009D8D, 0x000810,
- 0x08043A, 0x2A1206, 0x000007, 0x000815,
- 0x08001A, 0x010984, 0x0A5186, 0x00137D,
- 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
- 0x038A60, 0x018040, 0x00107D, 0x018042,
- 0x08000A, 0x000215, 0x010984, 0x3A8186,
- 0x000007, 0x007FBD, 0x383DC4, 0x000007,
- 0x001A7D, 0x001375, 0x018042, 0x09004A,
- 0x10000A, 0x0B8D04, 0x139504, 0x000007,
- 0x000820, 0x019060, 0x001104, 0x225886,
- 0x010040, 0x0017FD, 0x018042, 0x08000A,
- 0x000904, 0x225A86, 0x000007, 0x00197D,
- 0x038042, 0x09804A, 0x10000A, 0x000924,
- 0x001664, 0x0011FD, 0x038042, 0x2B804A,
- 0x19804A, 0x00008D, 0x218944, 0x000007,
- 0x002244, 0x0C1986, 0x000007, 0x001A64,
- 0x002A24, 0x00197D, 0x080102, 0x100122,
- 0x000820, 0x039060, 0x018040, 0x003DFD,
- 0x00008D, 0x000820, 0x018040, 0x001375,
- 0x001A7D, 0x010042, 0x09804A, 0x10000A,
- 0x00021D, 0x0189E4, 0x2992E4, 0x309144,
- 0x000007, 0x00060D, 0x000A15, 0x000C1D,
- 0x001025, 0x00A9E4, 0x012BE4, 0x000464,
- 0x01B3E4, 0x0232E4, 0x000464, 0x000464,
- 0x000464, 0x000464, 0x00040D, 0x08B1C4,
- 0x000007, 0x000820, 0x000BF5, 0x030040,
- 0x00197D, 0x038042, 0x09804A, 0x000A24,
- 0x08000A, 0x080E64, 0x000007, 0x100122,
- 0x000820, 0x031060, 0x010040, 0x0064AC,
- 0x00027D, 0x000020, 0x018040, 0x00107D,
- 0x018042, 0x0011FD, 0x3B804A, 0x09804A,
- 0x20000A, 0x000095, 0x1A1144, 0x00A144,
- 0x0E5886, 0x00040D, 0x00B984, 0x0E5986,
- 0x0018FD, 0x018042, 0x0010FD, 0x09804A,
- 0x28000A, 0x000095, 0x010924, 0x002A64,
- 0x0E4986, 0x000007, 0x002904, 0x0E5A86,
- 0x000007, 0x0E6206, 0x080002, 0x00008D,
- 0x00387D, 0x000820, 0x018040, 0x00127D,
- 0x018042, 0x10000A, 0x003904, 0x0F0986,
- 0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986,
- 0x000025, 0x0FB206, 0x00002D, 0x000015,
- 0x00082D, 0x02E00D, 0x000820, 0x0FFA06,
- 0x00000D, 0x7F8035, 0x00B984, 0x0FA986,
- 0x400025, 0x00008D, 0x110944, 0x000007,
- 0x00018D, 0x109504, 0x000007, 0x009164,
- 0x000424, 0x000424, 0x000424, 0x100102,
- 0x280002, 0x02DF0D, 0x000820, 0x0FFA06,
- 0x00018D, 0x00042D, 0x00008D, 0x109504,
- 0x000007, 0x00020D, 0x109184, 0x000007,
- 0x02DF8D, 0x000820, 0x00008D, 0x0038FD,
- 0x018040, 0x003BFD, 0x001020, 0x03A860,
- 0x000815, 0x313184, 0x212184, 0x000007,
- 0x03B060, 0x03A060, 0x018040, 0x0022FD,
- 0x000095, 0x010924, 0x000424, 0x000424,
- 0x001264, 0x100102, 0x000820, 0x039060,
- 0x018040, 0x001924, 0x010F0D, 0x00397D,
- 0x000820, 0x058040, 0x038042, 0x09844A,
- 0x000606, 0x08040A, 0x000424, 0x000424,
- 0x00117D, 0x018042, 0x08000A, 0x000A24,
- 0x280502, 0x280C02, 0x09800D, 0x000820,
- 0x0002FD, 0x018040, 0x200007, 0x0022FD,
- 0x018042, 0x08000A, 0x000095, 0x280DC4,
- 0x011924, 0x00197D, 0x018042, 0x0011FD,
- 0x09804A, 0x10000A, 0x0000B5, 0x113144,
- 0x0A8D04, 0x000007, 0x080A44, 0x129504,
- 0x000007, 0x0023FD, 0x001020, 0x038040,
- 0x101244, 0x000007, 0x000820, 0x039060,
- 0x018040, 0x0002FD, 0x018042, 0x08000A,
- 0x000904, 0x123286, 0x000007, 0x003BFD,
- 0x000100, 0x000A10, 0x0B807A, 0x13804A,
- 0x090984, 0x000007, 0x000095, 0x013D04,
- 0x12B886, 0x10000A, 0x100002, 0x090984,
- 0x000007, 0x038042, 0x11804A, 0x090D04,
- 0x000007, 0x10000A, 0x090D84, 0x000007,
- 0x00257D, 0x000820, 0x018040, 0x00010D,
- 0x000810, 0x28143A, 0x00127D, 0x018042,
- 0x20000A, 0x00197D, 0x018042, 0x00117D,
- 0x31804A, 0x10000A, 0x003124, 0x013B8D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x300102,
- 0x003124, 0x000424, 0x000424, 0x001224,
- 0x280502, 0x001A4C, 0x143986, 0x700002,
- 0x00002D, 0x030000, 0x00387D, 0x018042,
- 0x10000A, 0x146206, 0x002124, 0x0000AD,
- 0x100002, 0x00010D, 0x000924, 0x006B24,
- 0x014A0D, 0x00397D, 0x000820, 0x058040,
- 0x038042, 0x09844A, 0x000606, 0x08040A,
- 0x003264, 0x00008D, 0x000A24, 0x001020,
- 0x00227D, 0x018040, 0x014F8D, 0x000810,
- 0x08043A, 0x2B5A06, 0x000007, 0x002820,
- 0x00207D, 0x018040, 0x00117D, 0x038042,
- 0x13804A, 0x33800A, 0x00387D, 0x018042,
- 0x08000A, 0x000904, 0x177286, 0x000007,
- 0x00008D, 0x030964, 0x015B0D, 0x00397D,
- 0x000820, 0x058040, 0x038042, 0x09844A,
- 0x000606, 0x08040A, 0x380102, 0x000424,
- 0x000424, 0x001224, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x15DA86, 0x000007,
- 0x280502, 0x001A4C, 0x177186, 0x000007,
- 0x032164, 0x00632C, 0x003DFD, 0x018042,
- 0x08000A, 0x000095, 0x090904, 0x000007,
- 0x000820, 0x001A4C, 0x169986, 0x018040,
- 0x030000, 0x16B206, 0x002124, 0x00010D,
- 0x000924, 0x006B24, 0x016F0D, 0x00397D,
- 0x000820, 0x058040, 0x038042, 0x09844A,
- 0x000606, 0x08040A, 0x003A64, 0x000095,
- 0x001224, 0x0002FD, 0x018042, 0x08000A,
- 0x000904, 0x171286, 0x000007, 0x01760D,
- 0x000810, 0x08043A, 0x2B5A06, 0x000007,
- 0x160A06, 0x000007, 0x007020, 0x08010A,
- 0x10012A, 0x0020FD, 0x038860, 0x039060,
- 0x018040, 0x00227D, 0x018042, 0x003DFD,
- 0x08000A, 0x31844A, 0x000904, 0x181086,
- 0x18008B, 0x00008D, 0x189904, 0x00312C,
- 0x18E206, 0x000007, 0x00324C, 0x186B86,
- 0x000007, 0x001904, 0x186886, 0x000007,
- 0x000095, 0x199144, 0x00222C, 0x003124,
- 0x00636C, 0x000E3D, 0x001375, 0x000BFD,
- 0x010042, 0x09804A, 0x10000A, 0x038AEC,
- 0x0393EC, 0x00224C, 0x18E186, 0x000007,
- 0x00008D, 0x189904, 0x00226C, 0x00322C,
- 0x30050A, 0x301DAB, 0x002083, 0x0018FD,
- 0x018042, 0x08000A, 0x018924, 0x300502,
- 0x001083, 0x001875, 0x010042, 0x10000A,
- 0x00008D, 0x010924, 0x001375, 0x330542,
- 0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB,
- 0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B,
- 0x006083, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x19B286, 0x000007, 0x001E2D,
- 0x0005FD, 0x018042, 0x08000A, 0x028924,
- 0x280502, 0x00060D, 0x000810, 0x280C3A,
- 0x00008D, 0x000810, 0x28143A, 0x0A808D,
- 0x000820, 0x0002F5, 0x010040, 0x220007,
- 0x001275, 0x030042, 0x21004A, 0x00008D,
- 0x1A0944, 0x000007, 0x01AB8D, 0x000810,
- 0x08043A, 0x2CAA06, 0x000007, 0x0001F5,
- 0x030042, 0x0D004A, 0x10000A, 0x089144,
- 0x000007, 0x000820, 0x010040, 0x0025F5,
- 0x0A3144, 0x000007, 0x000820, 0x032860,
- 0x030040, 0x00217D, 0x038042, 0x0B804A,
- 0x10000A, 0x000820, 0x031060, 0x030040,
- 0x00008D, 0x000124, 0x00012C, 0x000E64,
- 0x001A64, 0x00636C, 0x08010A, 0x10012A,
- 0x000820, 0x031060, 0x030040, 0x0020FD,
- 0x018042, 0x08000A, 0x00227D, 0x018042,
- 0x10000A, 0x000820, 0x031060, 0x030040,
- 0x00197D, 0x018042, 0x08000A, 0x0022FD,
- 0x038042, 0x10000A, 0x000820, 0x031060,
- 0x030040, 0x090D04, 0x000007, 0x000820,
- 0x030040, 0x038042, 0x0B804A, 0x10000A,
- 0x000820, 0x031060, 0x030040, 0x038042,
- 0x13804A, 0x19804A, 0x110D04, 0x198D04,
- 0x000007, 0x08000A, 0x001020, 0x031860,
- 0x030860, 0x030040, 0x00008D, 0x0B0944,
- 0x000007, 0x000820, 0x010040, 0x0005F5,
- 0x030042, 0x08000A, 0x000820, 0x010040,
- 0x0000F5, 0x010042, 0x08000A, 0x000904,
- 0x1D9886, 0x001E75, 0x030042, 0x01044A,
- 0x000C0A, 0x1DAA06, 0x000007, 0x000402,
- 0x000C02, 0x00177D, 0x001AF5, 0x018042,
- 0x03144A, 0x031C4A, 0x03244A, 0x032C4A,
- 0x03344A, 0x033C4A, 0x03444A, 0x004C0A,
- 0x00043D, 0x0013F5, 0x001AFD, 0x030042,
- 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
- 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
- 0x005502, 0x005D0A, 0x030042, 0x0B004A,
- 0x1B804A, 0x13804A, 0x20000A, 0x089144,
- 0x19A144, 0x0389E4, 0x0399EC, 0x006502,
- 0x006D0A, 0x030042, 0x0B004A, 0x19004A,
- 0x2B804A, 0x13804A, 0x21804A, 0x30000A,
- 0x089144, 0x19A144, 0x2AB144, 0x0389E4,
- 0x0399EC, 0x007502, 0x007D0A, 0x03A9E4,
- 0x000702, 0x00107D, 0x000415, 0x018042,
- 0x08000A, 0x0109E4, 0x000F02, 0x002AF5,
- 0x0019FD, 0x010042, 0x09804A, 0x10000A,
- 0x000934, 0x001674, 0x0029F5, 0x010042,
- 0x10000A, 0x00917C, 0x002075, 0x010042,
- 0x08000A, 0x000904, 0x200A86, 0x0026F5,
- 0x0027F5, 0x030042, 0x09004A, 0x10000A,
- 0x000A3C, 0x00167C, 0x001A75, 0x000BFD,
- 0x010042, 0x51804A, 0x48000A, 0x160007,
- 0x001075, 0x010042, 0x282C0A, 0x281D12,
- 0x282512, 0x001F32, 0x1E0007, 0x0E0007,
- 0x001975, 0x010042, 0x002DF5, 0x0D004A,
- 0x10000A, 0x009144, 0x20EA86, 0x010042,
- 0x28340A, 0x000E5D, 0x00008D, 0x000375,
- 0x000820, 0x010040, 0x05D2F4, 0x54D104,
- 0x00735C, 0x218B86, 0x000007, 0x0C0007,
- 0x080007, 0x0A0007, 0x02178D, 0x000810,
- 0x08043A, 0x34B206, 0x000007, 0x219206,
- 0x000007, 0x080007, 0x002275, 0x010042,
- 0x20000A, 0x002104, 0x225886, 0x001E2D,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x21CA86, 0x000007, 0x002010, 0x30043A,
- 0x00057D, 0x0180C3, 0x08000A, 0x028924,
- 0x280502, 0x280C02, 0x0A810D, 0x000820,
- 0x0002F5, 0x010040, 0x220007, 0x0004FD,
- 0x018042, 0x70000A, 0x030000, 0x007020,
- 0x07FA06, 0x018040, 0x022B8D, 0x000810,
- 0x08043A, 0x2CAA06, 0x000007, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x22C286,
- 0x000007, 0x020206, 0x000007, 0x000875,
- 0x0009FD, 0x00010D, 0x234206, 0x000295,
- 0x000B75, 0x00097D, 0x00000D, 0x000515,
- 0x010042, 0x18000A, 0x001904, 0x2A0086,
- 0x0006F5, 0x001020, 0x010040, 0x0004F5,
- 0x000820, 0x010040, 0x000775, 0x010042,
- 0x09804A, 0x10000A, 0x001124, 0x000904,
- 0x23F286, 0x000815, 0x080102, 0x101204,
- 0x241206, 0x000575, 0x081204, 0x000007,
- 0x100102, 0x000575, 0x000425, 0x021124,
- 0x100102, 0x000820, 0x031060, 0x010040,
- 0x001924, 0x2A0086, 0x00008D, 0x000464,
- 0x009D04, 0x291086, 0x180102, 0x000575,
- 0x010042, 0x28040A, 0x00018D, 0x000924,
- 0x280D02, 0x00000D, 0x000924, 0x281502,
- 0x10000D, 0x000820, 0x0002F5, 0x010040,
- 0x200007, 0x001175, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x24FA86, 0x000007,
- 0x000100, 0x080B20, 0x130B60, 0x1B0B60,
- 0x030A60, 0x010040, 0x050042, 0x3D004A,
- 0x35004A, 0x2D004A, 0x20000A, 0x0006F5,
- 0x010042, 0x28140A, 0x0004F5, 0x010042,
- 0x08000A, 0x000315, 0x010D04, 0x260286,
- 0x004015, 0x000095, 0x010D04, 0x25F086,
- 0x100022, 0x10002A, 0x261A06, 0x000007,
- 0x333104, 0x2AA904, 0x000007, 0x032124,
- 0x280502, 0x284402, 0x001124, 0x400102,
- 0x000424, 0x000424, 0x003224, 0x00292C,
- 0x00636C, 0x277386, 0x000007, 0x02B164,
- 0x000464, 0x000464, 0x00008D, 0x000A64,
- 0x280D02, 0x10008D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x00008D, 0x38B904,
- 0x000007, 0x03296C, 0x30010A, 0x0002F5,
- 0x010042, 0x08000A, 0x000904, 0x270286,
- 0x000007, 0x00212C, 0x28050A, 0x00316C,
- 0x00046C, 0x00046C, 0x28450A, 0x001124,
- 0x006B64, 0x100102, 0x00008D, 0x01096C,
- 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x004124, 0x000424,
- 0x000424, 0x003224, 0x300102, 0x032944,
- 0x27FA86, 0x000007, 0x300002, 0x0004F5,
- 0x010042, 0x08000A, 0x000315, 0x010D04,
- 0x284086, 0x003124, 0x000464, 0x300102,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x284A86, 0x000007, 0x284402, 0x003124,
- 0x300502, 0x003924, 0x300583, 0x000883,
- 0x0005F5, 0x010042, 0x28040A, 0x00008D,
- 0x008124, 0x280D02, 0x00008D, 0x008124,
- 0x281502, 0x10018D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x001025, 0x000575,
- 0x030042, 0x09004A, 0x10000A, 0x0A0904,
- 0x121104, 0x000007, 0x001020, 0x050860,
- 0x050040, 0x0006FD, 0x018042, 0x09004A,
- 0x10000A, 0x0000A5, 0x0A0904, 0x121104,
- 0x000007, 0x000820, 0x019060, 0x010040,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x29CA86, 0x000007, 0x244206, 0x000007,
- 0x000606, 0x000007, 0x0002F5, 0x010042,
- 0x08000A, 0x000904, 0x2A1A86, 0x000007,
- 0x000100, 0x080B20, 0x138B60, 0x1B8B60,
- 0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60,
- 0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60,
- 0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60,
- 0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60,
- 0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60,
- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
- 0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60,
- 0x038A60, 0x000606, 0x018040, 0x00008D,
- 0x000A64, 0x280D02, 0x000A24, 0x00027D,
- 0x018042, 0x10000A, 0x001224, 0x0003FD,
- 0x018042, 0x08000A, 0x000904, 0x2C0A86,
- 0x000007, 0x00018D, 0x000A24, 0x000464,
- 0x000464, 0x080102, 0x000924, 0x000424,
- 0x000424, 0x100102, 0x02000D, 0x009144,
- 0x2C6186, 0x000007, 0x0001FD, 0x018042,
- 0x08000A, 0x000A44, 0x2C4386, 0x018042,
- 0x0A000D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00027D, 0x001020, 0x000606,
- 0x018040, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x2CB286, 0x000007, 0x00037D,
- 0x018042, 0x08000A, 0x000904, 0x2CE286,
- 0x000007, 0x000075, 0x002E7D, 0x010042,
- 0x0B804A, 0x000020, 0x000904, 0x000686,
- 0x010040, 0x31844A, 0x30048B, 0x000883,
- 0x00008D, 0x000810, 0x28143A, 0x00008D,
- 0x000810, 0x280C3A, 0x000675, 0x010042,
- 0x08000A, 0x003815, 0x010924, 0x280502,
- 0x0B000D, 0x000820, 0x0002F5, 0x010040,
- 0x000606, 0x220007, 0x000464, 0x000464,
- 0x000606, 0x000007, 0x000134, 0x007F8D,
- 0x00093C, 0x281D12, 0x282512, 0x001F32,
- 0x0E0007, 0x00010D, 0x00037D, 0x000820,
- 0x018040, 0x05D2F4, 0x000007, 0x080007,
- 0x00037D, 0x018042, 0x08000A, 0x000904,
- 0x2E8A86, 0x000007, 0x000606, 0x000007,
- 0x000007, 0x000012, 0x100007, 0x320007,
- 0x600007, 0x460007, 0x100080, 0x48001A,
- 0x004904, 0x2EF186, 0x000007, 0x001210,
- 0x58003A, 0x000145, 0x5C5D04, 0x000007,
- 0x000080, 0x48001A, 0x004904, 0x2F4186,
- 0x000007, 0x001210, 0x50003A, 0x005904,
- 0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5,
- 0x7FFF7D, 0x07D524, 0x004224, 0x500102,
- 0x200502, 0x000082, 0x40001A, 0x004104,
- 0x2FC986, 0x000007, 0x003865, 0x40001A,
- 0x004020, 0x00104D, 0x04C184, 0x31AB86,
- 0x000040, 0x040007, 0x000165, 0x000145,
- 0x004020, 0x000040, 0x000765, 0x080080,
- 0x40001A, 0x004104, 0x305986, 0x000007,
- 0x001210, 0x40003A, 0x004104, 0x30B286,
- 0x00004D, 0x0000CD, 0x004810, 0x20043A,
- 0x000882, 0x40001A, 0x004104, 0x30C186,
- 0x000007, 0x004820, 0x005904, 0x319886,
- 0x000040, 0x0007E5, 0x200480, 0x2816A0,
- 0x3216E0, 0x3A16E0, 0x4216E0, 0x021260,
- 0x000040, 0x000032, 0x400075, 0x00007D,
- 0x07D574, 0x200512, 0x000082, 0x40001A,
- 0x004104, 0x317186, 0x000007, 0x038A06,
- 0x640007, 0x0000E5, 0x000020, 0x000040,
- 0x000A65, 0x000020, 0x020040, 0x020040,
- 0x000040, 0x000165, 0x000042, 0x70000A,
- 0x007104, 0x323286, 0x000007, 0x060007,
- 0x019A06, 0x640007, 0x050000, 0x007020,
- 0x000040, 0x038A06, 0x640007, 0x000007,
- 0x00306D, 0x028860, 0x029060, 0x08000A,
- 0x028860, 0x008040, 0x100012, 0x00100D,
- 0x009184, 0x32D186, 0x000E0D, 0x009184,
- 0x33E186, 0x000007, 0x300007, 0x001020,
- 0x003B6D, 0x008040, 0x000080, 0x08001A,
- 0x000904, 0x32F186, 0x000007, 0x001220,
- 0x000DED, 0x008040, 0x008042, 0x10000A,
- 0x40000D, 0x109544, 0x000007, 0x001020,
- 0x000DED, 0x008040, 0x008042, 0x20040A,
- 0x000082, 0x08001A, 0x000904, 0x338186,
- 0x000007, 0x003B6D, 0x008042, 0x08000A,
- 0x000E15, 0x010984, 0x342B86, 0x600007,
- 0x08001A, 0x000C15, 0x010984, 0x341386,
- 0x000020, 0x1A0007, 0x0002ED, 0x008040,
- 0x620007, 0x00306D, 0x028042, 0x0A804A,
- 0x000820, 0x0A804A, 0x000606, 0x10804A,
- 0x000007, 0x282512, 0x001F32, 0x05D2F4,
- 0x54D104, 0x00735C, 0x000786, 0x000007,
- 0x0C0007, 0x0A0007, 0x1C0007, 0x003465,
- 0x020040, 0x004820, 0x025060, 0x40000A,
- 0x024060, 0x000040, 0x454944, 0x000007,
- 0x004020, 0x003AE5, 0x000040, 0x0028E5,
- 0x000042, 0x48000A, 0x004904, 0x39F886,
- 0x002C65, 0x000042, 0x40000A, 0x0000D5,
- 0x454104, 0x000007, 0x000655, 0x054504,
- 0x368286, 0x0001D5, 0x054504, 0x368086,
- 0x002B65, 0x000042, 0x003AE5, 0x50004A,
- 0x40000A, 0x45C3D4, 0x000007, 0x454504,
- 0x000007, 0x0000CD, 0x444944, 0x000007,
- 0x454504, 0x000007, 0x00014D, 0x554944,
- 0x000007, 0x045144, 0x367986, 0x002C65,
- 0x000042, 0x48000A, 0x4CD104, 0x000007,
- 0x04C144, 0x368386, 0x000007, 0x160007,
- 0x002CE5, 0x040042, 0x40000A, 0x004020,
- 0x000040, 0x002965, 0x000042, 0x40000A,
- 0x004104, 0x36F086, 0x000007, 0x002402,
- 0x383206, 0x005C02, 0x0025E5, 0x000042,
- 0x40000A, 0x004274, 0x002AE5, 0x000042,
- 0x40000A, 0x004274, 0x500112, 0x0029E5,
- 0x000042, 0x40000A, 0x004234, 0x454104,
- 0x000007, 0x004020, 0x000040, 0x003EE5,
- 0x000020, 0x000040, 0x002DE5, 0x400152,
- 0x50000A, 0x045144, 0x37DA86, 0x0000C5,
- 0x003EE5, 0x004020, 0x000040, 0x002BE5,
- 0x000042, 0x40000A, 0x404254, 0x000007,
- 0x002AE5, 0x004020, 0x000040, 0x500132,
- 0x040134, 0x005674, 0x0029E5, 0x020042,
- 0x42000A, 0x000042, 0x50000A, 0x05417C,
- 0x0028E5, 0x000042, 0x48000A, 0x0000C5,
- 0x4CC144, 0x38A086, 0x0026E5, 0x0027E5,
- 0x020042, 0x40004A, 0x50000A, 0x00423C,
- 0x00567C, 0x0028E5, 0x004820, 0x000040,
- 0x281D12, 0x282512, 0x001F72, 0x002965,
- 0x000042, 0x40000A, 0x004104, 0x393A86,
- 0x0E0007, 0x160007, 0x1E0007, 0x003EE5,
- 0x000042, 0x40000A, 0x004104, 0x397886,
- 0x002D65, 0x000042, 0x28340A, 0x003465,
- 0x020042, 0x42004A, 0x004020, 0x4A004A,
- 0x50004A, 0x05D2F4, 0x54D104, 0x00735C,
- 0x39E186, 0x000007, 0x000606, 0x080007,
- 0x0C0007, 0x080007, 0x0A0007, 0x0001E5,
- 0x020045, 0x004020, 0x000060, 0x000365,
- 0x000040, 0x002E65, 0x001A20, 0x0A1A60,
- 0x000040, 0x003465, 0x020042, 0x42004A,
- 0x004020, 0x4A004A, 0x000606, 0x50004A,
- 0x0017FD, 0x018042, 0x08000A, 0x000904,
- 0x225A86, 0x000007, 0x00107D, 0x018042,
- 0x0011FD, 0x33804A, 0x19804A, 0x20000A,
- 0x000095, 0x2A1144, 0x01A144, 0x3B9086,
- 0x00040D, 0x00B184, 0x3B9186, 0x0018FD,
- 0x018042, 0x0010FD, 0x09804A, 0x38000A,
- 0x000095, 0x010924, 0x003A64, 0x3B8186,
- 0x000007, 0x003904, 0x3B9286, 0x000007,
- 0x3B9A06, 0x00000D, 0x00008D, 0x000820,
- 0x00387D, 0x018040, 0x700002, 0x00117D,
- 0x018042, 0x00197D, 0x29804A, 0x30000A,
- 0x380002, 0x003124, 0x000424, 0x000424,
- 0x002A24, 0x280502, 0x00068D, 0x000810,
- 0x28143A, 0x00750D, 0x00B124, 0x002264,
- 0x3D0386, 0x284402, 0x000810, 0x280C3A,
- 0x0B800D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00758D, 0x00B124, 0x100102,
- 0x012144, 0x3E4986, 0x001810, 0x10003A,
- 0x00387D, 0x018042, 0x08000A, 0x000904,
- 0x3E4886, 0x030000, 0x3E4A06, 0x0000BD,
- 0x00008D, 0x023164, 0x000A64, 0x280D02,
- 0x0B808D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00387D, 0x018042, 0x08000A,
- 0x000904, 0x3E3286, 0x030000, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x3D8286,
- 0x000007, 0x002810, 0x28043A, 0x00750D,
- 0x030924, 0x002264, 0x280D02, 0x02316C,
- 0x28450A, 0x0B810D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x00008D, 0x000A24,
- 0x3E4A06, 0x100102, 0x001810, 0x10003A,
- 0x0000BD, 0x003810, 0x30043A, 0x00187D,
- 0x018042, 0x0018FD, 0x09804A, 0x20000A,
- 0x0000AD, 0x028924, 0x07212C, 0x001010,
- 0x300583, 0x300D8B, 0x3014BB, 0x301C83,
- 0x002083, 0x00137D, 0x038042, 0x33844A,
- 0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB,
- 0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083,
- 0x001E0D, 0x0005FD, 0x018042, 0x20000A,
- 0x020924, 0x00068D, 0x00A96C, 0x00009D,
- 0x0002FD, 0x018042, 0x08000A, 0x000904,
- 0x3F6A86, 0x000007, 0x280502, 0x280D0A,
- 0x284402, 0x001810, 0x28143A, 0x0C008D,
- 0x000820, 0x0002FD, 0x018040, 0x220007,
- 0x003904, 0x225886, 0x001E0D, 0x00057D,
- 0x018042, 0x20000A, 0x020924, 0x0000A5,
- 0x0002FD, 0x018042, 0x08000A, 0x000904,
- 0x402A86, 0x000007, 0x280502, 0x280C02,
- 0x002010, 0x28143A, 0x0C010D, 0x000820,
- 0x0002FD, 0x018040, 0x225A06, 0x220007,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000
-};
-
-#endif //_HWMCODE_
diff --git a/sound/oss/yss225.c b/sound/oss/yss225.c
deleted file mode 100644
index e700400..0000000
--- a/sound/oss/yss225.c
+++ /dev/null
@@ -1,319 +0,0 @@
-#include <linux/init.h>
-
-unsigned char page_zero[] __initdata = {
-0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
-0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
-0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19,
-0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01,
-0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00,
-0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02,
-0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
-0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00,
-0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02,
-0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40,
-0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02,
-0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00,
-0x1d, 0x02, 0xdf
-};
-
-unsigned char page_one[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
-0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
-0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
-0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00,
-0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7,
-0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
-0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00,
-0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
-0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00,
-0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02,
-0x60, 0x00, 0x1b
-};
-
-unsigned char page_two[] __initdata = {
-0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
-0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07,
-0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46,
-0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46,
-0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07,
-0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05,
-0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05,
-0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
-};
-
-unsigned char page_three[] __initdata = {
-0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
-0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
-0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
-0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40,
-0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00,
-0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
-};
-
-unsigned char page_four[] __initdata = {
-0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
-0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
-0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60,
-0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00,
-0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22,
-0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
-};
-
-unsigned char page_six[] __initdata = {
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
-0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
-0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
-0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00,
-0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24,
-0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00,
-0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00,
-0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a,
-0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d,
-0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50,
-0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00,
-0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17,
-0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66,
-0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c,
-0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00,
-0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c,
-0x80, 0x00, 0x7e, 0x80, 0x80
-};
-
-unsigned char page_seven[] __initdata = {
-0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
-0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
-0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
-0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f,
-0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38,
-0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06,
-0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b,
-0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06,
-0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55,
-0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14,
-0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93,
-0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x02, 0x00
-};
-
-unsigned char page_zero_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_one_v2[] __initdata = {
-0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_two_v2[] __initdata = {
-0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-unsigned char page_three_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-unsigned char page_four_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_seven_v2[] __initdata = {
-0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-unsigned char mod_v2[] __initdata = {
-0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
-0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
-0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
-0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20,
-0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3,
-0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff,
-0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16,
-0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff,
-0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31,
-0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00,
-0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44,
-0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00,
-0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
-0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00,
-0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72,
-0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0,
-0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85,
-0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00,
-0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0,
-0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00,
-0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3,
-0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00,
-0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
-0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00,
-0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02,
-0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03,
-0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
-0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
-};
-unsigned char coefficients[] __initdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
-0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
-0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
-0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00,
-0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47,
-0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07,
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00,
-0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01,
-0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43,
-0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07,
-0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02,
-0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44,
-0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07,
-0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40,
-0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a,
-0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56,
-0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07,
-0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda,
-0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05,
-0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79,
-0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07,
-0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52,
-0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03,
-0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a,
-0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06,
-0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3,
-0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20,
-0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c,
-0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06,
-0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48,
-0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
-0xba
-};
-unsigned char coefficients2[] __initdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
-0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
-0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
-0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
-0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
-};
-unsigned char coefficients3[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
-0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
-0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
-0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99,
-0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02,
-0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f,
-0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03,
-0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c,
-0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03,
-0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51,
-0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04,
-0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e,
-0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05,
-0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14,
-0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06,
-0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1,
-0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07,
-0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7,
-0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08,
-0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3,
-0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09,
-0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99,
-0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a,
-0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66,
-0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a,
-0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c,
-0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b,
-0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28,
-0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c,
-0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e,
-0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d,
-0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb,
-0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e,
-0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1,
-0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f,
-0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae,
-0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff
-};
-
diff --git a/sound/oss/yss225.h b/sound/oss/yss225.h
deleted file mode 100644
index 56d8b6b..0000000
--- a/sound/oss/yss225.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __yss255_h__
-#define __yss255_h__
-
-extern unsigned char page_zero[256];
-extern unsigned char page_one[256];
-extern unsigned char page_two[128];
-extern unsigned char page_three[128];
-extern unsigned char page_four[128];
-extern unsigned char page_six[192];
-extern unsigned char page_seven[256];
-extern unsigned char page_zero_v2[96];
-extern unsigned char page_one_v2[96];
-extern unsigned char page_two_v2[48];
-extern unsigned char page_three_v2[48];
-extern unsigned char page_four_v2[48];
-extern unsigned char page_seven_v2[96];
-extern unsigned char mod_v2[304];
-extern unsigned char coefficients[364];
-extern unsigned char coefficients2[56];
-extern unsigned char coefficients3[404];
-
-
-#endif /* __ys225_h__ */
-
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 0b0a016..5322c50 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -366,25 +366,6 @@
EXPORT_SYMBOL(register_sound_dsp);
/**
- * register_sound_synth - register a synth device
- * @fops: File operations for the driver
- * @dev: Unit number to allocate
- *
- * Allocate a synth device. Unit is the number of the synth device requested.
- * Pass -1 to request the next free synth unit. On success the allocated
- * number is returned, on failure a negative error code is returned.
- */
-
-
-int register_sound_synth(const struct file_operations *fops, int dev)
-{
- return sound_insert_unit(&chains[9], fops, dev, 9, 137,
- "synth", S_IRUSR | S_IWUSR, NULL);
-}
-
-EXPORT_SYMBOL(register_sound_synth);
-
-/**
* unregister_sound_special - unregister a special sound device
* @unit: unit number to allocate
*
@@ -449,21 +430,6 @@
EXPORT_SYMBOL(unregister_sound_dsp);
-/**
- * unregister_sound_synth - unregister a synth device
- * @unit: unit number to allocate
- *
- * Release a sound device that was allocated with register_sound_synth().
- * The unit passed is the return value from the register function.
- */
-
-void unregister_sound_synth(int unit)
-{
- return sound_remove_unit(&chains[9], unit);
-}
-
-EXPORT_SYMBOL(unregister_sound_synth);
-
/*
* Now our file operations
*/