diff --git a/[refs] b/[refs]
index 1e016330f9f9..adee35defa71 100644
--- a/[refs]
+++ b/[refs]
@@ -1,2 +1,2 @@
---
-refs/heads/master: a0a00cbf8ae5cea3d72e28982c06f3270420c657
+refs/heads/master: 4b8a311bb161a3bd2ab44311f42c526b6dc76270
diff --git a/trunk/CREDITS b/trunk/CREDITS
index 5d75254bcb81..dba3e6334691 100644
--- a/trunk/CREDITS
+++ b/trunk/CREDITS
@@ -2240,12 +2240,6 @@ D: tc: HFSC scheduler
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
@@ -2987,10 +2981,6 @@ S: 69 rue Dunois
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.
@@ -3303,12 +3293,6 @@ S: 3 Ballow Crescent
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/trunk/Documentation/DocBook/kernel-api.tmpl b/trunk/Documentation/DocBook/kernel-api.tmpl
index 2b5ac604948c..49c745720f47 100644
--- a/trunk/Documentation/DocBook/kernel-api.tmpl
+++ b/trunk/Documentation/DocBook/kernel-api.tmpl
@@ -158,7 +158,6 @@ X!Ilib/string.c
!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/trunk/Documentation/DocBook/libata.tmpl b/trunk/Documentation/DocBook/libata.tmpl
index 07a635590b36..c684abf0d3b2 100644
--- a/trunk/Documentation/DocBook/libata.tmpl
+++ b/trunk/Documentation/DocBook/libata.tmpl
@@ -14,7 +14,7 @@
- 2003-2006
+ 2003-2005
Jeff Garzik
diff --git a/trunk/Documentation/RCU/checklist.txt b/trunk/Documentation/RCU/checklist.txt
index f4dffadbcb00..1d50cf0c905e 100644
--- a/trunk/Documentation/RCU/checklist.txt
+++ b/trunk/Documentation/RCU/checklist.txt
@@ -221,41 +221,3 @@ over a rather long period of time, but improvements are always welcome!
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/trunk/Documentation/RCU/rcu.txt b/trunk/Documentation/RCU/rcu.txt
index f84407cba816..02e27bf1d365 100644
--- a/trunk/Documentation/RCU/rcu.txt
+++ b/trunk/Documentation/RCU/rcu.txt
@@ -45,8 +45,7 @@ o How can I see where RCU is currently used in the Linux kernel?
Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
"rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
- "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu",
- "synchronize_net", and "synchronize_srcu".
+ "synchronize_rcu", and "synchronize_net".
o What guidelines should I follow when writing code that uses RCU?
diff --git a/trunk/Documentation/RCU/torture.txt b/trunk/Documentation/RCU/torture.txt
index 25a3c3f7d378..a4948591607d 100644
--- a/trunk/Documentation/RCU/torture.txt
+++ b/trunk/Documentation/RCU/torture.txt
@@ -28,15 +28,6 @@ nreaders This is the number of RCU reading threads supported.
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.
@@ -53,12 +44,9 @@ test_no_idle_hz Whether or not to test the ability of RCU to operate in
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_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().
+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.
verbose Enable debug printk()s. Default is disabled.
@@ -130,21 +118,6 @@ o "Free-Block Circulation": Shows the number of torture structures
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/trunk/Documentation/RCU/whatisRCU.txt b/trunk/Documentation/RCU/whatisRCU.txt
index e0d6d99b8f9b..820fee236967 100644
--- a/trunk/Documentation/RCU/whatisRCU.txt
+++ b/trunk/Documentation/RCU/whatisRCU.txt
@@ -778,8 +778,6 @@ Markers for RCU read-side critical sections:
rcu_read_unlock
rcu_read_lock_bh
rcu_read_unlock_bh
- srcu_read_lock
- srcu_read_unlock
RCU pointer/list traversal:
@@ -806,7 +804,6 @@ RCU grace period:
synchronize_net
synchronize_sched
synchronize_rcu
- synchronize_srcu
call_rcu
call_rcu_bh
diff --git a/trunk/Documentation/ecryptfs.txt b/trunk/Documentation/ecryptfs.txt
deleted file mode 100644
index 01d8a08351ac..000000000000
--- a/trunk/Documentation/ecryptfs.txt
+++ /dev/null
@@ -1,77 +0,0 @@
-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
-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/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt
index 24f3c63b3017..42b95e0ad558 100644
--- a/trunk/Documentation/feature-removal-schedule.txt
+++ b/trunk/Documentation/feature-removal-schedule.txt
@@ -29,6 +29,14 @@ Who: Adrian Bunk
---------------------------
+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
+
+---------------------------
+
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/trunk/Documentation/kbuild/kconfig-language.txt b/trunk/Documentation/kbuild/kconfig-language.txt
index 125093c3ef76..7f34778dd23b 100644
--- a/trunk/Documentation/kbuild/kconfig-language.txt
+++ b/trunk/Documentation/kbuild/kconfig-language.txt
@@ -1,7 +1,7 @@
Introduction
------------
-The configuration database is a collection of configuration options
+The configuration database is collection of configuration options
organized in a tree structure:
+- Code maturity level options
diff --git a/trunk/Documentation/kbuild/makefiles.txt b/trunk/Documentation/kbuild/makefiles.txt
index 50f4eddf899c..e2cbd59cf2d0 100644
--- a/trunk/Documentation/kbuild/makefiles.txt
+++ b/trunk/Documentation/kbuild/makefiles.txt
@@ -390,7 +390,7 @@ more details, with real examples.
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 usually the gcc compiler, but other alternatives are
+ $(CC) is useally the gcc compiler, but other alternatives are
available.
as-option
diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt
index ff571f9298e0..12b3b24bfd2f 100644
--- a/trunk/Documentation/kernel-parameters.txt
+++ b/trunk/Documentation/kernel-parameters.txt
@@ -289,6 +289,9 @@ and is between 256 and 4096 characters. It is defined in the file
autotest [IA64]
+ awe= [HW,OSS] AWE32/SB32/AWE64 wave table synth
+ Format: ,,
+
aztcd= [HW,CD] Aztech CD268 CDROM driver
Format: ,0x79 (?)
@@ -533,6 +536,10 @@ and is between 256 and 4096 characters. It is defined in the file
Default value is 0.
Value can be changed at runtime via /selinux/enforce.
+ es1370= [HW,OSS]
+ Format: [,]
+ See also header of sound/oss/es1370.c.
+
es1371= [HW,OSS]
Format: ,[,[]]
See also header of sound/oss/es1371.c.
@@ -573,6 +580,9 @@ and is between 256 and 4096 characters. It is defined in the file
gscd= [HW,CD]
Format:
+ gus= [HW,OSS]
+ Format: ,,,
+
gvp11= [HW,SCSI]
hashdist= [KNL,NUMA] Large hashes allocated during boot
@@ -831,6 +841,12 @@ and is between 256 and 4096 characters. It is defined in the file
(machvec) in a generic kernel.
Example: machvec=hpzx1_swiotlb
+ mad16= [HW,OSS] Format:
+ ,,,,,,
+
+ maui= [HW,OSS]
+ Format: ,
+
max_loop= [LOOP] Maximum number of loopback devices that can
be mounted
Format: <1-256>
@@ -1098,6 +1114,9 @@ and is between 256 and 4096 characters. It is defined in the file
opl3= [HW,OSS]
Format:
+ opl3sa= [HW,OSS]
+ Format: ,,,,,
+
opl3sa2= [HW,OSS] Format:
,,,,,,,[,,
Run specified binary instead of /init from the ramdisk,
@@ -1432,6 +1455,9 @@ and is between 256 and 4096 characters. It is defined in the file
sg_def_reserved_size= [SCSI]
+ sgalaxy= [HW,OSS]
+ Format: ,,,,
+
shapers= [NET]
Maximal number of shapers.
@@ -1572,6 +1598,9 @@ and is between 256 and 4096 characters. It is defined in the file
snd-ymfpci= [HW,ALSA]
+ sonicvibes= [HW,OSS]
+ Format:
+
sonycd535= [HW,CD]
Format: [,]
diff --git a/trunk/Documentation/sound/oss/AWE32 b/trunk/Documentation/sound/oss/AWE32
new file mode 100644
index 000000000000..b5908a66ff55
--- /dev/null
+++ b/trunk/Documentation/sound/oss/AWE32
@@ -0,0 +1,76 @@
+ 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/trunk/Documentation/sound/oss/CMI8338 b/trunk/Documentation/sound/oss/CMI8338
new file mode 100644
index 000000000000..387d058c3f95
--- /dev/null
+++ b/trunk/Documentation/sound/oss/CMI8338
@@ -0,0 +1,85 @@
+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/trunk/Documentation/sound/oss/INSTALL.awe b/trunk/Documentation/sound/oss/INSTALL.awe
new file mode 100644
index 000000000000..310f42ca1e83
--- /dev/null
+++ b/trunk/Documentation/sound/oss/INSTALL.awe
@@ -0,0 +1,134 @@
+================================================================
+ INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX
+ Takashi Iwai
+================================================================
+
+----------------------------------------------------------------
+* 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/trunk/Documentation/sound/oss/MAD16 b/trunk/Documentation/sound/oss/MAD16
new file mode 100644
index 000000000000..865dbd848742
--- /dev/null
+++ b/trunk/Documentation/sound/oss/MAD16
@@ -0,0 +1,56 @@
+(This recipe has been edited to update the configuration symbols,
+ and change over to modprobe.conf for 2.6)
+
+From: Shaw Carruthers
+
+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/trunk/Documentation/sound/oss/Maestro b/trunk/Documentation/sound/oss/Maestro
new file mode 100644
index 000000000000..4a80eb3f8e00
--- /dev/null
+++ b/trunk/Documentation/sound/oss/Maestro
@@ -0,0 +1,123 @@
+ 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/trunk/Documentation/sound/oss/Maestro3 b/trunk/Documentation/sound/oss/Maestro3
new file mode 100644
index 000000000000..a113718e8034
--- /dev/null
+++ b/trunk/Documentation/sound/oss/Maestro3
@@ -0,0 +1,92 @@
+ 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/trunk/Documentation/sound/oss/NEWS b/trunk/Documentation/sound/oss/NEWS
new file mode 100644
index 000000000000..a81e0ef72ae9
--- /dev/null
+++ b/trunk/Documentation/sound/oss/NEWS
@@ -0,0 +1,42 @@
+Linux 2.4 Sound Changes
+2000-September-25
+Christoph Hellwig,
+
+
+
+=== 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/trunk/Documentation/sound/oss/OPL3-SA b/trunk/Documentation/sound/oss/OPL3-SA
new file mode 100644
index 000000000000..66a91835d918
--- /dev/null
+++ b/trunk/Documentation/sound/oss/OPL3-SA
@@ -0,0 +1,52 @@
+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?
+
diff --git a/trunk/Documentation/sound/oss/README.awe b/trunk/Documentation/sound/oss/README.awe
new file mode 100644
index 000000000000..80054cd8fcde
--- /dev/null
+++ b/trunk/Documentation/sound/oss/README.awe
@@ -0,0 +1,218 @@
+================================================================
+ AWE32 Sound Driver for Linux / FreeBSD
+ version 0.4.3; Nov. 1, 1998
+
+ Takashi Iwai
+================================================================
+
+* 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 ,
+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/trunk/Documentation/sound/oss/Wavefront b/trunk/Documentation/sound/oss/Wavefront
new file mode 100644
index 000000000000..16f57ea43052
--- /dev/null
+++ b/trunk/Documentation/sound/oss/Wavefront
@@ -0,0 +1,339 @@
+ 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
+ tar -zxvf
+
+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
+ 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
+ .
+ .
+ .
+
+ 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);
+<> { 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
+
+
diff --git a/trunk/Documentation/sound/oss/es1370 b/trunk/Documentation/sound/oss/es1370
new file mode 100644
index 000000000000..7b38b1a096a3
--- /dev/null
+++ b/trunk/Documentation/sound/oss/es1370
@@ -0,0 +1,70 @@
+/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/trunk/Documentation/sound/oss/rme96xx b/trunk/Documentation/sound/oss/rme96xx
new file mode 100644
index 000000000000..87d7b7b65fa1
--- /dev/null
+++ b/trunk/Documentation/sound/oss/rme96xx
@@ -0,0 +1,767 @@
+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
+
+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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "rme96xx.h"
+
+/*
+ remctrl.c
+ (C) 2000 Guenter Geiger
+ HP20020201 - Heiko Purnhagen
+*/
+
+/* # define DEVICE_NAME "/dev/mixer" */
+# define DEVICE_NAME "/dev/mixer1"
+
+
+void usage(void)
+{
+ fprintf(stderr,"usage: rmectrl [/dev/mixer] [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 set sync master\n");
+ fprintf(stderr," pro set spdif out pro\n");
+ fprintf(stderr," emphasis set spdif out emphasis\n");
+ fprintf(stderr," dolby set spdif out no audio\n");
+ fprintf(stderr," optout set spdif out optical\n");
+ fprintf(stderr," wordclock set sync wordclock\n");
+ fprintf(stderr," spdifin set spdif in (0=optical,1=coax,2=intern)\n");
+ fprintf(stderr," syncref set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n");
+ fprintf(stderr," adat1cd set ADAT1 on internal CD\n");
+ fprintf(stderr," offset 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 */
+}
+
+
+---------------------------- --------------------------------
+#!/usr/bin/wish
+
+# xrmectrl
+# (C) 2000 Guenter Geiger
+# HP20020201 - Heiko Purnhagen
+
+#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/trunk/Documentation/sound/oss/solo1 b/trunk/Documentation/sound/oss/solo1
new file mode 100644
index 000000000000..95c4c83422b3
--- /dev/null
+++ b/trunk/Documentation/sound/oss/solo1
@@ -0,0 +1,70 @@
+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/trunk/Documentation/sound/oss/sonicvibes b/trunk/Documentation/sound/oss/sonicvibes
new file mode 100644
index 000000000000..84dee2e0b37d
--- /dev/null
+++ b/trunk/Documentation/sound/oss/sonicvibes
@@ -0,0 +1,81 @@
+/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/trunk/MAINTAINERS b/trunk/MAINTAINERS
index 8c35b3c503aa..1c6223d3ce70 100644
--- a/trunk/MAINTAINERS
+++ b/trunk/MAINTAINERS
@@ -977,13 +977,6 @@ L: ebtables-devel@lists.sourceforge.net
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
@@ -1900,6 +1893,11 @@ M: rroesler@syskonnect.de
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
@@ -2436,19 +2434,6 @@ M: mporter@kernel.crashing.org
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
@@ -2869,11 +2854,6 @@ M: hlhung3i@gmail.com
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
@@ -3397,6 +3377,12 @@ M: Henk.Vergonet@gmail.com
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/trunk/Makefile b/trunk/Makefile
index adb2c748e105..4c6c5e32ef96 100644
--- a/trunk/Makefile
+++ b/trunk/Makefile
@@ -1321,7 +1321,7 @@ define xtags
--langdef=kconfig \
--language-force=kconfig \
--regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \
- $(all-defconfigs) | xargs -r $1 -a \
+ $(all-defconfigs) | xargs $1 -a \
--langdef=dotconfig \
--language-force=dotconfig \
--regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \
@@ -1329,7 +1329,7 @@ define xtags
$(all-sources) | xargs $1 -a; \
$(all-kconfigs) | xargs $1 -a \
--regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \
- $(all-defconfigs) | xargs -r $1 -a \
+ $(all-defconfigs) | xargs $1 -a \
--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
else \
$(all-sources) | xargs $1 -a; \
diff --git a/trunk/arch/i386/kernel/acpi/boot.c b/trunk/arch/i386/kernel/acpi/boot.c
index 92f79cdd9a48..1aaea6ab8c46 100644
--- a/trunk/arch/i386/kernel/acpi/boot.c
+++ b/trunk/arch/i386/kernel/acpi/boot.c
@@ -62,6 +62,8 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return
#include
#endif /* CONFIG_X86_LOCAL_APIC */
+static inline int gsi_irq_sharing(int gsi) { return gsi; }
+
#endif /* X86 */
#define BAD_MADT_ENTRY(entry, end) ( \
@@ -466,7 +468,12 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
- *irq = gsi;
+#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);
return 0;
}
diff --git a/trunk/arch/i386/kernel/i8259.c b/trunk/arch/i386/kernel/i8259.c
index d07ed31f11e3..ea5f4e7958d8 100644
--- a/trunk/arch/i386/kernel/i8259.c
+++ b/trunk/arch/i386/kernel/i8259.c
@@ -34,15 +34,35 @@
* moves to arch independent land
*/
-static int i8259A_auto_eoi;
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;
+
static void mask_and_ack_8259A(unsigned int);
-static struct irq_chip i8259A_chip = {
- .name = "XT-PIC",
- .mask = disable_8259A_irq,
- .unmask = enable_8259A_irq,
- .mask_ack = mask_and_ack_8259A,
+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,
};
/*
@@ -113,7 +133,7 @@ void make_8259A_irq(unsigned int irq)
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<
#include
#include
-#include
-#include
-#include
#include
#include
@@ -41,8 +38,6 @@
#include
#include
#include
-#include
-#include
#include
#include
@@ -91,6 +86,15 @@ static struct irq_pin_list {
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;
@@ -276,7 +280,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
break;
entry = irq_2_pin + entry->next;
}
- set_native_irq_info(irq, cpumask);
+ set_irq_info(irq, cpumask);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -1177,45 +1181,46 @@ static inline int IO_APIC_irq_trigger(int irq)
/* 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 };
-static int __assign_irq_vector(int irq)
+int assign_irq_vector(int irq)
{
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+ unsigned long flags;
int vector;
- BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+ BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
- if (IO_APIC_VECTOR(irq) > 0)
- return IO_APIC_VECTOR(irq);
+ 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 == SYSCALL_VECTOR)
- current_vector += 8;
+ goto next;
if (current_vector >= FIRST_SYSTEM_VECTOR) {
offset++;
- if (!(offset % 8))
+ if (!(offset%8)) {
+ spin_unlock_irqrestore(&vector_lock, flags);
return -ENOSPC;
+ }
current_vector = FIRST_DEVICE_VECTOR + offset;
}
vector = current_vector;
- IO_APIC_VECTOR(irq) = vector;
-
- return vector;
-}
-
-static int assign_irq_vector(int irq)
-{
- unsigned long flags;
- int vector;
+ vector_irq[vector] = irq;
+ if (irq != AUTO_ASSIGN)
+ IO_APIC_VECTOR(irq) = 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;
+
+static struct hw_interrupt_type ioapic_level_type;
+static struct hw_interrupt_type ioapic_edge_type;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
@@ -1223,14 +1228,16 @@ static struct irq_chip ioapic_chip;
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)
- set_irq_chip_and_handler(irq, &ioapic_chip,
- handle_fasteoi_irq);
+ irq_desc[idx].chip = &ioapic_level_type;
else
- set_irq_chip_and_handler(irq, &ioapic_chip,
- handle_edge_irq);
- set_intr_gate(vector, interrupt[irq]);
+ irq_desc[idx].chip = &ioapic_edge_type;
+ set_intr_gate(vector, interrupt[idx]);
}
static void __init setup_IO_APIC_irqs(void)
@@ -1339,8 +1346,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
* 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_chip;
- set_irq_handler(0, handle_edge_irq);
+ irq_desc[0].chip = &ioapic_edge_type;
/*
* Add it to the IO-APIC irq-routing table:
@@ -1475,12 +1481,17 @@ void __init print_IO_APIC(void)
);
}
}
+ 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;
- printk(KERN_DEBUG "IRQ%d ", i);
+ if (use_pci_vector() && !platform_legacy_irq(i))
+ printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
+ else
+ printk(KERN_DEBUG "IRQ%d ", i);
for (;;) {
printk("-> %d:%d", entry->apic, entry->pin);
if (!entry->next)
@@ -1907,8 +1918,6 @@ static int __init timer_irq_works(void)
*/
/*
- * 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
@@ -1916,10 +1925,8 @@ static int __init timer_irq_works(void)
*
* 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_ioapic_irq(unsigned int irq)
+static unsigned int startup_edge_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
unsigned long flags;
@@ -1936,18 +1943,47 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
return was_pending;
}
-static void ack_ioapic_irq(unsigned int irq)
+/*
+ * 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)
{
- move_native_irq(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();
}
-static void ack_ioapic_quirk_irq(unsigned int 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)
{
unsigned long v;
int i;
- move_native_irq(irq);
+ move_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
@@ -1982,26 +2018,105 @@ static void ack_ioapic_quirk_irq(unsigned int irq)
}
}
-static int ioapic_retrigger_irq(unsigned int 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
+#endif
+
+static int ioapic_retrigger(unsigned int irq)
{
send_IPI_self(IO_APIC_VECTOR(irq));
return 1;
}
-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,
+/*
+ * 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,
#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity_irq,
+ .set_affinity = set_ioapic_affinity,
#endif
- .retrigger = ioapic_retrigger_irq,
+ .retrigger = ioapic_retrigger,
};
+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)
{
@@ -2020,6 +2135,11 @@ static inline void init_IO_APIC_traps(void)
*/
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,
@@ -2030,21 +2150,20 @@ static inline void init_IO_APIC_traps(void)
make_8259A_irq(irq);
else
/* Strange. Oh, well.. */
- irq_desc[irq].chip = &no_irq_chip;
+ irq_desc[irq].chip = &no_irq_type;
}
}
}
-/*
- * The local APIC irq-chip implementation:
- */
-
-static void ack_apic(unsigned int irq)
+static void enable_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 mask_lapic_irq (unsigned int irq)
+static void disable_lapic_irq (unsigned int irq)
{
unsigned long v;
@@ -2052,19 +2171,21 @@ static void mask_lapic_irq (unsigned int irq)
apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
}
-static void unmask_lapic_irq (unsigned int irq)
+static void ack_lapic_irq (unsigned int irq)
{
- unsigned long v;
-
- v = apic_read(APIC_LVT0);
- apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+ ack_APIC_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 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 void setup_nmi (void)
@@ -2235,7 +2356,7 @@ static inline void check_timer(void)
printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
disable_8259A_irq(0);
- set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq);
+ irq_desc[0].chip = &lapic_irq_type;
apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
enable_8259A_irq(0);
@@ -2410,238 +2531,6 @@ static int __init ioapic_init_sysfs(void)
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
-------------------------------------------------------------------------- */
@@ -2795,7 +2684,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
ioapic_write_entry(ioapic, pin, entry);
spin_lock_irqsave(&ioapic_lock, flags);
- set_native_irq_info(irq, TARGET_CPUS);
+ set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
diff --git a/trunk/arch/i386/kernel/irq.c b/trunk/arch/i386/kernel/irq.c
index 3dd2e180151b..5fe547cd8f9f 100644
--- a/trunk/arch/i386/kernel/irq.c
+++ b/trunk/arch/i386/kernel/irq.c
@@ -55,7 +55,6 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
{
/* 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;
@@ -95,7 +94,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
* current stack (which is the irq stack already after all)
*/
if (curctx != irqctx) {
- int arg1, arg2, arg3, ebx;
+ int arg1, arg2, ebx;
/* build the stack frame on the IRQ stack */
isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -111,17 +110,16 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
(curctx->tinfo.preempt_count & SOFTIRQ_MASK);
asm volatile(
- " xchgl %%ebx,%%esp \n"
- " call *%%edi \n"
+ " xchgl %%ebx,%%esp \n"
+ " call __do_IRQ \n"
" movl %%ebx,%%esp \n"
- : "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx)
- : "0" (irq), "1" (desc), "2" (regs), "3" (isp),
- "D" (desc->handle_irq)
- : "memory", "cc"
+ : "=a" (arg1), "=d" (arg2), "=b" (ebx)
+ : "0" (irq), "1" (regs), "2" (isp)
+ : "memory", "cc", "ecx"
);
} else
#endif
- desc->handle_irq(irq, desc, regs);
+ __do_IRQ(irq, regs);
irq_exit();
@@ -255,8 +253,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- seq_printf(p, " %8s", irq_desc[i].chip->name);
- seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
+ seq_printf(p, " %14s", irq_desc[i].chip->typename);
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
diff --git a/trunk/arch/i386/pci/irq.c b/trunk/arch/i386/pci/irq.c
index 47f02af74be3..4a8995c9c762 100644
--- a/trunk/arch/i386/pci/irq.c
+++ b/trunk/arch/i386/pci/irq.c
@@ -981,6 +981,10 @@ static void __init pcibios_fixup_irqs(void)
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;
@@ -1165,3 +1169,33 @@ static int pirq_enable_irq(struct pci_dev *dev)
}
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/trunk/arch/ia64/kernel/Makefile b/trunk/arch/ia64/kernel/Makefile
index cfa099b04cda..31497496eb4b 100644
--- a/trunk/arch/ia64/kernel/Makefile
+++ b/trunk/arch/ia64/kernel/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
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/trunk/arch/ia64/kernel/irq_ia64.c b/trunk/arch/ia64/kernel/irq_ia64.c
index ab2d19c3661f..aafca18ab33b 100644
--- a/trunk/arch/ia64/kernel/irq_ia64.c
+++ b/trunk/arch/ia64/kernel/irq_ia64.c
@@ -30,7 +30,6 @@
#include
#include
#include
-#include
#include
#include
@@ -106,25 +105,6 @@ reserve_irq_vector (int vector)
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/trunk/arch/ia64/kernel/msi_ia64.c b/trunk/arch/ia64/kernel/msi_ia64.c
deleted file mode 100644
index 822e59a1b822..000000000000
--- a/trunk/arch/ia64/kernel/msi_ia64.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * MSI hooks for standard x86 apic
- */
-
-#include
-#include
-#include
-#include
-
-/*
- * 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/trunk/arch/ia64/pci/pci.c b/trunk/arch/ia64/pci/pci.c
index b30be7c48ba8..15c7c670da39 100644
--- a/trunk/arch/ia64/pci/pci.c
+++ b/trunk/arch/ia64/pci/pci.c
@@ -810,3 +810,12 @@ pcibios_prep_mwi (struct pci_dev *dev)
}
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/trunk/arch/ia64/sn/kernel/Makefile b/trunk/arch/ia64/sn/kernel/Makefile
index 2d78f34dd763..ab9c48c88012 100644
--- a/trunk/arch/ia64/sn/kernel/Makefile
+++ b/trunk/arch/ia64/sn/kernel/Makefile
@@ -19,4 +19,3 @@ xp-y := xp_main.o xp_nofault.o
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/trunk/arch/powerpc/boot/Makefile b/trunk/arch/powerpc/boot/Makefile
index 003520b56303..c383d56bbe18 100644
--- a/trunk/arch/powerpc/boot/Makefile
+++ b/trunk/arch/powerpc/boot/Makefile
@@ -113,7 +113,7 @@ endif
endif
quiet_cmd_wrap = WRAP $@
- cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
+ cmd_wrap =$(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/trunk/arch/powerpc/sysdev/mpic.c b/trunk/arch/powerpc/sysdev/mpic.c
index 3ee03a9a98fa..723972bb5bd9 100644
--- a/trunk/arch/powerpc/sysdev/mpic.c
+++ b/trunk/arch/powerpc/sysdev/mpic.c
@@ -341,7 +341,7 @@ static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
if (id == PCI_CAP_ID_HT) {
id = readb(devbase + pos + 3);
- if (id == HT_CAPTYPE_IRQ)
+ if (id == 0x80)
break;
}
}
diff --git a/trunk/arch/x86_64/kernel/i8259.c b/trunk/arch/x86_64/kernel/i8259.c
index 0612a33bb896..2dd51f364ea2 100644
--- a/trunk/arch/x86_64/kernel/i8259.c
+++ b/trunk/arch/x86_64/kernel/i8259.c
@@ -43,10 +43,17 @@
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
@@ -58,12 +65,17 @@
*
* (these are usually mapped into the 0x30-0xff vector range)
*/
- BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+ BUILD_16_IRQS(0x1) 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) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
+
+#ifdef CONFIG_PCI_MSI
+ BUILD_15_IRQS(0xe)
+#endif
#undef BUILD_16_IRQS
+#undef BUILD_15_IRQS
#undef BI
@@ -76,15 +88,29 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
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(0x2), IRQLIST_16(0x3),
+ IRQLIST_16(0x0),
+
+ IRQLIST_16(0x1), 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), IRQLIST_16(0xe), IRQLIST_16(0xf)
+ IRQLIST_16(0xc), IRQLIST_16(0xd)
+
+#ifdef CONFIG_PCI_MSI
+ , IRQLIST_15(0xe)
+#endif
+
};
#undef IRQ
#undef IRQLIST_16
+#undef IRQLIST_14
/*
* This is the 'legacy' 8259A Programmable Interrupt Controller,
@@ -95,15 +121,42 @@ void (*interrupt[NR_IRQS])(void) = {
* moves to arch independent land
*/
-static int i8259A_auto_eoi;
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
+
static void mask_and_ack_8259A(unsigned int);
-static struct irq_chip i8259A_chip = {
- .name = "XT-PIC",
- .mask = disable_8259A_irq,
- .unmask = enable_8259A_irq,
- .mask_ack = mask_and_ack_8259A,
+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,
};
/*
@@ -178,7 +231,7 @@ void make_8259A_irq(unsigned int irq)
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<= NR_IRQS)
+ break;
if (vector != IA32_SYSCALL_VECTOR)
set_intr_gate(vector, interrupt[i]);
}
@@ -520,7 +554,7 @@ void __init init_IRQ(void)
* IRQ0 must be given a fixed assignment and initialized,
* because it's used before the IO-APIC is set up.
*/
- __get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0;
+ set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
/*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
diff --git a/trunk/arch/x86_64/kernel/io_apic.c b/trunk/arch/x86_64/kernel/io_apic.c
index 91728d9d3472..0491019d4c8d 100644
--- a/trunk/arch/x86_64/kernel/io_apic.c
+++ b/trunk/arch/x86_64/kernel/io_apic.c
@@ -26,12 +26,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
-#include
#ifdef CONFIG_ACPI
#include
#endif
@@ -44,10 +41,6 @@
#include
#include
#include
-#include
-#include
-
-static int assign_irq_vector(int irq, cpumask_t mask);
#define __apicdebuginit __init
@@ -88,6 +81,14 @@ static struct irq_pin_list {
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) \
\
{ \
@@ -138,35 +139,11 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
}
#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))
@@ -174,13 +151,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
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);
+ dest = cpu_mask_to_apicid(mask);
/*
* Only the high 8 bits are valid.
@@ -188,12 +159,14 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
dest = SET_APIC_LOGICAL_ID(dest);
spin_lock_irqsave(&ioapic_lock, flags);
- __target_IO_APIC_irq(irq, dest, vector & 0xff);
- set_native_irq_info(irq, mask);
+ __DO_ACTION(1, = dest, )
+ set_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
@@ -519,6 +492,64 @@ static inline int irq_trigger(int idx)
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;
@@ -540,6 +571,7 @@ static int pin_2_irq(int idx, int apic, int pin)
while (i < apic)
irq += nr_ioapic_registers[i++];
irq += pin;
+ irq = gsi_irq_sharing(irq);
}
BUG_ON(irq >= NR_IRQS);
return irq;
@@ -563,83 +595,46 @@ static inline int IO_APIC_irq_trigger(int irq)
}
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-unsigned int irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_EXTERNAL_VECTOR, 0 };
+u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
-static int __assign_irq_vector(int irq, cpumask_t mask)
+int assign_irq_vector(int irq)
{
- /*
- * 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((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;
- }
+ static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+ unsigned long flags;
+ int vector;
+
+ BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+
+ spin_lock_irqsave(&vector_lock, flags);
- for_each_cpu_mask(cpu, mask) {
- int vector, offset;
- vector = pos[cpu].vector;
- offset = pos[cpu].offset;
+ if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
+ spin_unlock_irqrestore(&vector_lock, flags);
+ return IO_APIC_VECTOR(irq);
+ }
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;
+ 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;
}
- return -ENOSPC;
-}
-static int assign_irq_vector(int irq, cpumask_t mask)
-{
- int vector;
- unsigned long flags;
+ vector = current_vector;
+ vector_irq[vector] = irq;
+ if (irq != AUTO_ASSIGN)
+ IO_APIC_VECTOR(irq) = vector;
- spin_lock_irqsave(&vector_lock, flags);
- vector = __assign_irq_vector(irq, mask);
spin_unlock_irqrestore(&vector_lock, flags);
+
return vector;
}
extern void (*interrupt[NR_IRQS])(void);
-
-static struct irq_chip ioapic_chip;
+static struct hw_interrupt_type ioapic_level_type;
+static struct hw_interrupt_type ioapic_edge_type;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
@@ -647,13 +642,16 @@ static struct irq_chip ioapic_chip;
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)
- set_irq_chip_and_handler(irq, &ioapic_chip,
- handle_fasteoi_irq);
+ irq_desc[idx].chip = &ioapic_level_type;
else
- set_irq_chip_and_handler(irq, &ioapic_chip,
- handle_edge_irq);
+ irq_desc[idx].chip = &ioapic_edge_type;
+ set_intr_gate(vector, interrupt[idx]);
}
static void __init setup_IO_APIC_irqs(void)
@@ -703,15 +701,8 @@ static void __init setup_IO_APIC_irqs(void)
continue;
if (IO_APIC_IRQ(irq)) {
- 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;
+ vector = assign_irq_vector(irq);
+ entry.vector = vector;
ioapic_register_intr(irq, vector, IOAPIC_AUTO);
if (!apic && (irq < 16))
@@ -761,7 +752,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
* The timer IRQ doesn't have to know that behind the
* scene we have a 8259A-master in AEOI mode ...
*/
- set_irq_chip_and_handler(0, &ioapic_chip, handle_edge_irq);
+ irq_desc[0].chip = &ioapic_edge_type;
/*
* Add it to the IO-APIC irq-routing table:
@@ -877,12 +868,17 @@ void __apicdebuginit print_IO_APIC(void)
);
}
}
+ 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;
- printk(KERN_DEBUG "IRQ%d ", i);
+ if (use_pci_vector() && !platform_legacy_irq(i))
+ printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
+ else
+ printk(KERN_DEBUG "IRQ%d ", i);
for (;;) {
printk("-> %d:%d", entry->apic, entry->pin);
if (!entry->next)
@@ -1189,7 +1185,7 @@ static int __init timer_irq_works(void)
* an edge even if it isn't on the 8259A...
*/
-static unsigned int startup_ioapic_irq(unsigned int irq)
+static unsigned int startup_edge_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
unsigned long flags;
@@ -1206,16 +1202,107 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
return was_pending;
}
-static int ioapic_retrigger_irq(unsigned int irq)
+/*
+ * 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)
+{
+ move_irq(irq);
+ if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
+ == (IRQ_PENDING | IRQ_DISABLED))
+ mask_IO_APIC_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)
+{
+ 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)
{
- cpumask_t mask;
- unsigned vector;
+ int irq = vector_to_irq(vector);
- vector = irq_vector[irq];
- cpus_clear(mask);
- cpu_set(vector >> 8, mask);
+ 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);
+}
- send_IPI_mask(mask, vector & 0xff);
+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));
return 1;
}
@@ -1229,47 +1316,32 @@ static int ioapic_retrigger_irq(unsigned int irq)
* races.
*/
-static void ack_apic_edge(unsigned int irq)
-{
- move_native_irq(irq);
- ack_APIC_irq();
-}
-
-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);
- }
+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,
+};
- /*
- * 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,
+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_irq,
+ .set_affinity = set_ioapic_affinity,
#endif
- .retrigger = ioapic_retrigger_irq,
+ .retrigger = ioapic_retrigger,
};
static inline void init_IO_APIC_traps(void)
@@ -1289,6 +1361,11 @@ static inline void init_IO_APIC_traps(void)
*/
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,
@@ -1299,7 +1376,7 @@ static inline void init_IO_APIC_traps(void)
make_8259A_irq(irq);
else
/* Strange. Oh, well.. */
- irq_desc[irq].chip = &no_irq_chip;
+ irq_desc[irq].chip = &no_irq_type;
}
}
}
@@ -1418,6 +1495,8 @@ static inline void unlock_ExtINT_logic(void)
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
@@ -1435,7 +1514,8 @@ static inline void check_timer(void)
* get/set the timer IRQ vector:
*/
disable_8259A_irq(0);
- vector = assign_irq_vector(0, TARGET_CPUS);
+ vector = assign_irq_vector(0);
+ set_intr_gate(vector, interrupt[0]);
/*
* Subtle, code in do_timer_interrupt() expects an AEOI
@@ -1454,6 +1534,9 @@ static inline void check_timer(void)
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);
@@ -1657,253 +1740,6 @@ static int __init ioapic_init_sysfs(void)
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
-------------------------------------------------------------------------- */
@@ -1929,8 +1765,6 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
{
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",
@@ -1938,20 +1772,6 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
return -EINVAL;
}
- /*
- * 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
@@ -1962,11 +1782,19 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
entry.delivery_mode = INT_DELIVERY_MODE;
entry.dest_mode = INT_DEST_MODE;
- entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
+ entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
entry.trigger = triggering;
entry.polarity = polarity;
entry.mask = 1; /* Disabled (masked) */
- entry.vector = vector & 0xff;
+
+ 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);
apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
"IRQ %d Mode:%i Active:%i)\n", ioapic,
@@ -1981,7 +1809,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
ioapic_write_entry(ioapic, pin, entry);
spin_lock_irqsave(&ioapic_lock, flags);
- set_native_irq_info(irq, TARGET_CPUS);
+ set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
diff --git a/trunk/arch/x86_64/kernel/irq.c b/trunk/arch/x86_64/kernel/irq.c
index 506f27c85ca5..b3677e6ccc6e 100644
--- a/trunk/arch/x86_64/kernel/irq.c
+++ b/trunk/arch/x86_64/kernel/irq.c
@@ -74,8 +74,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- seq_printf(p, " %8s", irq_desc[i].chip->name);
- seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
+ seq_printf(p, " %14s", irq_desc[i].chip->typename);
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
@@ -105,12 +104,7 @@ int show_interrupts(struct seq_file *p, void *v)
asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
{
/* high bit used in ret_from_ code */
- unsigned vector = ~regs->orig_rax;
- unsigned irq;
-
- exit_idle();
- irq_enter();
- irq = __get_cpu_var(vector_irq)[vector];
+ unsigned irq = ~regs->orig_rax;
if (unlikely(irq >= NR_IRQS)) {
printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
@@ -118,10 +112,12 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
BUG();
}
+ exit_idle();
+ irq_enter();
#ifdef CONFIG_DEBUG_STACKOVERFLOW
stack_overflow_check(regs);
#endif
- generic_handle_irq(irq, regs);
+ __do_IRQ(irq, regs);
irq_exit();
return 1;
diff --git a/trunk/arch/x86_64/kernel/mpparse.c b/trunk/arch/x86_64/kernel/mpparse.c
index b147ab19fbd4..b8d53dfa9931 100644
--- a/trunk/arch/x86_64/kernel/mpparse.c
+++ b/trunk/arch/x86_64/kernel/mpparse.c
@@ -790,11 +790,20 @@ void __init mp_config_acpi_legacy_irqs(void)
}
}
+#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;
@@ -827,11 +836,42 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
if ((1< 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/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c
index 54e1f38ce301..1aabc81d82f1 100644
--- a/trunk/drivers/ata/ahci.c
+++ b/trunk/drivers/ata/ahci.c
@@ -299,46 +299,76 @@ static const struct ata_port_info ahci_port_info[] = {
static const struct pci_device_id ahci_pci_tbl[] = {
/* Intel */
- { 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 */
+ { 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 */
/* JMicron */
- { 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 */
+ { 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 */
/* ATI */
- { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
- { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
+ { 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 */
/* VIA */
- { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
+ { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
- { 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 */
+ { 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 */
/* SiS */
- { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
- { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
+ { 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 */
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/libata-core.c b/trunk/drivers/ata/libata-core.c
index dce65651d858..b4abd6850367 100644
--- a/trunk/drivers/ata/libata-core.c
+++ b/trunk/drivers/ata/libata-core.c
@@ -2340,8 +2340,7 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
if (status & ATA_BUSY)
ata_port_printk(ap, KERN_WARNING,
- "port is slow to respond, please be patient "
- "(Status 0x%x)\n", status);
+ "port is slow to respond, please be patient\n");
timeout = timer_start + tmout;
while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
@@ -2351,8 +2350,7 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
if (status & ATA_BUSY) {
ata_port_printk(ap, KERN_ERR, "port failed to respond "
- "(%lu secs, Status 0x%x)\n",
- tmout / HZ, status);
+ "(%lu secs)\n", tmout / HZ);
return 1;
}
@@ -5480,10 +5478,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
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");
@@ -5741,7 +5740,7 @@ void ata_host_remove(struct ata_host *host)
/**
* ata_scsi_release - SCSI layer callback hook for host unload
- * @shost: libata host to be unloaded
+ * @host: libata host to be unloaded
*
* Performs all duties necessary to shut down a libata port...
* Kill port kthread, disable port, and release resources.
@@ -5787,7 +5786,6 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
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/trunk/drivers/ata/libata-scsi.c b/trunk/drivers/ata/libata-scsi.c
index b0d0cc41f3e8..3986ec8741b4 100644
--- a/trunk/drivers/ata/libata-scsi.c
+++ b/trunk/drivers/ata/libata-scsi.c
@@ -889,7 +889,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev;
- unsigned long flags;
int max_depth;
if (queue_depth < 1)
@@ -905,14 +904,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
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;
}
@@ -1302,8 +1293,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
*/
goto nothing_to_do;
- if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
- ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+ if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
/* yay, NCQ */
if (!lba_48_ok(block, n_block))
goto out_of_range;
@@ -3184,7 +3174,7 @@ void ata_scsi_dev_rescan(void *data)
/**
* ata_sas_port_alloc - Allocate port for a SAS attached SATA device
- * @host: ATA host container for all SAS ports
+ * @pdev: PCI device that the scsi device is attached to
* @port_info: Information from low-level host driver
* @shost: SCSI host that the scsi device is attached to
*
diff --git a/trunk/drivers/ata/libata-sff.c b/trunk/drivers/ata/libata-sff.c
index 06daaa3736a2..08b3a407473e 100644
--- a/trunk/drivers/ata/libata-sff.c
+++ b/trunk/drivers/ata/libata-sff.c
@@ -828,6 +828,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
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);
@@ -877,6 +878,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
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;
@@ -906,8 +908,6 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
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,21 +946,35 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
{
struct ata_probe_ent *probe_ent = NULL;
struct ata_port_info *port[2];
- u8 mask;
+ u8 tmp8, 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
@@ -973,16 +987,6 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
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;
@@ -1035,7 +1039,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
goto err_out_regions;
}
- /* TODO: If we get no DMA mask we should fall back to PIO */
+ /* FIXME: 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;
@@ -1058,17 +1062,13 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
pci_set_master(pdev);
- if (!ata_device_add(probe_ent)) {
- rc = -ENODEV;
- goto err_out_ent;
- }
+ /* FIXME: check ata_device_add return */
+ ata_device_add(probe_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/trunk/drivers/ata/pata_ali.c b/trunk/drivers/ata/pata_ali.c
index 1d695df5860a..87af3b5861ab 100644
--- a/trunk/drivers/ata/pata_ali.c
+++ b/trunk/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@
#include
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.6.6"
+#define DRV_VERSION "0.6.5"
/*
* Cable special cases
@@ -630,7 +630,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
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,11 +644,10 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
-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_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 struct pci_driver ali_pci_driver = {
diff --git a/trunk/drivers/ata/pata_amd.c b/trunk/drivers/ata/pata_amd.c
index 29234c897118..599ee266722c 100644
--- a/trunk/drivers/ata/pata_amd.c
+++ b/trunk/drivers/ata/pata_amd.c
@@ -662,28 +662,27 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
static const struct pci_device_id amd[] = {
- { 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 },
-
- { },
+ { 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, },
};
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
@@ -699,6 +698,7 @@ static void __exit amd_exit(void)
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/trunk/drivers/ata/pata_artop.c b/trunk/drivers/ata/pata_artop.c
index 690828eb5226..c4ccb75a4f1d 100644
--- a/trunk/drivers/ata/pata_artop.c
+++ b/trunk/drivers/ata/pata_artop.c
@@ -426,7 +426,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &artop6260_ops,
};
struct ata_port_info *port_info[2];
- struct ata_port_info *info = NULL;
+ struct ata_port_info *info;
int ports = 2;
if (!printed_version++)
@@ -470,20 +470,16 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
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[] = {
- { 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 },
-
+ { 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},
{ } /* terminate list */
};
@@ -504,6 +500,7 @@ static void __exit artop_exit(void)
pci_unregister_driver(&artop_pci_driver);
}
+
module_init(artop_init);
module_exit(artop_exit);
diff --git a/trunk/drivers/ata/pata_atiixp.c b/trunk/drivers/ata/pata_atiixp.c
index 1ce28d2125f4..6c2269b6bd3c 100644
--- a/trunk/drivers/ata/pata_atiixp.c
+++ b/trunk/drivers/ata/pata_atiixp.c
@@ -267,13 +267,12 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-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_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 struct pci_driver atiixp_pci_driver = {
@@ -294,6 +293,7 @@ static void __exit atiixp_exit(void)
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/trunk/drivers/ata/pata_cmd64x.c b/trunk/drivers/ata/pata_cmd64x.c
index b9bbd1d454bf..e92b0ef43ec5 100644
--- a/trunk/drivers/ata/pata_cmd64x.c
+++ b/trunk/drivers/ata/pata_cmd64x.c
@@ -468,17 +468,16 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
-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_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 struct pci_driver cmd64x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = cmd64x,
.probe = cmd64x_init_one,
.remove = ata_pci_remove_one
@@ -489,11 +488,13 @@ static int __init cmd64x_init(void)
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/trunk/drivers/ata/pata_cs5520.c b/trunk/drivers/ata/pata_cs5520.c
index 2cd3c0ff76df..a6c6cebd0dae 100644
--- a/trunk/drivers/ata/pata_cs5520.c
+++ b/trunk/drivers/ata/pata_cs5520.c
@@ -299,11 +299,10 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev)
/* For now keep DMA off. We can set it for all but A rev CS5510 once the
core ATA code can handle it */
-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_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 struct pci_driver cs5520_pci_driver = {
@@ -313,6 +312,7 @@ static struct pci_driver cs5520_pci_driver = {
.remove = cs5520_remove_one
};
+
static int __init cs5520_init(void)
{
return pci_register_driver(&cs5520_pci_driver);
diff --git a/trunk/drivers/ata/pata_cs5530.c b/trunk/drivers/ata/pata_cs5530.c
index a07cc81ef791..7bba4d954e9c 100644
--- a/trunk/drivers/ata/pata_cs5530.c
+++ b/trunk/drivers/ata/pata_cs5530.c
@@ -353,14 +353,13 @@ static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}
-static const struct pci_device_id cs5530[] = {
- { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
-
- { },
+static struct pci_device_id cs5530[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
+ { 0, },
};
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
@@ -371,11 +370,13 @@ static int __init cs5530_init(void)
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/trunk/drivers/ata/pata_cs5535.c b/trunk/drivers/ata/pata_cs5535.c
index f8def3f9c618..d64fcdceaf01 100644
--- a/trunk/drivers/ata/pata_cs5535.c
+++ b/trunk/drivers/ata/pata_cs5535.c
@@ -257,10 +257,9 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, ports, 1);
}
-static const struct pci_device_id cs5535[] = {
- { PCI_VDEVICE(NS, 0x002D), },
-
- { },
+static struct pci_device_id cs5535[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), },
+ { 0, },
};
static struct pci_driver cs5535_pci_driver = {
@@ -275,11 +274,13 @@ static int __init cs5535_init(void)
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/trunk/drivers/ata/pata_cypress.c b/trunk/drivers/ata/pata_cypress.c
index 247b43608b14..dfa5ac539048 100644
--- a/trunk/drivers/ata/pata_cypress.c
+++ b/trunk/drivers/ata/pata_cypress.c
@@ -184,8 +184,8 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
};
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,14 +193,13 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
return ata_pci_init_one(pdev, port_info, 1);
}
-static const struct pci_device_id cy82c693[] = {
- { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), },
-
- { },
+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 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/trunk/drivers/ata/pata_efar.c b/trunk/drivers/ata/pata_efar.c
index ef18c60fe140..95cd1ca181f5 100644
--- a/trunk/drivers/ata/pata_efar.c
+++ b/trunk/drivers/ata/pata_efar.c
@@ -305,8 +305,7 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
static const struct pci_device_id efar_pci_tbl[] = {
- { PCI_VDEVICE(EFAR, 0x9130), },
-
+ { 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* terminate list */
};
@@ -327,6 +326,7 @@ static void __exit efar_exit(void)
pci_unregister_driver(&efar_pci_driver);
}
+
module_init(efar_init);
module_exit(efar_exit);
diff --git a/trunk/drivers/ata/pata_hpt366.c b/trunk/drivers/ata/pata_hpt366.c
index 6d3e4c0f15fe..8c757438f350 100644
--- a/trunk/drivers/ata/pata_hpt366.c
+++ b/trunk/drivers/ata/pata_hpt366.c
@@ -444,14 +444,13 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static const struct pci_device_id hpt36x[] = {
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
-
- { },
+static struct pci_device_id hpt36x[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { 0, },
};
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/trunk/drivers/ata/pata_hpt37x.c b/trunk/drivers/ata/pata_hpt37x.c
index 7350443948c1..10318c0012ef 100644
--- a/trunk/drivers/ata/pata_hpt37x.c
+++ b/trunk/drivers/ata/pata_hpt37x.c
@@ -1219,18 +1219,17 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-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_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 struct pci_driver hpt37x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt37x,
.probe = hpt37x_init_one,
.remove = ata_pci_remove_one
@@ -1241,11 +1240,13 @@ static int __init hpt37x_init(void)
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/trunk/drivers/ata/pata_hpt3x2n.c b/trunk/drivers/ata/pata_hpt3x2n.c
index 58cfb2bc8098..5c5d4f6ab901 100644
--- a/trunk/drivers/ata/pata_hpt3x2n.c
+++ b/trunk/drivers/ata/pata_hpt3x2n.c
@@ -560,17 +560,16 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-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_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 struct pci_driver hpt3x2n_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt3x2n,
.probe = hpt3x2n_init_one,
.remove = ata_pci_remove_one
@@ -581,11 +580,13 @@ static int __init hpt3x2n_init(void)
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/trunk/drivers/ata/pata_hpt3x3.c b/trunk/drivers/ata/pata_hpt3x3.c
index 3334d72e251b..1f084ab1ccc6 100644
--- a/trunk/drivers/ata/pata_hpt3x3.c
+++ b/trunk/drivers/ata/pata_hpt3x3.c
@@ -192,14 +192,13 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static const struct pci_device_id hpt3x3[] = {
- { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), },
-
- { },
+static struct pci_device_id hpt3x3[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), },
+ { 0, },
};
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/trunk/drivers/ata/pata_it821x.c b/trunk/drivers/ata/pata_it821x.c
index 18ff3e59a89b..82a46ff40000 100644
--- a/trunk/drivers/ata/pata_it821x.c
+++ b/trunk/drivers/ata/pata_it821x.c
@@ -808,15 +808,14 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
-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_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 struct pci_driver it821x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = it821x,
.probe = it821x_init_one,
.remove = ata_pci_remove_one
@@ -827,11 +826,13 @@ static int __init it821x_init(void)
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/trunk/drivers/ata/pata_jmicron.c b/trunk/drivers/ata/pata_jmicron.c
index 52a2bdf3c38d..be3a866b111f 100644
--- a/trunk/drivers/ata/pata_jmicron.c
+++ b/trunk/drivers/ata/pata_jmicron.c
@@ -229,12 +229,11 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
}
static const struct pci_device_id jmicron_pci_tbl[] = {
- { 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},
-
+ { 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},
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/pata_mpiix.c b/trunk/drivers/ata/pata_mpiix.c
index 9dfe3e9abea3..3c65393c1f01 100644
--- a/trunk/drivers/ata/pata_mpiix.c
+++ b/trunk/drivers/ata/pata_mpiix.c
@@ -274,10 +274,11 @@ static void __devexit mpiix_remove_one(struct pci_dev *pdev)
dev_set_drvdata(dev, NULL);
}
-static const struct pci_device_id mpiix[] = {
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
- { },
+
+static const struct pci_device_id mpiix[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
+ { 0, },
};
static struct pci_driver mpiix_pci_driver = {
@@ -292,11 +293,13 @@ static int __init mpiix_init(void)
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/trunk/drivers/ata/pata_netcell.c b/trunk/drivers/ata/pata_netcell.c
index f5672de99c22..76eb9c90bee1 100644
--- a/trunk/drivers/ata/pata_netcell.c
+++ b/trunk/drivers/ata/pata_netcell.c
@@ -142,8 +142,7 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
}
static const struct pci_device_id netcell_pci_tbl[] = {
- { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), },
-
+ { PCI_DEVICE(PCI_VENDOR_ID_NETCELL, PCI_DEVICE_ID_REVOLUTION), },
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/pata_ns87410.c b/trunk/drivers/ata/pata_ns87410.c
index 2a3dbeed89b4..2005a95f48f6 100644
--- a/trunk/drivers/ata/pata_ns87410.c
+++ b/trunk/drivers/ata/pata_ns87410.c
@@ -200,13 +200,12 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id ns87410[] = {
- { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), },
-
- { },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410), },
+ { 0, },
};
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
@@ -217,11 +216,13 @@ static int __init ns87410_init(void)
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/trunk/drivers/ata/pata_oldpiix.c b/trunk/drivers/ata/pata_oldpiix.c
index fc947dfecd73..31a285ca88dc 100644
--- a/trunk/drivers/ata/pata_oldpiix.c
+++ b/trunk/drivers/ata/pata_oldpiix.c
@@ -303,8 +303,7 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e
}
static const struct pci_device_id oldpiix_pci_tbl[] = {
- { PCI_VDEVICE(INTEL, 0x1230), },
-
+ { PCI_DEVICE(0x8086, 0x1230), },
{ } /* terminate list */
};
@@ -325,6 +324,7 @@ static void __exit oldpiix_exit(void)
pci_unregister_driver(&oldpiix_pci_driver);
}
+
module_init(oldpiix_init);
module_exit(oldpiix_exit);
diff --git a/trunk/drivers/ata/pata_opti.c b/trunk/drivers/ata/pata_opti.c
index a7320ba15575..57fe21f3a975 100644
--- a/trunk/drivers/ata/pata_opti.c
+++ b/trunk/drivers/ata/pata_opti.c
@@ -256,14 +256,13 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id opti[] = {
- { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
- { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
-
- { },
+ { 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, },
};
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
@@ -274,6 +273,7 @@ static int __init opti_init(void)
return pci_register_driver(&opti_pci_driver);
}
+
static void __exit opti_exit(void)
{
pci_unregister_driver(&opti_pci_driver);
diff --git a/trunk/drivers/ata/pata_optidma.c b/trunk/drivers/ata/pata_optidma.c
index c6906b4215de..7296a20cd107 100644
--- a/trunk/drivers/ata/pata_optidma.c
+++ b/trunk/drivers/ata/pata_optidma.c
@@ -512,13 +512,12 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id optidma[] = {
- { PCI_VDEVICE(OPTI, 0xD568), }, /* Opti 82C700 */
-
- { },
+ { PCI_DEVICE(0x1045, 0xD568), }, /* Opti 82C700 */
+ { 0, },
};
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
@@ -529,11 +528,13 @@ static int __init optidma_init(void)
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/trunk/drivers/ata/pata_pcmcia.c b/trunk/drivers/ata/pata_pcmcia.c
index e93ea2702c73..cb501e145a42 100644
--- a/trunk/drivers/ata/pata_pcmcia.c
+++ b/trunk/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.2.11"
+#define DRV_VERSION "0.2.9"
/*
* Private data structure to glue stuff together
@@ -355,8 +355,6 @@ static struct pcmcia_device_id pcmcia_devices[] = {
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/trunk/drivers/ata/pata_pdc2027x.c b/trunk/drivers/ata/pata_pdc2027x.c
index d894d9918b1d..bd4ed6734edc 100644
--- a/trunk/drivers/ata/pata_pdc2027x.c
+++ b/trunk/drivers/ata/pata_pdc2027x.c
@@ -108,14 +108,13 @@ static struct pdc2027x_udma_timing {
};
static const struct pci_device_id pdc2027x_pci_tbl[] = {
- { 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 },
-
+ { 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 },
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/pata_pdc202xx_old.c b/trunk/drivers/ata/pata_pdc202xx_old.c
index 5ba9eb20a6c2..48f43432764e 100644
--- a/trunk/drivers/ata/pata_pdc202xx_old.c
+++ b/trunk/drivers/ata/pata_pdc202xx_old.c
@@ -385,18 +385,17 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-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_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 struct pci_driver pdc_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = pdc,
.probe = pdc_init_one,
.remove = ata_pci_remove_one
@@ -407,11 +406,13 @@ static int __init pdc_init(void)
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/trunk/drivers/ata/pata_radisys.c b/trunk/drivers/ata/pata_radisys.c
index 1af83d7694d5..c20bcf43ed6d 100644
--- a/trunk/drivers/ata/pata_radisys.c
+++ b/trunk/drivers/ata/pata_radisys.c
@@ -300,8 +300,7 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e
}
static const struct pci_device_id radisys_pci_tbl[] = {
- { PCI_VDEVICE(RADISYS, 0x8201), },
-
+ { 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* terminate list */
};
@@ -322,6 +321,7 @@ static void __exit radisys_exit(void)
pci_unregister_driver(&radisys_pci_driver);
}
+
module_init(radisys_init);
module_exit(radisys_exit);
diff --git a/trunk/drivers/ata/pata_rz1000.c b/trunk/drivers/ata/pata_rz1000.c
index 4533b6357d99..eccc6fd45032 100644
--- a/trunk/drivers/ata/pata_rz1000.c
+++ b/trunk/drivers/ata/pata_rz1000.c
@@ -170,20 +170,20 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en
return -ENODEV;
}
-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_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 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/trunk/drivers/ata/pata_sc1200.c b/trunk/drivers/ata/pata_sc1200.c
index 067d9d223e35..107e6cd3dc0d 100644
--- a/trunk/drivers/ata/pata_sc1200.c
+++ b/trunk/drivers/ata/pata_sc1200.c
@@ -253,14 +253,13 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 1);
}
-static const struct pci_device_id sc1200[] = {
- { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
-
- { },
+static struct pci_device_id sc1200[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
+ { 0, },
};
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
@@ -271,11 +270,13 @@ static int __init sc1200_init(void)
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/trunk/drivers/ata/pata_serverworks.c b/trunk/drivers/ata/pata_serverworks.c
index 5bbf76ec14a4..a5c8d7e121d1 100644
--- a/trunk/drivers/ata/pata_serverworks.c
+++ b/trunk/drivers/ata/pata_serverworks.c
@@ -553,14 +553,13 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
return ata_pci_init_one(pdev, port_info, ports);
}
-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_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 struct pci_driver serverworks_pci_driver = {
@@ -575,11 +574,13 @@ static int __init serverworks_init(void)
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/trunk/drivers/ata/pata_sil680.c b/trunk/drivers/ata/pata_sil680.c
index 4a2b72b4be8a..c8b2e26db70d 100644
--- a/trunk/drivers/ata/pata_sil680.c
+++ b/trunk/drivers/ata/pata_sil680.c
@@ -348,13 +348,12 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
static const struct pci_device_id sil680[] = {
- { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
-
- { },
+ { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), },
+ { 0, },
};
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
@@ -365,11 +364,13 @@ static int __init sil680_init(void)
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/trunk/drivers/ata/pata_sis.c b/trunk/drivers/ata/pata_sis.c
index b9ffafb4198c..17791e2785f9 100644
--- a/trunk/drivers/ata/pata_sis.c
+++ b/trunk/drivers/ata/pata_sis.c
@@ -988,9 +988,8 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */
- { PCI_VDEVICE(SI, 0x5518), }, /* SiS 5518 */
-
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5513), }, /* SiS 5513 */
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5518), }, /* SiS 5518 */
{ }
};
@@ -1011,6 +1010,7 @@ static void __exit sis_exit(void)
pci_unregister_driver(&sis_pci_driver);
}
+
module_init(sis_init);
module_exit(sis_exit);
diff --git a/trunk/drivers/ata/pata_sl82c105.c b/trunk/drivers/ata/pata_sl82c105.c
index 08a6dc88676f..5b762acc5687 100644
--- a/trunk/drivers/ata/pata_sl82c105.c
+++ b/trunk/drivers/ata/pata_sl82c105.c
@@ -351,10 +351,9 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
return ata_pci_init_one(dev, port_info, 1); /* For now */
}
-static const struct pci_device_id sl82c105[] = {
- { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
-
- { },
+static struct pci_device_id sl82c105[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
+ { 0, },
};
static struct pci_driver sl82c105_pci_driver = {
@@ -369,11 +368,13 @@ static int __init sl82c105_init(void)
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/trunk/drivers/ata/pata_triflex.c b/trunk/drivers/ata/pata_triflex.c
index 9640f80e8b0d..a954ed93a40c 100644
--- a/trunk/drivers/ata/pata_triflex.c
+++ b/trunk/drivers/ata/pata_triflex.c
@@ -248,13 +248,13 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id triflex[] = {
- { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
-
- { },
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
};
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,11 +265,13 @@ static int __init triflex_init(void)
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/trunk/drivers/ata/pata_via.c b/trunk/drivers/ata/pata_via.c
index 1e7be9eee9c3..7b5dd2343b9a 100644
--- a/trunk/drivers/ata/pata_via.c
+++ b/trunk/drivers/ata/pata_via.c
@@ -529,16 +529,15 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
static const struct pci_device_id via[] = {
- { 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), },
-
- { },
+ { 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, },
};
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
@@ -549,11 +548,13 @@ static int __init via_init(void)
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/trunk/drivers/ata/pdc_adma.c b/trunk/drivers/ata/pdc_adma.c
index 81f3d219e70e..0e23ecb77bc2 100644
--- a/trunk/drivers/ata/pdc_adma.c
+++ b/trunk/drivers/ata/pdc_adma.c
@@ -192,7 +192,8 @@ static struct ata_port_info adma_port_info[] = {
};
static const struct pci_device_id adma_ata_pci_tbl[] = {
- { PCI_VDEVICE(PDC, 0x1841), board_1841_idx },
+ { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_1841_idx },
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/sata_mv.c b/trunk/drivers/ata/sata_mv.c
index e6aa1a86d5cf..c01496df4a99 100644
--- a/trunk/drivers/ata/sata_mv.c
+++ b/trunk/drivers/ata/sata_mv.c
@@ -533,20 +533,19 @@ static const struct ata_port_info mv_port_info[] = {
};
static const struct pci_device_id mv_pci_tbl[] = {
- { 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_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_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
-
- { } /* terminate list */
+ {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_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_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
+ {} /* terminate list */
};
static struct pci_driver mv_pci_driver = {
diff --git a/trunk/drivers/ata/sata_nv.c b/trunk/drivers/ata/sata_nv.c
index d09d20a17790..8cd730fe5dd3 100644
--- a/trunk/drivers/ata/sata_nv.c
+++ b/trunk/drivers/ata/sata_nv.c
@@ -106,32 +106,45 @@ enum nv_host_type
};
static const struct pci_device_id nv_pci_tbl[] = {
- { 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_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_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 },
-
- { } /* terminate list */
+ { 0, } /* terminate list */
};
static struct pci_driver nv_pci_driver = {
diff --git a/trunk/drivers/ata/sata_promise.c b/trunk/drivers/ata/sata_promise.c
index 15c9437710fc..d627812ea73d 100644
--- a/trunk/drivers/ata/sata_promise.c
+++ b/trunk/drivers/ata/sata_promise.c
@@ -234,31 +234,48 @@ static const struct ata_port_info pdc_port_info[] = {
};
static const struct pci_device_id pdc_ata_pci_tbl[] = {
- { 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_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_VDEVICE(PROMISE, 0x6629), board_20619 },
+ { 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_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_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ 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_VDEVICE(PROMISE, 0x3570), board_20771 },
+ { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20771 },
#endif
{ } /* terminate list */
diff --git a/trunk/drivers/ata/sata_qstor.c b/trunk/drivers/ata/sata_qstor.c
index 7f6cc3c07de5..fa29dfe2a7b5 100644
--- a/trunk/drivers/ata/sata_qstor.c
+++ b/trunk/drivers/ata/sata_qstor.c
@@ -185,7 +185,8 @@ static const struct ata_port_info qs_port_info[] = {
};
static const struct pci_device_id qs_ata_pci_tbl[] = {
- { PCI_VDEVICE(PDC, 0x2068), board_2068_idx },
+ { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2068_idx },
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/sata_sil.c b/trunk/drivers/ata/sata_sil.c
index 3d9fa1cc834d..c63dbabc0cd9 100644
--- a/trunk/drivers/ata/sata_sil.c
+++ b/trunk/drivers/ata/sata_sil.c
@@ -123,14 +123,13 @@ static void sil_thaw(struct ata_port *ap);
static const struct pci_device_id sil_pci_tbl[] = {
- { 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 },
-
+ { 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 },
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/sata_sil24.c b/trunk/drivers/ata/sata_sil24.c
index a951f40c2f21..39cb07baebae 100644
--- a/trunk/drivers/ata/sata_sil24.c
+++ b/trunk/drivers/ata/sata_sil24.c
@@ -344,12 +344,11 @@ static int sil24_pci_device_resume(struct pci_dev *pdev);
#endif
static const struct pci_device_id sil24_pci_tbl[] = {
- { 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 },
-
+ { 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 },
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/sata_sis.c b/trunk/drivers/ata/sata_sis.c
index 0738f52463a9..18d49fff8dc4 100644
--- a/trunk/drivers/ata/sata_sis.c
+++ b/trunk/drivers/ata/sata_sis.c
@@ -67,13 +67,13 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
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_VDEVICE(SI, 0x180), sis_180 },
- { PCI_VDEVICE(SI, 0x181), sis_180 },
- { PCI_VDEVICE(SI, 0x182), sis_180 },
-
+ { 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 },
{ } /* terminate list */
};
+
static struct pci_driver sis_pci_driver = {
.name = DRV_NAME,
.id_table = sis_pci_tbl,
diff --git a/trunk/drivers/ata/sata_svw.c b/trunk/drivers/ata/sata_svw.c
index 84025a2fd5be..d6d6658d8328 100644
--- a/trunk/drivers/ata/sata_svw.c
+++ b/trunk/drivers/ata/sata_svw.c
@@ -469,15 +469,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
* controller
* */
static const struct pci_device_id k2_sata_pci_tbl[] = {
- { 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 },
-
+ { 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 },
{ }
};
+
static struct pci_driver k2_sata_pci_driver = {
.name = DRV_NAME,
.id_table = k2_sata_pci_tbl,
@@ -485,16 +485,19 @@ static struct pci_driver k2_sata_pci_driver = {
.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/trunk/drivers/ata/sata_sx4.c b/trunk/drivers/ata/sata_sx4.c
index 8c74f2ff4344..091867e10ea3 100644
--- a/trunk/drivers/ata/sata_sx4.c
+++ b/trunk/drivers/ata/sata_sx4.c
@@ -230,11 +230,12 @@ static const struct ata_port_info pdc_port_info[] = {
};
static const struct pci_device_id pdc_sata_pci_tbl[] = {
- { PCI_VDEVICE(PROMISE, 0x6622), board_20621 },
-
+ { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20621 },
{ } /* terminate list */
};
+
static struct pci_driver pdc_sata_pci_driver = {
.name = DRV_NAME,
.id_table = pdc_sata_pci_tbl,
diff --git a/trunk/drivers/ata/sata_uli.c b/trunk/drivers/ata/sata_uli.c
index 5c603ca3a50a..dd76f37be182 100644
--- a/trunk/drivers/ata/sata_uli.c
+++ b/trunk/drivers/ata/sata_uli.c
@@ -61,13 +61,13 @@ static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
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_VDEVICE(AL, 0x5289), uli_5289 },
- { PCI_VDEVICE(AL, 0x5287), uli_5287 },
- { PCI_VDEVICE(AL, 0x5281), uli_5281 },
-
+ { 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 },
{ } /* terminate list */
};
+
static struct pci_driver uli_pci_driver = {
.name = DRV_NAME,
.id_table = uli_pci_tbl,
diff --git a/trunk/drivers/ata/sata_via.c b/trunk/drivers/ata/sata_via.c
index f4455a1efe2d..a72a2389a11c 100644
--- a/trunk/drivers/ata/sata_via.c
+++ b/trunk/drivers/ata/sata_via.c
@@ -77,9 +77,9 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void vt6420_error_handler(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
- { PCI_VDEVICE(VIA, 0x0591), vt6420 },
- { PCI_VDEVICE(VIA, 0x3149), vt6420 },
- { PCI_VDEVICE(VIA, 0x3249), vt6421 },
+ { 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 },
{ } /* terminate list */
};
diff --git a/trunk/drivers/ata/sata_vsc.c b/trunk/drivers/ata/sata_vsc.c
index 273d88fcf980..d0d92f33de54 100644
--- a/trunk/drivers/ata/sata_vsc.c
+++ b/trunk/drivers/ata/sata_vsc.c
@@ -442,15 +442,16 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
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,
@@ -458,16 +459,19 @@ static struct pci_driver vsc_sata_pci_driver = {
.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/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c
index f2904f67af47..a6b2aa67c9b2 100644
--- a/trunk/drivers/block/pktcdvd.c
+++ b/trunk/drivers/block/pktcdvd.c
@@ -62,8 +62,6 @@
#include
-#define DRIVER_NAME "pktcdvd"
-
#if PACKET_DEBUG
#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
#else
@@ -82,7 +80,7 @@
static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
static struct proc_dir_entry *pkt_proc;
-static int pktdev_major;
+static int pkt_major;
static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
static mempool_t *psd_pool;
@@ -91,7 +89,7 @@ static void pkt_bio_finished(struct pktcdvd_device *pd)
{
BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
- VPRINTK(DRIVER_NAME": queue empty\n");
+ VPRINTK("pktcdvd: queue empty\n");
atomic_set(&pd->iosched.attention, 1);
wake_up(&pd->wqueue);
}
@@ -402,7 +400,7 @@ static void pkt_dump_sense(struct packet_command *cgc)
int i;
struct request_sense *sense = cgc->sense;
- printk(DRIVER_NAME":");
+ printk("pktcdvd:");
for (i = 0; i < CDROM_PACKET_SIZE; i++)
printk(" %02x", cgc->cmd[i]);
printk(" - ");
@@ -530,7 +528,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
need_write_seek = 0;
if (need_write_seek && reads_queued) {
if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- VPRINTK(DRIVER_NAME": write, waiting\n");
+ VPRINTK("pktcdvd: write, waiting\n");
break;
}
pkt_flush_cache(pd);
@@ -539,7 +537,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
} else {
if (!reads_queued && writes_queued) {
if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- VPRINTK(DRIVER_NAME": read, waiting\n");
+ VPRINTK("pktcdvd: read, waiting\n");
break;
}
pd->iosched.writing = 1;
@@ -602,7 +600,7 @@ static int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q
set_bit(PACKET_MERGE_SEGS, &pd->flags);
return 0;
} else {
- printk(DRIVER_NAME": cdrom max_phys_segments too small\n");
+ printk("pktcdvd: cdrom max_phys_segments too small\n");
return -EIO;
}
}
@@ -1051,7 +1049,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
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(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt);
+ VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt);
atomic_set(&pkt->io_wait, 1);
pkt->w_bio->bi_rw = WRITE;
@@ -1288,7 +1286,7 @@ static int kcdrwd(void *foobar)
static void pkt_print_settings(struct pktcdvd_device *pd)
{
- printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
+ printk("pktcdvd: %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');
}
@@ -1473,7 +1471,7 @@ static int pkt_set_write_settings(struct pktcdvd_device *pd)
/*
* paranoia
*/
- printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type);
+ printk("pktcdvd: write mode wrong %d\n", wp->data_block_type);
return 1;
}
wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
@@ -1517,7 +1515,7 @@ static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
if (ti->rt == 1 && ti->blank == 0)
return 1;
- printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
+ printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
return 0;
}
@@ -1535,7 +1533,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
case 0x12: /* DVD-RAM */
return 1;
default:
- VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile);
+ VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
return 0;
}
@@ -1544,22 +1542,22 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
* but i'm not sure, should we leave this to user apps? probably.
*/
if (di->disc_type == 0xff) {
- printk(DRIVER_NAME": Unknown disc. No track?\n");
+ printk("pktcdvd: Unknown disc. No track?\n");
return 0;
}
if (di->disc_type != 0x20 && di->disc_type != 0) {
- printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type);
+ printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
return 0;
}
if (di->erasable == 0) {
- printk(DRIVER_NAME": Disc not erasable\n");
+ printk("pktcdvd: Disc not erasable\n");
return 0;
}
if (di->border_status == PACKET_SESSION_RESERVED) {
- printk(DRIVER_NAME": Can't write to last track (reserved)\n");
+ printk("pktcdvd: Can't write to last track (reserved)\n");
return 0;
}
@@ -1595,12 +1593,12 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
- printk(DRIVER_NAME": failed get_track\n");
+ printk("pktcdvd: failed get_track\n");
return ret;
}
if (!pkt_writable_track(pd, &ti)) {
- printk(DRIVER_NAME": can't write to this track\n");
+ printk("pktcdvd: can't write to this track\n");
return -EROFS;
}
@@ -1610,11 +1608,11 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
*/
pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
if (pd->settings.size == 0) {
- printk(DRIVER_NAME": detected zero packet size!\n");
+ printk("pktcdvd: detected zero packet size!\n");
return -ENXIO;
}
if (pd->settings.size > PACKET_MAX_SECTORS) {
- printk(DRIVER_NAME": packet size is too big\n");
+ printk("pktcdvd: packet size is too big\n");
return -EROFS;
}
pd->settings.fp = ti.fp;
@@ -1656,7 +1654,7 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
pd->settings.block_mode = PACKET_BLOCK_MODE2;
break;
default:
- printk(DRIVER_NAME": unknown data mode\n");
+ printk("pktcdvd: unknown data mode\n");
return -EROFS;
}
return 0;
@@ -1690,10 +1688,10 @@ static int pkt_write_caching(struct pktcdvd_device *pd, int set)
cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
ret = pkt_mode_select(pd, &cgc);
if (ret) {
- printk(DRIVER_NAME": write caching control failed\n");
+ printk("pktcdvd: write caching control failed\n");
pkt_dump_sense(&cgc);
} else if (!ret && set)
- printk(DRIVER_NAME": enabled write caching on %s\n", pd->name);
+ printk("pktcdvd: enabled write caching on %s\n", pd->name);
return ret;
}
@@ -1807,11 +1805,11 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
}
if (!buf[6] & 0x40) {
- printk(DRIVER_NAME": Disc type is not CD-RW\n");
+ printk("pktcdvd: Disc type is not CD-RW\n");
return 1;
}
if (!buf[6] & 0x4) {
- printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
+ printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n");
return 1;
}
@@ -1831,14 +1829,14 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
*speed = us_clv_to_speed[sp];
break;
default:
- printk(DRIVER_NAME": Unknown disc sub-type %d\n",st);
+ printk("pktcdvd: Unknown disc sub-type %d\n",st);
return 1;
}
if (*speed) {
- printk(DRIVER_NAME": Max. media speed: %d\n",*speed);
+ printk("pktcdvd: Max. media speed: %d\n",*speed);
return 0;
} else {
- printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st);
+ printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st);
return 1;
}
}
@@ -1849,7 +1847,7 @@ static int pkt_perform_opc(struct pktcdvd_device *pd)
struct request_sense sense;
int ret;
- VPRINTK(DRIVER_NAME": Performing OPC\n");
+ VPRINTK("pktcdvd: Performing OPC\n");
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.sense = &sense;
@@ -1867,12 +1865,12 @@ static int pkt_open_write(struct pktcdvd_device *pd)
unsigned int write_speed, media_write_speed, read_speed;
if ((ret = pkt_probe_settings(pd))) {
- VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name);
+ VPRINTK("pktcdvd: %s failed probe\n", pd->name);
return ret;
}
if ((ret = pkt_set_write_settings(pd))) {
- DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name);
+ DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name);
return -EIO;
}
@@ -1884,26 +1882,26 @@ static int pkt_open_write(struct pktcdvd_device *pd)
case 0x13: /* DVD-RW */
case 0x1a: /* DVD+RW */
case 0x12: /* DVD-RAM */
- DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed);
+ DPRINTK("pktcdvd: 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(DRIVER_NAME": write speed %ux\n", write_speed / 176);
+ DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176);
break;
}
read_speed = write_speed;
if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
- DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name);
+ DPRINTK("pktcdvd: %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(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name);
+ DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name);
}
return 0;
@@ -1931,7 +1929,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
goto out_putdev;
if ((ret = pkt_get_last_written(pd, &lba))) {
- printk(DRIVER_NAME": pkt_get_last_written failed\n");
+ printk("pktcdvd: pkt_get_last_written failed\n");
goto out_unclaim;
}
@@ -1961,11 +1959,11 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
if (write) {
if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
- printk(DRIVER_NAME": not enough memory for buffers\n");
+ printk("pktcdvd: not enough memory for buffers\n");
ret = -ENOMEM;
goto out_unclaim;
}
- printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
+ printk("pktcdvd: %lukB available on disc\n", lba << 1);
}
return 0;
@@ -1985,7 +1983,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
{
if (flush && pkt_flush_cache(pd))
- DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name);
+ DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);
pkt_lock_door(pd, 0);
@@ -2008,7 +2006,7 @@ static int pkt_open(struct inode *inode, struct file *file)
struct pktcdvd_device *pd = NULL;
int ret;
- VPRINTK(DRIVER_NAME": entering open\n");
+ VPRINTK("pktcdvd: entering open\n");
mutex_lock(&ctl_mutex);
pd = pkt_find_dev_from_minor(iminor(inode));
@@ -2042,7 +2040,7 @@ static int pkt_open(struct inode *inode, struct file *file)
out_dec:
pd->refcnt--;
out:
- VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
+ VPRINTK("pktcdvd: failed open (%d)\n", ret);
mutex_unlock(&ctl_mutex);
return ret;
}
@@ -2090,7 +2088,7 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
pd = q->queuedata;
if (!pd) {
- printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
+ printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
goto end_io;
}
@@ -2112,13 +2110,13 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
}
if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
- printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n",
+ printk("pktcdvd: 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(DRIVER_NAME": wrong bio size\n");
+ printk("pktcdvd: wrong bio size\n");
goto end_io;
}
@@ -2321,7 +2319,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
struct block_device *bdev;
if (pd->pkt_dev == dev) {
- printk(DRIVER_NAME": Recursive setup not allowed\n");
+ printk("pktcdvd: Recursive setup not allowed\n");
return -EBUSY;
}
for (i = 0; i < MAX_WRITERS; i++) {
@@ -2329,11 +2327,11 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
if (!pd2)
continue;
if (pd2->bdev->bd_dev == dev) {
- printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b));
+ printk("pktcdvd: %s already setup\n", bdevname(pd2->bdev, b));
return -EBUSY;
}
if (pd2->pkt_dev == dev) {
- printk(DRIVER_NAME": Can't chain pktcdvd devices\n");
+ printk("pktcdvd: Can't chain pktcdvd devices\n");
return -EBUSY;
}
}
@@ -2356,7 +2354,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
atomic_set(&pd->cdrw.pending_bios, 0);
pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
if (IS_ERR(pd->cdrw.thread)) {
- printk(DRIVER_NAME": can't start kernel thread\n");
+ printk("pktcdvd: can't start kernel thread\n");
ret = -ENOMEM;
goto out_mem;
}
@@ -2366,7 +2364,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
proc->data = pd;
proc->proc_fops = &pkt_proc_fops;
}
- DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
+ DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
return 0;
out_mem:
@@ -2403,7 +2401,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
default:
- VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
+ VPRINTK("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
return -ENOTTY;
}
@@ -2448,7 +2446,7 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
if (!pkt_devs[idx])
break;
if (idx == MAX_WRITERS) {
- printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
+ printk("pktcdvd: max %d writers supported\n", MAX_WRITERS);
return -EBUSY;
}
@@ -2472,15 +2470,15 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
spin_lock_init(&pd->lock);
spin_lock_init(&pd->iosched.lock);
- sprintf(pd->name, DRIVER_NAME"%d", idx);
+ sprintf(pd->name, "pktcdvd%d", idx);
init_waitqueue_head(&pd->wqueue);
pd->bio_queue = RB_ROOT;
- disk->major = pktdev_major;
+ disk->major = pkt_major;
disk->first_minor = idx;
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
- sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
+ sprintf(disk->disk_name, "pktcdvd%d", idx);
disk->private_data = pd;
disk->queue = blk_alloc_queue(GFP_KERNEL);
if (!disk->queue)
@@ -2522,7 +2520,7 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
break;
}
if (idx == MAX_WRITERS) {
- DPRINTK(DRIVER_NAME": dev not setup\n");
+ DPRINTK("pktcdvd: dev not setup\n");
return -ENXIO;
}
@@ -2535,7 +2533,7 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
blkdev_put(pd->bdev);
remove_proc_entry(pd->name, pkt_proc);
- DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name);
+ DPRINTK("pktcdvd: writer %s unmapped\n", pd->name);
del_gendisk(pd->disk);
blk_cleanup_queue(pd->disk->queue);
@@ -2612,7 +2610,7 @@ static struct file_operations pkt_ctl_fops = {
static struct miscdevice pkt_misc = {
.minor = MISC_DYNAMIC_MINOR,
- .name = DRIVER_NAME,
+ .name = "pktcdvd",
.fops = &pkt_ctl_fops
};
@@ -2625,28 +2623,28 @@ static int __init pkt_init(void)
if (!psd_pool)
return -ENOMEM;
- ret = register_blkdev(pktdev_major, DRIVER_NAME);
+ ret = register_blkdev(pkt_major, "pktcdvd");
if (ret < 0) {
- printk(DRIVER_NAME": Unable to register block device\n");
+ printk("pktcdvd: Unable to register block device\n");
goto out2;
}
- if (!pktdev_major)
- pktdev_major = ret;
+ if (!pkt_major)
+ pkt_major = ret;
ret = misc_register(&pkt_misc);
if (ret) {
- printk(DRIVER_NAME": Unable to register misc device\n");
+ printk("pktcdvd: Unable to register misc device\n");
goto out;
}
mutex_init(&ctl_mutex);
- pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
+ pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
return 0;
out:
- unregister_blkdev(pktdev_major, DRIVER_NAME);
+ unregister_blkdev(pkt_major, "pktcdvd");
out2:
mempool_destroy(psd_pool);
return ret;
@@ -2654,9 +2652,9 @@ static int __init pkt_init(void)
static void __exit pkt_exit(void)
{
- remove_proc_entry(DRIVER_NAME, proc_root_driver);
+ remove_proc_entry("pktcdvd", proc_root_driver);
misc_deregister(&pkt_misc);
- unregister_blkdev(pktdev_major, DRIVER_NAME);
+ unregister_blkdev(pkt_major, "pktcdvd");
mempool_destroy(psd_pool);
}
diff --git a/trunk/drivers/char/amiserial.c b/trunk/drivers/char/amiserial.c
index 486f97c3f4e5..d0e92ed0a367 100644
--- a/trunk/drivers/char/amiserial.c
+++ b/trunk/drivers/char/amiserial.c
@@ -112,6 +112,17 @@ static struct serial_state rs_table[1];
#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
#define serial_isroot() (capable(CAP_SYS_ADMIN))
@@ -901,7 +912,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
- if (!info->xmit.buf)
+ if (!info->xmit.buf || !tmp_buf)
return 0;
local_save_flags(flags);
@@ -1767,6 +1778,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
{
struct async_struct *info;
int retval, line;
+ unsigned long page;
line = tty->index;
if ((line < 0) || (line >= NR_PORTS)) {
@@ -1786,6 +1798,17 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
#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
*/
@@ -2067,6 +2090,11 @@ static __exit void rs_exit(void)
kfree(info);
}
+ if (tmp_buf) {
+ free_page((unsigned long) tmp_buf);
+ tmp_buf = NULL;
+ }
+
release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
}
diff --git a/trunk/drivers/char/cyclades.c b/trunk/drivers/char/cyclades.c
index 87b2fb510871..f85b4eb16618 100644
--- a/trunk/drivers/char/cyclades.c
+++ b/trunk/drivers/char/cyclades.c
@@ -747,6 +747,18 @@ static struct cyclades_port cy_port[NR_PORTS];
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
@@ -2454,6 +2466,7 @@ cy_open(struct tty_struct *tty, struct file * filp)
{
struct cyclades_port *info;
int retval, line;
+ unsigned long page;
line = tty->index;
if ((line < 0) || (NR_PORTS <= line)){
@@ -2532,6 +2545,15 @@ cy_open(struct tty_struct *tty, struct file * filp)
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
@@ -2810,7 +2832,7 @@ cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
return 0;
}
- if (!info->xmit_buf)
+ if (!info->xmit_buf || !tmp_buf)
return 0;
CY_LOCK(info, flags);
@@ -5468,6 +5490,10 @@ cy_cleanup_module(void)
#endif
}
}
+ if (tmp_buf) {
+ free_page((unsigned long) tmp_buf);
+ tmp_buf = NULL;
+ }
} /* cy_cleanup_module */
module_init(cy_init);
diff --git a/trunk/drivers/char/epca.c b/trunk/drivers/char/epca.c
index c3f95583a120..3baa2ab8cbd4 100644
--- a/trunk/drivers/char/epca.c
+++ b/trunk/drivers/char/epca.c
@@ -1113,8 +1113,11 @@ static void __exit epca_module_exit(void)
ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++)
{ /* Begin for each port */
- if (ch && ch->tty)
- tty_hangup(ch->tty);
+ if (ch) {
+ if (ch->tty)
+ tty_hangup(ch->tty);
+ kfree(ch->tmp_buf);
+ }
} /* End for each port */
} /* End for each card */
pci_unregister_driver (&epca_driver);
@@ -1632,6 +1635,16 @@ static void post_fep_init(unsigned int crd)
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/trunk/drivers/char/epca.h b/trunk/drivers/char/epca.h
index a297238cd3ba..456d6c8f94a8 100644
--- a/trunk/drivers/char/epca.h
+++ b/trunk/drivers/char/epca.h
@@ -130,6 +130,7 @@ struct channel
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/trunk/drivers/char/generic_serial.c b/trunk/drivers/char/generic_serial.c
index 87127e49c0db..4711d9b3a595 100644
--- a/trunk/drivers/char/generic_serial.c
+++ b/trunk/drivers/char/generic_serial.c
@@ -33,6 +33,8 @@
#define DEBUG
+static char * tmp_buf;
+
static int gs_debug;
#ifdef DEBUG
@@ -203,7 +205,7 @@ int gs_write(struct tty_struct * tty,
if (!tty) return -EIO;
port = tty->driver_data;
- if (!port || !port->xmit_buf)
+ if (!port || !port->xmit_buf || !tmp_buf)
return -EIO;
local_save_flags(flags);
@@ -835,9 +837,24 @@ void gs_set_termios (struct tty_struct * tty,
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/trunk/drivers/char/riscom8.c b/trunk/drivers/char/riscom8.c
index b0ab3f28cc6a..214d850112fd 100644
--- a/trunk/drivers/char/riscom8.c
+++ b/trunk/drivers/char/riscom8.c
@@ -81,6 +81,7 @@
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,
@@ -1123,7 +1124,7 @@ static int rc_write(struct tty_struct * tty,
bp = port_Board(port);
- if (!tty || !port->xmit_buf)
+ if (!tty || !port->xmit_buf || !tmp_buf)
return 0;
save_flags(flags);
@@ -1611,6 +1612,11 @@ static inline int rc_init_drivers(void)
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";
@@ -1623,6 +1629,7 @@ static inline int rc_init_drivers(void)
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",
@@ -1650,6 +1657,7 @@ static void rc_release_drivers(void)
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/trunk/drivers/char/serial167.c b/trunk/drivers/char/serial167.c
index f4809c8183cc..b4ea1266b663 100644
--- a/trunk/drivers/char/serial167.c
+++ b/trunk/drivers/char/serial167.c
@@ -118,6 +118,17 @@ struct cyclades_port cy_port[] = {
};
#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
@@ -1121,7 +1132,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
return;
- if (!info->xmit_buf)
+ if (!tty || !info->xmit_buf)
return;
local_irq_save(flags);
@@ -1187,7 +1198,7 @@ cy_write(struct tty_struct * tty,
return 0;
}
- if (!info->xmit_buf){
+ if (!tty || !info->xmit_buf || !tmp_buf){
return 0;
}
@@ -1972,6 +1983,13 @@ cy_open(struct tty_struct *tty, struct file * filp)
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/trunk/drivers/clocksource/scx200_hrt.c b/trunk/drivers/clocksource/scx200_hrt.c
index 22915cc46ba7..d418b8297211 100644
--- a/trunk/drivers/clocksource/scx200_hrt.c
+++ b/trunk/drivers/clocksource/scx200_hrt.c
@@ -63,7 +63,7 @@ static struct clocksource cs_hrt = {
static int __init init_hrt_clocksource(void)
{
- /* Make sure scx200 has initialized the configuration block */
+ /* Make sure scx200 has initializedd the configuration block */
if (!scx200_cb_present())
return -ENODEV;
@@ -76,7 +76,7 @@ static int __init init_hrt_clocksource(void)
}
/* 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/trunk/drivers/cpufreq/cpufreq.c b/trunk/drivers/cpufreq/cpufreq.c
index 86e69b7f9122..2caaf71d80c8 100644
--- a/trunk/drivers/cpufreq/cpufreq.c
+++ b/trunk/drivers/cpufreq/cpufreq.c
@@ -52,14 +52,8 @@ static void handle_update(void *data);
* The mutex locks both lists.
*/
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
-static struct srcu_notifier_head cpufreq_transition_notifier_list;
+static BLOCKING_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);
@@ -268,14 +262,14 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
freqs->old = policy->cur;
}
}
- srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+ blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break;
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
- srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+ blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu))
policy->cur = freqs->new;
@@ -1055,7 +1049,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
+ blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_SUSPENDCHANGE, &freqs);
adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
@@ -1136,7 +1130,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- srcu_notifier_call_chain(
+ blocking_notifier_call_chain(
&cpufreq_transition_notifier_list,
CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
@@ -1182,7 +1176,7 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
- ret = srcu_notifier_chain_register(
+ ret = blocking_notifier_chain_register(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
@@ -1214,7 +1208,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
- ret = srcu_notifier_chain_unregister(
+ ret = blocking_notifier_chain_unregister(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
diff --git a/trunk/drivers/isdn/hisax/niccy.c b/trunk/drivers/isdn/hisax/niccy.c
index 0945336c28da..489022bdef7b 100644
--- a/trunk/drivers/isdn/hisax/niccy.c
+++ b/trunk/drivers/isdn/hisax/niccy.c
@@ -13,6 +13,7 @@
*
*/
+
#include
#include "hisax.h"
#include "isac.h"
@@ -44,31 +45,33 @@ static const char *niccy_revision = "$Revision: 1.21.2.4 $";
#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);
@@ -76,34 +79,39 @@ static inline void writefifo(unsigned int ale, unsigned int adr, u_char off,
/* 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);
@@ -122,8 +130,8 @@ static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset,
#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;
@@ -133,23 +141,21 @@ static irqreturn_t niccy_interrupt(int intno, void *dev_id,
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");
@@ -162,21 +168,21 @@ static irqreturn_t niccy_interrupt(int intno, void *dev_id,
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);
@@ -188,7 +194,8 @@ static void release_io_niccy(struct IsdnCardState *cs)
}
}
-static void niccy_reset(struct IsdnCardState *cs)
+static void
+niccy_reset(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
int val;
@@ -200,28 +207,29 @@ static void niccy_reset(struct IsdnCardState *cs)
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;
@@ -229,7 +237,8 @@ static struct pci_dev *niccy_dev __devinitdata = NULL;
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];
@@ -237,44 +246,40 @@ int __devinit setup_niccy(struct IsdnCard *card)
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;
- 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;
+ 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_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]) {
@@ -286,51 +291,50 @@ int __devinit setup_niccy(struct IsdnCard *card)
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;
@@ -339,28 +343,29 @@ int __devinit setup_niccy(struct IsdnCard *card)
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;
@@ -374,10 +379,10 @@ int __devinit setup_niccy(struct IsdnCard *card)
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/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig
index 3df0e7a07c46..7fc692a8f5b0 100644
--- a/trunk/drivers/misc/Kconfig
+++ b/trunk/drivers/misc/Kconfig
@@ -18,7 +18,7 @@ config IBM_ASM
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 for
@@ -28,33 +28,5 @@ config IBM_ASM
If unsure, say N.
-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/trunk/drivers/misc/Makefile b/trunk/drivers/misc/Makefile
index d65ece76095a..c1bf1fb04c5c 100644
--- a/trunk/drivers/misc/Makefile
+++ b/trunk/drivers/misc/Makefile
@@ -6,5 +6,3 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
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/trunk/drivers/misc/tifm_7xx1.c b/trunk/drivers/misc/tifm_7xx1.c
deleted file mode 100644
index a7ed30446185..000000000000
--- a/trunk/drivers/misc/tifm_7xx1.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * tifm_7xx1.c - TI FlashMedia driver
- *
- * Copyright (C) 2006 Alex Dubov
- *
- * 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
-#include
-
-#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/trunk/drivers/misc/tifm_core.c b/trunk/drivers/misc/tifm_core.c
deleted file mode 100644
index cca5f8522469..000000000000
--- a/trunk/drivers/misc/tifm_core.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * tifm_core.c - TI FlashMedia driver
- *
- * Copyright (C) 2006 Alex Dubov
- *
- * 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
-#include
-#include
-
-#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/trunk/drivers/mmc/Kconfig b/trunk/drivers/mmc/Kconfig
index ea41852ec8cd..f540bd88dc5a 100644
--- a/trunk/drivers/mmc/Kconfig
+++ b/trunk/drivers/mmc/Kconfig
@@ -109,20 +109,4 @@ config MMC_IMX
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/trunk/drivers/mmc/Makefile b/trunk/drivers/mmc/Makefile
index acfd4de0aba5..b1f6e03e7aa9 100644
--- a/trunk/drivers/mmc/Makefile
+++ b/trunk/drivers/mmc/Makefile
@@ -23,7 +23,6 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
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/trunk/drivers/mmc/mmc.c b/trunk/drivers/mmc/mmc.c
index ee8863c123e3..5b9caa7978d3 100644
--- a/trunk/drivers/mmc/mmc.c
+++ b/trunk/drivers/mmc/mmc.c
@@ -1166,9 +1166,9 @@ static void mmc_setup(struct mmc_host *host)
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
if (delay)
- mmc_schedule_delayed_work(&host->detect, delay);
+ schedule_delayed_work(&host->detect, delay);
else
- mmc_schedule_work(&host->detect);
+ schedule_work(&host->detect);
}
EXPORT_SYMBOL(mmc_detect_change);
@@ -1311,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
- mmc_flush_scheduled_work();
+ flush_scheduled_work();
mmc_free_host_sysfs(host);
}
diff --git a/trunk/drivers/mmc/mmc.h b/trunk/drivers/mmc/mmc.h
index cd5e0ab3d84b..97bae00292fa 100644
--- a/trunk/drivers/mmc/mmc.h
+++ b/trunk/drivers/mmc/mmc.h
@@ -18,8 +18,4 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
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/trunk/drivers/mmc/mmc_block.c b/trunk/drivers/mmc/mmc_block.c
index c1293f1bda87..db0e8ad439a5 100644
--- a/trunk/drivers/mmc/mmc_block.c
+++ b/trunk/drivers/mmc/mmc_block.c
@@ -158,13 +158,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
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,27 +278,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
cmd_err:
mmc_card_release_host(card);
- ret = 1;
-
/*
- * 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.
+ * 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.
*/
- 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);
- while (ret) {
+ do {
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/trunk/drivers/mmc/mmc_sysfs.c b/trunk/drivers/mmc/mmc_sysfs.c
index 10cc9734eaa0..a2a35fd946ee 100644
--- a/trunk/drivers/mmc/mmc_sysfs.c
+++ b/trunk/drivers/mmc/mmc_sysfs.c
@@ -13,7 +13,6 @@
#include
#include
#include
-#include
#include
#include
@@ -318,41 +317,10 @@ void mmc_free_host_sysfs(struct mmc_host *host)
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;
-
- workqueue = create_singlethread_workqueue("kmmcd");
- if (!workqueue)
- return -ENOMEM;
-
- ret = bus_register(&mmc_bus_type);
+ int ret = bus_register(&mmc_bus_type);
if (ret == 0) {
ret = class_register(&mmc_host_class);
if (ret)
@@ -365,7 +333,6 @@ static void __exit mmc_exit(void)
{
class_unregister(&mmc_host_class);
bus_unregister(&mmc_bus_type);
- destroy_workqueue(workqueue);
}
module_init(mmc_init);
diff --git a/trunk/drivers/mmc/sdhci.c b/trunk/drivers/mmc/sdhci.c
index 20711acb0120..4dab5ec392ea 100644
--- a/trunk/drivers/mmc/sdhci.c
+++ b/trunk/drivers/mmc/sdhci.c
@@ -35,8 +35,6 @@ static unsigned int debug_quirks = 0;
#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 = {
{
@@ -53,8 +51,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_RICOH_R5C822,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = SDHCI_QUIRK_FORCE_DMA |
- SDHCI_QUIRK_NO_CARD_NO_RESET,
+ .driver_data = SDHCI_QUIRK_FORCE_DMA,
},
{
@@ -128,12 +125,6 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
{
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)
@@ -726,7 +717,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
} else
sdhci_send_command(host, mrq->cmd);
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -763,7 +753,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ctrl &= ~SDHCI_CTRL_4BITBUS;
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -871,7 +860,6 @@ static void sdhci_tasklet_finish(unsigned long param)
sdhci_deactivate_led(host);
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq);
@@ -905,7 +893,6 @@ static void sdhci_timeout_timer(unsigned long data)
}
}
- mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -1043,7 +1030,6 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
result = IRQ_HANDLED;
- mmiowb();
out:
spin_unlock(&host->lock);
@@ -1109,7 +1095,6 @@ static int sdhci_resume (struct pci_dev *pdev)
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;
@@ -1183,9 +1168,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
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);
@@ -1342,7 +1324,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
sdhci_dumpregs(host);
#endif
- mmiowb();
+ host->chip = chip;
+ chip->hosts[slot] = host;
mmc_add_host(mmc);
diff --git a/trunk/drivers/mmc/tifm_sd.c b/trunk/drivers/mmc/tifm_sd.c
deleted file mode 100644
index 6d23dc08d169..000000000000
--- a/trunk/drivers/mmc/tifm_sd.c
+++ /dev/null
@@ -1,933 +0,0 @@
-/*
- * tifm_sd.c - TI FlashMedia driver
- *
- * Copyright (C) 2006 Alex Dubov
- *
- * 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
-#include
-#include
-#include
-
-#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/trunk/drivers/pci/Kconfig b/trunk/drivers/pci/Kconfig
index 30294127a0aa..c27e782e6df9 100644
--- a/trunk/drivers/pci/Kconfig
+++ b/trunk/drivers/pci/Kconfig
@@ -52,11 +52,3 @@ config PCI_DEBUG
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/trunk/drivers/pci/Makefile b/trunk/drivers/pci/Makefile
index e3beb784406f..f2d152b818f0 100644
--- a/trunk/drivers/pci/Makefile
+++ b/trunk/drivers/pci/Makefile
@@ -14,12 +14,6 @@ obj-$(CONFIG_HOTPLUG) += hotplug.o
# 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
#
@@ -33,6 +27,11 @@ obj-$(CONFIG_PPC64) += setup-bus.o
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/trunk/drivers/pci/htirq.c b/trunk/drivers/pci/htirq.c
deleted file mode 100644
index 0e27f2404a83..000000000000
--- a/trunk/drivers/pci/htirq.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * File: htirq.c
- * Purpose: Hypertransport Interrupt Capability
- *
- * Copyright (C) 2006 Linux Networx
- * Copyright (C) Eric Biederman
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* 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/trunk/arch/ia64/sn/kernel/msi_sn.c b/trunk/drivers/pci/msi-altix.c
similarity index 65%
rename from trunk/arch/ia64/sn/kernel/msi_sn.c
rename to trunk/drivers/pci/msi-altix.c
index 6ffd1f850d41..bed4183a5e39 100644
--- a/trunk/arch/ia64/sn/kernel/msi_sn.c
+++ b/trunk/drivers/pci/msi-altix.c
@@ -7,10 +7,8 @@
*/
#include
-#include
#include
#include
-#include
#include
#include
@@ -18,16 +16,17 @@
#include
#include
+#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[NR_IRQS];
-
-static struct irq_chip sn_msi_chip;
+static struct sn_msi_info *sn_msi_info;
-void sn_teardown_msi_irq(unsigned int irq)
+static void
+sn_msi_teardown(unsigned int vector)
{
nasid_t nasid;
int widget;
@@ -37,7 +36,7 @@ void sn_teardown_msi_irq(unsigned int irq)
struct pcibus_bussoft *bussoft;
struct sn_pcibus_provider *provider;
- sn_irq_info = sn_msi_info[irq].sn_irq_info;
+ sn_irq_info = sn_msi_info[vector].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return;
@@ -46,9 +45,9 @@ void sn_teardown_msi_irq(unsigned int irq)
provider = SN_PCIDEV_BUSPROVIDER(pdev);
(*provider->dma_unmap)(pdev,
- sn_msi_info[irq].pci_addr,
+ sn_msi_info[vector].pci_addr,
PCI_DMA_FROMDEVICE);
- sn_msi_info[irq].pci_addr = 0;
+ sn_msi_info[vector].pci_addr = 0;
bussoft = SN_PCIDEV_BUSSOFT(pdev);
nasid = NASID_GET(bussoft->bs_base);
@@ -57,15 +56,15 @@ void sn_teardown_msi_irq(unsigned int irq)
SWIN_WIDGETNUM(bussoft->bs_base);
sn_intr_free(nasid, widget, sn_irq_info);
- sn_msi_info[irq].sn_irq_info = NULL;
+ sn_msi_info[vector].sn_irq_info = NULL;
return;
}
-int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int
+sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
+ u32 *addr_hi, u32 *addr_lo, u32 *data)
{
- struct msi_msg msg;
- struct msi_desc *entry;
int widget;
int status;
nasid_t nasid;
@@ -74,10 +73,6 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
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;
@@ -98,7 +93,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
if (! sn_irq_info)
return -ENOMEM;
- status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
+ status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
if (status) {
kfree(sn_irq_info);
return -ENOMEM;
@@ -124,32 +119,29 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
return -ENOMEM;
}
- sn_msi_info[irq].sn_irq_info = sn_irq_info;
- sn_msi_info[irq].pci_addr = bus_addr;
+ sn_msi_info[vector].sn_irq_info = sn_irq_info;
+ sn_msi_info[vector].pci_addr = bus_addr;
- msg.address_hi = (u32)(bus_addr >> 32);
- msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+ *addr_hi = (u32)(bus_addr >> 32);
+ *addr_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.
*/
- msg.data = 0x100 + irq;
+ *data = 0x100 + (unsigned int)vector;
#ifdef CONFIG_SMP
- set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
+ set_irq_affinity_info((vector & 0xff), 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;
}
-#ifdef CONFIG_SMP
-static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
+static void
+sn_msi_target(unsigned int vector, unsigned int cpu,
+ u32 *addr_hi, u32 *addr_lo)
{
- struct msi_msg msg;
int slice;
nasid_t nasid;
u64 bus_addr;
@@ -158,10 +150,8 @@ static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
struct sn_irq_info *sn_irq_info;
struct sn_irq_info *new_irq_info;
struct sn_pcibus_provider *provider;
- unsigned int cpu;
- cpu = first_cpu(cpu_mask);
- sn_irq_info = sn_msi_info[irq].sn_irq_info;
+ sn_irq_info = sn_msi_info[vector].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return;
@@ -169,20 +159,19 @@ static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
* 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)(msg.address_hi) << 32 | (u64)(msg.address_lo);
+ bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
- sn_msi_info[irq].pci_addr = 0;
+ sn_msi_info[vector].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[irq].sn_irq_info = new_irq_info;
+ sn_msi_info[vector].sn_irq_info = new_irq_info;
if (new_irq_info == NULL)
return;
@@ -195,36 +184,27 @@ static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
sizeof(new_irq_info->irq_xtalkaddr),
SN_DMA_MSI|SN_DMA_ADDR_XIO);
- 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);
+ sn_msi_info[vector].pci_addr = bus_addr;
+ *addr_hi = (u32)(bus_addr >> 32);
+ *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
}
-#endif /* CONFIG_SMP */
-static void sn_ack_msi_irq(unsigned int irq)
-{
- move_native_irq(irq);
- ia64_eoi();
-}
+struct msi_ops sn_msi_ops = {
+ .setup = sn_msi_setup,
+ .teardown = sn_msi_teardown,
+#ifdef CONFIG_SMP
+ .target = sn_msi_target,
+#endif
+};
-static int sn_msi_retrigger_irq(unsigned int irq)
+int
+sn_msi_init(void)
{
- unsigned int vector = irq;
- ia64_resend_irq(vector);
+ sn_msi_info =
+ kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
+ if (! sn_msi_info)
+ return -ENOMEM;
- return 1;
+ msi_register(&sn_msi_ops);
+ return 0;
}
-
-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/trunk/drivers/pci/msi-apic.c b/trunk/drivers/pci/msi-apic.c
new file mode 100644
index 000000000000..5ed798b319c7
--- /dev/null
+++ b/trunk/drivers/pci/msi-apic.c
@@ -0,0 +1,101 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include
+#include
+#include
+
+#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/trunk/drivers/pci/msi.c b/trunk/drivers/pci/msi.c
index f9fdc54473c4..27a057409eca 100644
--- a/trunk/drivers/pci/msi.c
+++ b/trunk/drivers/pci/msi.c
@@ -6,7 +6,6 @@
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
-#include
#include
#include
#include
@@ -15,7 +14,6 @@
#include
#include
#include
-#include
#include
#include
@@ -29,6 +27,23 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
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)
{
@@ -40,25 +55,26 @@ static int msi_cache_init(void)
return 0;
}
-static void msi_set_mask_bit(unsigned int irq, int flag)
+static void msi_set_mask_bit(unsigned int vector, int flag)
{
struct msi_desc *entry;
- entry = msi_desc[irq];
- BUG_ON(!entry || !entry->dev);
+ entry = (struct msi_desc *)msi_desc[vector];
+ if (!entry || !entry->dev || !entry->mask_base)
+ return;
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
- 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);
- }
+ {
+ 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);
break;
+ }
case PCI_CAP_ID_MSIX:
{
int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -67,101 +83,261 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
break;
}
default:
- BUG();
break;
}
}
-void read_msi_msg(unsigned int irq, struct msi_msg *msg)
+#ifdef CONFIG_SMP
+static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
{
- 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;
- u16 data;
-
- 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:
- {
- void __iomem *base;
- base = entry->mask_base +
- entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+ struct msi_desc *entry;
+ u32 address_hi, address_lo;
+ unsigned int irq = vector;
+ unsigned int dest_cpu = first_cpu(cpu_mask);
- 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();
- }
-}
+ entry = (struct msi_desc *)msi_desc[vector];
+ if (!entry || !entry->dev)
+ return;
-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;
-
- 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);
- }
+ int pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI);
+
+ 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);
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);
+ 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;
+
+ address_hi = readl(entry->mask_base + offset_hi);
+ address_lo = readl(entry->mask_base + offset_lo);
+
+ msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+ writel(address_hi, entry->mask_base + offset_hi);
+ writel(address_lo, entry->mask_base + offset_lo);
+ set_native_irq_info(irq, cpu_mask);
break;
}
default:
- BUG();
+ break;
}
}
+#else
+#define set_msi_affinity NULL
+#endif /* CONFIG_SMP */
+
+static void mask_MSI_irq(unsigned int vector)
+{
+ msi_set_mask_bit(vector, 1);
+}
-void mask_msi_irq(unsigned int irq)
+static void unmask_MSI_irq(unsigned int vector)
{
- msi_set_mask_bit(irq, 1);
+ msi_set_mask_bit(vector, 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);
}
-void unmask_msi_irq(unsigned int irq)
+static void end_msi_irq_wo_maskbit(unsigned int vector)
{
- msi_set_mask_bit(irq, 0);
+ 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;
@@ -176,6 +352,22 @@ static int msi_init(void)
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;
@@ -183,9 +375,23 @@ static int msi_init(void)
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;
@@ -200,44 +406,29 @@ static struct msi_desc* alloc_msi_entry(void)
return entry;
}
-static void attach_msi_entry(struct msi_desc *entry, int irq)
+static void attach_msi_entry(struct msi_desc *entry, int vector)
{
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
- msi_desc[irq] = entry;
+ msi_desc[vector] = entry;
spin_unlock_irqrestore(&msi_lock, flags);
}
-static int create_msi_irq(void)
+static void irq_handler_init(int cap_id, int pos, int mask)
{
- struct msi_desc *entry;
- int irq;
-
- entry = alloc_msi_entry();
- if (!entry)
- return -ENOMEM;
+ unsigned long flags;
- irq = create_irq();
- if (irq < 0) {
- kmem_cache_free(msi_cachep, entry);
- return -EBUSY;
+ 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;
}
-
- 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);
+ spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
}
static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
@@ -282,21 +473,21 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
}
}
-static int msi_lookup_irq(struct pci_dev *dev, int type)
+static int msi_lookup_vector(struct pci_dev *dev, int type)
{
- int irq;
+ int vector;
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
- 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)
+ 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)
continue;
spin_unlock_irqrestore(&msi_lock, flags);
- /* This pre-assigned MSI irq for this device
- already exits. Override dev->irq with this irq */
- dev->irq = irq;
+ /* This pre-assigned MSI vector for this device
+ already exits. Override dev->irq with this vector */
+ dev->irq = vector;
return 0;
}
spin_unlock_irqrestore(&msi_lock, flags);
@@ -308,6 +499,11 @@ void pci_scan_msi_device(struct pci_dev *dev)
{
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
@@ -381,7 +577,7 @@ int pci_save_msix_state(struct pci_dev *dev)
{
int pos;
int temp;
- int irq, head, tail = 0;
+ int vector, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
@@ -403,20 +599,33 @@ int pci_save_msix_state(struct pci_dev *dev)
/* save the table */
temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
kfree(save_state);
return -EINVAL;
}
- irq = head = dev->irq;
+ vector = head = dev->irq;
while (head != tail) {
+ int j;
+ void __iomem *base;
struct msi_desc *entry;
- entry = msi_desc[irq];
- read_msi_msg(irq, &entry->msg_save);
-
- tail = msi_desc[irq]->link.tail;
- irq = tail;
+ entry = msi_desc[vector];
+ base = entry->mask_base;
+ j = entry->msi_attrib.entry_nr;
+
+ 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;
}
dev->irq = temp;
@@ -429,7 +638,9 @@ void pci_restore_msix_state(struct pci_dev *dev)
{
u16 save;
int pos;
- int irq, head, tail = 0;
+ int vector, head, tail = 0;
+ void __iomem *base;
+ int j;
struct msi_desc *entry;
int temp;
struct pci_cap_saved_state *save_state;
@@ -447,15 +658,26 @@ void pci_restore_msix_state(struct pci_dev *dev)
/* route the table */
temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
+ if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX))
return;
- irq = head = dev->irq;
+ vector = head = dev->irq;
while (head != tail) {
- entry = msi_desc[irq];
- write_msi_msg(irq, &entry->msg_save);
-
- tail = msi_desc[irq]->link.tail;
- irq = tail;
+ entry = msi_desc[vector];
+ base = entry->mask_base;
+ j = entry->msi_attrib.entry_nr;
+
+ 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;
}
dev->irq = temp;
@@ -464,68 +686,104 @@ void pci_restore_msix_state(struct pci_dev *dev)
}
#endif
+static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
+{
+ int status;
+ u32 address_hi;
+ u32 address_lo;
+ u32 data;
+ int pos, vector = dev->irq;
+ u16 control;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ pci_read_config_word(dev, msi_control_reg(pos), &control);
+
+ /* 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);
+ if (entry->msi_attrib.maskbit) {
+ unsigned int maskbits, temp;
+ /* All MSIs are unmasked by default, Mask them all */
+ pci_read_config_dword(dev,
+ msi_mask_bits_reg(pos, is_64bit_address(control)),
+ &maskbits);
+ temp = (1 << multi_msi_capable(control));
+ temp = ((temp - 1) & ~temp);
+ maskbits |= temp;
+ pci_write_config_dword(dev,
+ 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 irq, regardless of device function is capable of handling
+ * 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 irq or non-zero for otherwise.
+ * 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, irq;
+ 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 */
- irq = create_msi_irq();
- if (irq < 0)
- return irq;
+ entry = alloc_msi_entry();
+ if (!entry)
+ return -ENOMEM;
- entry = get_irq_data(irq);
- entry->link.head = irq;
- entry->link.tail = irq;
+ 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.is_64 = is_64bit_address(control);
+ 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_irq = dev->irq; /* Save IOAPIC IRQ */
- entry->msi_attrib.pos = pos;
+ 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));
}
- entry->dev = dev;
- if (entry->msi_attrib.maskbit) {
- unsigned int maskbits, temp;
- /* All MSIs are unmasked by default, Mask them all */
- pci_read_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
- &maskbits);
- temp = (1 << multi_msi_capable(control));
- temp = ((temp - 1) & ~temp);
- maskbits |= temp;
- pci_write_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
- maskbits);
- }
+ /* Replace with MSI handler */
+ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
/* Configure MSI capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
+ status = msi_register_init(dev, entry);
+ if (status != 0) {
+ dev->irq = entry->msi_attrib.default_vector;
+ kmem_cache_free(msi_cachep, entry);
return status;
}
- attach_msi_entry(entry, irq);
+ attach_msi_entry(entry, vector);
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
- dev->irq = irq;
return 0;
}
@@ -536,15 +794,18 @@ static int msi_capability_init(struct pci_dev *dev)
* @nvec: number of @entries
*
* Setup the MSI-X capability structure of device function with a
- * 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.
+ * 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.
**/
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 irq, pos, i, j, nr_entries, temp = 0;
+ int vector, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
u16 control;
@@ -566,56 +827,65 @@ static int msix_capability_init(struct pci_dev *dev,
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- irq = create_msi_irq();
- if (irq < 0)
+ entry = alloc_msi_entry();
+ if (!entry)
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 = irq;
+ entries[i].vector = vector;
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
- entry->msi_attrib.is_64 = 1;
+ entry->msi_attrib.state = 0; /* Mark it not active */
entry->msi_attrib.entry_nr = j;
entry->msi_attrib.maskbit = 1;
- entry->msi_attrib.default_irq = dev->irq;
- entry->msi_attrib.pos = pos;
+ entry->msi_attrib.default_vector = dev->irq;
entry->dev = dev;
entry->mask_base = base;
if (!head) {
- entry->link.head = irq;
- entry->link.tail = irq;
+ entry->link.head = vector;
+ entry->link.tail = vector;
head = entry;
} else {
entry->link.head = temp;
entry->link.tail = tail->link.tail;
- tail->link.tail = irq;
- head->link.head = irq;
+ tail->link.tail = vector;
+ head->link.head = vector;
}
- temp = irq;
+ temp = vector;
tail = entry;
+ /* Replace with MSI-X handler */
+ irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
/* Configure MSI-X capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
+ status = msi_ops->setup(dev, vector,
+ &address_hi,
+ &address_lo,
+ &data);
+ if (status < 0)
break;
- }
- attach_msi_entry(entry, irq);
+ 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);
}
if (i != nvec) {
- int avail = i - 1;
i--;
for (; i >= 0; i--) {
- irq = (entries + i)->vector;
- msi_free_irq(dev, irq);
+ vector = (entries + i)->vector;
+ msi_free_vector(dev, vector, 0);
(entries + i)->vector = 0;
}
- /* If we had some success report the number of irqs
- * we succeeded in setting up.
- */
- if (avail <= 0)
- avail = -EBUSY;
- return avail;
+ return -EBUSY;
}
/* Set MSI-X enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -655,14 +925,15 @@ int pci_msi_supported(struct pci_dev * dev)
* @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 upon its software driver call to request for
+ * a single MSI vector 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
- * irq or non-zero for otherwise.
+ * vector 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;
@@ -677,25 +948,52 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+ if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+ /* Lookup Sucess */
+ unsigned long flags;
- /* Check whether driver already requested for MSI-X irqs */
+ 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 */
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X irq assigned\n",
+ "Device already has MSI-X vectors 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_irq;
+ int pos, default_vector;
u16 control;
unsigned long flags;
@@ -712,41 +1010,41 @@ void pci_disable_msi(struct pci_dev* dev)
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 (irq_has_action(dev->irq)) {
+ if (entry->msi_attrib.state) {
spin_unlock_irqrestore(&msi_lock, flags);
printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
- "free_irq() on MSI irq %d\n",
+ "free_irq() on MSI vector %d\n",
pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ BUG_ON(entry->msi_attrib.state > 0);
} else {
- default_irq = entry->msi_attrib.default_irq;
+ vector_irq[dev->irq] = 0; /* free it */
+ nr_released_vectors++;
+ default_vector = entry->msi_attrib.default_vector;
spin_unlock_irqrestore(&msi_lock, flags);
- msi_free_irq(dev, dev->irq);
-
- /* Restore dev->irq to its default pin-assertion irq */
- dev->irq = default_irq;
+ /* 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);
}
}
-static int msi_free_irq(struct pci_dev* dev, int irq)
+static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
{
struct msi_desc *entry;
int head, entry_nr, type;
void __iomem *base;
unsigned long flags;
- arch_teardown_msi_irq(irq);
+ msi_ops->teardown(vector);
spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[irq];
+ entry = msi_desc[vector];
if (!entry || entry->dev != dev) {
spin_unlock_irqrestore(&msi_lock, flags);
return -EINVAL;
@@ -758,42 +1056,100 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
msi_desc[entry->link.head]->link.tail = entry->link.tail;
msi_desc[entry->link.tail]->link.head = entry->link.head;
entry->dev = NULL;
- msi_desc[irq] = NULL;
+ if (!reassign) {
+ vector_irq[vector] = 0;
+ nr_released_vectors++;
+ }
+ msi_desc[vector] = NULL;
spin_unlock_irqrestore(&msi_lock, flags);
- destroy_msi_irq(irq);
+ kmem_cache_free(msi_cachep, entry);
if (type == PCI_CAP_ID_MSIX) {
- writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+ if (!reassign)
+ writel(1, base +
+ entry_nr * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
- if (head == irq)
+ if (head == vector)
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 irqs requested for allocation by device driver
+ * @nvec: number of MSI-X vectors requested for allocation by device driver
*
* Setup the MSI-X capability structure of device function with the number
- * of requested irqs upon its software driver call to request for
+ * of requested vectors 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 irqs. A return of < 0 indicates a failure.
+ * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
* Or a return of > 0 indicates that driver request is exceeding the number
- * of irqs available. Driver should use the returned value to re-send
+ * of vectors 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;
+ int status, pos, nr_entries, free_vectors;
int i, j, temp;
u16 control;
+ unsigned long flags;
if (!entries || pci_msi_supported(dev) < 0)
return -EINVAL;
@@ -807,6 +1163,9 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
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;
@@ -821,18 +1180,56 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
}
}
temp = dev->irq;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
-
- /* Check whether driver already requested for MSI 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 */
if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
- "Device already has an MSI irq assigned\n",
+ "Device already has an MSI vector 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;
}
@@ -854,47 +1251,53 @@ void pci_disable_msix(struct pci_dev* dev)
if (!(control & PCI_MSIX_FLAGS_ENABLE))
return;
- disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
-
temp = dev->irq;
- if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- int irq, head, tail = 0, warning = 0;
+ if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+ int state, vector, head, tail = 0, warning = 0;
unsigned long flags;
- irq = head = dev->irq;
- dev->irq = temp; /* Restore pin IRQ */
+ vector = head = dev->irq;
+ spin_lock_irqsave(&msi_lock, flags);
while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (irq_has_action(irq))
+ state = msi_desc[vector]->msi_attrib.state;
+ if (state)
warning = 1;
- else if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
+ else {
+ vector_irq[vector] = 0; /* free it */
+ nr_released_vectors++;
+ }
+ tail = msi_desc[vector]->link.tail;
+ vector = tail;
}
- msi_free_irq(dev, irq);
+ spin_unlock_irqrestore(&msi_lock, flags);
if (warning) {
+ dev->irq = temp;
printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X irqs\n",
+ "free_irq() on all MSI-X vectors\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) irqs to unused state
+ * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors 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 irqs, if
+ * is hot-removed. All previous assigned MSI/MSI-X vectors, 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 pos, temp;
+ int state, pos, temp;
unsigned long flags;
if (!pci_msi_enable || !dev)
@@ -902,38 +1305,42 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
temp = dev->irq; /* Save IOAPIC IRQ */
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
- if (irq_has_action(dev->irq)) {
+ 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) {
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on MSI irq %d\n",
+ "called without free_irq() on MSI vector %d\n",
pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
- } else /* Release MSI irq assigned to this device */
- msi_free_irq(dev, dev->irq);
+ BUG_ON(state > 0);
+ } else /* Release MSI vector assigned to this device */
+ msi_free_vector(dev, dev->irq, 0);
dev->irq = temp; /* Restore IOAPIC IRQ */
}
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- int irq, head, tail = 0, warning = 0;
+ if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+ int vector, head, tail = 0, warning = 0;
void __iomem *base = NULL;
- irq = head = dev->irq;
+ vector = head = dev->irq;
while (head != tail) {
spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- base = msi_desc[irq]->mask_base;
+ state = msi_desc[vector]->msi_attrib.state;
+ tail = msi_desc[vector]->link.tail;
+ base = msi_desc[vector]->mask_base;
spin_unlock_irqrestore(&msi_lock, flags);
- if (irq_has_action(irq))
+ if (state)
warning = 1;
- else if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
+ else if (vector != head) /* Release MSI-X vector */
+ msi_free_vector(dev, vector, 0);
+ vector = tail;
}
- msi_free_irq(dev, irq);
+ msi_free_vector(dev, vector, 0);
if (warning) {
iounmap(base);
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on all MSI-X irqs\n",
+ "called without free_irq() on all MSI-X vectors\n",
pci_name(dev));
BUG_ON(warning > 0);
}
diff --git a/trunk/drivers/pci/msi.h b/trunk/drivers/pci/msi.h
index f0cca1772f9c..56951c39d3a3 100644
--- a/trunk/drivers/pci/msi.h
+++ b/trunk/drivers/pci/msi.h
@@ -6,6 +6,84 @@
#ifndef MSI_H
#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
+
+/*
+ * 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
*/
@@ -32,8 +110,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
@@ -47,4 +125,32 @@
#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/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c
index 8f7bcf56f149..54404917be9a 100644
--- a/trunk/drivers/pci/setup-bus.c
+++ b/trunk/drivers/pci/setup-bus.c
@@ -55,16 +55,16 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 class = dev->class >> 8;
- /* Don't touch classless devices or host bridges or ioapics. */
+ /* Don't touch classless devices or host bridges. */
if (class == PCI_CLASS_NOT_DEFINED ||
class == PCI_CLASS_BRIDGE_HOST)
continue;
- /* Don't touch ioapic devices already enabled by firmware */
+ /* Don't touch ioapics if it has the assigned resources. */
if (class == PCI_CLASS_SYSTEM_PIC) {
- u16 command;
- pci_read_config_word(dev, PCI_COMMAND, &command);
- if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
+ res = &dev->resource[0];
+ if (res[0].start || res[1].start || res[2].start ||
+ res[3].start || res[4].start || res[5].start)
continue;
}
diff --git a/trunk/drivers/rtc/rtc-ds1307.c b/trunk/drivers/rtc/rtc-ds1307.c
index 3f0f7b8fa813..cc5032b6f42a 100644
--- a/trunk/drivers/rtc/rtc-ds1307.c
+++ b/trunk/drivers/rtc/rtc-ds1307.c
@@ -141,9 +141,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
- "write", t->tm_sec, t->tm_min,
- t->tm_hour, t->tm_mday,
- t->tm_mon, t->tm_year, t->tm_wday);
+ "write", dt->tm_sec, dt->tm_min,
+ dt->tm_hour, dt->tm_mday,
+ dt->tm_mon, dt->tm_year, dt->tm_wday);
*buf++ = 0; /* first register addr */
buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
diff --git a/trunk/drivers/rtc/rtc-ds1672.c b/trunk/drivers/rtc/rtc-ds1672.c
index 67e816a9a39f..9c68ec99afa5 100644
--- a/trunk/drivers/rtc/rtc-ds1672.c
+++ b/trunk/drivers/rtc/rtc-ds1672.c
@@ -55,7 +55,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
}
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 @@ static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
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/trunk/drivers/rtc/rtc-rs5c372.c b/trunk/drivers/rtc/rtc-rs5c372.c
index 2a86632580f1..bbdad099471d 100644
--- a/trunk/drivers/rtc/rtc-rs5c372.c
+++ b/trunk/drivers/rtc/rtc-rs5c372.c
@@ -91,7 +91,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
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 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
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/trunk/drivers/video/riva/fbdev.c b/trunk/drivers/video/riva/fbdev.c
index a433cc78ef90..b120896c8ab4 100644
--- a/trunk/drivers/video/riva/fbdev.c
+++ b/trunk/drivers/video/riva/fbdev.c
@@ -1843,7 +1843,7 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
for (i = 0; propnames[i] != NULL; ++i) {
pedid = get_property(dp, propnames[i], NULL);
if (pedid != NULL) {
- par->EDID = (unsigned char *)pedid;
+ par->EDID = pedid;
NVTRACE("LCD found.\n");
return 1;
}
diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig
index 674cfbb83a95..68f4561423ff 100644
--- a/trunk/fs/Kconfig
+++ b/trunk/fs/Kconfig
@@ -995,18 +995,6 @@ config AFFS_FS
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
- to learn more about
- eCryptfs. Userspace components are required and can be
- obtained from .
-
- 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/trunk/fs/Makefile b/trunk/fs/Makefile
index fd24d67a7cdb..819b2a93bebe 100644
--- a/trunk/fs/Makefile
+++ b/trunk/fs/Makefile
@@ -75,7 +75,6 @@ obj-$(CONFIG_BFS_FS) += bfs/
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/trunk/fs/dcache.c b/trunk/fs/dcache.c
index 2355bddad8de..fc2faa44f8d1 100644
--- a/trunk/fs/dcache.c
+++ b/trunk/fs/dcache.c
@@ -291,9 +291,9 @@ struct dentry * dget_locked(struct dentry *dentry)
* it can be unhashed only if it has no children, or if it is the root
* of a filesystem.
*
- * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
+ * If the inode has a DCACHE_DISCONNECTED alias, then prefer
* any other hashed alias over that one unless @want_discon is set,
- * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
+ * in which case only return a DCACHE_DISCONNECTED alias.
*/
static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
@@ -309,8 +309,7 @@ static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
prefetch(next);
alias = list_entry(tmp, struct dentry, d_alias);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
- if (IS_ROOT(alias) &&
- (alias->d_flags & DCACHE_DISCONNECTED))
+ if (alias->d_flags & DCACHE_DISCONNECTED)
discon_alias = alias;
else if (!want_discon) {
__dget_locked(alias);
@@ -1005,7 +1004,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
{
struct dentry *new = NULL;
- if (inode && S_ISDIR(inode->i_mode)) {
+ if (inode) {
spin_lock(&dcache_lock);
new = __d_find_alias(inode, 1);
if (new) {
diff --git a/trunk/fs/ecryptfs/Makefile b/trunk/fs/ecryptfs/Makefile
deleted file mode 100644
index ca6562451eeb..000000000000
--- a/trunk/fs/ecryptfs/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# 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/trunk/fs/ecryptfs/crypto.c b/trunk/fs/ecryptfs/crypto.c
deleted file mode 100644
index ed35a9712fa1..000000000000
--- a/trunk/fs/ecryptfs/crypto.c
+++ /dev/null
@@ -1,1659 +0,0 @@
-/**
- * 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
- * Michael C. Thompson
- *
- * 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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#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/trunk/fs/ecryptfs/debug.c b/trunk/fs/ecryptfs/debug.c
deleted file mode 100644
index 61f8e894284f..000000000000
--- a/trunk/fs/ecryptfs/debug.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * eCryptfs: Linux filesystem encryption layer
- * Functions only useful for debugging.
- *
- * Copyright (C) 2006 International Business Machines Corp.
- * Author(s): Michael A. Halcrow
- *
- * 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/trunk/fs/ecryptfs/dentry.c b/trunk/fs/ecryptfs/dentry.c
deleted file mode 100644
index f0d2a433242b..000000000000
--- a/trunk/fs/ecryptfs/dentry.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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
- *
- * 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
-#include
-#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/trunk/fs/ecryptfs/ecryptfs_kernel.h b/trunk/fs/ecryptfs/ecryptfs_kernel.h
deleted file mode 100644
index 872c9958531a..000000000000
--- a/trunk/fs/ecryptfs/ecryptfs_kernel.h
+++ /dev/null
@@ -1,482 +0,0 @@
-/**
- * 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
- *
- * 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
-#include
-#include
-
-/* 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/trunk/fs/ecryptfs/file.c b/trunk/fs/ecryptfs/file.c
deleted file mode 100644
index c8550c9f9cd2..000000000000
--- a/trunk/fs/ecryptfs/file.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/**
- * 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
- * Michael C. Thompson
- *
- * 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
-#include
-#include
-#include
-#include
-#include
-#include
-#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/trunk/fs/ecryptfs/inode.c b/trunk/fs/ecryptfs/inode.c
deleted file mode 100644
index efdd2b7b62d7..000000000000
--- a/trunk/fs/ecryptfs/inode.c
+++ /dev/null
@@ -1,1079 +0,0 @@
-/**
- * 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
- * Michael C. Thompsion
- *
- * 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
-#include
-#include
-#include
-#include
-#include
-#include
-#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/trunk/fs/ecryptfs/keystore.c b/trunk/fs/ecryptfs/keystore.c
deleted file mode 100644
index ba454785a0c5..000000000000
--- a/trunk/fs/ecryptfs/keystore.c
+++ /dev/null
@@ -1,1061 +0,0 @@
-/**
- * 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
- * Michael C. Thompson
- *
- * 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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#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/trunk/fs/ecryptfs/main.c b/trunk/fs/ecryptfs/main.c
deleted file mode 100644
index 7a11b8ae6644..000000000000
--- a/trunk/fs/ecryptfs/main.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/**
- * 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
- * Michael C. Thompson
- *
- * 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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#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 ");
-MODULE_DESCRIPTION("eCryptfs");
-
-MODULE_LICENSE("GPL");
-
-module_init(ecryptfs_init)
-module_exit(ecryptfs_exit)
diff --git a/trunk/fs/ecryptfs/mmap.c b/trunk/fs/ecryptfs/mmap.c
deleted file mode 100644
index 924dd90a4cf5..000000000000
--- a/trunk/fs/ecryptfs/mmap.c
+++ /dev/null
@@ -1,788 +0,0 @@
-/**
- * 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
- *
- * 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
-#include