summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-03 21:46:06 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-03 21:46:06 +0000
commit3e414096429d55fbc8116171bba3487647bbe638 (patch)
tree2b5fcfd9d16fa3a32c829fc2076f6e3785b43374
parent20b23bfcf36fcb2d16d8b844501072541970637c (diff)
Merge with Linux 2.4.0-test3-pre2.
-rw-r--r--CREDITS10
-rw-r--r--Documentation/Changes8
-rw-r--r--Documentation/Configure.help52
-rw-r--r--Documentation/filesystems/vfs.txt5
-rw-r--r--Documentation/networking/tulip.txt4
-rw-r--r--Documentation/usb/ov511.txt4
-rw-r--r--MAINTAINERS7
-rw-r--r--Makefile5
-rw-r--r--arch/alpha/Makefile8
-rw-r--r--arch/alpha/config.in4
-rw-r--r--arch/alpha/kernel/core_cia.c20
-rw-r--r--arch/alpha/kernel/pci.c16
-rw-r--r--arch/alpha/kernel/setup.c56
-rw-r--r--arch/alpha/kernel/sys_sx164.c33
-rw-r--r--arch/alpha/vmlinux.lds.in96
-rw-r--r--arch/arm/config.in5
-rw-r--r--arch/arm/kernel/armksyms.c4
-rw-r--r--arch/arm/kernel/arthur.c2
-rw-r--r--arch/arm/kernel/bios32.c1
-rw-r--r--arch/arm/kernel/dma-footbridge.c1
-rw-r--r--arch/arm/kernel/dma-rpc.c1
-rw-r--r--arch/arm/kernel/dma.c2
-rw-r--r--arch/arm/kernel/ecard.c10
-rw-r--r--arch/arm/kernel/hw-footbridge.c145
-rw-r--r--arch/arm/kernel/hw-sa1100.c2
-rw-r--r--arch/arm/kernel/irq.c2
-rw-r--r--arch/arm/kernel/isa.c1
-rw-r--r--arch/arm/kernel/leds-footbridge.c2
-rw-r--r--arch/arm/kernel/leds-sa1100.c2
-rw-r--r--arch/arm/kernel/process.c10
-rw-r--r--arch/arm/kernel/ptrace.c571
-rw-r--r--arch/arm/kernel/ptrace.h16
-rw-r--r--arch/arm/kernel/semaphore.c1
-rw-r--r--arch/arm/kernel/setup.c1
-rw-r--r--arch/arm/kernel/signal.c23
-rw-r--r--arch/arm/kernel/time.c1
-rw-r--r--arch/arm/kernel/traps.c126
-rw-r--r--arch/arm/mm/fault-common.c1
-rw-r--r--arch/arm/mm/mm-armv.c28
-rw-r--r--arch/arm/mm/proc-arm2,3.S3
-rw-r--r--arch/arm/mm/proc-arm6,7.S4
-rw-r--r--arch/arm/mm/proc-arm720.S4
-rw-r--r--arch/i386/kernel/apic.c4
-rw-r--r--arch/i386/kernel/pci-irq.c2
-rw-r--r--arch/i386/kernel/setup.c5
-rw-r--r--arch/mips/kernel/irixelf.c3
-rw-r--r--arch/sparc/config.in4
-rw-r--r--arch/sparc/kernel/sys_sparc.c4
-rw-r--r--arch/sparc/kernel/sys_sunos.c4
-rw-r--r--arch/sparc64/kernel/sys_sparc.c4
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c5
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c4
-rw-r--r--drivers/acorn/char/Makefile1
-rw-r--r--drivers/acorn/char/defkeymap-acorn.c358
-rw-r--r--drivers/atm/fore200e.c2
-rw-r--r--drivers/block/elevator.c2
-rw-r--r--drivers/block/ll_rw_blk.c21
-rw-r--r--drivers/char/i810_rng.c386
-rw-r--r--drivers/char/n_tty.c30
-rw-r--r--drivers/char/ppdev.c1
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/tty_io.c71
-rw-r--r--drivers/isdn/avmb1/Makefile7
-rw-r--r--drivers/isdn/avmb1/b1.c10
-rw-r--r--drivers/isdn/avmb1/b1dma.c15
-rw-r--r--drivers/isdn/avmb1/b1pci.c60
-rw-r--r--drivers/isdn/avmb1/c4.c44
-rw-r--r--drivers/isdn/avmb1/capi.c73
-rw-r--r--drivers/isdn/avmb1/capidrv.c43
-rw-r--r--drivers/isdn/avmb1/kcapi.c12
-rw-r--r--drivers/isdn/avmb1/t1pci.c31
-rw-r--r--drivers/net/3c59x.c1
-rw-r--r--drivers/net/8390.c4
-rw-r--r--drivers/net/Config.in6
-rw-r--r--drivers/net/am79c961a.h4
-rw-r--r--drivers/net/arcnet/arcnet.c22
-rw-r--r--drivers/net/arcnet/com90xx.c3
-rw-r--r--drivers/net/eepro.c57
-rw-r--r--drivers/net/eepro100.c7
-rw-r--r--drivers/net/epic100.c12
-rw-r--r--drivers/net/shaper.c1
-rw-r--r--drivers/net/sk_g16.c91
-rw-r--r--drivers/net/sk_mca.c2
-rw-r--r--drivers/net/slip.c2
-rw-r--r--drivers/net/starfire.c16
-rw-r--r--drivers/net/sunlance.c1
-rw-r--r--drivers/net/tulip/21142.c4
-rw-r--r--drivers/net/tulip/interrupt.c4
-rw-r--r--drivers/net/tulip/tulip_core.c11
-rw-r--r--drivers/pci/pci.ids87
-rw-r--r--drivers/pnp/isapnp.c2
-rw-r--r--drivers/scsi/aic7xxx.c2
-rw-r--r--drivers/scsi/gdth.c2
-rw-r--r--drivers/scsi/hosts.c2
-rw-r--r--drivers/scsi/st.c46
-rw-r--r--drivers/sound/i810_audio.c7
-rw-r--r--drivers/sound/vidc.c1
-rw-r--r--drivers/usb/Config.in8
-rw-r--r--drivers/usb/Makefile14
-rw-r--r--drivers/usb/microtek.c13
-rw-r--r--drivers/usb/microtek.h3
-rw-r--r--drivers/usb/ov511.c172
-rw-r--r--drivers/usb/printer.c8
-rw-r--r--drivers/usb/serial/digi_acceleport.c181
-rw-r--r--drivers/usb/serial/usb-serial.h3
-rw-r--r--drivers/usb/serial/usbserial.c71
-rw-r--r--drivers/usb/serial/visor.c6
-rw-r--r--drivers/usb/storage/Makefile32
-rw-r--r--drivers/usb/storage/debug.c185
-rw-r--r--drivers/usb/storage/debug.h66
-rw-r--r--drivers/usb/storage/protocol.c304
-rw-r--r--drivers/usb/storage/protocol.h63
-rw-r--r--drivers/usb/storage/scsiglue.c824
-rw-r--r--drivers/usb/storage/scsiglue.h54
-rw-r--r--drivers/usb/storage/transport.c904
-rw-r--r--drivers/usb/storage/transport.h132
-rw-r--r--drivers/usb/storage/usb.c803
-rw-r--r--drivers/usb/storage/usb.h182
-rw-r--r--drivers/usb/usb.c5
-rw-r--r--drivers/video/fbmem.c53
-rw-r--r--drivers/video/riva/fbdev.c139
-rw-r--r--drivers/video/sisfb.c6
-rw-r--r--drivers/video/tdfxfb.c2
-rw-r--r--fs/binfmt_elf.c6
-rw-r--r--fs/binfmt_em86.c2
-rw-r--r--fs/binfmt_misc.c1
-rw-r--r--fs/binfmt_script.c1
-rw-r--r--fs/block_dev.c6
-rw-r--r--fs/buffer.c35
-rw-r--r--fs/coda/dir.c2
-rw-r--r--fs/coda/file.c4
-rw-r--r--fs/coda/psdev.c41
-rw-r--r--fs/coda/upcall.c6
-rw-r--r--fs/exec.c101
-rw-r--r--fs/ext2/fsync.c2
-rw-r--r--fs/ext2/inode.c2
-rw-r--r--fs/ext2/super.c1
-rw-r--r--fs/fat/inode.c2
-rw-r--r--fs/fcntl.c2
-rw-r--r--fs/file_table.c24
-rw-r--r--fs/hpfs/file.c2
-rw-r--r--fs/hpfs/hpfs_fn.h2
-rw-r--r--fs/hpfs/namei.c10
-rw-r--r--fs/inode.c14
-rw-r--r--fs/ioctl.c2
-rw-r--r--fs/lockd/clntlock.c29
-rw-r--r--fs/lockd/svclock.c2
-rw-r--r--fs/locks.c1192
-rw-r--r--fs/minix/bitmap.c3
-rw-r--r--fs/minix/fsync.c2
-rw-r--r--fs/minix/inode.c4
-rw-r--r--fs/namei.c324
-rw-r--r--fs/ncpfs/dir.c6
-rw-r--r--fs/ncpfs/file.c38
-rw-r--r--fs/ncpfs/inode.c11
-rw-r--r--fs/ncpfs/ioctl.c16
-rw-r--r--fs/ncpfs/mmap.c1
-rw-r--r--fs/ncpfs/ncplib_kernel.c24
-rw-r--r--fs/ncpfs/ncplib_kernel.h4
-rw-r--r--fs/ncpfs/symlink.c56
-rw-r--r--fs/nfs/file.c4
-rw-r--r--fs/nfsd/export.c13
-rw-r--r--fs/nfsd/nfscache.c13
-rw-r--r--fs/nfsd/nfsctl.c1
-rw-r--r--fs/nfsd/nfsfh.c16
-rw-r--r--fs/nfsd/nfsproc.c4
-rw-r--r--fs/nfsd/nfssvc.c12
-rw-r--r--fs/nfsd/vfs.c150
-rw-r--r--fs/ntfs/fs.c2
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/base.c10
-rw-r--r--fs/qnx4/inode.c1
-rw-r--r--fs/ramfs/inode.c10
-rw-r--r--fs/smbfs/file.c2
-rw-r--r--fs/super.c224
-rw-r--r--fs/sysv/fsync.c2
-rw-r--r--fs/sysv/ialloc.c2
-rw-r--r--fs/sysv/inode.c3
-rw-r--r--fs/udf/fsync.c2
-rw-r--r--fs/udf/inode.c4
-rw-r--r--fs/udf/super.c1
-rw-r--r--fs/udf/udfdecl.h4
-rw-r--r--fs/ufs/inode.c5
-rw-r--r--fs/umsdos/inode.c4
-rw-r--r--include/asm-alpha/pci.h5
-rw-r--r--include/asm-alpha/system.h7
-rw-r--r--include/asm-arm/arch-arc/ide.h8
-rw-r--r--include/asm-arm/arch-cl7500/ide.h5
-rw-r--r--include/asm-arm/arch-ebsa285/ide.h5
-rw-r--r--include/asm-arm/arch-l7200/ide.h2
-rw-r--r--include/asm-arm/arch-nexuspci/ide.h5
-rw-r--r--include/asm-arm/arch-rpc/ide.h8
-rw-r--r--include/asm-arm/arch-sa1100/ide.h14
-rw-r--r--include/asm-arm/arch-sa1100/irq.h3
-rw-r--r--include/asm-arm/arch-shark/hardware.h2
-rw-r--r--include/asm-arm/arch-shark/ide.h8
-rw-r--r--include/asm-arm/atomic.h28
-rw-r--r--include/asm-arm/cpu-multi26.h2
-rw-r--r--include/asm-arm/dma.h3
-rw-r--r--include/asm-arm/floppy.h23
-rw-r--r--include/asm-arm/io.h21
-rw-r--r--include/asm-arm/memory.h31
-rw-r--r--include/asm-arm/proc-armo/system.h26
-rw-r--r--include/asm-arm/proc-armv/system.h26
-rw-r--r--include/asm-arm/ptrace.h4
-rw-r--r--include/asm-arm/system.h19
-rw-r--r--include/asm-ppc/unistd.h2
-rw-r--r--include/linux/affs_fs.h2
-rw-r--r--include/linux/arcdevice.h6
-rw-r--r--include/linux/coda_psdev.h4
-rw-r--r--include/linux/ext2_fs.h4
-rw-r--r--include/linux/fs.h55
-rw-r--r--include/linux/kernelcapi.h8
-rw-r--r--include/linux/minix_fs.h2
-rw-r--r--include/linux/mm.h1
-rw-r--r--include/linux/mount.h1
-rw-r--r--include/linux/msdos_fs.h2
-rw-r--r--include/linux/ncp_fs_i.h3
-rw-r--r--include/linux/nfsd/cache.h4
-rw-r--r--include/linux/nfsd/export.h12
-rw-r--r--include/linux/nfsd/nfsd.h11
-rw-r--r--include/linux/nfsd/nfsfh.h33
-rw-r--r--include/linux/pci_ids.h8
-rw-r--r--include/linux/qnx4_fs.h2
-rw-r--r--include/linux/sysv_fs.h4
-rw-r--r--include/linux/timer.h21
-rw-r--r--include/linux/ufs_fs.h3
-rw-r--r--include/linux/umsdos_fs.p2
-rw-r--r--ipc/shm.c6
-rw-r--r--kernel/exec_domain.c49
-rw-r--r--kernel/itimer.c1
-rw-r--r--kernel/ksyms.c5
-rw-r--r--kernel/module.c5
-rw-r--r--kernel/sched.c4
-rw-r--r--kernel/sysctl.c4
-rw-r--r--kernel/timer.c50
-rw-r--r--mm/filemap.c9
-rw-r--r--mm/mmap.c29
-rw-r--r--mm/page_alloc.c2
-rw-r--r--mm/swap_state.c4
-rw-r--r--mm/swapfile.c14
-rw-r--r--net/ax25/af_ax25.c2
-rw-r--r--net/ax25/ax25_in.c2
-rw-r--r--net/ax25/ax25_out.c2
-rw-r--r--net/ax25/ax25_route.c2
-rw-r--r--net/core/neighbour.c5
-rw-r--r--net/decnet/dn_dev.c1
-rw-r--r--net/ipv4/tcp_timer.c4
-rw-r--r--net/netrom/nr_route.c4
-rw-r--r--net/netsyms.c2
-rw-r--r--net/sunrpc/svcsock.c11
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--scripts/kernel-doc6
253 files changed, 7584 insertions, 2692 deletions
diff --git a/CREDITS b/CREDITS
index 53968d777..475ea29b3 100644
--- a/CREDITS
+++ b/CREDITS
@@ -950,7 +950,7 @@ S: London SE16 1GD
S: United Kingdom
N: Kai Harrekilde-Petersen
-E: khp@olicom.dk
+E: kai.harrekilde@get2net.dk
D: Original author of the ftape-HOWTO, i82078 fdc detection code.
N: Bart Hartgers
@@ -1216,6 +1216,10 @@ S: Treforest, Pontypridd,
S: Mid Glamorgan, CF37 1NW,
S: Wales, United Kingdom
+N: Ani Joshi
+E: ajoshi@shell.unixbox.com
+D: fbdev hacking
+
N: Bernhard Kaindl
E: bkaindl@netway.at
E: edv@bartelt.via.at
@@ -2662,10 +2666,10 @@ S: USA
N: Tim Waugh
E: tim@cyberelk.demon.co.uk
D: Co-architect of the parallel-port sharing system
-S: 34 Bladon Close
+S: 17 Curling Vale
S: GUILDFORD
S: Surrey
-S: GU1 1TY
+S: GU2 7PJ
S: United Kingdom
N: Juergen Weigert
diff --git a/Documentation/Changes b/Documentation/Changes
index 0b9e549fc..525932df1 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -41,7 +41,7 @@ Card) hardware, for example, you probably needn't concern yourself
with pcmcia-cs.
o Gnu C 2.7.2.3 # gcc --version
-o binutils 2.9.1.0.7 # ld -v
+o binutils 2.9.1.0.22 # ld -v
o util-linux 2.10g # chsh -v
o modutils 2.3.10 # insmod -V
o e2fsprogs 1.18 # /sbin/tune2fs --version
@@ -78,7 +78,7 @@ release of binutils.
If you can, upgrade to the latest 2.9.5 binutils release. Older
releases such as 2.8, 2.8.xx, and the FSF's 2.9.1 should be avoided if
-at all possible. The later releases of 2.9.1.0.x (anything where x >= 7)
+at all possible. The later releases of 2.9.1.0.x (anything where x >= 22)
can and do compile the kernel properly, but there are many benefits
to upgrading to 2.9.5 if you're up to it.
@@ -248,8 +248,8 @@ o ftp://ftp.varesearch.com/pub/support/hjl/binutils/2.9.1/binutils-2.9.1.0.25.t
2.9.5 series
------------
-o ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.gz
- <ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.29.tar.bz2>
+o ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.gz
+ <ftp://ftp.varesearch.com/pub/support/hjl/binutils/binutils-2.9.5.0.46.tar.bz2>
System utilities
****************
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index 5e4f351e5..edaa621b0 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -2136,6 +2136,20 @@ CONFIG_ALPHA_SRM
If unsure, say N.
+Legacy kernel start address
+CONFIG_ALPHA_LEGACY_START_ADDRESS
+ The 2.4 kernel changed the kernel start address from 0x310000
+ to 0x810000 to make room for the Wildfire's larger SRM console.
+
+ If you're using aboot 0.7 or later, the bootloader will examine
+ the ELF headers to determine where to transfer control. Unfortunately,
+ most older bootloaders -- APB, or MILO -- hardcoded the kernel
+ start address rather than examining the ELF headers, and the result
+ is a hard lockup.
+
+ Say Y if you have a broken bootloader. Say N if you do not, or
+ if you wish to run on Wildfire.
+
Non-standard serial port support
CONFIG_SERIAL_NONSTANDARD
Say Y here if you have any non-standard serial boards -- boards
@@ -3260,6 +3274,14 @@ CONFIG_FB_VIRTUAL
If unsure, say N.
+CONFIG_FB_SA1100
+ This is a framebuffer device for the SA-1100 LCD Controller.
+ See http://www.linux-fbdev.org/ for information on framebuffer
+ devices.
+
+ If you plan to use the LCD display with your SA-1100 system, say
+ Y here.
+
Advanced low level driver options
CONFIG_FBCON_ADVANCED
The frame buffer console uses character drawing routines that are
@@ -10049,8 +10071,9 @@ CONFIG_USB_DSBR
Microtek USB scanner support
CONFIG_USB_MICROTEK
Say Y here if you want support for the Microtek X6USB and possibly
- some other scanners. The scanner will appear as a scsi device to the
- rest of the system. A patched version of SANE is necessary to use the
+ some other scanners by that vendor. The scanner will appear as a
+ scsi generic device to the rest of the system.
+ A patched version of SANE is necessary to use the
scanner. It's available at
http://fachschaft.cup.uni-muenchen.de/~neukum/scanner.html
This driver can be compiled as a module.
@@ -15450,6 +15473,20 @@ CONFIG_ARCH_PERSONAL_SERVER
If you have any questions or comments about the Compaq Personal
Server, send e-mail to skiff@crl.dec.com
+Include support for Assabet
+CONFIG_SA1100_ASSABET
+ Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
+ Microprocessor Development Board (also known as the Assabet).
+
+Include support for the Compaq iPAQ 3600
+CONFIG_SA1100_BITSY
+ Say Y here if you intend to run this kernel on the Compaq iPAQ 3600
+ handheld computer. Information about this machine and the Linux
+ port to this machine can be found at:
+
+ http://www.handhelds.org/Compaq/index.html#iPAQ_H3600
+ http://www.compaq.com/products/handhelds/pocketpc/
+
Math emulation
CONFIG_NWFPE
Say Y to include the NWFPE floating point emulator in the kernel.
@@ -15506,6 +15543,17 @@ CONFIG_DEBUG_INFO
time and disk space needed for compilation of the kernel. If in
doubt say N.
+Kernel low-level debugging functions
+CONFIG_DEBUG_LL
+ Say Y here to include definitions of printascii, printchar, printhex
+ in the kernel. This is helpful if you are debugging code that
+ executes before the console is initialized.
+
+Kernel low-level debugging messages via footbridge serial port
+CONFIG_DEBUG_DC21285_PORT
+ Say Y here if you want the low-level print routines to direct their
+ output to the serial port in the DC21285 (Footbridge).
+
Split initialisation functions into discardable section
CONFIG_TEXT_SECTIONS
If you say Y here, kernel code that is only used during
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 7256f5aaf..7d1f5ca72 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -176,7 +176,7 @@ filesystem. As of kernel 2.1.99, the following members are defined:
struct super_operations {
void (*read_inode) (struct inode *);
- void (*write_inode) (struct inode *);
+ void (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
void (*delete_inode) (struct inode *);
int (*notify_change) (struct dentry *, struct iattr *);
@@ -198,7 +198,8 @@ or bottom half).
read. Other members are filled in by this method
write_inode: this method is called when the VFS needs to write an
- inode to disc
+ inode to disc. The second parameter indicates whether the write
+ should be synchronous or not, not all filesystems check this flag.
put_inode: called when the VFS inode is removed from the inode
cache. This method is optional
diff --git a/Documentation/networking/tulip.txt b/Documentation/networking/tulip.txt
index b936846af..11494e1dc 100644
--- a/Documentation/networking/tulip.txt
+++ b/Documentation/networking/tulip.txt
@@ -142,6 +142,10 @@ tulip_core.c - Driver core (a.k.a. where "everything else" goes)
Version history
===============
+0.9.7 (June 17, 2000):
+* Timer cleanups (Andrew Morton)
+* Alpha compile fix (somebody?)
+
0.9.6 (May 31, 2000):
* Revert 21143-related support flag patch
* Add HPPA/media-table debugging printk
diff --git a/Documentation/usb/ov511.txt b/Documentation/usb/ov511.txt
index a92453129..e5634fd7f 100644
--- a/Documentation/usb/ov511.txt
+++ b/Documentation/usb/ov511.txt
@@ -6,7 +6,7 @@ Author: Mark McClelland
Homepage: http://alpha.dyndns.org/ov511
NEW IN THIS VERSION:
- o Race conditions and other bugs fixed
+ o Preliminary support for YUV422 and YUV422P V4L modes
INTRODUCTION:
@@ -209,7 +209,7 @@ TODO:
o Setting of contrast and brightness not working with 7620
o Driver/camera state save/restore for when USB supports suspend/resume
o Multiple cameras reportedly do not work simultaneously
- o Problems with OHCI
+ o Unstable on SMP systems
HOW TO CONTACT ME:
diff --git a/MAINTAINERS b/MAINTAINERS
index 6ce7ccf42..3f1cec084 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -784,8 +784,8 @@ L: linux-kernel@vger.rutgers.edu
S: Odd Fixes
NVIDIA (RIVA) FRAMEBUFFER DRIVER
-P: Jeff Garzik
-M: jgarzik@mandrakesoft.com
+P: Ani Joshi
+M: ajoshi@shell.unixbox.com
L: linux-nvidia@lists.surfsouth.com
S: Maintained
@@ -1135,7 +1135,8 @@ S: Maintained
USB SUBSYSTEM
P: Randy Dunlap
M: randy.dunlap@intel.com
-L: linux-usb@suse.com
+L: linux-usb-users@lists.sourceforge.net
+L: linux-usb-devel@lists.sourceforge.net
W: http://www.linux-usb.org
S: Supported
diff --git a/Makefile b/Makefile
index ab6efd482..dadae6f41 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test2
+EXTRAVERSION = -test3
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -82,7 +82,7 @@ endif
CPPFLAGS := -D__KERNEL__ -I$(HPATH)
-CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -Werror
AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
#
@@ -329,6 +329,7 @@ modules_install:
if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES net; fi; \
if [ -f SKFP_MODULES ]; then inst_mod SKFP_MODULES net; fi; \
if [ -f USB_MODULES ]; then inst_mod USB_MODULES usb; fi; \
+ if [ -f USB_STORAGE_MODULES ]; then inst_mod USB_STORAGE_MODULES usb; fi; \
if [ -f USB_SERIAL_MODULES ]; then inst_mod USB_SERIAL_MODULES usb; fi; \
if [ -f IEEE1394_MODULES ]; then inst_mod IEEE1394_MODULES ieee1394; fi; \
if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
index 36f4d4e6d..3daa2c73c 100644
--- a/arch/alpha/Makefile
+++ b/arch/alpha/Makefile
@@ -10,7 +10,7 @@
NM := nm -B
-LINKFLAGS = -static -T arch/alpha/vmlinux.lds #-N -relax
+LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N #-relax
CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
# Determine if we can use the BWX instructions with GAS.
@@ -90,7 +90,7 @@ endif
LIBS := $(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+MAKEBOOT = $(MAKE) -C arch/alpha/boot
rawboot:
@$(MAKEBOOT) rawboot
@@ -109,13 +109,15 @@ srmboot:
@$(MAKEBOOT) srmboot
archclean:
- @$(MAKE) -C arch/$(ARCH)/kernel clean
+ @$(MAKE) -C arch/alpha/kernel clean
@$(MAKEBOOT) clean
+ rm -f arch/alpha/vmlinux.lds
archmrproper:
archdep:
@$(MAKEBOOT) dep
+ $(CPP) $(CPPFLAGS) -xc -P arch/alpha/vmlinux.lds.in -o arch/alpha/vmlinux.lds
bootpfile:
@$(MAKEBOOT) bootpfile
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 5f344e0f5..7441083b6 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -331,7 +331,6 @@ source drivers/usb/Config.in
mainmenu_option next_comment
comment 'Kernel hacking'
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Kernel FP software completion' CONFIG_MATHEMU
else
@@ -339,4 +338,7 @@ else
fi
bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+
+bool 'Legacy kernel start address' CONFIG_ALPHA_LEGACY_START_ADDRESS
+
endmenu
diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c
index 88c88a4e6..348bd843f 100644
--- a/arch/alpha/kernel/core_cia.c
+++ b/arch/alpha/kernel/core_cia.c
@@ -19,6 +19,7 @@
#include <asm/system.h>
#include <asm/ptrace.h>
+#include <asm/hwrpb.h>
#define __EXTERN_INLINE inline
#include <asm/io.h>
@@ -712,6 +713,25 @@ cia_init_arch(void)
void __init
pyxis_init_arch(void)
{
+ /* On pyxis machines we can precisely calculate the
+ CPU clock frequency using pyxis real time counter.
+ It's especially useful for SX164 with broken RTC.
+
+ Both CPU and chipset are driven by the single 16.666M
+ or 16.667M crystal oscillator. PYXIS_RT_COUNT clock is
+ 66.66 MHz. -ink */
+
+ unsigned int cc0, cc1;
+ unsigned long pyxis_cc;
+
+ __asm__ __volatile__ ("rpcc %0" : "=r"(cc0));
+ pyxis_cc = *(vulp)PYXIS_RT_COUNT;
+ do { } while(*(vulp)PYXIS_RT_COUNT - pyxis_cc < 4096);
+ __asm__ __volatile__ ("rpcc %0" : "=r"(cc1));
+ cc1 -= cc0;
+ hwrpb->cycle_freq = ((cc1 >> 11) * 100000000UL) / 3;
+ hwrpb_update_checksum(hwrpb);
+
do_init_arch(1);
}
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 7a916ad08..2dc6f00dd 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -369,6 +369,22 @@ pcibios_enable_device(struct pci_dev *dev)
return 0;
}
+/*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain firmware forgets to set it properly, as seen
+ * on SX164 and LX164 with SRM.
+ */
+void
+pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat >= 16) return;
+ printk("PCI: Setting latency timer of device %s to 64\n",
+ dev->slot_name);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+}
+
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
static void __init
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 988c3cbec..073ee5381 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -246,11 +246,12 @@ get_mem_size_limit(char *s)
}
static void __init
-setup_memory(void * kernel_end)
+setup_memory(void *kernel_end)
{
struct memclust_struct * cluster;
struct memdesc_struct * memdesc;
- unsigned long start_pfn, bootmap_size, bootmap_pages, bootmap_start;
+ unsigned long start_kernel_pfn, end_kernel_pfn;
+ unsigned long bootmap_size, bootmap_pages, bootmap_start;
unsigned long start, end;
int i;
@@ -282,12 +283,13 @@ setup_memory(void * kernel_end)
max_low_pfn = mem_size_limit;
}
- /* Find the end of the memory used by the kernel. */
- start_pfn = PFN_UP(virt_to_phys(kernel_end));
+ /* Find the bounds of kernel memory. */
+ start_kernel_pfn = PFN_DOWN(KERNEL_START_PHYS);
+ end_kernel_pfn = PFN_UP(virt_to_phys(kernel_end));
bootmap_start = -1;
try_again:
- if (max_low_pfn <= start_pfn)
+ if (max_low_pfn <= end_kernel_pfn)
panic("not enough memory to boot");
/* We need to know how many physically contiguous pages
@@ -301,14 +303,19 @@ setup_memory(void * kernel_end)
start = cluster->start_pfn;
end = start + cluster->numpages;
- if (end <= start_pfn)
- continue;
if (start >= max_low_pfn)
continue;
- if (start < start_pfn)
- start = start_pfn;
if (end > max_low_pfn)
end = max_low_pfn;
+ if (start < start_kernel_pfn) {
+ if (end > end_kernel_pfn
+ && end - end_kernel_pfn >= bootmap_pages) {
+ bootmap_start = end_kernel_pfn;
+ break;
+ } else if (end > start_kernel_pfn)
+ end = start_kernel_pfn;
+ } else if (start < end_kernel_pfn)
+ start = end_kernel_pfn;
if (end - start >= bootmap_pages) {
bootmap_start = start;
break;
@@ -329,22 +336,28 @@ setup_memory(void * kernel_end)
continue;
start = cluster->start_pfn;
- if (start < start_pfn)
- start = start_pfn;
-
end = cluster->start_pfn + cluster->numpages;
+ if (start >= max_low_pfn)
+ continue;
if (end > max_low_pfn)
end = max_low_pfn;
-
+ if (start < start_kernel_pfn) {
+ if (end > end_kernel_pfn) {
+ free_bootmem(PFN_PHYS(start),
+ (PFN_PHYS(start_kernel_pfn)
+ - PFN_PHYS(start)));
+ printk("freeing pages %ld:%ld\n",
+ start, start_kernel_pfn);
+ start = end_kernel_pfn;
+ } else if (end > start_kernel_pfn)
+ end = start_kernel_pfn;
+ } else if (start < end_kernel_pfn)
+ start = end_kernel_pfn;
if (start >= end)
continue;
- start = PFN_PHYS(start);
- end = PFN_PHYS(end);
-
- free_bootmem(start, end - start);
- printk("freeing pages %ld:%ld\n",
- PFN_UP(start), PFN_DOWN(end));
+ free_bootmem(PFN_PHYS(start), PFN_PHYS(end) - PFN_PHYS(start));
+ printk("freeing pages %ld:%ld\n", start, end);
}
/* Reserve the bootmap memory. */
@@ -461,11 +474,12 @@ void __init unregister_srm_console(void)
void __init
setup_arch(char **cmdline_p)
{
+ extern char _end[];
+
struct alpha_machine_vector *vec = NULL;
struct percpu_struct *cpu;
char *type_name, *var_name, *p;
- extern char _end;
- void * kernel_end = &_end; /* end of kernel */
+ void *kernel_end = _end; /* end of kernel */
hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);
boot_cpuid = hard_smp_processor_id();
diff --git a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c
index b98e46028..19abbb6c3 100644
--- a/arch/alpha/kernel/sys_sx164.c
+++ b/arch/alpha/kernel/sys_sx164.c
@@ -24,6 +24,7 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/core_cia.h>
+#include <asm/hwrpb.h>
#include "proto.h"
#include "irq_impl.h"
@@ -114,6 +115,36 @@ sx164_init_pci(void)
SMC669_Init(0);
}
+static void __init
+sx164_init_arch(void)
+{
+ /*
+ * OSF palcode v1.23 forgets to enable PCA56 Motion Video
+ * Instructions. Let's enable it.
+ * We have to check palcode revision because CSERVE interface
+ * is subject to change without notice. For example, it
+ * has been changed completely since v1.16 (found in MILO
+ * distribution). -ink
+ */
+ struct percpu_struct *cpu = (struct percpu_struct*)
+ ((char*)hwrpb + hwrpb->processor_offset);
+
+ if (alpha_using_srm && (cpu->pal_revision & 0xffff) == 0x117) {
+ __asm__ __volatile__(
+ "lda $16,8($31)\n"
+ "call_pal 9\n" /* Allow PALRES insns in kernel mode */
+ ".long 0x64000118\n\n" /* hw_mfpr $0,icsr */
+ "ldah $16,(1<<(19-16))($31)\n"
+ "or $0,$16,$0\n" /* set MVE bit */
+ ".long 0x74000118\n" /* hw_mtpr $0,icsr */
+ "lda $16,9($31)\n"
+ "call_pal 9" /* Disable PALRES insns */
+ : : : "$0", "$16");
+ printk("PCA56 MVI set enabled\n");
+ }
+
+ pyxis_init_arch();
+}
/*
* The System Vector
@@ -133,7 +164,7 @@ struct alpha_machine_vector sx164_mv __initmv = {
nr_irqs: 48,
device_interrupt: pyxis_device_interrupt,
- init_arch: pyxis_init_arch,
+ init_arch: sx164_init_arch,
init_irq: sx164_init_irq,
init_rtc: common_init_rtc,
init_pci: sx164_init_pci,
diff --git a/arch/alpha/vmlinux.lds.in b/arch/alpha/vmlinux.lds.in
new file mode 100644
index 000000000..a153e5bd1
--- /dev/null
+++ b/arch/alpha/vmlinux.lds.in
@@ -0,0 +1,96 @@
+#include <linux/config.h>
+
+OUTPUT_FORMAT("elf64-alpha")
+ENTRY(__start)
+PHDRS { kernel PT_LOAD ; }
+SECTIONS
+{
+#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
+ . = 0xfffffc0000310000;
+#else
+ . = 0xfffffc0000810000;
+#endif
+
+ _text = .;
+ .text : { *(.text) } :kernel
+ _etext = .;
+
+ /* Exception table */
+ . = ALIGN(16);
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ /* Kernel symbol table */
+ . = ALIGN(8);
+ __start___ksymtab = .;
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+ .kstrtab : { *(.kstrtab) }
+
+ /* Startup code */
+ . = ALIGN(8192);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+
+ . = ALIGN(16);
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+
+ . = ALIGN(8);
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+
+ . = ALIGN(2*8192); /* Align double page for init_task_union */
+ __init_end = .;
+
+ /* The initial task and kernel stack */
+ init_task : { *(init_task) }
+
+ /* Global data */
+ _data = .;
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ .rodata : { *(.rodata) }
+ .data : { *(.data) CONSTRUCTORS }
+ .got : { *(.got) }
+ .sdata : { *(.sdata) }
+ _edata = .;
+
+ __bss_start = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss : { *(.bss) *(COMMON) }
+ __bss_stop = .;
+ _end = .;
+
+ .mdebug 0 : { *(.mdebug) }
+ .note 0 : { *(.note) }
+ .comment 0 : { *(.comment) }
+
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ /DISCARD/ : { *(.text.exit) *(.data.exit) }
+}
diff --git a/arch/arm/config.in b/arch/arm/config.in
index ff683b30b..15fba3403 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -12,6 +12,7 @@ define_bool CONFIG_UID16 y
mainmenu_option next_comment
comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+bool 'Prompt for obsolete code/drivers' CONFIG_OBSOLETE
endmenu
@@ -45,8 +46,8 @@ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then
bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET
fi
- bool ' Include support for Bitsy' CONFIG_SA1100_BITSY
bool ' Include support for Brutus' CONFIG_SA1100_BRUTUS
+ bool ' Include support for Compaq iPAQ 3600 (Bitsy)' CONFIG_SA1100_BITSY
# bool ' Include support for Empeg' CONFIG_SA1100_EMPEG
# bool ' Include support for Itsy' CONFIG_SA1100_ITSY
bool ' Include support for LART' CONFIG_SA1100_LART
@@ -342,7 +343,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool 'Kernel low-level debugging functions' CONFIG_DEBUG_LL
if [ "$CONFIG_DEBUG_LL" = "y" ]; then
if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
- bool 'Kernel low-level debugging messages via DC21285 port' CONFIG_DEBUG_DC21285_PORT
+ bool 'Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT
fi
fi
fi
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index ffd0f1b5e..5ac0743be 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -31,6 +31,8 @@ extern void outswb(unsigned int port, const void *to, int len);
extern unsigned int local_bh_count[NR_CPUS];
extern unsigned int local_irq_count[NR_CPUS];
+extern void __bad_xchg(volatile void *ptr, int size);
+
/*
* syscalls
*/
@@ -90,7 +92,6 @@ EXPORT_SYMBOL(kd_mksound);
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(udelay);
-EXPORT_SYMBOL(xchg_str);
EXPORT_SYMBOL(local_bh_count);
EXPORT_SYMBOL(local_irq_count);
#ifdef CONFIG_CPU_32
@@ -103,6 +104,7 @@ EXPORT_SYMBOL(system_serial_low);
EXPORT_SYMBOL(system_serial_high);
EXPORT_SYMBOL(mem_fclk_21285);
EXPORT_SYMBOL(__bug);
+EXPORT_SYMBOL(__bad_xchg);
EXPORT_SYMBOL(__readwrite_bug);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
diff --git a/arch/arm/kernel/arthur.c b/arch/arm/kernel/arthur.c
index 8a8a5510d..0547302f8 100644
--- a/arch/arm/kernel/arthur.c
+++ b/arch/arm/kernel/arthur.c
@@ -3,8 +3,8 @@
* Copyright (C) 1998-1999 Philip Blundell
*/
-#include <linux/personality.h>
#include <linux/module.h>
+#include <linux/personality.h>
#include <linux/stddef.h>
#include <linux/signal.h>
#include <linux/sched.h>
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 2fbda24be..a077f13b9 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -8,7 +8,6 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/errno.h>
#include <linux/init.h>
#include <asm/irq.h>
diff --git a/arch/arm/kernel/dma-footbridge.c b/arch/arm/kernel/dma-footbridge.c
index 65875831c..1d2ef26c4 100644
--- a/arch/arm/kernel/dma-footbridge.c
+++ b/arch/arm/kernel/dma-footbridge.c
@@ -13,7 +13,6 @@
#include <linux/config.h>
#include <linux/sched.h>
-#include <linux/errno.h>
#include <linux/init.h>
#include <asm/dma.h>
diff --git a/arch/arm/kernel/dma-rpc.c b/arch/arm/kernel/dma-rpc.c
index e1b54233b..f4bc97f1d 100644
--- a/arch/arm/kernel/dma-rpc.c
+++ b/arch/arm/kernel/dma-rpc.c
@@ -15,6 +15,7 @@
#include <asm/fiq.h>
#include <asm/io.h>
#include <asm/iomd.h>
+#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
index 7d1a11cd5..ff8322d34 100644
--- a/arch/arm/kernel/dma.c
+++ b/arch/arm/kernel/dma.c
@@ -14,9 +14,9 @@
*
* Moved DMA resource allocation here...
*/
+#include <linux/malloc.h>
#include <linux/sched.h>
#include <linux/module.h>
-#include <linux/malloc.h>
#include <linux/mman.h>
#include <linux/init.h>
#include <linux/spinlock.h>
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index 61eb422b2..b4d38e00f 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -33,9 +33,7 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#include <linux/errno.h>
#include <linux/proc_fs.h>
-#include <linux/unistd.h>
#include <linux/init.h>
#include <asm/dma.h>
@@ -913,7 +911,6 @@ ecard_probe(int slot, card_type_t type)
ecard_t **ecp;
ecard_t *ec;
struct ex_ecid cid;
- char buffer[200];
int i, rc = -ENOMEM;
ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
@@ -994,12 +991,9 @@ ecard_probe(int slot, card_type_t type)
nodev:
if (rc && ec)
kfree(ec);
- else {
+ else
slot_to_expcard[slot] = ec;
- ecard_prints(buffer, ec);
- printk("%s", buffer);
- }
return rc;
}
@@ -1075,7 +1069,7 @@ void __init ecard_init(void)
init_waitqueue_head(&ecard_done);
#endif
- printk("Probing expansion cards: (does not imply support)\n");
+ printk("Probing expansion cards\n");
for (slot = 0; slot < 8; slot ++) {
if (ecard_probe(slot, ECARD_EASI) == -ENODEV)
diff --git a/arch/arm/kernel/hw-footbridge.c b/arch/arm/kernel/hw-footbridge.c
index 08aac078e..b56b944e7 100644
--- a/arch/arm/kernel/hw-footbridge.c
+++ b/arch/arm/kernel/hw-footbridge.c
@@ -8,19 +8,12 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/ptrace.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/smp.h>
-#include <linux/mm.h>
#include <linux/init.h>
-#include <asm/dec21285.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/leds.h>
#include <asm/system.h>
@@ -28,6 +21,13 @@
#define GP1_IO_BASE 0x338
#define GP2_IO_BASE 0x33a
+
+#ifdef CONFIG_LEDS
+#define DEFAULT_LEDS 0
+#else
+#define DEFAULT_LEDS GPIO_GREEN_LED
+#endif
+
/*
* Netwinder stuff
*/
@@ -396,9 +396,9 @@ static unsigned char rwa_unlock[] __initdata =
0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };
#ifndef DEBUG
-#define dprintk if (0) printk
+#define dprintk(x...)
#else
-#define dprintk printk
+#define dprintk(x...) printk(x)
#endif
#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0)
@@ -602,74 +602,13 @@ EXPORT_SYMBOL(gpio_modify_op);
EXPORT_SYMBOL(gpio_modify_io);
EXPORT_SYMBOL(cpld_modify);
-#endif
-
-#ifdef CONFIG_LEDS
-#define DEFAULT_LEDS 0
-#else
-#define DEFAULT_LEDS GPIO_GREEN_LED
-#endif
-
-/*
- * CATS stuff
- */
-#ifdef CONFIG_ARCH_CATS
-
-#define CONFIG_PORT 0x370
-#define INDEX_PORT (CONFIG_PORT)
-#define DATA_PORT (CONFIG_PORT + 1)
-
-static void __init cats_hw_init(void)
-{
- /* Set Aladdin to CONFIGURE mode */
- outb(0x51, CONFIG_PORT);
- outb(0x23, CONFIG_PORT);
-
- /* Select logical device 3 */
- outb(0x07, INDEX_PORT);
- outb(0x03, DATA_PORT);
-
- /* Set parallel port to DMA channel 3, ECP+EPP1.9,
- enable EPP timeout */
- outb(0x74, INDEX_PORT);
- outb(0x03, DATA_PORT);
-
- outb(0xf0, INDEX_PORT);
- outb(0x0f, DATA_PORT);
-
- outb(0xf1, INDEX_PORT);
- outb(0x07, DATA_PORT);
-
- /* Select logical device 4 */
- outb(0x07, INDEX_PORT);
- outb(0x04, DATA_PORT);
-
- /* UART1 high speed mode */
- outb(0xf0, INDEX_PORT);
- outb(0x02, DATA_PORT);
-
- /* Select logical device 5 */
- outb(0x07, INDEX_PORT);
- outb(0x05, DATA_PORT);
-
- /* UART2 high speed mode */
- outb(0xf0, INDEX_PORT);
- outb(0x02, DATA_PORT);
-
- /* Set Aladdin to RUN mode */
- outb(0xbb, CONFIG_PORT);
-}
-
-#endif
-
/*
* Initialise any other hardware after we've got the PCI bus
* initialised. We may need the PCI bus to talk to this other
* hardware.
*/
-static int __init hw_init(void)
+static int __init nw_hw_init(void)
{
-#ifdef CONFIG_ARCH_NETWINDER
/*
* this ought to have a better home...
* Since this calls the above routines, which are
@@ -688,12 +627,66 @@ static int __init hw_init(void)
gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
spin_unlock_irqrestore(&gpio_lock, flags);
}
+ return 0;
+}
+
+__initcall(nw_hw_init);
#endif
+
+/*
+ * CATS stuff
+ */
#ifdef CONFIG_ARCH_CATS
- if (machine_is_cats())
- cats_hw_init();
-#endif
+
+#define CONFIG_PORT 0x370
+#define INDEX_PORT (CONFIG_PORT)
+#define DATA_PORT (CONFIG_PORT + 1)
+
+static int __init cats_hw_init(void)
+{
+ if (machine_is_cats()) {
+ /* Set Aladdin to CONFIGURE mode */
+ outb(0x51, CONFIG_PORT);
+ outb(0x23, CONFIG_PORT);
+
+ /* Select logical device 3 */
+ outb(0x07, INDEX_PORT);
+ outb(0x03, DATA_PORT);
+
+ /* Set parallel port to DMA channel 3, ECP+EPP1.9,
+ enable EPP timeout */
+ outb(0x74, INDEX_PORT);
+ outb(0x03, DATA_PORT);
+
+ outb(0xf0, INDEX_PORT);
+ outb(0x0f, DATA_PORT);
+
+ outb(0xf1, INDEX_PORT);
+ outb(0x07, DATA_PORT);
+
+ /* Select logical device 4 */
+ outb(0x07, INDEX_PORT);
+ outb(0x04, DATA_PORT);
+
+ /* UART1 high speed mode */
+ outb(0xf0, INDEX_PORT);
+ outb(0x02, DATA_PORT);
+
+ /* Select logical device 5 */
+ outb(0x07, INDEX_PORT);
+ outb(0x05, DATA_PORT);
+
+ /* UART2 high speed mode */
+ outb(0xf0, INDEX_PORT);
+ outb(0x02, DATA_PORT);
+
+ /* Set Aladdin to RUN mode */
+ outb(0xbb, CONFIG_PORT);
+ }
+
return 0;
}
-__initcall(hw_init);
+__initcall(cats_hw_init);
+#endif
+
diff --git a/arch/arm/kernel/hw-sa1100.c b/arch/arm/kernel/hw-sa1100.c
index 539bb721b..862c3a2c4 100644
--- a/arch/arm/kernel/hw-sa1100.c
+++ b/arch/arm/kernel/hw-sa1100.c
@@ -10,9 +10,9 @@
*
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/sched.h>
#include <asm/delay.h>
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 7a761b7c6..40a47c45f 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -17,7 +17,6 @@
*/
#include <linux/config.h>
#include <linux/ptrace.h>
-#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -26,7 +25,6 @@
#include <linux/malloc.h>
#include <linux/random.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/hardware.h>
diff --git a/arch/arm/kernel/isa.c b/arch/arm/kernel/isa.c
index a5424f8b6..17696acb0 100644
--- a/arch/arm/kernel/isa.c
+++ b/arch/arm/kernel/isa.c
@@ -13,7 +13,6 @@
#include <linux/stddef.h>
#include <linux/types.h>
-#include <linux/linkage.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
#include <linux/init.h>
diff --git a/arch/arm/kernel/leds-footbridge.c b/arch/arm/kernel/leds-footbridge.c
index 4fa2237eb..b309c2ea3 100644
--- a/arch/arm/kernel/leds-footbridge.c
+++ b/arch/arm/kernel/leds-footbridge.c
@@ -18,8 +18,8 @@
* 02-05-1999 RMK Various cleanups
*/
#include <linux/config.h>
-#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
diff --git a/arch/arm/kernel/leds-sa1100.c b/arch/arm/kernel/leds-sa1100.c
index ef6918d7c..f2f0325c3 100644
--- a/arch/arm/kernel/leds-sa1100.c
+++ b/arch/arm/kernel/leds-sa1100.c
@@ -29,8 +29,8 @@
*
*/
#include <linux/config.h>
-#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 40b3b9e72..cab969c5c 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -7,28 +7,22 @@
#include <stdarg.h>
-#include <linux/errno.h>
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
-#include <linux/vmalloc.h>
#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/interrupt.h>
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/init.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/uaccess.h>
/*
* Values for cpu_do_idle()
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 1684c5f5f..e45e03fcb 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -8,7 +8,6 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
@@ -16,6 +15,10 @@
#include <asm/pgtable.h>
#include <asm/system.h>
+#include "ptrace.h"
+
+#define REG_PC 15
+#define REG_PSR 16
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
@@ -27,6 +30,18 @@
#define BREAKINST 0xef9f0001
/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ */
+static inline struct pt_regs *
+get_user_regs(struct task_struct *task)
+{
+ return (struct pt_regs *)
+ ((unsigned long)task + 8192 - sizeof(struct pt_regs));
+}
+
+/*
* this routine will get a word off of the processes privileged stack.
* the offset is how far from the base addr as stored in the THREAD.
* this routine assumes that all the privileged stacks are in our
@@ -34,11 +49,7 @@
*/
static inline long get_stack_long(struct task_struct *task, int offset)
{
- struct pt_regs *regs;
-
- regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
-
- return regs->uregs[offset];
+ return get_user_regs(task)->uregs[offset];
}
/*
@@ -47,20 +58,16 @@ static inline long get_stack_long(struct task_struct *task, int offset)
* this routine assumes that all the privileged stacks are in our
* data space.
*/
-static inline long put_stack_long(struct task_struct *task, int offset,
- unsigned long data)
+static inline int
+put_stack_long(struct task_struct *task, int offset, long data)
{
- struct pt_regs *regs;
-
- regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs));
-
- regs->uregs[offset] = data;
+ get_user_regs(task)->uregs[offset] = data;
return 0;
}
-static int
-read_long(struct task_struct *child, unsigned long addr, unsigned long *res)
+static inline int
+read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res)
{
int copied;
@@ -69,8 +76,8 @@ read_long(struct task_struct *child, unsigned long addr, unsigned long *res)
return copied != sizeof(*res) ? -EIO : 0;
}
-static int
-write_long(struct task_struct *child, unsigned long addr, unsigned long val)
+static inline int
+write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val)
{
int copied;
@@ -82,35 +89,33 @@ write_long(struct task_struct *child, unsigned long addr, unsigned long val)
/*
* Get value of register `rn' (in the instruction)
*/
-static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getrn(struct task_struct *child, unsigned long insn)
{
unsigned int reg = (insn >> 16) & 15;
unsigned long val;
+ val = get_stack_long(child, reg);
if (reg == 15)
- val = pc_pointer (get_stack_long (child, reg));
- else
- val = get_stack_long (child, reg);
+ val = pc_pointer(val);
-printk ("r%02d=%08lX ", reg, val);
return val;
}
/*
* Get value of operand 2 (in an ALU instruction)
*/
-static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getaluop2(struct task_struct *child, unsigned long insn)
{
unsigned long val;
int shift;
int type;
-printk ("op2=");
if (insn & 1 << 25) {
val = insn & 255;
shift = (insn >> 8) & 15;
type = 3;
-printk ("(imm)");
} else {
val = get_stack_long (child, insn & 15);
@@ -120,9 +125,8 @@ printk ("(imm)");
shift = (insn >> 7) & 31;
type = (insn >> 5) & 3;
-printk ("(r%02ld)", insn & 15);
}
-printk ("sh%dx%d", type, shift);
+
switch (type) {
case 0: val <<= shift; break;
case 1: val >>= shift; break;
@@ -133,24 +137,23 @@ printk ("sh%dx%d", type, shift);
val = (val >> shift) | (val << (32 - shift));
break;
}
-printk ("=%08lX ", val);
return val;
}
/*
* Get value of operand 2 (in a LDR instruction)
*/
-static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getldrop2(struct task_struct *child, unsigned long insn)
{
unsigned long val;
int shift;
int type;
- val = get_stack_long (child, insn & 15);
+ val = get_stack_long(child, insn & 15);
shift = (insn >> 7) & 31;
type = (insn >> 5) & 3;
-printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type);
switch (type) {
case 0: val <<= shift; break;
case 1: val >>= shift; break;
@@ -161,7 +164,6 @@ printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type);
val = (val >> shift) | (val << (32 - shift));
break;
}
-printk ("=%08lX ", val);
return val;
}
@@ -170,95 +172,72 @@ get_branch_address(struct task_struct *child, unsigned long pc, unsigned long in
{
unsigned long alt = 0;
-printk(KERN_DEBUG "ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc);
- switch (insn & 0x0e100000) {
+ switch (insn & 0x0e000000) {
case 0x00000000:
- case 0x00100000:
- case 0x02000000:
- case 0x02100000: /* data processing */
- printk ("data ");
- switch (insn & 0x01e0f000) {
- case 0x0000f000:
- alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn);
- break;
- case 0x0020f000:
- alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn);
- break;
- case 0x0040f000:
- alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn);
- break;
- case 0x0060f000:
- alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn);
- break;
- case 0x0080f000:
- alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn);
- break;
- case 0x00a0f000:
- alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x00c0f000:
- alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x00e0f000:
- alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) +
- (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
- break;
- case 0x0180f000:
- alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn);
- break;
- case 0x01a0f000:
- alt = ptrace_getaluop2(child, insn);
- break;
- case 0x01c0f000:
- alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn);
- break;
- case 0x01e0f000:
- alt = ~ptrace_getaluop2(child, insn);
+ case 0x02000000: {
+ /*
+ * data processing
+ */
+ long aluop1, aluop2, ccbit;
+
+ if ((insn & 0xf000) != 0xf000)
break;
+
+ aluop1 = ptrace_getrn(child, insn);
+ aluop2 = ptrace_getaluop2(child, insn);
+ ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0;
+
+ switch (insn & 0x01e00000) {
+ case 0x00000000: alt = aluop1 & aluop2; break;
+ case 0x00200000: alt = aluop1 ^ aluop2; break;
+ case 0x00400000: alt = aluop1 - aluop2; break;
+ case 0x00600000: alt = aluop2 - aluop1; break;
+ case 0x00800000: alt = aluop1 + aluop2; break;
+ case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break;
+ case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break;
+ case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break;
+ case 0x01800000: alt = aluop1 | aluop2; break;
+ case 0x01a00000: alt = aluop2; break;
+ case 0x01c00000: alt = aluop1 & ~aluop2; break;
+ case 0x01e00000: alt = ~aluop2; break;
}
break;
+ }
+
+ case 0x04000000:
+ case 0x06000000:
+ /*
+ * ldr
+ */
+ if ((insn & 0x0010f000) == 0x0010f000) {
+ unsigned long base;
- case 0x04100000: /* ldr */
- if ((insn & 0xf000) == 0xf000) {
-printk ("ldr ");
- alt = ptrace_getrn(child, insn);
+ base = ptrace_getrn(child, insn);
if (insn & 1 << 24) {
- if (insn & 1 << 23)
- alt += ptrace_getldrop2 (child, insn);
+ long aluop2;
+
+ if (insn & 0x02000000)
+ aluop2 = ptrace_getldrop2(child, insn);
else
- alt -= ptrace_getldrop2 (child, insn);
- }
- if (read_long (child, alt, &alt) < 0)
- alt = 0; /* not valid */
- else
- alt = pc_pointer (alt);
- }
- break;
+ aluop2 = insn & 0xfff;
- case 0x06100000: /* ldr imm */
- if ((insn & 0xf000) == 0xf000) {
-printk ("ldrimm ");
- alt = ptrace_getrn(child, insn);
- if (insn & 1 << 24) {
if (insn & 1 << 23)
- alt += insn & 0xfff;
+ base += aluop2;
else
- alt -= insn & 0xfff;
+ base -= aluop2;
}
- if (read_long (child, alt, &alt) < 0)
- alt = 0; /* not valid */
- else
- alt = pc_pointer (alt);
+ if (read_tsk_long(child, base, &alt) == 0)
+ alt = pc_pointer(alt);
}
break;
- case 0x08100000: /* ldm */
- if (insn & (1 << 15)) {
+ case 0x08000000:
+ /*
+ * ldm
+ */
+ if ((insn & 0x00108000) == 0x00108000) {
unsigned long base;
- int nr_regs;
-printk ("ldm ");
+ unsigned int nr_regs;
if (insn & (1 << 23)) {
nr_regs = insn & 65535;
@@ -278,23 +257,22 @@ printk ("ldm ");
nr_regs = 0;
}
- base = ptrace_getrn (child, insn);
+ base = ptrace_getrn(child, insn);
- if (read_long (child, base + nr_regs, &alt) < 0)
- alt = 0; /* not valid */
- else
+ if (read_tsk_long(child, base + nr_regs, &alt) == 0)
alt = pc_pointer (alt);
break;
}
break;
- case 0x0a000000:
- case 0x0a100000: { /* bl or b */
+ case 0x0a000000: {
+ /*
+ * bl or b
+ */
signed long displ;
-printk ("b/bl ");
/* It's a branch/branch link: instead of trying to
* figure out whether the branch will be taken or not,
- * we'll put a breakpoint at either location. This is
+ * we'll put a breakpoint at both locations. This is
* simpler, more reliable, and probably not a whole lot
* slower than the alternative approach of emulating the
* branch.
@@ -306,7 +284,6 @@ printk ("b/bl ");
}
break;
}
-printk ("=%08lX\n", alt);
return alt;
}
@@ -318,9 +295,9 @@ add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long
int res = -EINVAL;
if (nr < 2) {
- res = read_long(child, addr, &dbg->bp[nr].insn);
+ res = read_tsk_long(child, addr, &dbg->bp[nr].insn);
if (res == 0)
- res = write_long(child, addr, BREAKINST);
+ res = write_tsk_long(child, addr, BREAKINST);
if (res == 0) {
dbg->bp[nr].address = addr;
@@ -332,257 +309,309 @@ add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long
return res;
}
-int ptrace_set_bpt (struct task_struct *child)
+int ptrace_set_bpt(struct task_struct *child)
{
- struct debug_info *dbg = &child->thread.debug;
- unsigned long insn, pc, alt;
+ unsigned long insn, pc;
int res;
- pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/));
+ pc = pc_pointer(get_stack_long(child, REG_PC));
- res = read_long(child, pc, &insn);
- if (res >= 0) {
- res = 0;
+ res = read_tsk_long(child, pc, &insn);
+ if (!res) {
+ struct debug_info *dbg = &child->thread.debug;
+ unsigned long alt;
dbg->nsaved = 0;
- res = add_breakpoint(child, dbg, pc + 4);
+ alt = get_branch_address(child, pc, insn);
+ if (alt)
+ res = add_breakpoint(child, dbg, alt);
- if (res == 0) {
- alt = get_branch_address(child, pc, insn);
- if (alt)
- res = add_breakpoint(child, dbg, alt);
- }
+ if (!res && (!alt || predicate(insn) != PREDICATE_ALWAYS))
+ res = add_breakpoint(child, dbg, pc + 4);
}
return res;
}
-/* Ensure no single-step breakpoint is pending. Returns non-zero
+/*
+ * Ensure no single-step breakpoint is pending. Returns non-zero
* value if child was being single-stepped.
*/
-int ptrace_cancel_bpt (struct task_struct *child)
+void __ptrace_cancel_bpt(struct task_struct *child)
{
struct debug_info *dbg = &child->thread.debug;
- unsigned long tmp;
int i, nsaved = dbg->nsaved;
dbg->nsaved = 0;
if (nsaved > 2) {
- printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
+ printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
nsaved = 2;
}
for (i = 0; i < nsaved; i++) {
- read_long(child, dbg->bp[i].address, &tmp);
+ unsigned long tmp;
+
+ read_tsk_long(child, dbg->bp[i].address, &tmp);
if (tmp != BREAKINST)
printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
- write_long(child, dbg->bp[i].address, dbg->bp[i].insn);
+ write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn);
}
-
- return nsaved != 0;
}
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+static int do_ptrace(int request, struct task_struct *child, long addr, long data)
{
- struct task_struct *child;
+ unsigned long tmp;
int ret;
- lock_kernel();
- ret = -EPERM;
- if (request == PTRACE_TRACEME) {
- /* are we already being traced? */
- if (current->ptrace & PT_PTRACED)
- goto out;
- /* set the ptrace bit in the process flags. */
- current->ptrace |= PT_PTRACED;
- ret = 0;
- goto out;
- }
- if (pid == 1) /* you may not mess with init */
- goto out;
- ret = -ESRCH;
- if (!(child = find_task_by_pid(pid)))
- goto out;
- ret = -EPERM;
- if (request == PTRACE_ATTACH) {
- if (child == current)
- goto out;
- if ((!child->dumpable ||
- (current->uid != child->euid) ||
- (current->uid != child->suid) ||
- (current->uid != child->uid) ||
- (current->gid != child->egid) ||
- (current->gid != child->sgid) ||
- (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
- (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
- goto out;
- /* the same process cannot be attached many times */
- if (child->ptrace & PT_PTRACED)
- goto out;
- child->ptrace |= PT_PTRACED;
- if (child->p_pptr != current) {
- REMOVE_LINKS(child);
- child->p_pptr = current;
- SET_LINKS(child);
- }
- send_sig(SIGSTOP, child, 1);
- ret = 0;
- goto out;
- }
- ret = -ESRCH;
- if (!(child->ptrace & PT_PTRACED))
- goto out;
- if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL)
- goto out;
- }
- if (child->p_pptr != current)
- goto out;
-
switch (request) {
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
-
- ret = read_long(child, addr, &tmp);
+ /*
+ * read word at location "addr" in the child process.
+ */
+ case PTRACE_PEEKTEXT:
+ case PTRACE_PEEKDATA:
+ ret = read_tsk_long(child, addr, &tmp);
if (!ret)
ret = put_user(tmp, (unsigned long *) data);
- goto out;
- }
-
- case PTRACE_PEEKUSR: { /* read the word at location addr in the USER area. */
- unsigned long tmp;
+ break;
+ /*
+ * read the word at location "addr" in the user registers.
+ */
+ case PTRACE_PEEKUSR:
ret = -EIO;
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
- goto out;
+ break;
tmp = 0; /* Default return condition */
- if (addr < sizeof (struct pt_regs))
+ if (addr < sizeof(struct pt_regs))
tmp = get_stack_long(child, (int)addr >> 2);
ret = put_user(tmp, (unsigned long *)data);
- goto out;
- }
+ break;
- case PTRACE_POKETEXT: /* write the word at location addr. */
+ /*
+ * write the word at location addr.
+ */
+ case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = write_long(child, addr, data);
- goto out;
+ ret = write_tsk_long(child, addr, data);
+ break;
- case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ /*
+ * write the word at location addr in the user registers.
+ */
+ case PTRACE_POKEUSR:
ret = -EIO;
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
- goto out;
+ break;
if (addr < sizeof (struct pt_regs))
ret = put_stack_long(child, (int)addr >> 2, data);
- goto out;
+ break;
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: /* restart after signal. */
+ /*
+ * continue/restart and stop at next (return from) syscall
+ */
+ case PTRACE_SYSCALL:
+ case PTRACE_CONT:
ret = -EIO;
if ((unsigned long) data > _NSIG)
- goto out;
+ break;
if (request == PTRACE_SYSCALL)
child->ptrace |= PT_TRACESYS;
else
child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
- wake_up_process (child);
/* make sure single-step breakpoint is gone. */
- ptrace_cancel_bpt (child);
+ __ptrace_cancel_bpt(child);
+ wake_up_process(child);
ret = 0;
- goto out;
+ break;
- /* make the child exit. Best I can do is send it a sigkill.
+ /*
+ * make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
*/
case PTRACE_KILL:
- if (child->state == TASK_ZOMBIE) /* already dead */
- return 0;
- wake_up_process (child);
+ /* already dead */
+ ret = 0;
+ if (child->state == TASK_ZOMBIE)
+ break;
child->exit_code = SIGKILL;
/* make sure single-step breakpoint is gone. */
- ptrace_cancel_bpt (child);
+ __ptrace_cancel_bpt(child);
+ wake_up_process(child);
ret = 0;
- goto out;
+ break;
- case PTRACE_SINGLESTEP: /* execute single instruction. */
+ /*
+ * execute single instruction.
+ */
+ case PTRACE_SINGLESTEP:
ret = -EIO;
if ((unsigned long) data > _NSIG)
- goto out;
+ break;
child->thread.debug.nsaved = -1;
child->ptrace &= ~PT_TRACESYS;
- wake_up_process(child);
child->exit_code = data;
/* give it a chance to run. */
+ wake_up_process(child);
ret = 0;
- goto out;
-
- case PTRACE_GETREGS:
- { /* Get all gp regs from the child. */
- unsigned char *stack;
+ break;
+
+ /*
+ * detach a process that was attached.
+ */
+ case PTRACE_DETACH:
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
+ child->exit_code = data;
+ write_lock_irq(&tasklist_lock);
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ write_unlock_irq(&tasklist_lock);
+ /* make sure single-step breakpoint is gone. */
+ __ptrace_cancel_bpt(child);
+ wake_up_process (child);
+ ret = 0;
+ break;
+
+ /*
+ * Get all gp regs from the child.
+ */
+ case PTRACE_GETREGS: {
+ struct pt_regs *regs = get_user_regs(child);
ret = 0;
- stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs));
- if (copy_to_user((void *)data, stack,
+ if (copy_to_user((void *)data, regs,
sizeof(struct pt_regs)))
ret = -EFAULT;
- goto out;
- };
+ break;
+ }
- case PTRACE_SETREGS:
- {
- /* Set all gp regs in the child. */
- unsigned char *stack;
+ /*
+ * Set all gp regs in the child.
+ */
+ case PTRACE_SETREGS: {
+ struct pt_regs *regs = get_user_regs(child);
ret = 0;
- stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs));
- if (copy_from_user(stack, (void *)data,
+ if (copy_from_user(regs, (void *)data,
sizeof(struct pt_regs)))
ret = -EFAULT;
- goto out;
- };
+ break;
+ }
- case PTRACE_GETFPREGS:
- /* Get the child FPU state. */
- ret = 0;
- if (copy_to_user((void *)data, &child->thread.fpstate,
- sizeof(struct user_fp)))
- ret = -EFAULT;
- goto out;
+ /*
+ * Get the child FPU state.
+ */
+ case PTRACE_GETFPREGS:
+ ret = -EIO;
+ if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp)))
+ break;
+
+ /* we should check child->used_math here */
+ ret = __copy_to_user((void *)data, &child->thread.fpstate,
+ sizeof(struct user_fp)) ? -EFAULT : 0;
+ break;
+ /*
+ * Set the child FPU state.
+ */
case PTRACE_SETFPREGS:
- /* Set the child FPU state. */
- ret = 0;
- if (copy_from_user(&child->thread.fpstate, (void *)data,
- sizeof(struct user_fp)))
- ret = -EFAULT;
- goto out;
-
- case PTRACE_DETACH: /* detach a process that was attached. */
ret = -EIO;
- if ((unsigned long) data > _NSIG)
- goto out;
- child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
- wake_up_process (child);
- child->exit_code = data;
- REMOVE_LINKS(child);
- child->p_pptr = child->p_opptr;
- SET_LINKS(child);
- /* make sure single-step breakpoint is gone. */
- ptrace_cancel_bpt (child);
- ret = 0;
- goto out;
+ if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp)))
+ break;
+
+ child->used_math = 1;
+ ret = __copy_from_user(&child->thread.fpstate, (void *)data,
+ sizeof(struct user_fp)) ? -EFAULT : 0;
+ break;
default:
ret = -EIO;
+ break;
+ }
+
+ return ret;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ int ret;
+
+ lock_kernel();
+ ret = -EPERM;
+ if (request == PTRACE_TRACEME) {
+ /* are we already being traced? */
+ if (current->ptrace & PT_PTRACED)
goto out;
+ /* set the ptrace bit in the process flags. */
+ current->ptrace |= PT_PTRACED;
+ ret = 0;
+ goto out;
}
+ ret = -ESRCH;
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ if (child)
+ get_task_struct(child);
+ read_unlock(&tasklist_lock);
+ if (!child)
+ goto out;
+
+ ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out_tsk;
+
+ if (request == PTRACE_ATTACH) {
+ if (child == current)
+ goto out_tsk;
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->suid) ||
+ (current->uid != child->uid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+ goto out_tsk;
+ /* the same process cannot be attached many times */
+ if (child->ptrace & PT_PTRACED)
+ goto out_tsk;
+ child->ptrace |= PT_PTRACED;
+
+ write_lock_irq(&tasklist_lock);
+ if (child->p_pptr != current) {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ write_unlock_irq(&tasklist_lock);
+
+ send_sig(SIGSTOP, child, 1);
+ ret = 0;
+ goto out_tsk;
+ }
+ ret = -ESRCH;
+ if (!(child->ptrace & PT_PTRACED))
+ goto out_tsk;
+ if (child->state != TASK_STOPPED && request != PTRACE_KILL)
+ goto out_tsk;
+ if (child->p_pptr != current)
+ goto out_tsk;
+
+ ret = do_ptrace(request, child, addr, data);
+
+out_tsk:
+ free_task_struct(child);
out:
unlock_kernel();
return ret;
diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h
new file mode 100644
index 000000000..feae0acd8
--- /dev/null
+++ b/arch/arm/kernel/ptrace.h
@@ -0,0 +1,16 @@
+extern void __ptrace_cancel_bpt(struct task_struct *);
+extern int ptrace_set_bpt(struct task_struct *);
+
+/*
+ * Clear a breakpoint, if one exists.
+ */
+static inline int ptrace_cancel_bpt(struct task_struct *tsk)
+{
+ int nsaved = tsk->thread.debug.nsaved;
+
+ if (nsaved)
+ __ptrace_cancel_bpt(tsk);
+
+ return nsaved;
+}
+
diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c
index 93a370f2d..8118b6a68 100644
--- a/arch/arm/kernel/semaphore.c
+++ b/arch/arm/kernel/semaphore.c
@@ -8,7 +8,6 @@
* Modified for ARM by Russell King
*/
#include <linux/sched.h>
-#include <linux/errno.h>
#include <asm/semaphore.h>
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 1f4295540..c6010476a 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -35,6 +35,7 @@ extern void paging_init(struct meminfo *);
extern void bootmem_init(struct meminfo *);
extern void reboot_setup(char *str);
extern void disable_hlt(void);
+extern unsigned long memparse(char *ptr, char **retptr);
extern int root_mountflags;
extern int _stext, _text, _etext, _edata, _end;
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 431dd96c1..3e6cf6cb4 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -10,18 +10,19 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
-#include <linux/signal.h>
#include <linux/errno.h>
+#include <linux/signal.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
-#include <linux/unistd.h>
#include <linux/stddef.h>
-#include <linux/binfmts.h>
+#include <linux/unistd.h>
#include <linux/tty.h>
+#include <asm/pgalloc.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
+
+#include "ptrace.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -31,8 +32,6 @@
asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr,
int options, unsigned long *ru);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
-extern int ptrace_cancel_bpt (struct task_struct *);
-extern int ptrace_set_bpt (struct task_struct *);
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
@@ -234,7 +233,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
goto badframe;
/* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt (current))
+ if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
return regs->ARM_r0;
@@ -274,7 +273,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
/* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt (current))
+ if (ptrace_cancel_bpt(current))
send_sig(SIGTRAP, current, 1);
return regs->ARM_r0;
@@ -500,7 +499,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
if (!oldset)
oldset = &current->blocked;
- single_stepping = ptrace_cancel_bpt (current);
+ single_stepping = ptrace_cancel_bpt(current);
for (;;) {
unsigned long signr;
@@ -518,7 +517,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
- single_stepping |= ptrace_cancel_bpt (current);
+ single_stepping |= ptrace_cancel_bpt(current);
/* We're back. Did the debugger cancel the sig? */
if (!(signr = current->exit_code))
@@ -617,7 +616,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
/* Whee! Actually deliver the signal. */
handle_signal(signr, ka, &info, oldset, regs);
if (single_stepping)
- ptrace_set_bpt (current);
+ ptrace_set_bpt(current);
return 1;
}
@@ -629,6 +628,6 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
regs->ARM_pc -= 4;
}
if (single_stepping)
- ptrace_set_bpt (current);
+ ptrace_set_bpt(current);
return 0;
}
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index bdb725551..d7f6640eb 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -13,7 +13,6 @@
* "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
#include <linux/config.h>
-#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 1d692dd35..188f89722 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -17,16 +17,18 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
+#include <linux/ptrace.h>
#include <linux/init.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
#include <asm/atomic.h>
+#include <asm/io.h>
#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "ptrace.h"
extern void c_backtrace (unsigned long fp, int pmode);
-extern int ptrace_cancel_bpt (struct task_struct *);
char *processor_modes[]=
{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" ,
@@ -46,8 +48,6 @@ static inline void console_verbose(void)
console_loglevel = 15;
}
-int kstack_depth_to_print = 200;
-
/*
* Stack pointers should always be within the kernels view of
* physical memory. If it is not there, then we can't dump
@@ -199,37 +199,48 @@ void die_if_kernel(const char *str, struct pt_regs *regs, int err)
die(str, regs, err);
}
-void bad_user_access_alignment(const void *ptr)
-{
- printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr,
- __builtin_return_address(0));
- current->thread.error_code = 0;
- current->thread.trap_no = 11;
- force_sig(SIGBUS, current);
-/* die_if_kernel("Oops - bad user access alignment", regs, mode);*/
-}
-
asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode)
{
+ unsigned long addr = instruction_pointer(regs);
+ siginfo_t info;
+
#ifdef CONFIG_DEBUG_USER
printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n",
- current->comm, current->pid, instruction_pointer(regs));
+ current->comm, current->pid, addr);
#endif
+
current->thread.error_code = 0;
current->thread.trap_no = 6;
- force_sig(SIGILL, current);
+
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPC;
+ info.si_addr = (void *)addr;
+
+ force_sig_info(SIGILL, &info, current);
+
die_if_kernel("Oops - undefined instruction", regs, mode);
}
asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode)
{
+ siginfo_t info;
+
#ifdef CONFIG_DEBUG_USER
printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
current->comm, current->pid, instruction_pointer(regs));
#endif
+
current->thread.error_code = 0;
current->thread.trap_no = 11;
- force_sig(SIGBUS, current);
+
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+
+ force_sig_info(SIGBUS, &info, current);
+
die_if_kernel("Oops - address exception", regs, mode);
}
@@ -269,32 +280,38 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
}
/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task.
- *
- * We no longer save/restore the math state on every context switch
- * any more. We only do this now if it actually gets used.
- */
-asmlinkage void math_state_restore (void)
-{
- current->used_math = 1;
-}
-
-/*
* Handle some more esoteric system calls
*/
-asmlinkage int arm_syscall (int no, struct pt_regs *regs)
+asmlinkage int arm_syscall(int no, struct pt_regs *regs)
{
+ siginfo_t info;
+
switch (no) {
case 0: /* branch through 0 */
- force_sig(SIGSEGV, current);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = NULL;
+
+ force_sig_info(SIGSEGV, &info, current);
+
die_if_kernel("branch through zero", regs, 0);
break;
- case 1: /* SWI_BREAK_POINT */
- regs->ARM_pc -= 4; /* Decrement PC by one instruction */
- ptrace_cancel_bpt(current);
- force_sig(SIGTRAP, current);
+ case 1: /* SWI BREAK_POINT */
+ /*
+ * The PC is always left pointing at the next
+ * instruction. Fix this.
+ */
+ regs->ARM_pc -= 4;
+ __ptrace_cancel_bpt(current);
+
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+ info.si_addr = (void *)instruction_pointer(regs);
+
+ force_sig_info(SIGTRAP, &info, current);
return regs->ARM_r0;
case 2: /* sys_cacheflush */
@@ -350,29 +367,24 @@ asmlinkage void deferred(int n, struct pt_regs *regs)
die_if_kernel("Oops", regs, n);
}
-asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr)
-{
- printk("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc);
-}
-
-asmlinkage void arm_invalidptr(const char *function, int size)
+void __bad_xchg(volatile void *ptr, int size)
{
- printk("Invalid pointer size in %s (pc=%p) size %d\n",
- function, __builtin_return_address(0), size);
+ printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
+ __builtin_return_address(0), ptr, size);
+ BUG();
}
/*
- * A data abort trap was taken, but the instruction was not an instruction
- * which should cause the trap to be taken. Try to abort it. Note that
- * the while(1) is there because we cannot currently handle returning from
- * this function.
+ * A data abort trap was taken, but we did not handle the instruction.
+ * Try to abort the user program, or panic if it was the kernel.
*/
asmlinkage void
baddataabort(int code, unsigned long instr, struct pt_regs *regs)
{
unsigned long addr = instruction_pointer(regs);
+ siginfo_t info;
-#ifdef CONFIG_DEBUG_ERRORS
+#ifdef CONFIG_DEBUG_USER
dump_instr(addr, 1);
{
pgd_t *pgd;
@@ -389,16 +401,22 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
printk ("\n");
}
#endif
- force_sig(SIGILL, current);
+
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPC;
+ info.si_addr = (void *)addr;
+
+ force_sig_info(SIGILL, &info, current);
die_if_kernel("unknown data abort code", regs, instr);
- while (1);
}
void __bug(const char *file, int line, void *data)
{
- printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
+ printk(KERN_CRIT"kernel BUG at %s:%d!", file, line);
if (data)
- printk(KERN_CRIT"extra data = %p\n", data);
+ printk(KERN_CRIT" - extra data = %p", data);
+ printk("\n");
BUG();
}
diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c
index 385937708..519f1965a 100644
--- a/arch/arm/mm/fault-common.c
+++ b/arch/arm/mm/fault-common.c
@@ -187,6 +187,7 @@ static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
tsk->thread.error_code = mode;
tsk->thread.trap_no = 14;
si.si_signo = SIGSEGV;
+ si.si_errno = 0;
si.si_code = fault == -1 ? SEGV_ACCERR : SEGV_MAPERR;
si.si_addr = (void *)addr;
force_sig_info(SIGSEGV, &si, tsk);
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 34bd51366..1edbc35fd 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -410,9 +410,24 @@ void __init pagetable_init(struct meminfo *mi)
flush_cache_all();
}
-/*
- * The mem_map array can get very big. Free the unused area of the memory map.
- */
+static inline void free_memmap(unsigned long start, unsigned long end)
+{
+ unsigned long pg, pgend;
+
+ start = __phys_to_virt(start);
+ end = __phys_to_virt(end);
+
+ pg = PAGE_ALIGN((unsigned long)(mem_map + MAP_NR(start)));
+ pgend = ((unsigned long)(mem_map + MAP_NR(end))) & PAGE_MASK;
+
+ start = __virt_to_phys(pg);
+ end = __virt_to_phys(pgend);
+ /*
+ * The mem_map is always stored in node 0
+ */
+ free_bootmem_node(0, start, end - start);
+}
+
static inline void free_unused_memmap_node(int node, struct meminfo *mi)
{
unsigned long bank_start, prev_bank_end = 0;
@@ -434,14 +449,17 @@ static inline void free_unused_memmap_node(int node, struct meminfo *mi)
* between the current bank and the previous, free it.
*/
if (prev_bank_end && prev_bank_end != bank_start)
- free_bootmem_node(node, prev_bank_end,
- bank_start - prev_bank_end);
+ free_memmap(prev_bank_end, bank_start);
prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
mi->bank[i].size);
}
}
+/*
+ * The mem_map array can get very big. Free
+ * the unused area of the memory map.
+ */
void __init create_memmap_holes(struct meminfo *mi)
{
int node;
diff --git a/arch/arm/mm/proc-arm2,3.S b/arch/arm/mm/proc-arm2,3.S
index 36a9d8b28..6dd48c919 100644
--- a/arch/arm/mm/proc-arm2,3.S
+++ b/arch/arm/mm/proc-arm2,3.S
@@ -286,7 +286,6 @@ SYMBOL_NAME(arm2_processor_functions):
.word _arm2_proc_fin
.word _arm2_set_pgd
.word _arm2_xchg_1
- .word SYMBOL_NAME(abort)
.word _arm2_xchg_4
cpu_arm2_info:
@@ -300,7 +299,6 @@ SYMBOL_NAME(arm250_processor_functions):
.word _arm2_proc_fin
.word _arm2_set_pgd
.word _arm3_xchg_1
- .word SYMBOL_NAME(abort)
.word _arm3_xchg_4
cpu_arm250_info:
@@ -314,7 +312,6 @@ SYMBOL_NAME(arm3_processor_functions):
.word _arm3_proc_fin
.word _arm3_set_pgd
.word _arm3_xchg_1
- .word SYMBOL_NAME(abort)
.word _arm3_xchg_4
cpu_arm3_info:
diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S
index 5d7605b85..b18d69d98 100644
--- a/arch/arm/mm/proc-arm6,7.S
+++ b/arch/arm/mm/proc-arm6,7.S
@@ -158,8 +158,8 @@ Ldata_unknown: @ Part of jumptable
mov r0, r2
mov r1, r4
mov r2, r3
- b baddataabort
-
+ bl baddataabort
+ b ret_from_sys_call
Ldata_lateldrpreconst:
tst r4, #1 << 21 @ check writeback bit
diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
index 738ff9a43..d49196625 100644
--- a/arch/arm/mm/proc-arm720.S
+++ b/arch/arm/mm/proc-arm720.S
@@ -146,8 +146,8 @@ Ldata_unknown: @ Part of jumptable
mov r0, r2
mov r1, r4
mov r2, r3
- b baddataabort
-
+ bl baddataabort
+ b ret_from_sys_call
Ldata_lateldrpreconst:
tst r4, #1 << 21 @ check writeback bit
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 6a1a8aa40..100a5ba5a 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -597,7 +597,9 @@ static inline void handle_smp_time (int user, int cpu)
}
kstat.cpu_system += system;
kstat.per_cpu_system[cpu] += system;
-
+ } else if (local_bh_count(cpu) || local_irq_count(cpu) > 1) {
+ kstat.cpu_system += system;
+ kstat.per_cpu_system[cpu] += system;
}
irq_exit(cpu, 0);
}
diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
index 933d6c3c9..b98bf4748 100644
--- a/arch/i386/kernel/pci-irq.c
+++ b/arch/i386/kernel/pci-irq.c
@@ -464,7 +464,7 @@ void __init pcibios_fixup_irqs(void)
}
}
-void __init pcibios_penalize_isa_irq(int irq)
+void pcibios_penalize_isa_irq(int irq)
{
/*
* If any ISAPnP device reports an IRQ in its list of possible
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index e0425f411..771caa7e7 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -43,6 +43,11 @@
* Pentium III FXSR, SSE support
* General FPU state handling cleanups
* Gareth Hughes <gareth@valinux.com>, May 2000
+ *
+ * Added proper Cascades CPU and L2 cache detection for Cascades
+ * and 8-way type cache happy bunch from Intel:^)
+ * Dragan Stancevic <visitor@valinux.com>, May 2000
+ *
*/
/*
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 8e0e59907..24a18824e 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -778,9 +778,8 @@ out:
return retval;
out_free_dentry:
- lock_kernel();
+ allow_write_access(interpreter);
fput(interpreter);
- unlock_kernel();
out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index 0f4bb555f..3ed5915ba 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,6 +1,6 @@
-# $Id: config.in,v 1.96 2000/06/20 01:10:00 anton Exp $
+# $Id: config.in,v 1.94 2000/06/04 22:23:10 anton Exp $
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
mainmenu_name "Linux/SPARC Kernel Configuration"
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index 05ed9d932..82d3027aa 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -215,7 +215,6 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len,
goto out;
}
- down(&current->mm->mmap_sem);
lock_kernel();
retval = -EINVAL;
len = PAGE_ALIGN(len);
@@ -230,11 +229,12 @@ static unsigned long do_mmap2(unsigned long addr, unsigned long len,
goto out_putf;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(&current->mm->mmap_sem);
retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up(&current->mm->mmap_sem);
out_putf:
unlock_kernel();
- up(&current->mm->mmap_sem);
if (file)
fput(file);
out:
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 1c3dfe6e2..f64563cab 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -68,7 +68,6 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
struct file * file = NULL;
unsigned long retval, ret_type;
- down(&current->mm->mmap_sem);
lock_kernel();
if(flags & MAP_NORESERVE) {
static int cnt;
@@ -118,7 +117,9 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(&current->mm->mmap_sem);
retval = do_mmap(file, addr, len, prot, flags, off);
+ up(&current->mm->mmap_sem);
if(!ret_type)
retval = ((retval < PAGE_OFFSET) ? 0 : retval);
@@ -127,7 +128,6 @@ out_putf:
fput(file);
out:
unlock_kernel();
- up(&current->mm->mmap_sem);
return retval;
}
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 9e51aadad..2aff3033a 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -227,7 +227,6 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
len = PAGE_ALIGN(len);
retval = -EINVAL;
- down(&current->mm->mmap_sem);
lock_kernel();
if (current->thread.flags & SPARC_FLAG_32BIT) {
@@ -241,11 +240,12 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
goto out_putf;
}
+ down(&current->mm->mmap_sem);
retval = do_mmap(file, addr, len, prot, flags, off);
+ up(&current->mm->mmap_sem);
out_putf:
unlock_kernel();
- up(&current->mm->mmap_sem);
if (file)
fput(file);
out:
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 26c5faecd..e27892de3 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -3029,9 +3029,7 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
- lock_kernel();
file = open_exec(filename);
- unlock_kernel();
retval = PTR_ERR(file);
if (IS_ERR(file))
@@ -3043,10 +3041,12 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count32(argv)) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count32(envp)) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.envc;
}
@@ -3075,6 +3075,7 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
out:
/* Something went wrong, return the inode and free the argument pages*/
+ allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index b13846fe9..70adfe21a 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -68,7 +68,6 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
struct file *file = NULL;
unsigned long retval, ret_type;
- down(&current->mm->mmap_sem);
lock_kernel();
if(flags & MAP_NORESERVE) {
static int cnt;
@@ -102,10 +101,12 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
flags &= ~_MAP_NEW;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(&current->mm->mmap_sem);
retval = do_mmap(file,
(unsigned long) addr, (unsigned long) len,
(unsigned long) prot, (unsigned long) flags,
(unsigned long) off);
+ up(&current->mm->mmap_sem);
if(!ret_type)
retval = ((retval < 0xf0000000) ? 0 : retval);
out_putf:
@@ -113,7 +114,6 @@ out_putf:
fput(file);
out:
unlock_kernel();
- up(&current->mm->mmap_sem);
return (u32) retval;
}
diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
index 316af0d4e..d4658724a 100644
--- a/drivers/acorn/char/Makefile
+++ b/drivers/acorn/char/Makefile
@@ -33,6 +33,7 @@ obj-rpc := keyb_ps2.o
obj-$(CONFIG_RPCMOUSE) += mouse_rpc.o
obj-$(CONFIG_ATOMWIDE_SERIAL) += serial-atomwide.o
obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o
+obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o
# Do the i2c and rtc last
obj-y += $(obj-$(MACHINE)) i2c.o pcf8583.o
diff --git a/drivers/acorn/char/defkeymap-acorn.c b/drivers/acorn/char/defkeymap-acorn.c
new file mode 100644
index 000000000..4974cd2b6
--- /dev/null
+++ b/drivers/acorn/char/defkeymap-acorn.c
@@ -0,0 +1,358 @@
+/*
+ * linux/arch/arm/drivers/char/defkeymap.c
+ *
+ * Copyright (C) 1995, 1996 Russell King
+ */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+/* Normal (maps 1:1 with no processing) */
+#define KTn 0xF0
+/* Function keys */
+#define KTf 0xF1
+/* Special (Performs special house-keeping funcs) */
+#define KTs 0xF2
+#define KIGNORE K(KTs, 0) /* Ignore */
+#define KENTER K(KTs, 1) /* Enter */
+#define KREGS K(KTs, 2) /* Regs */
+#define KMEM K(KTs, 3) /* Mem */
+#define KSTAT K(KTs, 4) /* State */
+#define KINTR K(KTs, 5) /* Intr */
+#define Ksl 6 /* Last console */
+#define KCAPSLK K(KTs, 7) /* Caps lock */
+#define KNUMLK K(KTs, 8) /* Num-lock */
+#define KSCRLLK K(KTs, 9) /* Scroll-lock */
+#define KSCRLFOR K(KTs,10) /* Scroll forward */
+#define KSCRLBAK K(KTs,11) /* Scroll back */
+#define KREBOOT K(KTs,12) /* Reboot */
+#define KCAPSON K(KTs,13) /* Caps on */
+#define KCOMPOSE K(KTs,14) /* Compose */
+#define KSAK K(KTs,15) /* SAK */
+#define CONS_DEC K(KTs,16) /* Dec console */
+#define CONS_INC K(KTs,17) /* Incr console */
+#define KFLOPPY K(KTs,18) /* Floppy */
+/* Key pad (0-9 = digits, 10=+, 11=-, 12=*, 13=/, 14=enter, 16=., 17=# */
+#define KTp 0xF3
+#define KPAD_0 K(KTp, 0 )
+#define KPAD_1 K(KTp, 1 )
+#define KPAD_2 K(KTp, 2 )
+#define KPAD_3 K(KTp, 3 )
+#define KPAD_4 K(KTp, 4 )
+#define KPAD_5 K(KTp, 5 )
+#define KPAD_6 K(KTp, 6 )
+#define KPAD_7 K(KTp, 7 )
+#define KPAD_8 K(KTp, 8 )
+#define KPAD_9 K(KTp, 9 )
+#define KPAD_PL K(KTp,10 )
+#define KPAD_MI K(KTp,11 )
+#define KPAD_ML K(KTp,12 )
+#define KPAD_DV K(KTp,13 )
+#define KPAD_EN K(KTp,14 )
+#define KPAD_DT K(KTp,16 )
+#define KPAD_HS K(KTp,20 )
+/* Console switching */
+#define KCn 0xF5
+/* Cursor */
+#define KTc 0xF6
+#define Kcd 0 /* Cursor down */
+#define Kcl 1 /* Cursor left */
+#define Kcr 2 /* Cursor right */
+#define Kcu 3 /* Cursor up */
+/* Shift/alt modifiers etc */
+#define KMd 0xF7
+#define KSHIFT K(KMd, 0 )
+#define KALTGR K(KMd, 1 )
+#define KCTRL K(KMd, 2 )
+#define KALT K(KMd, 3 )
+/* Meta */
+#define KMt 0xF8
+#define KAs 0xF9
+#define KPADA_0 K(KAs, 0 )
+#define KPADA_1 K(KAs, 1 )
+#define KPADA_2 K(KAs, 2 )
+#define KPADA_3 K(KAs, 3 )
+#define KPADA_4 K(KAs, 4 )
+#define KPADA_5 K(KAs, 5 )
+#define KPADA_6 K(KAs, 6 )
+#define KPADA_7 K(KAs, 7 )
+#define KPADA_8 K(KAs, 8 )
+#define KPADA_9 K(KAs, 9 )
+#define KPADB_0 K(KAs,10 )
+#define KPADB_1 K(KAs,11 )
+#define KPADB_2 K(KAs,12 )
+#define KPADB_3 K(KAs,13 )
+#define KPADB_4 K(KAs,14 )
+#define KPADB_5 K(KAs,15 )
+#define KPADB_6 K(KAs,16 )
+#define KPADB_7 K(KAs,17 )
+#define KPADB_8 K(KAs,18 )
+#define KPADB_9 K(KAs,19 )
+/* Locking keys */
+#define KLk 0xFA
+/* Letters */
+#define KTl 0xFB
+
+u_short plain_map[NR_KEYS]=
+{
+ K(KTn, 27),K(KTf, 0),K(KTf, 1),K(KTf, 2 ),K(KTf, 3),K(KTf, 4),K(KTf, 5 ),K(KTf, 6),
+ K(KTf, 7),K(KTf, 8),K(KTf, 9),K(KTf, 10 ),K(KTf, 11),KIGNORE ,KSCRLLK ,KINTR ,
+ K(KTn,'`'),K(KTn,'1'),K(KTn,'2'),K(KTn,'3' ),K(KTn,'4'),K(KTn,'5'),K(KTn,'6' ),K(KTn,'7'),
+ K(KTn,'8'),K(KTn,'9'),K(KTn,'0'),K(KTn,'-' ),K(KTn,'='),K(KTn,'£'),K(KTn,127 ),K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KTn, 9 ),K(KTl,'q'),
+ K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
+ K(KTl,'p'),K(KTn,'['),K(KTn,']'),K(KTn,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTl,'a'),K(KTl,'s'),K(KTl,'d' ),K(KTl,'f'),
+ K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),K(KTn,';'),K(KTn,'\''),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'),
+ K(KTl,'c'),K(KTl,'v'),K(KTl,'b'),K(KTl,'n' ),K(KTl,'m'),K(KTn,','),K(KTn,'.' ),K(KTn,'/'),
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn,' '),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short shift_map[NR_KEYS]=
+{
+ K(KTn, 27),K(KTf, 10),K(KTf, 11),K(KTf, 12 ),K(KTf, 13),K(KTf, 14),K(KTf, 15 ),K(KTf, 16),
+ K(KTf, 17),K(KTf, 18),K(KTf, 19),K(KTf, 20 ),K(KTf, 21),KIGNORE ,KMEM ,KINTR ,
+ K(KTn,'~'),K(KTn,'!'),K(KTn,'@'),K(KTn,'#' ),K(KTn,'$'),K(KTn,'%'),K(KTn,'^' ),K(KTn,'&'),
+ K(KTn,'*'),K(KTn,'('),K(KTn,')'),K(KTn,'_' ),K(KTn,'+'),K(KTn,'¤'),K(KTn,127 ),K(KTf,21 ),
+ K(KTf,20 ),KSCRLBAK ,KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KTn, 9 ),K(KTl,'Q'),
+ K(KTl,'W'),K(KTl,'E'),K(KTl,'R'),K(KTl,'T' ),K(KTl,'Y'),K(KTl,'U'),K(KTl,'I' ),K(KTl,'O'),
+ K(KTl,'P'),K(KTn,'{'),K(KTn,'}'),K(KTn,'|' ),K(KTf,22 ),K(KTf,23 ),KSCRLFOR ,KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTl,'A'),K(KTl,'S'),K(KTl,'D' ),K(KTl,'F'),
+ K(KTl,'G'),K(KTl,'H'),K(KTl,'J'),K(KTl,'K' ),K(KTl,'L'),K(KTn,':'),K(KTn,'"' ),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'Z' ),K(KTl,'X'),
+ K(KTl,'C'),K(KTl,'V'),K(KTl,'B'),K(KTl,'N' ),K(KTl,'M'),K(KTn,'<'),K(KTn,'>' ),K(KTn,'?'),
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn,' '),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short altgr_map[NR_KEYS]=
+{
+ KIGNORE ,K(KCn,12 ),K(KCn,13 ),K(KCn,14 ),K(KCn,15 ),K(KCn,16 ),K(KCn,17 ),K(KCn, 18),
+ K(KCn, 19),K(KCn,20 ),K(KCn,21 ),K(KCn,22 ),K(KCn,23 ),KIGNORE ,KREGS ,KINTR ,
+ KIGNORE ,KIGNORE ,K(KTn,'@'),KIGNORE ,K(KTn,'$'),KIGNORE ,KIGNORE ,K(KTn,'{'),
+ K(KTn,'['),K(KTn,']'),K(KTn,'}'),K(KTn,'\\'),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTl,'q'),
+ K(KTl,'w'),K(KTl,'e'),K(KTl,'r'),K(KTl,'t' ),K(KTl,'y'),K(KTl,'u'),K(KTl,'i' ),K(KTl,'o'),
+ K(KTl,'p'),KIGNORE ,K(KTn,'~'),KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADB_7 ,
+ KPADB_8 ,KPADB_9 ,KPAD_MI ,KCTRL ,K(KAs,20 ),K(KTl,'s'),K(KAs,23 ),K(KAs,25 ),
+ K(KTl,'g'),K(KTl,'h'),K(KTl,'j'),K(KTl,'k' ),K(KTl,'l'),KIGNORE ,KIGNORE ,KENTER ,
+ KPADB_4 ,KPADB_5 ,KPADB_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTl,'z' ),K(KTl,'x'),
+ K(KAs,22 ),K(KTl,'v'),K(KTl,21 ),K(KTl,'n' ),K(KTl,'m'),KIGNORE ,KIGNORE ,KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPADB_1 ,KPADB_2 ,KPADB_3 ,KCAPSLK ,KALT ,KIGNORE ,
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPADB_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short ctrl_map[NR_KEYS]=
+{
+ KIGNORE ,K(KTf, 0),K(KTf, 1),K(KTf, 2 ),K(KTf, 3),K(KTf, 4),K(KTf, 5 ),K(KTf, 6),
+ K(KTf, 7),K(KTf, 8),K(KTf, 9),K(KTf, 10 ),K(KTf, 11),KIGNORE ,KSTAT ,KINTR ,
+ KIGNORE ,K(KTn, 1 ),K(KTn, 2 ),K(KTn, 3 ),K(KTn, 4 ),K(KTn, 5 ),K(KTn, 6 ),K(KTn, 7 ),
+ K(KTn, 8 ),K(KTn, 9 ),K(KTn, 0 ),K(KTn,31 ),KIGNORE ,KIGNORE ,K(KTn, 8 ),K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ),
+ K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ),
+ K(KTn,16 ),K(KTn,27 ),K(KTn,29 ),K(KTn,28 ),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ),
+ K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ),
+ K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KCOMPOSE ,K(KTn,127),
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short shift_ctrl_map[NR_KEYS]=
+{
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KFLOPPY ,KINTR ,
+ KIGNORE ,KIGNORE ,K(KTn, 0 ),KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,K(KTn,31 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KTn,17 ),
+ K(KTn,23 ),K(KTn, 5 ),K(KTn,18 ),K(KTn,20 ),K(KTn,25 ),K(KTn,21 ),K(KTn, 9 ),K(KTn,15 ),
+ K(KTn,16 ),KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KTn, 1 ),K(KTn,19 ),K(KTn, 4 ),K(KTn, 6 ),
+ K(KTn, 7 ),K(KTn, 8 ),K(KTn,10 ),K(KTn,11 ),K(KTn,12 ),KIGNORE ,K(KTn, 7 ),KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KTn,26 ),K(KTn,24 ),
+ K(KTn, 3 ),K(KTn,22 ),K(KTn, 2 ),K(KTn,14 ),K(KTn,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,K(KTn, 0 ),
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short alt_map[NR_KEYS]=
+{
+ K(KMt,27 ),K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
+ K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KSCRLLK ,KINTR ,
+ K(KMt,'`'),K(KMt,'1'),K(KMt,'2'),K(KMt,'3' ),K(KMt,'4'),K(KMt,'5'),K(KMt,'6' ),K(KMt,'7'),
+ K(KMt,'8'),K(KMt,'9'),K(KMt,'0'),K(KMt,'-' ),K(KMt,'='),K(KMt,'£'),K(KMt,127 ),K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,K(KMt, 9 ),K(KMt,'q'),
+ K(KMt,'w'),K(KMt,'e'),K(KMt,'r'),K(KMt,'t' ),K(KMt,'y'),K(KMt,'u'),K(KMt,'i' ),K(KMt,'o'),
+ K(KMt,'p'),K(KMt,'['),K(KMt,']'),K(KMt,'\\'),K(KTf,22 ),K(KTf,23 ),K(KTf,25 ),KPADA_7 ,
+ KPADA_8 ,KPADA_9 ,KPAD_MI ,KCTRL ,K(KMt,'a'),K(KMt,'s'),K(KMt,'d' ),K(KMt,'f'),
+ K(KMt,'g'),K(KMt,'h'),K(KMt,'j'),K(KMt,'k' ),K(KMt,'l'),K(KMt,';'),K(KMt,'\''),K(KMt,13 ),
+ KPADA_4 ,KPADA_5 ,KPADA_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,'z' ),K(KMt,'x'),
+ K(KMt,'c'),K(KMt,'v'),K(KMt,'b'),K(KMt,'n' ),K(KMt,'m'),K(KMt,','),K(KMt,'.' ),KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPADA_1 ,KPADA_2 ,KPADA_3 ,KCAPSLK ,KALT ,K(KMt,' '),
+ KALTGR ,KCTRL ,CONS_DEC ,K(KTc,Kcd ),CONS_INC ,KPADA_0 ,KPAD_DT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+u_short ctrl_alt_map[NR_KEYS]=
+{
+ KIGNORE ,K(KCn, 0 ),K(KCn, 1 ),K(KCn, 2 ),K(KCn, 3 ),K(KCn, 4 ),K(KCn, 5 ),K(KCn, 6 ),
+ K(KCn, 7 ),K(KCn, 8 ),K(KCn, 9 ),K(KCn,10 ),K(KCn,11 ),KIGNORE ,KIGNORE ,KINTR ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,K(KTf,21 ),
+ K(KTf,20 ),K(KTf,24 ),KNUMLK ,KPAD_DV ,KPAD_ML ,KPAD_HS ,KIGNORE ,K(KMt,17 ),
+ K(KMt,23 ),K(KMt, 5 ),K(KMt,18 ),K(KMt,20 ),K(KMt,25 ),K(KMt,21 ),K(KMt, 9 ),K(KMt,15 ),
+ K(KMt,16 ),KIGNORE ,KIGNORE ,KIGNORE ,KREBOOT ,K(KTf,23 ),K(KTf,25 ),KPAD_7 ,
+ KPAD_8 ,KPAD_9 ,KPAD_MI ,KCTRL ,K(KMt, 1 ),K(KMt,19 ),K(KMt, 4 ),K(KMt, 6 ),
+ K(KMt, 7 ),K(KMt, 8 ),K(KMt,10 ),K(KMt,11 ),K(KMt,12 ),KIGNORE ,KIGNORE ,KENTER ,
+ KPAD_4 ,KPAD_5 ,KPAD_6 ,KPAD_PL ,KSHIFT ,KIGNORE ,K(KMt,26 ),K(KMt,24 ),
+ K(KMt, 3 ),K(KMt,22 ),K(KMt, 2 ),K(KMt,14 ),K(KMt,13 ),KIGNORE ,KIGNORE ,KIGNORE ,
+ KSHIFT ,K(KTc,Kcu),KPAD_1 ,KPAD_2 ,KPAD_3 ,KCAPSLK ,KALT ,KIGNORE ,
+ KALTGR ,KCTRL ,K(KTc,Kcl),K(KTc,Kcd ),K(KTc,Kcr),KPAD_0 ,KREBOOT ,KPAD_EN ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+ KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,KIGNORE ,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+ plain_map, shift_map, altgr_map, 0,
+ ctrl_map, shift_ctrl_map, 0, 0,
+ alt_map, 0, 0, 0,
+ ctrl_alt_map, 0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+ '\033', '[', '[', 'A', 0,
+ '\033', '[', '[', 'B', 0,
+ '\033', '[', '[', 'C', 0,
+ '\033', '[', '[', 'D', 0,
+ '\033', '[', '[', 'E', 0,
+ '\033', '[', '1', '7', '~', 0,
+ '\033', '[', '1', '8', '~', 0,
+ '\033', '[', '1', '9', '~', 0,
+ '\033', '[', '2', '0', '~', 0,
+ '\033', '[', '2', '1', '~', 0,
+ '\033', '[', '2', '3', '~', 0,
+ '\033', '[', '2', '4', '~', 0,
+ '\033', '[', '2', '5', '~', 0,
+ '\033', '[', '2', '6', '~', 0,
+ '\033', '[', '2', '8', '~', 0,
+ '\033', '[', '2', '9', '~', 0,
+ '\033', '[', '3', '1', '~', 0,
+ '\033', '[', '3', '2', '~', 0,
+ '\033', '[', '3', '3', '~', 0,
+ '\033', '[', '3', '4', '~', 0,
+ '\033', '[', '1', '~', 0,
+ '\033', '[', '2', '~', 0,
+ '\033', '[', '3', '~', 0,
+ '\033', '[', '4', '~', 0,
+ '\033', '[', '5', '~', 0,
+ '\033', '[', '6', '~', 0,
+ '\033', '[', 'M', 0,
+ '\033', '[', 'P', 0,
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0; /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+ func_buf + 0,
+ func_buf + 5,
+ func_buf + 10,
+ func_buf + 15,
+ func_buf + 20,
+ func_buf + 25,
+ func_buf + 31,
+ func_buf + 37,
+ func_buf + 43,
+ func_buf + 49,
+ func_buf + 55,
+ func_buf + 61,
+ func_buf + 67,
+ func_buf + 73,
+ func_buf + 79,
+ func_buf + 85,
+ func_buf + 91,
+ func_buf + 97,
+ func_buf + 103,
+ func_buf + 109,
+ func_buf + 115,
+ func_buf + 120,
+ func_buf + 125,
+ func_buf + 130,
+ func_buf + 135,
+ func_buf + 140,
+ func_buf + 145,
+ 0,
+ 0,
+ func_buf + 149,
+ 0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+ {'`', 'A', '\300'}, {'`', 'a', '\340'},
+ {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
+ {'^', 'A', '\302'}, {'^', 'a', '\342'},
+ {'~', 'A', '\303'}, {'~', 'a', '\343'},
+ {'"', 'A', '\304'}, {'"', 'a', '\344'},
+ {'O', 'A', '\305'}, {'o', 'a', '\345'},
+ {'0', 'A', '\305'}, {'0', 'a', '\345'},
+ {'A', 'A', '\305'}, {'a', 'a', '\345'},
+ {'A', 'E', '\306'}, {'a', 'e', '\346'},
+ {',', 'C', '\307'}, {',', 'c', '\347'},
+ {'`', 'E', '\310'}, {'`', 'e', '\350'},
+ {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
+ {'^', 'E', '\312'}, {'^', 'e', '\352'},
+ {'"', 'E', '\313'}, {'"', 'e', '\353'},
+ {'`', 'I', '\314'}, {'`', 'i', '\354'},
+ {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
+ {'^', 'I', '\316'}, {'^', 'i', '\356'},
+ {'"', 'I', '\317'}, {'"', 'i', '\357'},
+ {'-', 'D', '\320'}, {'-', 'd', '\360'},
+ {'~', 'N', '\321'}, {'~', 'n', '\361'},
+ {'`', 'O', '\322'}, {'`', 'o', '\362'},
+ {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
+ {'^', 'O', '\324'}, {'^', 'o', '\364'},
+ {'~', 'O', '\325'}, {'~', 'o', '\365'},
+ {'"', 'O', '\326'}, {'"', 'o', '\366'},
+ {'/', 'O', '\330'}, {'/', 'o', '\370'},
+ {'`', 'U', '\331'}, {'`', 'u', '\371'},
+ {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
+ {'^', 'U', '\333'}, {'^', 'u', '\373'},
+ {'"', 'U', '\334'}, {'"', 'u', '\374'},
+ {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
+ {'T', 'H', '\336'}, {'t', 'h', '\376'},
+ {'s', 's', '\337'}, {'"', 'y', '\377'},
+ {'s', 'z', '\337'}, {'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 82b2cc510..164ef4523 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -56,9 +56,7 @@
#include <asm/pgtable.h>
#endif
-#ifdef MODULE
#include <linux/module.h>
-#endif
#include "fore200e.h"
#include "suni.h"
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 2bf92251c..1eee6d545 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -138,6 +138,8 @@ void elevator_linus(struct request *req, elevator_t *elevator,
struct list_head *entry = real_head;
struct request *tmp;
+ req->elevator_sequence = orig_latency;
+
if (list_empty(real_head)) {
list_add(&req->queue, real_head);
return;
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 2ed93b300..9646adbd0 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -345,8 +345,6 @@ static inline struct request *get_request(request_queue_t *q, int rw)
register struct request *rq = NULL;
if (!list_empty(&q->request_freelist)) {
- elevator_t *e = &q->elevator;
-
if ((q->queue_requests > QUEUE_WRITES_MAX) && (rw == WRITE))
return NULL;
@@ -355,10 +353,6 @@ static inline struct request *get_request(request_queue_t *q, int rw)
rq->rq_status = RQ_ACTIVE;
rq->special = NULL;
rq->q = q;
- if (rq->cmd == READ)
- rq->elevator_sequence = e->read_latency;
- else
- rq->elevator_sequence = e->write_latency;
q->queue_requests++;
}
return rq;
@@ -657,6 +651,13 @@ static inline void __make_request(request_queue_t * q, int rw,
goto get_rq;
}
+ /*
+ * skip first entry, for devices with active queue head
+ */
+ head = &q->queue_head;
+ if (q->head_active && !q->plugged)
+ head = head->next;
+
el_ret = elevator->elevator_merge_fn(q, &req, bh, rw, &max_sectors, &max_segments);
switch (el_ret) {
@@ -709,12 +710,12 @@ get_rq:
req = __get_request_wait(q, rw);
spin_lock_irq(&io_request_lock);
+
+ head = &q->queue_head;
+ if (q->head_active && !q->plugged)
+ head = head->next;
}
- head = &q->queue_head;
- if (q->head_active && !q->plugged)
- head = head->next;
-
/* fill up the request-info, and add it to the queue */
req->cmd = rw;
req->errors = 0;
diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c
index 191ce5001..905d8e8cd 100644
--- a/drivers/char/i810_rng.c
+++ b/drivers/char/i810_rng.c
@@ -2,35 +2,35 @@
Hardware driver for Intel i810 Random Number Generator (RNG)
Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
-
+
Driver Web site: http://gtf.org/garzik/drivers/i810_rng/
-
+
Based on:
Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet
May 1999 Order Number: 290658-002 R
-
+
Intel 82802 Firmware Hub: Random Number Generator
Programmer's Reference Manual
December 1999 Order Number: 298029-001 R
-
+
Intel 82802 Firmware HUB Random Number Generator Driver
Copyright (c) 2000 Matt Sottek <msottek@quiknet.com>
Special thanks to Matt Sottek. I did the "guts", he
did the "brains" and all the testing. (Anybody wanna send
me an i810 or i820?)
-
+
----------------------------------------------------------
-
+
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
----------------------------------------------------------
-
+
From the firmware hub datasheet:
-
+
The Firmware Hub integrates a Random Number Generator (RNG)
using thermal noise generated from inherently random quantum
mechanical properties of silicon. When not generating new random
@@ -44,7 +44,7 @@
Theory of operation:
This driver has TWO modes of operation:
-
+
Mode 1
------
Character driver. Using the standard open()
@@ -52,16 +52,16 @@
the i810 RNG device. This data is NOT CHECKED by any
fitness tests, and could potentially be bogus (if the
hardware is faulty or has been tampered with).
-
+
/dev/intel_rng is char device major 10, minor 183.
-
+
Mode 2
------
Injection of entropy into the kernel entropy pool via a
timer function.
- A timer is run at RNG_TIMER_LEN intervals, reading 8 bits
+ A timer is run at rng_timer_len intervals, reading 8 bits
of data from the RNG. If the RNG has previously passed a
FIPS test, then the data will be added to the /dev/random
entropy pool. Then, those 8 bits are added to an internal
@@ -71,12 +71,12 @@
Thus, the RNG will never be enabled until it passes a
FIPS test. And, data will stop flowing into the system
entropy pool if the data is determined to be non-random.
-
+
Finally, note that the timer defaults to OFF. This ensures
that the system entropy pool will not be polluted with
RNG-originated data unless a conscious decision is made
by the user.
-
+
HOWEVER NOTE THAT UP TO 2499 BYTES OF DATA CAN BE BOGUS
BEFORE THE SYSTEM WILL NOTICE VIA THE FIPS TEST.
@@ -84,14 +84,13 @@
Driver notes:
- * You may enable and disable the RNG hardware (and this
- driver) via sysctl:
+ * You may enable and disable the RNG timer via sysctl:
# disable RNG
- echo 0 > /proc/sys/dev/i810_hw_enabled
+ echo 0 > /proc/sys/dev/i810_rng_timer
# enable RNG
- echo 1 > /proc/sys/dev/i810_hw_enabled
+ echo 1 > /proc/sys/dev/i810_rng_timer
* The default number of entropy bits added by default is
the full 8 bits. If you wish to reduce this value for
@@ -103,10 +102,56 @@
* The default number of entropy bits can also be set via
a module parameter "rng_entropy" at module load time.
+ * When the RNG timer is enabled, the driver reads 1 byte
+ from the hardware RNG every N jiffies. By default, every
+ half-second. If you would like to change the timer interval,
+ do so via another sysctl:
+
+ echo 200 > /proc/sys/dev/i810_rng_interval
+
+ NOTE THIS VALUE IS IN JIFFIES, NOT SECONDS OR MILLISECONDS.
+ Minimum interval is 1 jiffy, maximum interval is 24 hours.
+
* In order to unload the i810_rng module, you must first
disable the hardware via sysctl i810_hw_enabled, as shown above,
- and make sure all users of the character device
-
+ and make sure all users of the character device have closed
+
+ * The timer and the character device may be used simultaneously,
+ if desired.
+
+ * FIXME: Currently only one open() of the character device is allowed.
+ If another user tries to open() the device, they will get an
+ -EBUSY error. Instead, this really should either support
+ multiple simultaneous users of the character device (not hard),
+ or simply block open() until the current user of the chrdev
+ calls close().
+
+ * FIXME: support poll()
+
+ * FIXME: should we be crazy and support mmap()?
+
+ * FIXME: It is possible for the timer function to read,
+ and shove into the kernel entropy pool, 2499 bytes of data
+ before the internal FIPS test notices that the data is bad.
+ The kernel should handle this (I think???), but we should use a
+ 2500-byte array, and re-run the FIPS test for every byte read.
+ This will slow things down but guarantee that bad data is
+ never passed upstream.
+
+ ----------------------------------------------------------
+
+ Change history:
+
+ 0.6.2:
+ * Clean up spinlocks. Since we don't have any interrupts
+ to worry about, but we do have a timer to worry about,
+ we use spin_lock_bh everywhere except the timer function
+ itself.
+ * Fix module load/unload.
+ * Fix timer function and h/w enable/disable logic
+ * New timer interval sysctl
+ * Clean up sysctl names
+
*/
@@ -115,6 +160,7 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/random.h>
#include <linux/sysctl.h>
@@ -127,24 +173,24 @@
/*
* core module and version information
*/
-#define RNG_VERSION "0.6.1"
+#define RNG_VERSION "0.6.2"
#define RNG_MODULE_NAME "i810_rng"
#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
-#define PFX RNG_MODULE_NAME ": "
+#define PFX RNG_MODULE_NAME ": "
/*
* debugging macros
*/
#undef RNG_DEBUG /* define to 1 to enable copious debugging info */
-
+
#ifdef RNG_DEBUG
/* note: prints function name for you */
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
-
+
#define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */
#if RNG_NDEBUG
#define assert(expr)
@@ -156,11 +202,11 @@
}
#endif
-
+
/*
* misc helper macros
*/
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
/*
* prototypes
@@ -191,7 +237,7 @@ static void rng_run_fips_test (void);
* Frequency that data is added to kernel entropy pool
* HZ>>1 == every half-second
*/
-#define RNG_TIMER_LEN (HZ >> 1)
+#define RNG_DEF_TIMER_LEN (HZ >> 1)
/*
@@ -206,18 +252,22 @@ static void rng_run_fips_test (void);
* various RNG status variables. they are globals
* as we only support a single RNG device
*/
-static int rng_allocated = 0; /* is someone using the RNG region? */
-static int rng_hw_enabled = 0; /* is the RNG h/w, and timer, enabled? */
-static int rng_trusted = 0; /* does FIPS trust out data? */
+static int rng_allocated; /* is someone using the RNG region? */
+static int rng_hw_enabled; /* is the RNG h/w enabled? */
+static int rng_timer_enabled; /* is the RNG timer enabled? */
+static int rng_use_count; /* number of times RNG has been enabled */
+static int rng_trusted; /* does FIPS trust out data? */
static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */
-static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */
-static int rng_entropy_sysctl; /* sysctl for changing entropy bits */
-static int rng_have_mem_region = 0; /* did we grab RNG region via request_mem_region? */
-static int rng_fips_counter = 0; /* size of internal FIPS test data pool */
-static void *rng_mem = NULL; /* token to our ioremap'd RNG register area */
+static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */
+static int rng_entropy_sysctl; /* sysctl for changing entropy bits */
+static int rng_interval_sysctl; /* sysctl for changing timer interval */
+static int rng_have_mem_region; /* did we grab RNG region via request_mem_region? */
+static int rng_fips_counter; /* size of internal FIPS test data pool */
+static int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */
+static void *rng_mem; /* token to our ioremap'd RNG register area */
static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */
static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */
-static atomic_t rng_open;
+static int rng_open; /* boolean, 0 (false) if chrdev is closed, 1 (true) if open */
/*
* inlined helper functions for accessing RNG registers
@@ -240,7 +290,7 @@ static inline int rng_data_present (void)
{
assert (rng_mem != NULL);
assert (rng_hw_enabled == 1);
-
+
return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
}
@@ -249,22 +299,21 @@ static inline int rng_data_read (void)
{
assert (rng_mem != NULL);
assert (rng_hw_enabled == 1);
-
+
return readb (rng_mem + RNG_DATA);
}
/*
- * rng_timer_ticker - executes every RNG_TIMER_LEN jiffies,
+ * rng_timer_ticker - executes every rng_timer_len jiffies,
* adds a single byte to system entropy
* and internal FIPS test pools
*/
static void rng_timer_tick (unsigned long data)
{
- unsigned long flags;
int rng_data;
- spin_lock_irqsave (&rng_lock, flags);
+ spin_lock (&rng_lock);
if (rng_data_present ()) {
/* gimme some thermal noise, baby */
@@ -285,11 +334,14 @@ static void rng_timer_tick (unsigned long data)
rng_run_fips_test ();
}
- spin_unlock_irqrestore (&rng_lock, flags);
+ /* run the timer again, if enabled */
+ if (rng_timer_enabled) {
+ rng_timer.expires = jiffies + rng_timer_len;
+ add_timer (&rng_timer);
+ }
+
+ spin_unlock (&rng_lock);
- /* run the timer again */
- rng_timer.expires = jiffies + RNG_TIMER_LEN;
- add_timer (&rng_timer);
}
@@ -298,43 +350,44 @@ static void rng_timer_tick (unsigned long data)
*/
static int rng_enable (int enable)
{
- unsigned long flags;
int rc = 0;
u8 hw_status;
-
+
DPRINTK ("ENTER\n");
-
- spin_lock_irqsave (&rng_lock, flags);
+
+ spin_lock_bh (&rng_lock);
hw_status = rng_hwstatus ();
-
- if (enable && !rng_hw_enabled) {
- rng_hwstatus_set (hw_status | RNG_ENABLED);
- printk (KERN_INFO PFX "RNG h/w enabled\n");
+ if (enable) {
rng_hw_enabled = 1;
+ rng_use_count++;
MOD_INC_USE_COUNT;
+ } else {
+ rng_use_count--;
+ if (rng_use_count == 0)
+ rng_hw_enabled = 0;
+ MOD_DEC_USE_COUNT;
}
-
- else if (!enable && rng_hw_enabled) {
- del_timer (&rng_timer);
- rng_hwstatus_set (hw_status & ~RNG_ENABLED);
+ if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) {
+ rng_hwstatus_set (hw_status | RNG_ENABLED);
+ printk (KERN_INFO PFX "RNG h/w enabled\n");
+ }
+ else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) {
+ rng_hwstatus_set (hw_status & ~RNG_ENABLED);
printk (KERN_INFO PFX "RNG h/w disabled\n");
- rng_hw_enabled = 0;
- MOD_DEC_USE_COUNT;
}
-
- if (enable != (rng_hwstatus () & RNG_ENABLED) ) {
- del_timer (&rng_timer);
+
+ spin_unlock_bh (&rng_lock);
+
+ if ((!!enable) != (!!(rng_hwstatus () & RNG_ENABLED))) {
printk (KERN_ERR PFX "Unable to %sable the RNG\n",
enable ? "en" : "dis");
rc = -EIO;
}
- spin_unlock_irqrestore (&rng_lock, flags);
-
DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
@@ -343,26 +396,42 @@ static int rng_enable (int enable)
/*
* rng_handle_sysctl_enable - handle a read or write of our enable/disable sysctl
*/
-
+
static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *filp,
void *buffer, size_t * lenp)
{
- unsigned long flags;
int enabled_save, rc;
DPRINTK ("ENTER\n");
-
- spin_lock_irqsave (&rng_lock, flags);
- rng_enabled_sysctl = enabled_save = rng_hw_enabled;
- spin_unlock_irqrestore (&rng_lock, flags);
+
+ spin_lock_bh (&rng_lock);
+
+ rng_enabled_sysctl = enabled_save = rng_timer_enabled;
rc = proc_dointvec (table, write, filp, buffer, lenp);
- if (rc)
+ if (rc) {
+ spin_unlock_bh (&rng_lock);
return rc;
-
- if (enabled_save != rng_enabled_sysctl)
+ }
+
+ if (enabled_save != rng_enabled_sysctl) {
+ rng_timer_enabled = rng_enabled_sysctl;
+ spin_unlock_bh (&rng_lock);
+
+ /* enable/disable hardware */
rng_enable (rng_enabled_sysctl);
+ /* enable/disable timer */
+ if (rng_enabled_sysctl) {
+ rng_timer.expires = jiffies + rng_timer_len;
+ add_timer (&rng_timer);
+ } else {
+ del_timer_sync (&rng_timer);
+ }
+ } else {
+ spin_unlock_bh (&rng_lock);
+ }
+
DPRINTK ("EXIT, returning 0\n");
return 0;
}
@@ -371,31 +440,30 @@ static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *
/*
* rng_handle_sysctl_entropy - handle a read or write of our entropy bits sysctl
*/
-
+
static int rng_handle_sysctl_entropy (ctl_table * table, int write, struct file *filp,
void *buffer, size_t * lenp)
{
- unsigned long flags;
int entropy_bits_save, rc;
DPRINTK ("ENTER\n");
-
- spin_lock_irqsave (&rng_lock, flags);
+
+ spin_lock_bh (&rng_lock);
rng_entropy_sysctl = entropy_bits_save = rng_entropy;
- spin_unlock_irqrestore (&rng_lock, flags);
+ spin_unlock_bh (&rng_lock);
rc = proc_dointvec (table, write, filp, buffer, lenp);
if (rc)
return rc;
-
+
if (entropy_bits_save == rng_entropy_sysctl)
goto out;
if ((rng_entropy_sysctl >= 0) &&
(rng_entropy_sysctl <= 8)) {
- spin_lock_irqsave (&rng_lock, flags);
+ spin_lock_bh (&rng_lock);
rng_entropy = rng_entropy_sysctl;
- spin_unlock_irqrestore (&rng_lock, flags);
+ spin_unlock_bh (&rng_lock);
printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl);
} else {
@@ -408,36 +476,89 @@ out:
return 0;
}
+/*
+ * rng_handle_sysctl_interval - handle a read or write of our timer interval len sysctl
+ */
+
+static int rng_handle_sysctl_interval (ctl_table * table, int write, struct file *filp,
+ void *buffer, size_t * lenp)
+{
+ int timer_len_save, rc;
+
+ DPRINTK ("ENTER\n");
+
+ spin_lock_bh (&rng_lock);
+ rng_interval_sysctl = timer_len_save = rng_timer_len;
+ spin_unlock_bh (&rng_lock);
+
+ rc = proc_dointvec (table, write, filp, buffer, lenp);
+ if (rc)
+ return rc;
+
+ if (timer_len_save == rng_interval_sysctl)
+ goto out;
+
+ if ((rng_interval_sysctl > 0) &&
+ (rng_interval_sysctl < (HZ*86400))) {
+ spin_lock_bh (&rng_lock);
+ rng_timer_len = rng_interval_sysctl;
+ spin_unlock_bh (&rng_lock);
+
+ printk (KERN_INFO PFX "timer interval now %d\n", rng_interval_sysctl);
+ } else {
+ printk (KERN_INFO PFX "ignoring invalid timer interval (%d)\n",
+ rng_interval_sysctl);
+ }
+
+out:
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
/*
* rng_sysctl - add or remove the rng sysctl
*/
static void rng_sysctl (int add)
{
-#define DEV_I810_RNG 1
-#define DEV_I810_RNG_ENTROPY 2
+#define DEV_I810_TIMER 1
+#define DEV_I810_ENTROPY 2
+#define DEV_I810_INTERVAL 3
+
/* Definition of the sysctl */
+ /* FIXME: use new field:value style of struct initialization */
static ctl_table rng_sysctls[] = {
- {DEV_I810_RNG, /* ID */
- RNG_MODULE_NAME "_enabled", /* name in /proc */
+ {DEV_I810_TIMER, /* ID */
+ RNG_MODULE_NAME "_timer", /* name in /proc */
&rng_enabled_sysctl,
sizeof (rng_enabled_sysctl), /* data ptr, data size */
- 0644, /* mode */
- 0, /* child */
+ 0644, /* mode */
+ 0, /* child */
rng_handle_sysctl_enable, /* proc handler */
- 0, /* strategy */
- 0, /* proc control block */
+ 0, /* strategy */
+ 0, /* proc control block */
0, 0}
,
- {DEV_I810_RNG_ENTROPY, /* ID */
+ {DEV_I810_ENTROPY, /* ID */
RNG_MODULE_NAME "_entropy", /* name in /proc */
&rng_entropy_sysctl,
sizeof (rng_entropy_sysctl), /* data ptr, data size */
- 0644, /* mode */
- 0, /* child */
+ 0644, /* mode */
+ 0, /* child */
rng_handle_sysctl_entropy, /* proc handler */
- 0, /* strategy */
- 0, /* proc control block */
+ 0, /* strategy */
+ 0, /* proc control block */
+ 0, 0}
+ ,
+ {DEV_I810_INTERVAL, /* ID */
+ RNG_MODULE_NAME "_interval", /* name in /proc */
+ &rng_interval_sysctl,
+ sizeof (rng_interval_sysctl), /* data ptr, data size */
+ 0644, /* mode */
+ 0, /* child */
+ rng_handle_sysctl_interval, /* proc handler */
+ 0, /* strategy */
+ 0, /* proc control block */
0, 0}
,
{0}
@@ -467,35 +588,36 @@ static void rng_sysctl (int add)
static int rng_dev_open (struct inode *inode, struct file *filp)
{
int rc = -EINVAL;
- unsigned long flags;
if ((filp->f_mode & FMODE_READ) == 0)
goto err_out;
if (filp->f_mode & FMODE_WRITE)
goto err_out;
- spin_lock_irqsave (&rng_lock, flags);
-
- if (atomic_read(&rng_open)) {
- spin_unlock_irqrestore (&rng_lock, flags);
+ spin_lock_bh (&rng_lock);
+
+ /* only allow one open of this device, exit with -EBUSY if already open */
+ /* FIXME: we should sleep on a semaphore here, unless O_NONBLOCK */
+ if (rng_open) {
+ spin_unlock_bh (&rng_lock);
rc = -EBUSY;
goto err_out;
}
-
- atomic_set (&rng_open, 1);
- spin_unlock_irqrestore (&rng_lock, flags);
-
+ rng_open = 1;
+
+ spin_unlock_bh (&rng_lock);
+
if (rng_enable(1) != 0) {
- spin_lock_irqsave (&rng_lock, flags);
- atomic_set (&rng_open, 0);
- spin_unlock_irqrestore (&rng_lock, flags);
+ spin_lock_bh (&rng_lock);
+ rng_open = 0;
+ spin_unlock_bh (&rng_lock);
rc = -EIO;
goto err_out;
}
-
+
return 0;
-
+
err_out:
return rc;
}
@@ -503,14 +625,13 @@ err_out:
static int rng_dev_release (struct inode *inode, struct file *filp)
{
- unsigned long flags;
if (rng_enable(0) != 0)
return -EIO;
- spin_lock_irqsave (&rng_lock, flags);
- atomic_set (&rng_open, 0);
- spin_unlock_irqrestore (&rng_lock, flags);
+ spin_lock_bh (&rng_lock);
+ rng_open = 0;
+ spin_unlock_bh (&rng_lock);
return 0;
}
@@ -520,14 +641,13 @@ static ssize_t rng_dev_read (struct file *filp, char * buf, size_t size,
loff_t *offp)
{
int have_data, copied = 0;
- unsigned long flags;
u8 data=0;
u8 *page;
-
+
if (size < 1)
return 0;
-
- page = (unsigned char *) get_zeroed_page (GFP_KERNEL);
+
+ page = (unsigned char *) get_free_page (GFP_KERNEL);
if (!page)
return -ENOMEM;
@@ -545,7 +665,7 @@ read_loop:
return tmpsize;
}
- spin_lock_irqsave (&rng_lock, flags);
+ spin_lock_bh (&rng_lock);
have_data = 0;
if (rng_data_present ()) {
@@ -553,8 +673,8 @@ read_loop:
have_data = 1;
}
- spin_unlock_irqrestore (&rng_lock, flags);
-
+ spin_unlock_bh (&rng_lock);
+
if (have_data) {
page[copied] = data;
copied++;
@@ -567,12 +687,12 @@ read_loop:
if (current->need_resched)
schedule ();
-
+
if (signal_pending (current)) {
free_page ((long)page);
return -ERESTARTSYS;
}
-
+
goto read_loop;
}
@@ -585,7 +705,7 @@ static int __init rng_init_one (struct pci_dev *dev,
{
int rc;
u8 hw_status;
-
+
DPRINTK ("ENTER\n");
if (rng_allocated) {
@@ -619,7 +739,7 @@ static int __init rng_init_one (struct pci_dev *dev,
if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY)
rng_entropy = RNG_MAX_ENTROPY;
-
+
/* init core RNG timer, but do not add it */
init_timer (&rng_timer);
rng_timer.function = rng_timer_tick;
@@ -653,7 +773,7 @@ const static struct pci_device_id rng_pci_tbl[] __initdata = {
{ 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, },
};
-MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
+MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
static struct pci_driver rng_driver = {
name: RNG_MODULE_NAME,
@@ -690,31 +810,21 @@ static int __init rng_init (void)
int rc;
DPRINTK ("ENTER\n");
-
- MOD_INC_USE_COUNT;
if (pci_register_driver (&rng_driver) < 1) {
DPRINTK ("EXIT, returning -ENODEV\n");
- MOD_DEC_USE_COUNT;
return -ENODEV;
}
-
+
rc = misc_register (&rng_miscdev);
if (rc) {
pci_unregister_driver (&rng_driver);
DPRINTK ("EXIT, returning %d\n", rc);
- MOD_DEC_USE_COUNT;
return rc;
}
printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
- /* FIXME: verify module unload logic, then remove
- * this additional MOD_INC_USE_COUNT */
- MOD_INC_USE_COUNT;
-
- MOD_DEC_USE_COUNT; /* init complete, unload allowed now */
-
DPRINTK ("EXIT, returning 0\n");
return 0;
}
@@ -725,13 +835,9 @@ static int __init rng_init (void)
*/
static void __exit rng_cleanup (void)
{
- unsigned long flags;
-
DPRINTK ("ENTER\n");
- spin_lock_irqsave (&rng_lock, flags);
- del_timer (&rng_timer);
- spin_unlock_irqrestore (&rng_lock, flags);
+ del_timer_sync (&rng_timer);
rng_sysctl (0);
pci_unregister_driver (&rng_driver);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index f488d9124..0e9d7b57f 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -18,6 +18,8 @@
* This file may be redistributed under the terms of the GNU Public
* License.
*
+ * Reduced memory usage for older ARM systems - Russell King.
+ *
* 2000/01/20 Fixed SMP locking on put_tty_queue using bits of
* the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
* who actually finally proved there really was a race.
@@ -61,6 +63,29 @@
#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
#define TTY_THRESHOLD_UNTHROTTLE 128
+static inline unsigned char *alloc_buf(void)
+{
+ unsigned char *p;
+ int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+
+ if (PAGE_SIZE != N_TTY_BUF_SIZE) {
+ p = kmalloc(N_TTY_BUF_SIZE, prio);
+ if (p)
+ memset(p, 0, N_TTY_BUF_SIZE);
+ } else
+ p = (unsigned char *)get_zeroed_page(prio);
+
+ return p;
+}
+
+static inline void free_buf(unsigned char *buf)
+{
+ if (PAGE_SIZE != N_TTY_BUF_SIZE)
+ kfree(buf);
+ else
+ free_page((unsigned long) buf);
+}
+
static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
{
unsigned long flags;
@@ -827,7 +852,7 @@ static void n_tty_close(struct tty_struct *tty)
{
n_tty_flush_buffer(tty);
if (tty->read_buf) {
- free_page((unsigned long) tty->read_buf);
+ free_buf(tty->read_buf);
tty->read_buf = 0;
}
}
@@ -838,8 +863,7 @@ static int n_tty_open(struct tty_struct *tty)
return -EINVAL;
if (!tty->read_buf) {
- tty->read_buf = (unsigned char *)
- get_zeroed_page(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ tty->read_buf = alloc_buf();
if (!tty->read_buf)
return -ENOMEM;
}
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index af52cf98f..ae4b9e112 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -106,6 +106,7 @@ static void pp_attach (struct parport *port)
}
add->next = pp_port_list;
+ add->port = port;
down (&pp_port_list_lock);
pp_port_list = add;
up (&pp_port_list_lock);
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index ba1b9caa9..235b0f131 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -780,7 +780,7 @@ void cleanup_module()
stlpanel_t *panelp;
stlport_t *portp;
unsigned long flags;
- int i, j, k, l;
+ int i, j, k;
#if DEBUG
printk("cleanup_module()\n");
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 613b2f967..4c0d29662 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -57,6 +57,9 @@
*
* Added support for a Unix98-style ptmx device.
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ * Reduced memory usage for older ARM systems
+ * -- Russell King <rmk@arm.linux.org.uk>
*/
#include <linux/config.h>
@@ -111,7 +114,7 @@ extern void con_init_devfs (void);
#define CHECK_TTY_COUNT 1
struct termios tty_std_termios; /* for the benefit of tty drivers */
-struct tty_driver *tty_drivers = NULL; /* linked list of tty drivers */
+struct tty_driver *tty_drivers; /* linked list of tty drivers */
struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
#ifdef CONFIG_UNIX98_PTYS
@@ -123,7 +126,7 @@ extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */
* redirect is the pseudo-tty that console output
* is redirected to if asked by TIOCCONS.
*/
-struct tty_struct * redirect = NULL;
+struct tty_struct * redirect;
static void initialize_tty_struct(struct tty_struct *tty);
@@ -135,35 +138,49 @@ static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(int fd, struct file * filp, int on);
-#ifdef CONFIG_SX
extern int sx_init (void);
-#endif
-#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
extern int vme_scc_init (void);
extern long vme_scc_console_init(void);
-#endif
-#ifdef CONFIG_SERIAL167
extern int serial167_init(void);
extern long serial167_console_init(void);
-#endif
-#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
extern void console_8xx_init(void);
extern int rs_8xx_init(void);
-#endif /* CONFIG_8xx */
-#ifdef CONFIG_SGI_SERIAL
-extern void sgi_serial_console_init(void);
-#endif
-#ifdef CONFIG_HWC
extern void hwc_console_init(void);
-#endif
-#ifdef CONFIG_3215
extern void con3215_init(void);
-#endif /* CONFIG_3215 */
-
+extern void rs285_console_init(void);
+extern void rs285_init(void);
+extern void sa1100_rs_console_init(void);
+extern void sa1100_rs_init(void);
+extern void sgi_serial_console_init(void);
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
+#ifndef MAX
+#define MAX(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+static inline struct tty_struct *alloc_tty_struct(void)
+{
+ struct tty_struct *tty;
+
+ if (PAGE_SIZE > 8192) {
+ tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
+ if (tty)
+ memset(tty, 0, sizeof(struct tty_struct));
+ } else
+ tty = (struct tty_struct *)get_zeroed_page(GFP_KERNEL);
+
+ return tty;
+}
+
+static inline void free_tty_struct(struct tty_struct *tty)
+{
+ if (PAGE_SIZE > 8192)
+ kfree(tty);
+ else
+ free_page((unsigned long) tty);
+}
/*
* This routine returns the name of tty.
@@ -695,7 +712,7 @@ static inline ssize_t do_tty_write(
unlock_kernel();
} else {
for (;;) {
- unsigned long size = PAGE_SIZE*2;
+ unsigned long size = MAX(PAGE_SIZE*2,16384);
if (size > count)
size = count;
lock_kernel();
@@ -826,7 +843,7 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
tp = o_tp = NULL;
ltp = o_ltp = NULL;
- tty = (struct tty_struct*) get_zeroed_page(GFP_KERNEL);
+ tty = alloc_tty_struct();
if(!tty)
goto fail_no_mem;
initialize_tty_struct(tty);
@@ -852,7 +869,7 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
}
if (driver->type == TTY_DRIVER_TYPE_PTY) {
- o_tty = (struct tty_struct *) get_zeroed_page(GFP_KERNEL);
+ o_tty = alloc_tty_struct();
if (!o_tty)
goto free_mem_out;
initialize_tty_struct(o_tty);
@@ -972,12 +989,12 @@ free_mem_out:
if (o_tp)
kfree_s(o_tp, sizeof(struct termios));
if (o_tty)
- free_page((unsigned long) o_tty);
+ free_tty_struct(o_tty);
if (ltp)
kfree_s(ltp, sizeof(struct termios));
if (tp)
kfree_s(tp, sizeof(struct termios));
- free_page((unsigned long) tty);
+ free_tty_struct(tty);
fail_no_mem:
retval = -ENOMEM;
@@ -1008,7 +1025,7 @@ static void release_mem(struct tty_struct *tty, int idx)
}
o_tty->magic = 0;
(*o_tty->driver.refcount)--;
- free_page((unsigned long) o_tty);
+ free_tty_struct(o_tty);
}
tty->driver.table[idx] = NULL;
@@ -1019,7 +1036,7 @@ static void release_mem(struct tty_struct *tty, int idx)
}
tty->magic = 0;
(*tty->driver.refcount)--;
- free_page((unsigned long) tty);
+ free_tty_struct(tty);
}
/*
@@ -1400,9 +1417,9 @@ init_dev_done:
static int nr_warns = 0;
if (nr_warns < 5) {
printk(KERN_WARNING "tty_io.c: "
- "process %d (%s) used obsolete /dev/%s - "
+ "process %d (%s) used obsolete /dev/%s - "
"update software to use /dev/ttyS%d\n",
- current->pid, current->comm,
+ current->pid, current->comm,
tty_name(tty, buf), TTY_NUMBER(tty));
nr_warns++;
}
diff --git a/drivers/isdn/avmb1/Makefile b/drivers/isdn/avmb1/Makefile
index 77a701611..cd2223911 100644
--- a/drivers/isdn/avmb1/Makefile
+++ b/drivers/isdn/avmb1/Makefile
@@ -1,5 +1,5 @@
#
-# $Id: Makefile,v 1.16 2000/03/17 12:15:44 calle Exp $
+# $Id: Makefile,v 1.18 2000/04/03 16:39:25 calle Exp $
#
# Makefile for the CAPI and AVM-B1 device drivers.
#
@@ -146,6 +146,11 @@ ifeq ($(CONFIG_ISDN_CAPI),y)
endif
ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
OX_OBJS += b1pcmcia.o
+ ifeq ($(CONFIG_HOTPLUG),y)
+ ifneq ($(CONFIG_PCMCIA),n)
+ M_OBJS += avm_cs.o
+ endif
+ endif
endif
ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
O_OBJS += t1pci.o
diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c
index 65c4368cd..ff13e1636 100644
--- a/drivers/isdn/avmb1/b1.c
+++ b/drivers/isdn/avmb1/b1.c
@@ -1,11 +1,14 @@
/*
- * $Id: b1.c,v 1.13 2000/01/25 14:33:38 calle Exp $
+ * $Id: b1.c,v 1.14 2000/06/19 16:51:53 keil Exp $
*
* Common module for AVM B1 cards.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1.c,v $
+ * Revision 1.14 2000/06/19 16:51:53 keil
+ * don't free skb in irq context
+ *
* Revision 1.13 2000/01/25 14:33:38 calle
* - Added Support AVM B1 PCI V4.0 (tested with prototype)
* - splitted up t1pci.c into b1dma.c for common function with b1pciv4
@@ -86,12 +89,13 @@
#include <linux/capi.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <linux/netdevice.h>
#include "capilli.h"
#include "avmcard.h"
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.13 $";
+static char *revision = "$Revision: 1.14 $";
/* ------------------------------------------------------------- */
@@ -420,7 +424,7 @@ void b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
b1_put_slice(port, skb->data, len);
}
restore_flags(flags);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
/* ------------------------------------------------------------- */
diff --git a/drivers/isdn/avmb1/b1dma.c b/drivers/isdn/avmb1/b1dma.c
index b40fafae9..168c7202f 100644
--- a/drivers/isdn/avmb1/b1dma.c
+++ b/drivers/isdn/avmb1/b1dma.c
@@ -1,11 +1,14 @@
/*
- * $Id: b1dma.c,v 1.4 2000/04/03 16:38:05 calle Exp $
+ * $Id: b1dma.c,v 1.5 2000/06/19 16:51:53 keil Exp $
*
* Common module for AVM B1 cards that support dma with AMCC
*
* (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1dma.c,v $
+ * Revision 1.5 2000/06/19 16:51:53 keil
+ * don't free skb in irq context
+ *
* Revision 1.4 2000/04/03 16:38:05 calle
* made suppress_pollack static.
*
@@ -32,12 +35,13 @@
#include <linux/capi.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <linux/netdevice.h>
#include "capilli.h"
#include "avmcard.h"
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 1.5 $";
/* ------------------------------------------------------------- */
@@ -430,7 +434,7 @@ static void b1dma_dispatch_tx(avmcard *card)
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
restore_flags(flags);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
/* ------------------------------------------------------------- */
@@ -615,11 +619,6 @@ static void b1dma_handle_interrupt(avmcard *card)
if ((status & TX_TC_INT) != 0) {
card->csr &= ~EN_TX_TC_INT;
b1dma_dispatch_tx(card);
- } else if (card->csr & EN_TX_TC_INT) {
- if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) {
- card->csr &= ~EN_TX_TC_INT;
- b1dma_dispatch_tx(card);
- }
}
b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
}
diff --git a/drivers/isdn/avmb1/b1pci.c b/drivers/isdn/avmb1/b1pci.c
index e98066806..9e230cb2e 100644
--- a/drivers/isdn/avmb1/b1pci.c
+++ b/drivers/isdn/avmb1/b1pci.c
@@ -1,11 +1,24 @@
/*
- * $Id: b1pci.c,v 1.21 2000/04/03 13:29:24 calle Exp $
+ * $Id: b1pci.c,v 1.25 2000/05/29 12:29:18 keil Exp $
*
* Module for AVM B1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: b1pci.c,v $
+ * Revision 1.25 2000/05/29 12:29:18 keil
+ * make pci_enable_dev compatible to 2.2 kernel versions
+ *
+ * Revision 1.24 2000/05/19 15:43:22 calle
+ * added calls to pci_device_start().
+ *
+ * Revision 1.23 2000/05/06 00:52:36 kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
+ * Revision 1.22 2000/04/21 13:01:33 calle
+ * Revision in b1pciv4 driver was missing.
+ *
* Revision 1.21 2000/04/03 13:29:24 calle
* make Tim Waugh happy (module unload races in 2.3.99-pre3).
* no real problem there, but now it is much cleaner ...
@@ -74,12 +87,13 @@
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
+#include <linux/isdn.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.21 $";
+static char *revision = "$Revision: 1.25 $";
/* ------------------------------------------------------------- */
@@ -466,16 +480,26 @@ static int add_card(struct pci_dev *dev)
struct capicardparams param;
int retval;
- if (pci_enable_device(dev))
- return 0; /* return failure */
-
- if (pci_resource_flags(dev, 2) & IORESOURCE_IO) { /* B1 PCI V4 */
+ if (pci_resource_start(dev, 2)) { /* B1 PCI V4 */
#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
driver = &b1pciv4_driver;
#endif
- param.membase = pci_resource_start (dev, 0);
- param.port = pci_resource_start (dev, 2);
+ param.membase = pci_resource_start(dev, 0);
+ param.port = pci_resource_start(dev, 2);
param.irq = dev->irq;
+
+ retval = pci_enable_device (dev);
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: failed to enable AVM-B1 V4 at i/o %#x, irq %d, mem %#x err=%d\n",
+ driver->name, param.port, param.irq, param.membase, retval);
+#ifdef MODULE
+ cleanup_module();
+#endif
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+
printk(KERN_INFO
"%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
driver->name, param.port, param.irq, param.membase);
@@ -491,8 +515,20 @@ static int add_card(struct pci_dev *dev)
}
} else {
param.membase = 0;
- param.port = pci_resource_start (dev, 1);
+ param.port = pci_resource_start(dev, 1);
param.irq = dev->irq;
+
+ retval = pci_enable_device (dev);
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: failed to enable AVM-B1 at i/o %#x, irq %d, err=%d\n",
+ driver->name, param.port, param.irq, retval);
+#ifdef MODULE
+ cleanup_module();
+#endif
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
printk(KERN_INFO
"%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
driver->name, param.port, param.irq);
@@ -522,6 +558,12 @@ int b1pci_init(void)
strncpy(driver->revision, p + 1, sizeof(driver->revision));
p = strchr(driver->revision, '$');
*p = 0;
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ p = strchr(revision, ':');
+ strncpy(driverv4->revision, p + 1, sizeof(driverv4->revision));
+ p = strchr(driverv4->revision, '$');
+ *p = 0;
+#endif
}
printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
diff --git a/drivers/isdn/avmb1/c4.c b/drivers/isdn/avmb1/c4.c
index 104c0f5cc..09c9bad99 100644
--- a/drivers/isdn/avmb1/c4.c
+++ b/drivers/isdn/avmb1/c4.c
@@ -1,11 +1,24 @@
/*
- * $Id: c4.c,v 1.8 2000/04/03 16:38:05 calle Exp $
+ * $Id: c4.c,v 1.12 2000/06/19 16:51:53 keil Exp $
*
* Module for AVM C4 card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: c4.c,v $
+ * Revision 1.12 2000/06/19 16:51:53 keil
+ * don't free skb in irq context
+ *
+ * Revision 1.11 2000/06/19 15:11:24 keil
+ * avoid use of freed structs
+ * changes from 2.4.0-ac21
+ *
+ * Revision 1.10 2000/05/29 12:29:18 keil
+ * make pci_enable_dev compatible to 2.2 kernel versions
+ *
+ * Revision 1.9 2000/05/19 15:43:22 calle
+ * added calls to pci_device_start().
+ *
* Revision 1.8 2000/04/03 16:38:05 calle
* made suppress_pollack static.
*
@@ -46,6 +59,7 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/capi.h>
+#include <linux/isdn.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "capicmd.h"
@@ -53,7 +67,7 @@
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.8 $";
+static char *revision = "$Revision: 1.12 $";
#undef CONFIG_C4_DEBUG
#undef CONFIG_C4_POLLDEBUG
@@ -510,7 +524,7 @@ static void c4_dispatch_tx(avmcard *card)
c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM);
restore_flags(flags);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
/* ------------------------------------------------------------- */
@@ -949,8 +963,10 @@ static void c4_remove_ctr(struct capi_ctr *ctrl)
for (i=0; i < 4; i++) {
cinfo = &card->ctrlinfo[i];
- if (cinfo->capi_ctrl)
+ if (cinfo->capi_ctrl) {
di->detach_ctr(cinfo->capi_ctrl);
+ cinfo->capi_ctrl = NULL;
+ }
}
free_irq(card->irq, card);
@@ -1163,7 +1179,6 @@ static int c4_add_card(struct capi_driver *driver, struct capicardparams *p)
cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
if (!cinfo) {
printk(KERN_WARNING "%s: no memory.\n", driver->name);
- kfree(card->ctrlinfo);
kfree(card->dma);
kfree(card);
MOD_DEC_USE_COUNT;
@@ -1333,12 +1348,21 @@ int c4_init(void)
PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, dev))) {
struct capicardparams param;
- if (pci_enable_device(dev))
- continue;
-
- param.port = pci_resource_start (dev, 1);
+ param.port = pci_resource_start(dev, 1);
param.irq = dev->irq;
- param.membase = pci_resource_start (dev, 0);
+ param.membase = pci_resource_start(dev, 0);
+
+ retval = pci_enable_device (dev);
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: failed to enable AVM-C4 at i/o %#x, irq %d, mem %#x err=%d\n",
+ driver->name, param.port, param.irq, param.membase, retval);
+#ifdef MODULE
+ cleanup_module();
+#endif
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
printk(KERN_INFO
"%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n",
diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c
index 8169df482..610c20b6d 100644
--- a/drivers/isdn/avmb1/capi.c
+++ b/drivers/isdn/avmb1/capi.c
@@ -1,11 +1,24 @@
/*
- * $Id: capi.c,v 1.31 2000/04/03 13:29:24 calle Exp $
+ * $Id: capi.c,v 1.35 2000/06/19 15:11:24 keil Exp $
*
* CAPI 2.0 Interface for Linux
*
* Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capi.c,v $
+ * Revision 1.35 2000/06/19 15:11:24 keil
+ * avoid use of freed structs
+ * changes from 2.4.0-ac21
+ *
+ * Revision 1.34 2000/06/18 16:09:54 keil
+ * more changes for 2.4
+ *
+ * Revision 1.33 2000/05/18 16:35:43 calle
+ * Uaaahh. Bad memory leak fixed.
+ *
+ * Revision 1.32 2000/04/21 12:38:42 calle
+ * Bugfix: error in proc_ functions, begin-off => off-begin
+ *
* Revision 1.31 2000/04/03 13:29:24 calle
* make Tim Waugh happy (module unload races in 2.3.99-pre3).
* no real problem there, but now it is much cleaner ...
@@ -158,7 +171,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -193,7 +205,7 @@
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
#include <linux/slab.h>
-static char *revision = "$Revision: 1.31 $";
+static char *revision = "$Revision: 1.35 $";
MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
@@ -816,7 +828,6 @@ static void capi_signal(__u16 applid, void *param)
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
-
datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
#ifdef _DEBUG_DATAFLOW
printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
@@ -854,14 +865,14 @@ static void capi_signal(__u16 applid, void *param)
/* -------- file_operations for capidev ----------------------------- */
-static long long capi_llseek(struct file *file,
- long long offset, int origin)
+static loff_t
+capi_llseek(struct file *file, loff_t offset, int origin)
{
return -ESPIPE;
}
-static ssize_t capi_read(struct file *file, char *buf,
- size_t count, loff_t *ppos)
+static ssize_t
+capi_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
struct capidev *cdev = (struct capidev *)file->private_data;
struct sk_buff *skb;
@@ -911,8 +922,8 @@ static ssize_t capi_read(struct file *file, char *buf,
return copied;
}
-static ssize_t capi_write(struct file *file, const char *buf,
- size_t count, loff_t *ppos)
+static ssize_t
+capi_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
struct capidev *cdev = (struct capidev *)file->private_data;
struct sk_buff *skb;
@@ -975,7 +986,8 @@ capi_poll(struct file *file, poll_table * wait)
return mask;
}
-static int capi_ioctl(struct inode *inode, struct file *file,
+static int
+capi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct capidev *cdev = (struct capidev *)file->private_data;
@@ -1190,7 +1202,8 @@ static int capi_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
-static int capi_open(struct inode *inode, struct file *file)
+static int
+capi_open(struct inode *inode, struct file *file)
{
if (file->private_data)
return -EEXIST;
@@ -1198,19 +1211,23 @@ static int capi_open(struct inode *inode, struct file *file)
if ((file->private_data = capidev_alloc(file)) == 0)
return -ENOMEM;
+ MOD_INC_USE_COUNT;
#ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE));
#endif
return 0;
}
-static int capi_release(struct inode *inode, struct file *file)
+static int
+capi_release(struct inode *inode, struct file *file)
{
struct capidev *cdev = (struct capidev *)file->private_data;
capincci_free(cdev, 0xffffffff);
capidev_free(cdev);
+ file->private_data = NULL;
+ MOD_DEC_USE_COUNT;
#ifdef _DEBUG_REFCOUNT
printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE));
#endif
@@ -1232,7 +1249,8 @@ static struct file_operations capi_fops =
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
/* -------- file_operations for capincci ---------------------------- */
-int capinc_raw_open(struct inode *inode, struct file *file)
+static int
+capinc_raw_open(struct inode *inode, struct file *file)
{
struct capiminor *mp;
@@ -1256,14 +1274,14 @@ int capinc_raw_open(struct inode *inode, struct file *file)
return 0;
}
-long long capinc_raw_llseek(struct file *file,
- long long offset, int origin)
+static loff_t
+capinc_raw_llseek(struct file *file, loff_t offset, int origin)
{
return -ESPIPE;
}
-ssize_t capinc_raw_read(struct file *file, char *buf,
- size_t count, loff_t *ppos)
+static ssize_t
+capinc_raw_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
struct capiminor *mp = (struct capiminor *)file->private_data;
struct sk_buff *skb;
@@ -1320,8 +1338,8 @@ ssize_t capinc_raw_read(struct file *file, char *buf,
return copied;
}
-ssize_t capinc_raw_write(struct file *file, const char *buf,
- size_t count, loff_t *ppos)
+static ssize_t
+capinc_raw_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
struct capiminor *mp = (struct capiminor *)file->private_data;
struct sk_buff *skb;
@@ -1358,7 +1376,7 @@ ssize_t capinc_raw_write(struct file *file, const char *buf,
return count;
}
-unsigned int
+static unsigned int
capinc_raw_poll(struct file *file, poll_table * wait)
{
struct capiminor *mp = (struct capiminor *)file->private_data;
@@ -1376,7 +1394,8 @@ capinc_raw_poll(struct file *file, poll_table * wait)
return mask;
}
-int capinc_raw_ioctl(struct inode *inode, struct file *file,
+static int
+capinc_raw_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct capiminor *mp = (struct capiminor *)file->private_data;
@@ -1388,15 +1407,17 @@ int capinc_raw_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
-int
+static int
capinc_raw_release(struct inode *inode, struct file *file)
{
struct capiminor *mp = (struct capiminor *)file->private_data;
if (mp) {
mp->file = 0;
- if (mp->nccip == 0)
+ if (mp->nccip == 0) {
capiminor_free(mp);
+ file->private_data = NULL;
+ }
}
#ifdef _DEBUG_REFCOUNT
@@ -1405,7 +1426,7 @@ capinc_raw_release(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations capinc_raw_fops =
+static struct file_operations capinc_raw_fops =
{
owner: THIS_MODULE,
llseek: capinc_raw_llseek,
@@ -1875,7 +1896,7 @@ endloop:
*eof = 1;
if (off >= len+begin)
return 0;
- *start = page + (off-begin);
+ *start = page + (begin-off);
return ((count < begin+len-off) ? count : begin+len-off);
}
diff --git a/drivers/isdn/avmb1/capidrv.c b/drivers/isdn/avmb1/capidrv.c
index 9521140f1..0b04920f8 100644
--- a/drivers/isdn/avmb1/capidrv.c
+++ b/drivers/isdn/avmb1/capidrv.c
@@ -1,11 +1,25 @@
/*
- * $Id: capidrv.c,v 1.32 2000/04/07 15:19:58 calle Exp $
+ * $Id: capidrv.c,v 1.36 2000/06/26 15:13:41 keil Exp $
*
* ISDN4Linux Driver, using capi20 interface (kernelcapi)
*
* Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: capidrv.c,v $
+ * Revision 1.36 2000/06/26 15:13:41 keil
+ * features should be or'ed
+ *
+ * Revision 1.35 2000/06/19 15:11:25 keil
+ * avoid use of freed structs
+ * changes from 2.4.0-ac21
+ *
+ * Revision 1.34 2000/06/19 13:13:55 calle
+ * Added Modemsupport!
+ *
+ * Revision 1.33 2000/05/06 00:52:36 kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
* Revision 1.32 2000/04/07 15:19:58 calle
* remove warnings
*
@@ -192,7 +206,7 @@
#include "capicmd.h"
#include "capidrv.h"
-static char *revision = "$Revision: 1.32 $";
+static char *revision = "$Revision: 1.36 $";
static int debugmode = 0;
MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -327,6 +341,8 @@ static inline __u32 b1prot(int l2, int l3)
return 2;
case ISDN_PROTO_L2_FAX:
return 4;
+ case ISDN_PROTO_L2_MODEM:
+ return 8;
}
}
@@ -343,6 +359,7 @@ static inline __u32 b2prot(int l2, int l3)
case ISDN_PROTO_L2_V11096:
case ISDN_PROTO_L2_V11019:
case ISDN_PROTO_L2_V11038:
+ case ISDN_PROTO_L2_MODEM:
return 1;
case ISDN_PROTO_L2_FAX:
return 4;
@@ -360,6 +377,7 @@ static inline __u32 b3prot(int l2, int l3)
case ISDN_PROTO_L2_V11096:
case ISDN_PROTO_L2_V11019:
case ISDN_PROTO_L2_V11038:
+ case ISDN_PROTO_L2_MODEM:
default:
return 0;
case ISDN_PROTO_L2_FAX:
@@ -2269,16 +2287,19 @@ static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
card->interface.writebuf_skb = if_sendbuf;
card->interface.writecmd = 0;
card->interface.readstat = if_readstat;
- card->interface.features = ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_X75UI |
- ISDN_FEATURE_L2_X75BUI |
- ISDN_FEATURE_L2_HDLC |
+ card->interface.features = ISDN_FEATURE_L2_HDLC |
ISDN_FEATURE_L2_TRANS |
ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_L2_V11096 |
+ ISDN_FEATURE_P_UNKNOWN |
+ ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_X75UI |
+ ISDN_FEATURE_L2_X75BUI;
+ if (profp->support1 & (1<<2))
+ card->interface.features |= ISDN_FEATURE_L2_V11096 |
ISDN_FEATURE_L2_V11019 |
- ISDN_FEATURE_L2_V11038 |
- ISDN_FEATURE_P_UNKNOWN;
+ ISDN_FEATURE_L2_V11038;
+ if (profp->support1 & (1<<8))
+ card->interface.features |= ISDN_FEATURE_L2_MODEM;
card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
@@ -2401,10 +2422,10 @@ static int capidrv_delcontr(__u16 contr)
}
spin_unlock_irqrestore(&global_lock, flags);
- kfree(card);
-
printk(KERN_INFO "%s: now down.\n", card->name);
+ kfree(card);
+
MOD_DEC_USE_COUNT;
return 0;
diff --git a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
index 848f4af97..d8dd4f97b 100644
--- a/drivers/isdn/avmb1/kcapi.c
+++ b/drivers/isdn/avmb1/kcapi.c
@@ -1,11 +1,17 @@
/*
- * $Id: kcapi.c,v 1.15 2000/04/06 15:01:25 calle Exp $
+ * $Id: kcapi.c,v 1.17 2000/04/21 13:00:56 calle Exp $
*
* Kernel CAPI 2.0 Module
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: kcapi.c,v $
+ * Revision 1.17 2000/04/21 13:00:56 calle
+ * Bugfix: driver_proc_info was also wrong.
+ *
+ * Revision 1.16 2000/04/21 12:38:42 calle
+ * Bugfix: error in proc_ functions, begin-off => off-begin
+ *
* Revision 1.15 2000/04/06 15:01:25 calle
* Bugfix: crash in capidrv.c when reseting a capi controller.
* - changed code order on remove of controller.
@@ -109,7 +115,7 @@
#include <linux/b1lli.h>
#endif
-static char *revision = "$Revision: 1.15 $";
+static char *revision = "$Revision: 1.17 $";
/* ------------------------------------------------------------- */
@@ -1100,7 +1106,7 @@ static int driver_read_proc(char *page, char **start, off_t off,
if (len < off)
return 0;
*eof = 1;
- *start = page - off;
+ *start = page + off;
return ((count < len-off) ? count : len-off);
}
diff --git a/drivers/isdn/avmb1/t1pci.c b/drivers/isdn/avmb1/t1pci.c
index 37ed305c2..07625bd0d 100644
--- a/drivers/isdn/avmb1/t1pci.c
+++ b/drivers/isdn/avmb1/t1pci.c
@@ -1,11 +1,18 @@
/*
- * $Id: t1pci.c,v 1.7 2000/04/07 15:26:55 calle Exp $
+ * $Id: t1pci.c,v 1.9 2000/05/19 15:43:22 calle Exp $
*
* Module for AVM T1 PCI-card.
*
* (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
*
* $Log: t1pci.c,v $
+ * Revision 1.9 2000/05/19 15:43:22 calle
+ * added calls to pci_device_start().
+ *
+ * Revision 1.8 2000/05/06 00:52:36 kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
* Revision 1.7 2000/04/07 15:26:55 calle
* better error message if cabel not connected or T1 has no power.
*
@@ -49,12 +56,13 @@
#include <linux/pci.h>
#include <linux/capi.h>
#include <asm/io.h>
+#include <linux/isdn.h>
#include "capicmd.h"
#include "capiutil.h"
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.9 $";
#undef CONFIG_T1PCI_DEBUG
#undef CONFIG_T1PCI_POLLDEBUG
@@ -305,12 +313,21 @@ int t1pci_init(void)
while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, dev))) {
struct capicardparams param;
- if (pci_enable_device(dev))
- continue;
-
- param.port = pci_resource_start (dev, 1);
+ param.port = pci_resource_start(dev, 1);
param.irq = dev->irq;
- param.membase = pci_resource_start (dev, 0);
+ param.membase = pci_resource_start(dev, 0);
+
+ retval = pci_enable_device (dev);
+ if (retval != 0) {
+ printk(KERN_ERR
+ "%s: failed to enable AVM-T1-PCI at i/o %#x, irq %d, mem %#x err=%d\n",
+ driver->name, param.port, param.irq, param.membase, retval);
+#ifdef MODULE
+ cleanup_module();
+#endif
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
printk(KERN_INFO
"%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 776345f21..3f74c6537 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1452,7 +1452,6 @@ static void vortex_timer(unsigned long data)
mod_timer(&vp->timer, RUN_AT(next_tick));
if (vp->deferred)
outw(FakeIntr, ioaddr + EL3_CMD);
- timer_exit(&vp->timer);
return;
}
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 1957b189f..9bbaf9631 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -1144,14 +1144,14 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
}
-#ifdef MODULE
-
EXPORT_SYMBOL(ei_open);
EXPORT_SYMBOL(ei_close);
EXPORT_SYMBOL(ei_interrupt);
EXPORT_SYMBOL(ethdev_init);
EXPORT_SYMBOL(NS8390_init);
+#if defined(MODULE)
+
int init_module(void)
{
return 0;
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index 5084ea70e..2238ce5a9 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -81,9 +81,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
fi
tristate ' SMC Ultra support' CONFIG_ULTRA
tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32
- if [ "$CONFIG_OBSOLETE" = "y" ]; then
- tristate ' SMC 9194 support' CONFIG_SMC9194
- fi
+ tristate ' SMC 9194 support' CONFIG_SMC9194
fi
bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
@@ -116,7 +114,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
if [ "$CONFIG_OBSOLETE" = "y" ]; then
tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
fi
- bool ' SK_G16 support' CONFIG_SK_G16
+ tristate ' SK_G16 support' CONFIG_SK_G16
fi
if [ "$CONFIG_MCA" = "y" ]; then
tristate ' SKnet MCA support' CONFIG_SKMC
diff --git a/drivers/net/am79c961a.h b/drivers/net/am79c961a.h
index 377c1b5d1..b2c549334 100644
--- a/drivers/net/am79c961a.h
+++ b/drivers/net/am79c961a.h
@@ -73,7 +73,8 @@
#define MODE_COLL 0x0010
#define MODE_DRETRY 0x0020
#define MODE_INTLOOP 0x0040
-#define MODE_PORT0 0x0080
+#define MODE_PORT_AUI 0x0000
+#define MODE_PORT_10BT 0x0080
#define MODE_DRXPA 0x2000
#define MODE_DRXBA 0x4000
#define MODE_PROMISC 0x8000
@@ -105,6 +106,7 @@
#define TST_LCAR 0x0800
#define TST_LCOL 0x1000
#define TST_UFLO 0x4000
+#define TST_BUFF 0x8000
struct dev_priv {
struct enet_statistics stats;
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 5bfa64f95..dd65e6c4e 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -672,21 +672,20 @@ static void arcnet_timeout(struct net_device *dev)
unsigned long flags;
struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
int status = ASTATUS();
+ char *msg;
save_flags(flags);
cli();
if (status & TXFREEflag) { /* transmit _DID_ finish */
- BUGMSG(D_NORMAL, "tx timeout - missed IRQ? (status=%Xh, mask=%Xh, dest=%02Xh)\n",
- status, lp->intmask, lp->lasttrans_dest);
- lp->stats.tx_errors++;
+ msg = " - missed IRQ?";
} else {
- BUGMSG(D_EXTRA, "tx timed out (status=%Xh, intmask=%Xh, dest=%02Xh)\n",
- status, lp->intmask, lp->lasttrans_dest);
- lp->stats.tx_errors++;
+ msg = "";
lp->stats.tx_aborted_errors++;
+ lp->timed_out = 1;
ACOMMAND(NOTXcmd | (lp->cur_tx << 3));
}
+ lp->stats.tx_errors++;
/* make sure we didn't miss a TX IRQ */
AINTMASK(0);
@@ -694,6 +693,12 @@ static void arcnet_timeout(struct net_device *dev)
AINTMASK(lp->intmask);
restore_flags(flags);
+
+ if (jiffies - lp->last_timeout > 10*HZ) {
+ BUGMSG(D_EXTRA, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)\n",
+ msg, status, lp->intmask, lp->lasttrans_dest);
+ lp->last_timeout = jiffies;
+ }
}
@@ -778,12 +783,12 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
didsomething++;
}
/* a transmit finished, and we're interested in it. */
- if (status & lp->intmask & TXFREEflag) {
+ if ((status & lp->intmask & TXFREEflag) || lp->timed_out) {
lp->intmask &= ~TXFREEflag;
BUGMSG(D_DURING, "TX IRQ (stat=%Xh)\n", status);
- if (lp->cur_tx != -1 && !(status & TXACKflag)) {
+ if (lp->cur_tx != -1 && !(status & TXACKflag) && !lp->timed_out) {
if (lp->lasttrans_dest != 0) {
BUGMSG(D_EXTRA, "transmit was not acknowledged! "
"(status=%Xh, dest=%02Xh)\n",
@@ -801,6 +806,7 @@ void arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
release_arcbuf(dev, lp->cur_tx);
lp->cur_tx = -1;
+ lp->timed_out = 0;
didsomething++;
/* send another packet if there is one */
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
index 97f8d0a41..1bc6f6667 100644
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -562,7 +562,8 @@ int com90xx_reset(struct net_device *dev, int really_reset)
/* verify that the ARCnet signature byte is present */
if (readb(lp->mem_start) != TESTvalue) {
- BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
+ if (really_reset)
+ BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
return 1;
}
/* enable extended (512-byte) packets */
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index fa7a5befd..324cf3934 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -23,6 +23,7 @@
This is a compatibility hardware problem.
Versions:
+ 0.12b misc fixes (aris, 06/26/2000)
0.12a port of version 0.12a of 2.2.x kernels to 2.3.x
(aris (aris@conectiva.com.br), 05/19/2000)
0.11e some tweaks about multiple cards support (PdP, jul/aug 1999)
@@ -95,7 +96,7 @@
*/
static const char *version =
- "eepro.c: v0.12a 04/26/2000 aris@conectiva.com.br\n";
+ "eepro.c: v0.12b 04/26/2000 aris@conectiva.com.br\n";
#include <linux/module.h>
@@ -509,6 +510,20 @@ static unsigned eeprom_reg = EEPROM_REG_PRO;
/* ack for tx int */
#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
+/* a complete sel reset */
+#define eepro_complete_selreset(ioaddr) { eepro_dis_int(ioaddr);\
+ lp->stats.tx_errors++;\
+ eepro_sel_reset(ioaddr);\
+ lp->tx_end = \
+ (XMT_LOWER_LIMIT << 8);\
+ lp->tx_start = lp->tx_end;\
+ lp->tx_last = 0;\
+ dev->trans_start = jiffies;\
+ netif_wake_queue(dev);\
+ eepro_en_int(ioaddr);\
+ eepro_en_rx(ioaddr);\
+ }
+
/* Check for a network adaptor of this type, and return '0' if one exists.
If dev->base_addr == 0, probe all likely locations.
If dev->base_addr == 1, always return failure.
@@ -738,7 +753,8 @@ int eepro_probe1(struct net_device *dev, short ioaddr)
*/
if (net_debug > 3)
- printk(", %dK RCV buffer", (int)(dev->mem_end)/1024);
+ printk(", %dK RCV buffer", (int)(dev->mem_end -
+ dev->mem_start)/1024);
/* ............... */
@@ -1085,23 +1101,7 @@ static void eepro_tx_timeout (struct net_device *dev)
one for the the log file */
printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
"network cable problem");
- lp->stats.tx_errors++;
-
- /* Try to restart the adaptor. */
- eepro_sel_reset(ioaddr);
-
- /* Do I also need to flush the transmit buffers here? YES? */
- lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT;
- lp->tx_last = 0;
-
- dev->trans_start = jiffies;
- netif_wake_queue (dev);
-
- /* enabling interrupts */
- eepro_en_int(ioaddr);
-
- /* enabling rx */
- eepro_en_rx(ioaddr);
+ eepro_complete_selreset(ioaddr);
}
@@ -1375,7 +1375,7 @@ set_multicast_list(struct net_device *dev)
/* Re-enable RX and TX interrupts */
eepro_en_int(ioaddr);
}
- eepro_en_rx(ioaddr);
+ eepro_complete_selreset(ioaddr);
}
/* The horrible routine to read a word from the serial EEPROM. */
@@ -1481,7 +1481,8 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
end = last + (((length + 3) >> 1) << 1) + XMT_HEADER;
}
- else end = (XMT_LOWER_LIMIT << 8) + (end - XMT_RAM);
+ else end = (XMT_LOWER_LIMIT << 8) + (end -
+ (XMT_UPPER_LIMIT <<8));
}
outw(last, ioaddr + HOST_ADDRESS_REG);
outw(XMT_CMD, ioaddr + IO_PORT);
@@ -1542,8 +1543,6 @@ hardware_send_packet(struct net_device *dev, void *buf, short length)
printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
return;
}
- eepro_en_int(ioaddr);
-
netif_stop_queue(dev);
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
@@ -1561,9 +1560,6 @@ eepro_rx(struct net_device *dev)
if (net_debug > 5)
printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
- /* clear all interrupts */
- eepro_clear_int(ioaddr);
-
/* Set the read pointer to the start of the RCV */
outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
@@ -1642,9 +1638,6 @@ eepro_rx(struct net_device *dev)
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
-
- /* enable tx/rx interrupts */
- eepro_en_int(ioaddr);
}
static void
@@ -1734,6 +1727,12 @@ eepro_transmit_interrupt(struct net_device *dev)
boguscount--;
}
+ /* if it reached here then it's probable that the adapter won't
+ * interrupt again for tx. in other words: tx timeout what will take
+ * a lot of time to happen, so we'll do a complete selreset.
+ */
+ if (!boguscount)
+ eepro_complete_selreset(ioaddr);
}
#define MAX_EEPRO 8
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 10477c624..27a6b188c 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1145,16 +1145,11 @@ static void speedo_timer(unsigned long data)
/* We must continue to monitor the media. */
sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */
add_timer(&sp->timer);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43)
- timer_exit(&sp->timer);
-#endif /* LINUX_VERSION_CODE */
}
static void speedo_show_state(struct net_device *dev)
{
struct speedo_private *sp = (struct speedo_private *)dev->priv;
- long ioaddr = dev->base_addr;
- int phy_num = sp->phy[0] & 0x1f;
int i;
/* Print a few items for debugging. */
@@ -1181,6 +1176,8 @@ static void speedo_show_state(struct net_device *dev)
(unsigned)sp->rx_ringp[i]->status : 0);
#if 0
+ long ioaddr = dev->base_addr;
+ int phy_num = sp->phy[0] & 0x1f;
for (i = 0; i < 16; i++) {
/* FIXME: what does it mean? --SAW */
if (i == 6) i = 21;
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 0a5f229b9..f1723670c 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -25,6 +25,9 @@
LK1.1.2 (jgarzik):
* Merge becker version 1.09
+ LK1.1.3:
+ * Major bugfix to 1.09 driver (Francis Romieu)
+
*/
/* The user-configurable values.
@@ -90,7 +93,7 @@ static int rx_copybreak = 200;
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
-"epic100.c:v1.09+LK1.1.2 4/28/2000 Written by Donald Becker <becker@scyld.com>\n";
+"epic100.c:v1.09+LK1.1.3 6/17/2000 Written by Donald Becker <becker@scyld.com>\n";
static char version2[] __devinitdata =
" http://www.scyld.com/network/epic100.html\n";
@@ -576,6 +579,7 @@ static int epic_open(struct net_device *dev)
struct epic_private *ep = (struct epic_private *)dev->priv;
long ioaddr = dev->base_addr;
int i;
+ int retval;
ep->full_duplex = ep->force_fd;
@@ -584,9 +588,9 @@ static int epic_open(struct net_device *dev)
MOD_INC_USE_COUNT;
- if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev)) {
+ if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) {
MOD_DEC_USE_COUNT;
- return -EAGAIN;
+ return retval;
}
epic_init_ring(dev);
@@ -1142,8 +1146,8 @@ static int epic_close(struct net_device *dev)
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, inl(ioaddr + INTSTAT));
+ del_timer_sync(&ep->timer);
epic_pause(dev);
- del_timer(&ep->timer);
free_irq(dev->irq, dev);
/* Free all the skbuffs in the Rx queue. */
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index acc1fcd46..b476e290c 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -300,7 +300,6 @@ static void shaper_timer(unsigned long data)
{
struct shaper *sh=(struct shaper *)data;
shaper_kick(sh);
- timer_exit(&sh->timer);
}
/*
diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
index 0699fc879..0f0d15518 100644
--- a/drivers/net/sk_g16.c
+++ b/drivers/net/sk_g16.c
@@ -19,6 +19,8 @@
* Paul Gortmaker, 03/97: Fix for v2.1.x to use read{b,w}
* write{b,w} and memcpy -> memcpy_{to,from}io
*
+ * Jeff Garzik, 06/2000, Modularize
+ *
-*/
static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
@@ -53,8 +55,10 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
* - Try to find out if the board is in 8 Bit or 16 Bit slot.
* If in 8 Bit mode don't use IRQ 11.
* - (Try to make it slightly faster.)
+ * - Power management support
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
@@ -455,7 +459,8 @@ struct priv
/* static variables */
static SK_RAM *board; /* pointer to our memory mapped board components */
-
+static struct net_device *SK_dev;
+unsigned long SK_ioaddr;
static spinlock_t SK_lock = SPIN_LOCK_UNLOCKED;
/* Macros */
@@ -537,7 +542,7 @@ void SK_print_ram(struct net_device *dev);
int __init SK_init(struct net_device *dev)
{
- int ioaddr = 0; /* I/O port address used for POS regs */
+ int ioaddr; /* I/O port address used for POS regs */
int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */
/* get preconfigured base_addr from dev which is done in Space.c */
@@ -548,15 +553,23 @@ int __init SK_init(struct net_device *dev)
if (base_addr > 0x0ff) /* Check a single specified address */
{
+ int rc = -ENODEV;
+
+ ioaddr = base_addr;
+
/* Check if on specified address is a SK_G16 */
+ if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16"))
+ return -EBUSY;
if ( (inb(SK_POS0) == SK_IDLOW) ||
(inb(SK_POS1) == SK_IDHIGH) )
{
- return SK_probe(dev, base_addr);
+ rc = SK_probe(dev, ioaddr);
}
- return -ENODEV; /* Sorry, but on specified address NO SK_G16 */
+ if (rc)
+ release_region(ioaddr, ETHERCARD_TOTAL_SIZE);
+ return rc;
}
else if (base_addr > 0) /* Don't probe at all */
{
@@ -571,7 +584,7 @@ int __init SK_init(struct net_device *dev)
/* Check if I/O Port region is used by another board */
- if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
+ if (!request_region(ioaddr, ETHERCARD_TOTAL_SIZE, "sk_g16"))
{
continue; /* Try next Port address */
}
@@ -581,6 +594,7 @@ int __init SK_init(struct net_device *dev)
if ( !(inb(SK_POS0) == SK_IDLOW) ||
!(inb(SK_POS1) == SK_IDHIGH) )
{
+ release_region(ioaddr, ETHERCARD_TOTAL_SIZE);
continue; /* Try next Port address */
}
@@ -590,6 +604,8 @@ int __init SK_init(struct net_device *dev)
{
return 0; /* Card found and initialized */
}
+
+ release_region(ioaddr, ETHERCARD_TOTAL_SIZE);
}
dev->base_addr = base_addr; /* Write back original base_addr */
@@ -598,6 +614,60 @@ int __init SK_init(struct net_device *dev)
} /* End of SK_init */
+
+static int io = 0; /* 0 == probe */
+MODULE_AUTHOR("Patrick J.D. Weichmann");
+MODULE_DESCRIPTION("Schneider & Koch G16 Ethernet Device Driver");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "0 to probe common ports (unsafe), or the I/O base of the board");
+
+
+#ifdef MODULE
+static int __init SK_init_module (void)
+{
+ int rc;
+
+ SK_dev = init_etherdev (NULL, 0);
+ if (!SK_dev)
+ return -ENOMEM;
+
+ rc = SK_init (SK_dev);
+ if (rc) {
+ unregister_netdev (SK_dev);
+ kfree (SK_dev);
+ SK_dev = NULL;
+ }
+
+ return rc;
+}
+#endif /* MODULE */
+
+
+static void __exit SK_cleanup_module (void)
+{
+ if (SK_dev) {
+ if (SK_dev->priv) {
+ kfree(SK_dev->priv);
+ SK_dev->priv = NULL;
+ }
+ unregister_netdev(SK_dev);
+ kfree(SK_dev);
+ SK_dev = NULL;
+ }
+ if (SK_ioaddr) {
+ release_region(SK_ioaddr, ETHERCARD_TOTAL_SIZE);
+ SK_ioaddr = 0;
+ }
+
+}
+
+
+#ifdef MODULE
+module_init(SK_init_module);
+#endif
+module_exit(SK_cleanup_module);
+
+
/*-
* Function : SK_probe
@@ -774,9 +844,6 @@ int __init SK_probe(struct net_device *dev, short ioaddr)
}
memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */
- /* Grab the I/O Port region */
- request_region(ioaddr, ETHERCARD_TOTAL_SIZE,"sk_g16");
-
/* Assign our Device Driver functions */
dev->open = SK_open;
@@ -817,6 +884,9 @@ int __init SK_probe(struct net_device *dev, short ioaddr)
SK_print_ram(dev);
#endif
+ SK_dev = dev;
+ SK_ioaddr = ioaddr;
+
return 0; /* Initialization done */
} /* End of SK_probe() */
@@ -1078,8 +1148,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode)
/* Prepare LANCE Control and Status Registers */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&SK_lock, flags);
SK_write_reg(CSR3, CSR3_ACON); /* Ale Control !!!THIS MUST BE SET!!!! */
@@ -1114,7 +1183,7 @@ static int SK_lance_init(struct net_device *dev, unsigned short mode)
SK_write_reg(CSR0, CSR0_INIT);
- restore_flags(flags);
+ spin_unlock_irqrestore(&SK_lock, flags);
/* Wait until LANCE finished initialization */
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
index f28196a2f..1b8e48e0f 100644
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -95,10 +95,8 @@ History:
#include <asm/bitops.h>
#include <asm/io.h>
-#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
-#endif
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 9e395d361..51e2d6494 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -1479,7 +1479,6 @@ static void sl_outfill(unsigned long sls)
}
out:
spin_unlock(&sl->lock);
- timer_exit(&sl->outfill_timer);
}
static void sl_keepalive(unsigned long sls)
@@ -1511,7 +1510,6 @@ static void sl_keepalive(unsigned long sls)
out:
spin_unlock(&sl->lock);
- timer_exit(&sl->keepalive_timer);
}
#endif
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index b5f70ff16..85089a8ea 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -26,6 +26,9 @@
LK1.1.2 (jgarzik):
- Merge Becker version 0.15
+
+ LK1.1.3 (Andrew Morton)
+ - Timer cleanups
*/
/* The user-configurable values.
@@ -100,7 +103,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* These identify the driver base version and may not be removed. */
static char version1[] __devinitdata =
-"starfire.c:v0.15+LK1.1.2 4/28/2000 Written by Donald Becker <becker@scyld.com>\n";
+"starfire.c:v0.15+LK1.1.3 6/17/2000 Written by Donald Becker <becker@scyld.com>\n";
static char version2[] __devinitdata =
" Updates and info at http://www.scyld.com/network/starfire.html\n";
@@ -536,15 +539,16 @@ static int netdev_open(struct net_device *dev)
{
struct netdev_private *np = (struct netdev_private *)dev->priv;
long ioaddr = dev->base_addr;
- int i;
+ int i, retval;
/* Do we ever need to reset the chip??? */
MOD_INC_USE_COUNT;
- if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
+ retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+ if (retval) {
MOD_DEC_USE_COUNT;
- return -EAGAIN;
+ return retval;
}
/* Disable the Rx and Tx, and reset the chip. */
@@ -1260,6 +1264,8 @@ static int netdev_close(struct net_device *dev)
netif_stop_queue(dev);
+ del_timer_sync(&np->timer);
+
if (debug > 1) {
printk(KERN_DEBUG "%s: Shutting down ethercard, status was Int %4.4x.\n",
dev->name, readl(ioaddr + IntrStatus));
@@ -1272,8 +1278,6 @@ static int netdev_close(struct net_device *dev)
/* Stop the chip's Tx and Rx processes. */
- del_timer(&np->timer);
-
#ifdef __i386__
if (debug > 2) {
printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n",
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index ada2ba5ca..ae14cf96d 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1290,7 +1290,6 @@ static void lance_set_multicast_retry(unsigned long _opaque)
struct lance_private *lp = (struct lance_private *) dev->priv;
lance_set_multicast(dev);
- timer_exit(&lp->multicast_timer);
}
static void lance_free_hwresources(struct lance_private *lp)
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 24d0d49c9..8398e1bea 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -198,7 +198,7 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
&& (csr12 & 2) == 2) ||
(tp->nway && (csr5 & (TPLnkFail)))) {
/* Link blew? Maybe restart NWay. */
- del_timer(&tp->timer);
+ del_timer_sync(&tp->timer);
t21142_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
add_timer(&tp->timer);
@@ -208,7 +208,7 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
dev->name, medianame[dev->if_port],
(csr12 & 2) ? "failed" : "good");
if ((csr12 & 2) && ! tp->medialock) {
- del_timer(&tp->timer);
+ del_timer_sync(&tp->timer);
t21142_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
add_timer(&tp->timer);
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 918357aff..39f87f7b7 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -298,6 +298,10 @@ void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
tulip_outl_csr(tp, tp->csr6 | csr6_st | csr6_sr, CSR6);
}
+ /*
+ * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this
+ * call is ever done under the spinlock
+ */
if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
if (tp->link_change)
(tp->link_change)(dev, csr5);
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index ae777d165..6b0c7dd15 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -19,7 +19,7 @@
*/
-static const char version[] = "Linux Tulip driver version 0.9.6 (May 31, 2000)\n";
+static const char version[] = "Linux Tulip driver version 0.9.7 (June 17, 2000)\n";
#include <linux/module.h>
#include "tulip.h"
@@ -401,11 +401,12 @@ media_picked:
static int
tulip_open(struct net_device *dev)
{
+ int retval;
MOD_INC_USE_COUNT;
-
- if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
+
+ if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
MOD_DEC_USE_COUNT;
- return -EBUSY;
+ return retval;
}
tulip_init_ring (dev);
@@ -639,7 +640,7 @@ static void tulip_down (struct net_device *dev)
struct tulip_private *tp = (struct tulip_private *) dev->priv;
unsigned long flags;
- del_timer (&tp->timer);
+ del_timer_sync (&tp->timer);
spin_lock_irqsave (&tp->lock, flags);
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 9219557f4..068c2fd14 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -4,7 +4,7 @@
# Maintained by Martin Mares <pci-ids@ucw.cz>
# If you have any new entries, send them to the maintainer.
#
-# $Id: pci.ids,v 1.60 2000/05/01 19:53:05 mj Exp $
+# $Id: pci.ids,v 1.62 2000/06/28 10:56:36 mj Exp $
#
# Vendors, devices and subsystems. Please keep sorted.
@@ -406,6 +406,7 @@
1014 0143 Yotta Input Controller (ytin)
0144 Yotta Video Compositor Output
1014 0145 Yotta Output Controller (ytout)
+ 0156 405GP PLB to PCI Bridge
ffff MPIC-2 interrupt controller
1015 LSI Logic Corp of Canada
1016 ICL Personal Systems
@@ -570,6 +571,10 @@
0001 PowerEdge Expandable RAID Controller 2/Si
0002 PowerEdge Expandable RAID Controller 3/Di
0003 PowerEdge Expandable RAID Controller 3/Si
+ 0004 PowerEdge Expandable RAID Controller 3/Si
+ 0005 PowerEdge Expandable RAID Controller 3/Di
+ 0006 PowerEdge Expandable RAID Controller 3/Di
+ 0008 PowerEdge Expandable RAID Controller 3/Di
1029 Siemens Nixdorf IS
102a LSI Logic
0000 HYDRA
@@ -919,6 +924,7 @@
8009 CXD1947Q i.LINK Controller
8039 CXD3222 i.LINK Controller
8056 Rockwell HCF 56K modem
+ 808a Memory Stick Controller
104e Oak Technology, Inc
0017 OTI-64017
0107 OTI-107 [Spitfire]
@@ -1250,6 +1256,7 @@
036c Bt879(??) Video Capture
13e9 0070 Win/TV (Video Section)
036e Bt878
+ 0070 13eb WinTV/GO
127a 0001 Bt878 Mediastream Controller NTSC
127a 0002 Bt878 Mediastream Controller PAL BG
127a 0003 Bt878a Mediastream Controller PAL BG
@@ -1297,6 +1304,7 @@
1851 1851 FlyVideo'98 EZ - video
1852 1852 FlyVideo'98 (with FM Tuner)
0878 Bt878
+ 0070 13eb WinTV/GO
127a 0001 Bt878 Video Capture (Audio Section)
127a 0002 Bt878 Video Capture (Audio Section)
127a 0003 Bt878 Video Capture (Audio Section)
@@ -1461,8 +1469,6 @@
5055 3c555 Laptop Hurricane
5057 3c575 [Megahertz] 10/100 LAN CardBus
10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card
- 5b57 3c575 [Megahertz] 10/100 LAN CardBus
- 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus
5157 3c575 [Megahertz] 10/100 LAN CardBus
10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card
5257 3CCFE575CT Cyclone CardBus
@@ -1472,9 +1478,11 @@
5951 3c595 100BaseT4 [Vortex]
5952 3c595 100Base-MII [Vortex]
5970 3c597 EISA Fast Demon/Vortex
+ 5b57 3c595 [Megahertz] 10/100 LAN CardBus
+ 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card
6560 3CCFE656 Cyclone CardBus
- 6562 3CCFEM656 Cyclone CardBus
- 6564 3CCFEM656 Cyclone CardBus (0x6564)
+ 6562 3CCFEM656 [id 6562] Cyclone CardBus
+ 6564 3CCFEM656 [id 6564] Cyclone CardBus
7646 3cSOHO100-TX Hurricane
8811 Token ring
9000 3c900 10BaseT [Boomerang]
@@ -1509,14 +1517,15 @@
1028 0098 3C905B Fast Etherlink XL 10/100
1028 0099 3C905B Fast Etherlink XL 10/100
10b7 9055 3C905B Fast Etherlink XL 10/100
+ 9056 3c905B-T4
9058 3c905B-Combo [Deluxe Etherlink XL 10/100]
905a 3c905B-FX [Fast Etherlink XL FX 10/100]
9200 3c905C-TX [Fast Etherlink]
10b7 1000 3C905C-TX Fast Etherlink for PC Management NIC
9800 3c980-TX [Fast Etherlink XL Server Adapter]
10b7 9800 3c980-TX Fast Etherlink XL Server Adapter
- 9805 3c980-TX [10/100 Base-TX NIC(Python-T)]
- 10b7 9805 3c980 10/100 Base-TX NIC(Python-T)
+ 9805 3c980-TX 10/100baseTX NIC [Python-T]
+ 10b7 9805 3c980 10/100baseTX NIC [Python-T]
10b8 Standard Microsystems Corp [SMC]
0005 83C170QF
1055 e000 LANEPIC
@@ -1683,6 +1692,7 @@
0010 Mutara V08 [NV2]
0020 Riva TnT 128 [NV04]
1043 0200 V3400 TNT
+ 1048 0c18 Erazor II SGRAM
1092 0550 Viper V550
1092 0552 Viper V550
1092 4804 Viper V550
@@ -1751,11 +1761,13 @@
1043 400a AGP-V6800 DDR SGRAM
1043 400b AGP-V6800 DDR SDRAM
1102 102e CT6971 GeForce 256 DDR
+ 14af 5021 3D Prophet DDR-DVI
0103 Quadro (GeForce 256 GL)
0110 NV11
0111 NV11 DDR
0113 NV11 GL
0150 NV15 (Geforce2 GTS)
+ 107d 2840 WinFast GeForce2 GTS with TV output
0151 NV15 DDR (Geforce2 GTS)
0152 NV15 Bladerunner (Geforce2 GTS)
0153 NV15 GL (Quadro2)
@@ -2051,10 +2063,18 @@
111a Efficient Networks, Inc
0000 155P-MF1 (FPGA)
0002 155P-MF1 (ASIC)
- 0003 ENI-25P ATM Adapter
+ 0003 ENI-25P ATM
111a 0000 ENI-25p Miniport ATM Adapter
- 0005 Speedstream 30xx ATM Adapter
- 111a 0001 SS-3010 Miniport ATM Adapter
+ 0005 SpeedStream (LANAI)
+ 111a 0001 ENI-3010 ATM
+ 111a 0101 ENI-3010 ATM
+ 111a 0009 ENI-3060 ADSL (VPI=0)
+ 111a 0109 ENI-3060CO ADSL (VPI=0)
+ 111a 0809 ENI-3060 ADSL (VPI=0 or 8)
+ 111a 0909 ENI-3060CO ADSL (VPI=0 or 8)
+ 111a 0a09 ENI-3060 ADSL (VPI=<0..15>)
+ 0007 SpeedStream ADSL
+ 111a 1001 ENI-3061 ADSL [ASIC]
111b Teledyne Electronic Systems
111c Tricord Systems Inc.
0001 Powerbis Bridge
@@ -2114,7 +2134,7 @@
1133 e004 DIVA 2.0 U
e010 DIVA Server BRI-2M
1133 e010 DIVA Server BRI-2M
- e014 DIVA Server PRO-30M
+ e014 DIVA Server PRI-30M
1133 e014 DIVA Server PRI-30M
1134 Mercury Computer Systems
0001 Raceway Bridge
@@ -2281,7 +2301,8 @@
0008 CNB20HE
0009 CNB20LE
0010 CIOB30
- 0011 CMIC_HE
+ 0011 CMIC-HE
+ 0200 OSB4
0201 CSB5
1167 Mutoh Industries Inc
1168 Thine Electronics Inc
@@ -2422,7 +2443,7 @@
11ad f003 LNE100TX
11ad ffff LNE100TX
1385 f004 FA310TX
- c115 LNE100TX Fast Ethernet Adapter
+ c115 LNE100TX [Linksys EtherFast 10/100]
11ae Aztech System Ltd
11af Avid Technology Inc.
11b0 V3 Semiconductor Inc.
@@ -2723,7 +2744,17 @@
1220 AMCC 5933 TMS320C80 DSP/Imaging board
1221 Contec Co., Ltd
1222 Ancor Communications, Inc.
-1223 Heurikon/Computer Products
+1223 Artesyn Communication Products
+ 0003 PM/Link
+ 0004 PM/T1
+ 0005 PM/E1
+ 0008 PM/SLS
+ 0009 BajaSpan Resource Target
+ 000a BajaSpan Section 0
+ 000b BajaSpan Section 1
+ 000c BajaSpan Section 2
+ 000d BajaSpan Section 3
+ 000e PM/PPC
1224 Interactive Images
1225 Power I/O, Inc.
1227 Tech-Source
@@ -4506,25 +4537,25 @@
1a21 82840 840 (Carmel) Chipset Host Bridge (Hub A)
1a23 82840 840 (Carmel) Chipset AGP Bridge
1a24 82840 840 (Carmel) Chipset PCI Bridge (Hub B)
- 2410 82801AA 82810 Chipset ISA Bridge (LPC)
- 2411 82801AA 82810 Chipset IDE
- 2412 82801AA 82810 Chipset USB
- 2413 82801AA 82810 Chipset SMBus
- 2415 82801AA 82810 AC'97 Audio
+ 2410 82801AA ISA Bridge (LPC)
+ 2411 82801AA IDE
+ 2412 82801AA USB
+ 2413 82801AA SMBus
+ 2415 82801AA AC'97 Audio
11d4 0040 SoundMAX Integrated Digital Audio
11d4 0048 SoundMAX Integrated Digital Audio
11d4 5340 SoundMAX Integrated Digital Audio
- 2416 82801AA 82810 AC'97 Modem
- 2418 82801AA 82810 PCI Bridge
- 2420 82801AB 82810 Chipset ISA Bridge (LPC)
- 2421 82801AB 82810 Chipset IDE
- 2422 82801AB 82810 Chipset USB
- 2423 82801AB 82810 Chipset SMBus
- 2425 82801AB 82810 AC'97 Audio
+ 2416 82801AA AC'97 Modem
+ 2418 82801AA PCI Bridge
+ 2420 82801AB ISA Bridge (LPC)
+ 2421 82801AB IDE
+ 2422 82801AB USB
+ 2423 82801AB SMBus
+ 2425 82801AB AC'97 Audio
11d4 0040 SoundMAX Integrated Digital Audio
11d4 0048 SoundMAX Integrated Digital Audio
- 2426 82801AB 82810 AC'97 Modem
- 2428 82801AB 82810 PCI Bridge
+ 2426 82801AB AC'97 Modem
+ 2428 82801AB PCI Bridge
2440 82820 820 (Camino 2) Chipset ISA Bridge (ICH2)
2442 82820 820 (Camino 2) Chipset USB (Hub A)
2443 82820 820 (Camino 2) Chipset SMBus
diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
index 2115cdac9..4b2aacce6 100644
--- a/drivers/pnp/isapnp.c
+++ b/drivers/pnp/isapnp.c
@@ -527,9 +527,11 @@ static void __init isapnp_add_irq_resource(struct pci_dev *dev,
ptr->next = irq;
else
(*res)->irq = irq;
+#ifdef CONFIG_PCI
for (i=0; i<16; i++)
if (irq->map & i)
pcibios_penalize_isa_irq(i);
+#endif
}
/*
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index d9f952ca6..7cbbc3f1f 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -9092,7 +9092,7 @@ aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
}
}
- p->sc = *sc;
+ memcpy(&p->sc, sc, sizeof(struct seeprom_config));
}
p->discenable = 0;
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index d04270af9..8f9d9216d 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -1493,7 +1493,7 @@ static int __init gdth_search_drives(int hanum)
ha->more_proc = FALSE;
if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
- ha->binfo = *(gdth_binfo_str *)ha->pscratch;
+ memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch, sizeof(gdth_binfo_str));
if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index fd1a3ba72..ab934fb2d 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -672,7 +672,7 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#endif
/* Put I2O last so that host specific controllers always win */
#ifdef CONFIG_I2O_SCSI
- I2OSCSI
+ I2OSCSI,
#endif
/* "Removable host adapters" below this line (Parallel Port/USB/other) */
#ifdef CONFIG_SCSI_PPA
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index bdc3e8002..a605233c0 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -12,7 +12,7 @@
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Sun Apr 23 23:41:32 2000 by makisara@kai.makisara.local
+ Last modified: Sat Jun 17 15:21:49 2000 by makisara@kai.makisara.local
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
@@ -65,10 +65,10 @@
#include "constants.h"
-static int buffer_kbs = 0;
-static int write_threshold_kbs = 0;
+static int buffer_kbs;
+static int write_threshold_kbs;
static int max_buffers = (-1);
-static int max_sg_segs = 0;
+static int max_sg_segs;
MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI Tape Driver");
@@ -138,7 +138,7 @@ static int st_max_sg_segs = ST_MAX_SG;
static Scsi_Tape **scsi_tapes = NULL;
-static int modes_defined = FALSE;
+static int modes_defined;
static ST_buffer *new_tape_buffer(int, int);
static int enlarge_buffer(ST_buffer *, int, int);
@@ -870,7 +870,7 @@ static int scsi_tape_open(struct inode *inode, struct file *filp)
static int scsi_tape_flush(struct file *filp)
{
int result = 0, result2;
- static unsigned char cmd[MAX_COMMAND_SIZE];
+ unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
Scsi_Tape *STp;
ST_mode *STm;
@@ -1027,7 +1027,7 @@ static ssize_t
ssize_t retval = 0;
int write_threshold;
int doing_write = 0;
- static unsigned char cmd[MAX_COMMAND_SIZE];
+ unsigned char cmd[MAX_COMMAND_SIZE];
const char *b_point;
Scsi_Request *SRpnt = NULL;
Scsi_Tape *STp;
@@ -1380,7 +1380,7 @@ static ssize_t
static long read_tape(Scsi_Tape *STp, long count, Scsi_Request ** aSRpnt)
{
int transfer, blks, bytes;
- static unsigned char cmd[MAX_COMMAND_SIZE];
+ unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request *SRpnt;
ST_mode *STm;
ST_partstat *STps;
@@ -2945,24 +2945,34 @@ static int st_ioctl(struct inode *inode, struct file *file,
if (mtc.mt_op == MTSETPART) {
if (!STp->can_partitions ||
- mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
- return (-EINVAL);
+ mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) {
+ retval = (-EINVAL);
+ goto out;
+ }
if (mtc.mt_count >= STp->nbr_partitions &&
- (STp->nbr_partitions = nbr_partitions(STp)) < 0)
- return (-EIO);
- if (mtc.mt_count >= STp->nbr_partitions)
- return (-EINVAL);
+ (STp->nbr_partitions = nbr_partitions(STp)) < 0) {
+ retval = (-EIO);
+ goto out;
+ }
+ if (mtc.mt_count >= STp->nbr_partitions) {
+ retval = (-EINVAL);
+ goto out;
+ }
STp->new_partition = mtc.mt_count;
retval = 0;
goto out;
}
if (mtc.mt_op == MTMKPART) {
- if (!STp->can_partitions)
- return (-EINVAL);
+ if (!STp->can_partitions) {
+ retval = (-EINVAL);
+ goto out;
+ }
if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
- (i = partition_tape(STp, mtc.mt_count)) < 0)
- return i;
+ (i = partition_tape(STp, mtc.mt_count)) < 0) {
+ retval = i;
+ goto out;
+ }
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
STp->ps[i].at_sm = 0;
diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c
index 1ac21c429..f04636a65 100644
--- a/drivers/sound/i810_audio.c
+++ b/drivers/sound/i810_audio.c
@@ -1627,12 +1627,11 @@ static int i810_release(struct inode *inode, struct file *file)
state->card->free_pcm_channel(state->card, dmabuf->channel->num);
}
- kfree(state->card->states[state->virt]);
- state->card->states[state->virt] = NULL;
- state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
/* we're covered by the open_sem */
up(&state->open_sem);
+
+ kfree(state->card->states[state->virt]);
+ state->card->states[state->virt] = NULL;
return 0;
}
diff --git a/drivers/sound/vidc.c b/drivers/sound/vidc.c
index 6342e511a..01fb315ab 100644
--- a/drivers/sound/vidc.c
+++ b/drivers/sound/vidc.c
@@ -22,6 +22,7 @@
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/iomd.h>
+#include <asm/irq.h>
#include <asm/system.h>
#include "sound_config.h"
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 5032a9b75..8695c9529 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -48,10 +48,10 @@ comment 'USB Devices'
dep_tristate ' USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate ' USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
- dep_tristate ' USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
- if [ "$CONFIG_USB_STORAGE" != "n" ]; then
- bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
- fi
+ fi
+ dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
+ if [ "$CONFIG_USB_STORAGE" != "n" ]; then
+ bool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
fi
dep_tristate ' USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 7d95c0c98..f59b44497 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -7,7 +7,7 @@
SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
MOD_IN_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) serial
+ALL_SUB_DIRS := $(SUB_DIRS) serial storage
# The target object and module list name.
@@ -49,6 +49,15 @@ else
endif
endif
+ifeq ($(CONFIG_USB_STORAGE),y)
+ SUB_DIRS += storage
+ obj-y += storage/usb-storage.o
+else
+ ifeq ($(CONFIG_USB_STORAGE),m)
+ MOD_IN_SUB_DIRS += storage
+ endif
+endif
+
# Each configuration option enables a list of files.
@@ -73,8 +82,7 @@ obj-$(CONFIG_USB_PRINTER) += printer.o
obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o
obj-$(CONFIG_USB_DC2XX) += dc2xx.o
-obj-$(CONFIG_USB_MDC800) += mdc800.o
-obj-$(CONFIG_USB_STORAGE) += usb-storage.o
+obj-$(CONFIG_USB_MDC800) += mdc800.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_PLUSB) += plusb.o
diff --git a/drivers/usb/microtek.c b/drivers/usb/microtek.c
index 6586b8c40..70a50d91f 100644
--- a/drivers/usb/microtek.c
+++ b/drivers/usb/microtek.c
@@ -52,11 +52,10 @@
* you want it, just send mail.
*
* Status:
- *
- * This driver does not work properly yet.
+ *
* Untested with multiple scanners.
* Untested on SMP.
- * Untested on UHCI.
+ * Untested on a bigendian machine.
*
* History:
*
@@ -97,6 +96,8 @@
* 20000602 Version 0.2.0
* 20000603 various cosmetic changes
* 20000603 Version 0.2.1
+ * 20000620 minor cosmetic changes
+ * 20000620 Version 0.2.2
*/
#include <linux/module.h>
@@ -146,7 +147,7 @@ static struct usb_driver mts_usb_driver = {
/* Internal driver stuff */
-#define MTS_VERSION "0.2.1"
+#define MTS_VERSION "0.2.2"
#define MTS_NAME "microtek usb (rev " MTS_VERSION "): "
#define MTS_WARNING(x...) \
@@ -409,7 +410,7 @@ static int mts_scsi_host_reset (Scsi_Cmnd *srb)
MTS_DEBUG_GOT_HERE();
mts_debug_dump(desc);
- usb_reset_device(desc->usb_dev);
+ usb_reset_device(desc->usb_dev); /*FIXME: untested on new reset code */
return 0; /* RANT why here 0 and not SUCCESS */
}
@@ -519,7 +520,7 @@ static void mts_transfer_done( struct urb *transfer )
MTS_INT_INIT();
- context->srb->result &= MTS_MAX_CHUNK_MASK;
+ context->srb->result &= MTS_SCSI_ERR_MASK;
context->srb->result |= (unsigned)context->status<<1;
mts_transfer_cleanup(transfer);
diff --git a/drivers/usb/microtek.h b/drivers/usb/microtek.h
index 939234560..8dcf734d3 100644
--- a/drivers/usb/microtek.h
+++ b/drivers/usb/microtek.h
@@ -68,6 +68,5 @@ struct mts_desc {
#define MTS_EP_IMAGE 0x3
#define MTS_EP_TOTAL 0x3
-#define MTS_MAX_CHUNK_MASK ~0x3fu
-/*maximum amount the scanner will transmit at once */
+#define MTS_SCSI_ERR_MASK ~0x3fu
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index faf057c16..66f73d3c1 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -30,7 +30,7 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-static const char version[] = "1.17";
+static const char version[] = "1.18";
#define __NO_VERSION__
@@ -49,10 +49,6 @@ static const char version[] = "1.17";
#include <asm/semaphore.h>
#include <linux/wrapper.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
#include "ov511.h"
#undef OV511_GBR422 /* Experimental -- sets the 7610 to GBR422 */
@@ -67,7 +63,7 @@ static const char version[] = "1.17";
#define DEFAULT_HEIGHT 480
#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384)
-#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : 24)
+#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : ((p) == VIDEO_PALETTE_YUV422 ? 8 : 24))
/* PARAMETER VARIABLES: */
static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */
@@ -626,6 +622,7 @@ static void ov511_dump_i2c_regs(struct usb_device *dev)
ov511_dump_i2c_range(dev, 0x00, 0x38);
}
+#if 0
static void ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn)
{
int i;
@@ -636,7 +633,6 @@ static void ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn)
}
}
-#if 0
static void ov511_dump_regs(struct usb_device *dev)
{
PDEBUG(1, "CAMERA INTERFACE REGS");
@@ -1088,7 +1084,7 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v,
#ifdef OV511_GBR422
static void
ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
- int iOutY, int iOutUV, int iHalf, int iWidth)
+ int iOutY, int iOutUV, int iHalf, int iWidth)
{
int k, l, m;
unsigned char *pIn;
@@ -1138,7 +1134,7 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
static void
ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
- int iOutY, int iOutUV, int iHalf, int iWidth)
+ int iOutY, int iOutUV, int iHalf, int iWidth)
{
#ifndef OV511_DUMPPIX
int k, l, m;
@@ -1231,6 +1227,139 @@ ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
}
#endif
+static void
+ov511_parse_data_yuv422(unsigned char *pIn0, unsigned char *pOut0,
+ int iOutY, int iOutUV, int iHalf, int iWidth)
+{
+ int k, l, m;
+ unsigned char *pIn;
+ unsigned char *pOut, *pOut1;
+
+ /* Just copy the Y's if in the first stripe */
+ if (!iHalf) {
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for (k = 0; k < 4; k++) {
+ pOut1 = pOut;
+ for (l = 0; l < 8; l++) {
+ for (m = 0; m < 8; m++) {
+ *pOut1++ = (*pIn++) & 0xF0;
+ }
+ pOut1 += iWidth - 8;
+ }
+ pOut += 8;
+ }
+ }
+
+ /* Use the first half of VUs to calculate value */
+ pIn = pIn0;
+ pOut = pOut0 + iOutUV;
+ for (l = 0; l < 4; l++) {
+ for (m=0; m<8; m++) {
+ unsigned char *p00 = pOut;
+ unsigned char *p01 = pOut+1;
+ unsigned char *p10 = pOut+iWidth;
+ unsigned char *p11 = pOut+iWidth+1;
+ int v = *(pIn+64) - 128;
+ int u = *pIn++ - 128;
+ int uv = ((u >> 4) & 0x0C) + (v >> 6);
+
+ *p00 |= uv;
+ *p01 |= uv;
+ *p10 |= uv;
+ *p11 |= uv;
+
+ pOut += 2;
+ }
+ pOut += (iWidth*2 - 16);
+ }
+
+ /* Just copy the other UV rows */
+ for (l = 0; l < 4; l++) {
+ for (m = 0; m < 8; m++) {
+ int v = *(pIn + 64) - 128;
+ int u = (*pIn++) - 128;
+ int uv = ((u >> 4) & 0x0C) + (v >> 6);
+ *(pOut) = uv;
+ pOut += 2;
+ }
+ pOut += (iWidth*2 - 16);
+ }
+
+ /* Calculate values if it's the second half */
+ if (iHalf) {
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for (k = 0; k < 4; k++) {
+ pOut1 = pOut;
+ for (l=0; l<4; l++) {
+ for (m=0; m<4; m++) {
+ int y10 = *(pIn+8);
+ int y00 = *pIn++;
+ int y11 = *(pIn+8);
+ int y01 = *pIn++;
+ int uv = *pOut1;
+
+ *pOut1 = (y00 & 0xF0) | uv;
+ *(pOut1+1) = (y01 & 0xF0) | uv;
+ *(pOut1+iWidth) = (y10 & 0xF0) | uv;
+ *(pOut1+iWidth+1) = (y11 & 0xF0) | uv;
+
+ pOut1 += 2;
+ }
+ pOut1 += (iWidth*2 - 8);
+ pIn += 8;
+ }
+ pOut += 8;
+ }
+ }
+}
+
+static void
+ov511_parse_data_yuv422p(unsigned char *pIn0, unsigned char *pOut0,
+ int iOutY, int iOutUV, int iWidth, int iHeight)
+{
+ int k, l, m;
+ unsigned char *pIn;
+ unsigned char *pOut, *pOut1;
+ unsigned a = iWidth * iHeight;
+ unsigned w = iWidth / 2;
+
+ pIn = pIn0;
+ pOut = pOut0 + iOutUV + a;
+ for (k = 0; k < 8; k++) {
+ pOut1 = pOut;
+ for (l = 0; l < 8; l++) {
+ *pOut1 = *(pOut1 + w) = *pIn++;
+ pOut1++;
+ }
+ pOut += iWidth;
+ }
+
+ pIn = pIn0 + 64;
+ pOut = pOut0 + iOutUV + a + a/2;
+ for (k = 0; k < 8; k++) {
+ pOut1 = pOut;
+ for (l = 0; l < 8; l++) {
+ *pOut1 = *(pOut1 + w) = *pIn++;
+ pOut1++;
+ }
+ pOut += iWidth;
+ }
+
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for (k = 0; k < 4; k++) {
+ pOut1 = pOut;
+ for (l = 0; l < 8; l++) {
+ for (m = 0; m < 8; m++)
+ *pOut1++ =*pIn++;
+ pOut1 += iWidth - 8;
+ }
+ pOut += 8;
+ }
+}
+
/*
* For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
* The segments represent 4 squares of 8x8 pixels as follows:
@@ -1432,7 +1561,7 @@ check_middle:
frame->segment < frame->width * frame->height / 256) {
int iSegY, iSegUV;
int iY, jY, iUV, jUV;
- int iOutY, iOutUV;
+ int iOutY, iOutYP, iOutUV, iOutUVP;
unsigned char *pOut;
iSegY = iSegUV = frame->segment;
@@ -1465,10 +1594,12 @@ check_middle:
*/
iY = iSegY / (frame->width / WDIV);
jY = iSegY - iY * (frame->width / WDIV);
- iOutY = (iY*HDIV*frame->width + jY*WDIV) * (frame->depth >> 3);
+ iOutYP = iY*HDIV*frame->width + jY*WDIV;
+ iOutY = iOutYP * (frame->depth >> 3);
iUV = iSegUV / (frame->width / WDIV * 2);
jUV = iSegUV - iUV * (frame->width / WDIV * 2);
- iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * (frame->depth >> 3);
+ iOutUVP = iUV*HDIV*2*frame->width + jUV*WDIV/2;
+ iOutUV = iOutUVP * (frame->depth >> 3);
switch (frame->format) {
case VIDEO_PALETTE_GREY:
@@ -1478,6 +1609,16 @@ check_middle:
ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV,
iY & 1, frame->width);
break;
+ case VIDEO_PALETTE_YUV422:
+ ov511_parse_data_yuv422(pData, pOut, iOutY, iOutUV,
+ iY & 1, frame->width);
+ break;
+ case VIDEO_PALETTE_YUV422P:
+ ov511_parse_data_yuv422p (pData, pOut, iOutYP, iOutUVP/2,
+ frame->width, frame->height);
+ break;
+ default:
+ err("Unsupported format: %d", frame->format);
}
pData = &cdata[iPix];
@@ -1995,17 +2136,22 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
- PDEBUG(4, "MCAPTURE");
+ PDEBUG(4, "CMCAPTURE");
PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
vm.frame, vm.width, vm.height, vm.format);
if (vm.format != VIDEO_PALETTE_RGB24 &&
+ vm.format != VIDEO_PALETTE_YUV422 &&
+ vm.format != VIDEO_PALETTE_YUV422P &&
vm.format != VIDEO_PALETTE_GREY)
return -EINVAL;
if ((vm.frame != 0) && (vm.frame != 1))
return -EINVAL;
+ if (vm.width > DEFAULT_WIDTH || vm.height > DEFAULT_HEIGHT)
+ return -EINVAL;
+
if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
return -EBUSY;
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index a36cd70d1..638a91ed9 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -70,7 +70,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
-#define USBLP_WRITE_TIMEOUT (60*HZ) /* 60 seconds */
+#define USBLP_WRITE_TIMEOUT (60*60*HZ) /* 60 minutes */
struct usblp {
struct usb_device *dev; /* USB device */
@@ -147,10 +147,8 @@ static int usblp_check_status(struct usblp *usblp)
info("usblp%d: off-line", usblp->minor);
return -EIO;
}
- if (~status & LP_PERRORP) {
- info("usblp%d: on fire", usblp->minor);
- return -EIO;
- }
+ info("usblp%d: on fire", usblp->minor);
+ return -EIO;
}
return 0;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index c3cce34c3..4355f3773 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -14,6 +14,25 @@
* Peter Berger (pberger@brimson.com)
* Al Borchers (borchers@steinerpoint.com)
*
+* (6/27/2000) pberger and borchers
+* -- Zeroed out sync field in the wakeup_task before first use;
+* otherwise the uninitialized value might prevent the task from
+* being scheduled.
+* -- Initialized ret value to 0 in write_bulk_callback, otherwise
+* the uninitialized value could cause a spurious debugging message.
+*
+* (6/22/2000) pberger and borchers
+* -- Made cond_wait_... inline--apparently on SPARC the flags arg
+* to spin_lock_irqsave cannot be passed to another function
+* to call spin_unlock_irqrestore. Thanks to Pauline Middelink.
+* -- In digi_set_modem_signals the inner nested spin locks use just
+* spin_lock() rather than spin_lock_irqsave(). The old code
+* mistakenly left interrupts off. Thanks to Pauline Middelink.
+* -- copy_from_user (which can sleep) is no longer called while a
+* spinlock is held. We copy to a local buffer before getting
+* the spinlock--don't like the extra copy but the code is simpler.
+* -- Printk and dbg are no longer called while a spin lock is held.
+*
* (6/4/2000) pberger and borchers
* -- Replaced separate calls to spin_unlock_irqrestore and
* interruptible_sleep_on_interruptible with a new function
@@ -119,8 +138,10 @@
* - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to
* recheck the condition they are sleeping on. This is defensive,
* in case a wake up is lost.
+* - Following Documentation/DocBook/kernel-locking.pdf no spin locks
+* are held when calling copy_to/from_user or printk.
*
-* $Id: digi_acceleport.c,v 1.56 2000/06/07 22:47:30 root Exp root $
+* $Id: digi_acceleport.c,v 1.63 2000/06/28 18:28:31 root Exp root $
*/
#include <linux/config.h>
@@ -307,7 +328,7 @@ typedef struct digi_private {
int dp_transmit_idle;
int dp_in_close;
wait_queue_head_t dp_close_wait; /* wait queue for close */
- struct tq_struct dp_tasks;
+ struct tq_struct dp_wakeup_task;
} digi_private_t;
@@ -402,7 +423,7 @@ struct usb_serial_device_type digi_acceleport_device = {
* wake ups. This is used to implement condition variables.
*/
-static long cond_wait_interruptible_timeout_irqrestore(
+static inline long cond_wait_interruptible_timeout_irqrestore(
wait_queue_head_t *q, long timeout,
spinlock_t *lock, unsigned long flags )
{
@@ -465,6 +486,7 @@ static void digi_wakeup_write( struct usb_serial_port *port )
/* wake up other tty processes */
wake_up_interruptible( &tty->write_wait );
+ /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
}
@@ -515,17 +537,17 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count );
if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
count -= len;
buf += len;
- } else {
- dbg(
- "digi_write_oob_command: usb_submit_urb failed, ret=%d",
- ret );
- break;
}
}
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
+ if( ret ) {
+ dbg( "digi_write_oob_command: usb_submit_urb failed, ret=%d",
+ ret );
+ }
+
return( ret );
}
@@ -569,8 +591,8 @@ count );
}
/* len must be a multiple of 4 and small enough to */
- /* guarantee the write will send all data (or none), */
- /* so commands are not split */
+ /* guarantee the write will send buffered data first, */
+ /* so commands are in order with data and not split */
len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
if( len > 4 )
len &= ~3;
@@ -588,35 +610,21 @@ count );
port->write_urb->transfer_buffer_length = len;
}
-#ifdef DEBUG_DATA
- {
- int i;
-
- printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=",
- priv->dp_port_num, port->write_urb->transfer_buffer_length );
- for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
- printk( "%.2x ",
- ((unsigned char *)port->write_urb->transfer_buffer)[i] );
- }
- printk( "\n" );
- }
-#endif
-
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
priv->dp_buf_len = 0;
count -= len;
buf += len;
- } else {
- dbg(
- "digi_write_inb_command: usb_submit_urb failed, ret=%d",
- ret );
- break;
}
}
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ if( ret ) {
+ dbg( "digi_write_inb_command: usb_submit_urb failed, ret=%d",
+ ret );
+ }
+
return( ret );
}
@@ -647,10 +655,10 @@ dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
port_priv->dp_port_num, modem_signals );
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
- spin_lock_irqsave( &port_priv->dp_port_lock, flags );
+ spin_lock( &port_priv->dp_port_lock );
while( oob_port->write_urb->status == -EINPROGRESS ) {
- spin_unlock_irqrestore( &port_priv->dp_port_lock, flags );
+ spin_unlock( &port_priv->dp_port_lock );
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags );
@@ -658,7 +666,7 @@ port_priv->dp_port_num, modem_signals );
return( -EINTR );
}
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
- spin_lock_irqsave( &port_priv->dp_port_lock, flags );
+ spin_lock( &port_priv->dp_port_lock );
}
data[0] = DIGI_CMD_SET_DTR_SIGNAL;
@@ -679,14 +687,16 @@ port_priv->dp_port_num, modem_signals );
port_priv->dp_modem_signals =
(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
| (modem_signals&(TIOCM_DTR|TIOCM_RTS));
- } else {
- dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d",
- ret );
}
- spin_unlock_irqrestore( &port_priv->dp_port_lock, flags );
+ spin_unlock( &port_priv->dp_port_lock );
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
+ if( ret ) {
+ dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d",
+ ret );
+ }
+
return( ret );
}
@@ -1046,12 +1056,19 @@ static int digi_write( struct usb_serial_port *port, int from_user,
int ret,data_len,new_len;
digi_private_t *priv = (digi_private_t *)(port->private);
unsigned char *data = port->write_urb->transfer_buffer;
+ unsigned char user_buf[64]; /* 64 bytes is max USB bulk packet */
unsigned long flags = 0;
dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d",
priv->dp_port_num, count, from_user, in_interrupt() );
+ /* copy user data (which can sleep) before getting spin lock */
+ count = MIN( 64, MIN( count, port->bulk_out_size-2 ) );
+ if( from_user && copy_from_user( user_buf, buf, count ) ) {
+ return( -EFAULT );
+ }
+
/* be sure only one write proceeds at a time */
/* there are races on the port private buffer */
/* and races to check write_urb->status */
@@ -1096,40 +1113,19 @@ priv->dp_port_num, count, from_user, in_interrupt() );
data += priv->dp_buf_len;
/* copy in new data */
- if( from_user ) {
- if( copy_from_user( data, buf, new_len ) ) {
- spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return( -EFAULT );
- }
- } else {
- memcpy( data, buf, new_len );
- }
-
-#ifdef DEBUG_DATA
- {
- int i;
-
- printk( KERN_DEBUG __FILE__ ": digi_write: port=%d, length=%d, data=",
- priv->dp_port_num, port->write_urb->transfer_buffer_length );
- for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
- printk( "%.2x ",
- ((unsigned char *)port->write_urb->transfer_buffer)[i] );
- }
- printk( "\n" );
- }
-#endif
+ memcpy( data, from_user ? user_buf : buf, new_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
ret = new_len;
priv->dp_buf_len = 0;
- } else {
- dbg( "digi_write: usb_submit_urb failed, ret=%d",
- ret );
}
/* return length of new data written, or error */
-dbg( "digi_write: returning %d", ret );
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ if( ret < 0 ) {
+ dbg( "digi_write: usb_submit_urb failed, ret=%d", ret );
+ }
+dbg( "digi_write: returning %d", ret );
return( ret );
}
@@ -1141,7 +1137,7 @@ static void digi_write_bulk_callback( struct urb *urb )
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
digi_private_t *priv = (digi_private_t *)(port->private);
- int ret;
+ int ret = 0;
dbg( "digi_write_bulk_callback: TOP: port=%d", priv->dp_port_num );
@@ -1175,24 +1171,8 @@ dbg( "digi_write_bulk_callback: TOP: port=%d", priv->dp_port_num );
memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
priv->dp_buf_len );
-#ifdef DEBUG_DATA
- {
- int i;
-
- printk( KERN_DEBUG __FILE__ ": digi_write_bulk_callback: port=%d, length=%d, data=",
- priv->dp_port_num, port->write_urb->transfer_buffer_length );
- for( i=0; i<port->write_urb->transfer_buffer_length; ++i ) {
- printk( "%.2x ",
- ((unsigned char *)port->write_urb->transfer_buffer)[i] );
- }
- printk( "\n" );
- }
-#endif
-
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
priv->dp_buf_len = 0;
- } else {
- dbg( "digi_write_bulk_callback: usb_submit_urb failed, ret=%d", ret );
}
}
@@ -1200,13 +1180,16 @@ dbg( "digi_write_bulk_callback: TOP: port=%d", priv->dp_port_num );
/* wake up processes sleeping on writes immediately */
digi_wakeup_write( port );
- spin_unlock( &priv->dp_port_lock );
-
/* also queue up a wakeup at scheduler time, in case we */
/* lost the race in write_chan(). */
- priv->dp_tasks.routine = (void *)digi_wakeup_write_lock;
- priv->dp_tasks.data = (void *)port;
- queue_task( &(priv->dp_tasks), &tq_scheduler );
+ queue_task( &priv->dp_wakeup_task, &tq_scheduler );
+
+ spin_unlock( &priv->dp_port_lock );
+
+ if( ret ) {
+ dbg( "digi_write_bulk_callback: usb_submit_urb failed, ret=%d",
+ ret );
+ }
}
@@ -1219,8 +1202,6 @@ static int digi_write_room( struct usb_serial_port *port )
unsigned long flags = 0;
-dbg( "digi_write_room: TOP: port=%d", priv->dp_port_num );
-
spin_lock_irqsave( &priv->dp_port_lock, flags );
if( port->write_urb->status == -EINPROGRESS )
@@ -1242,8 +1223,6 @@ static int digi_chars_in_buffer( struct usb_serial_port *port )
digi_private_t *priv = (digi_private_t *)(port->private);
-dbg( "digi_chars_in_buffer: TOP: port=%d", priv->dp_port_num );
-
if( port->write_urb->status == -EINPROGRESS ) {
dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 );
/* return( port->bulk_out_size - 2 ); */
@@ -1455,13 +1434,14 @@ static int digi_startup_device( struct usb_serial *serial )
int i,ret = 0;
- spin_lock( &startup_lock );
-
/* be sure this happens exactly once */
+ spin_lock( &startup_lock );
if( device_startup ) {
spin_unlock( &startup_lock );
return( 0 );
}
+ device_startup = 1;
+ spin_unlock( &startup_lock );
/* start reading from each bulk in endpoint for the device */
for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
@@ -1474,10 +1454,6 @@ static int digi_startup_device( struct usb_serial *serial )
}
- device_startup = 1;
-
- spin_unlock( &startup_lock );
-
return( ret );
}
@@ -1516,8 +1492,10 @@ dbg( "digi_startup: TOP" );
priv->dp_transmit_idle = 0;
priv->dp_in_close = 0;
init_waitqueue_head( &priv->dp_close_wait );
- priv->dp_tasks.next = NULL;
- priv->dp_tasks.data = NULL;
+ priv->dp_wakeup_task.next = NULL;
+ priv->dp_wakeup_task.sync = 0;
+ priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock;
+ priv->dp_wakeup_task.data = (void *)(&serial->port[i]);
spin_lock_init( &priv->dp_port_lock );
/* initialize write wait queue for this port */
@@ -1595,17 +1573,6 @@ dbg( "digi_read_bulk_callback: TOP: port=%d", priv->dp_port_num );
goto resubmit;
}
-#ifdef DEBUG_DATA
-if( urb->actual_length ) {
- printk( KERN_DEBUG __FILE__ ": digi_read_bulk_callback: port=%d, length=%d, data=",
- priv->dp_port_num, urb->actual_length );
- for( i=0; i<urb->actual_length; ++i ) {
- printk( "%.2x ", ((unsigned char *)urb->transfer_buffer)[i] );
- }
- printk( "\n" );
-}
-#endif
-
if( urb->actual_length != len + 2 )
err( KERN_INFO "digi_read_bulk_callback: INCOMPLETE PACKET, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", priv->dp_port_num, opcode, len, urb->actual_length, status );
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index b8e2e1d74..430a8fa64 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -51,6 +51,8 @@ struct usb_serial_port {
wait_queue_head_t write_wait;
+ struct tq_struct tqueue; /* task queue for line discipline waking up */
+
void * private; /* data private to the specific port */
};
@@ -178,6 +180,5 @@ static inline int port_paranoia_check (struct usb_serial_port *port, const char
return 0;
}
-
#endif /* ifdef __LINUX_USB_SERIAL_H */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index d60fd8e33..261d5ac00 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -14,6 +14,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/25/2000) gkh
+ * Changed generic_write_bulk_callback to not call wake_up_interruptible
+ * directly, but to have port_softint do it at a safer time.
+ *
* (06/23/2000) gkh
* Cleaned up debugging statements in a quest to find UHCI timeout bug.
*
@@ -222,6 +226,8 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
#ifdef CONFIG_USB_SERIAL_DEBUG
#define DEBUG
@@ -803,36 +809,32 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns
static int generic_write_room (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- int room;
+ int room = 0;
dbg(__FUNCTION__ " - port %d", port->number);
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS)
- room = 0;
- else
+ if (serial->num_bulk_out)
+ if (port->write_urb->status != -EINPROGRESS)
room = port->bulk_out_size;
- dbg(__FUNCTION__ " returns %d", room);
- return (room);
- }
- return (0);
+ dbg(__FUNCTION__ " - returns %d", room);
+ return (room);
}
static int generic_chars_in_buffer (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
+ int chars = 0;
dbg(__FUNCTION__ " - port %d", port->number);
- if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
- return (port->bulk_out_size);
- }
- }
+ if (serial->num_bulk_out)
+ if (port->write_urb->status == -EINPROGRESS)
+ chars = port->write_urb->transfer_buffer_length;
- return (0);
+ dbg (__FUNCTION__ " - returns %d", chars);
+ return (chars);
}
@@ -844,9 +846,10 @@ static void generic_read_bulk_callback (struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int i;
- dbg (__FUNCTION__ " - enter");
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
return;
}
@@ -877,8 +880,6 @@ static void generic_read_bulk_callback (struct urb *urb)
if (usb_submit_urb(urb))
dbg(__FUNCTION__ " - failed resubmitting read urb");
- dbg (__FUNCTION__ " - exit");
-
return;
}
@@ -887,11 +888,11 @@ static void generic_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
- struct tty_struct *tty;
- dbg (__FUNCTION__ " - enter");
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
return;
}
@@ -900,18 +901,36 @@ static void generic_write_bulk_callback (struct urb *urb)
return;
}
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ return;
+}
+
+
+static void port_softint(void *private)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)private;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ struct tty_struct *tty;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (!serial) {
+ return;
+ }
+
tty = port->tty;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+ dbg(__FUNCTION__ " - write wakeup call.");
(tty->ldisc.write_wakeup)(tty);
+ }
wake_up_interruptible(&tty->write_wait);
-
- dbg (__FUNCTION__ " - exit");
-
- return;
}
+
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
{
struct usb_serial *serial = NULL;
@@ -1117,6 +1136,8 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
+ port->tqueue.routine = port_softint;
+ port->tqueue.data = port;
}
/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 8be2dd351..fa7f475c6 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -11,6 +11,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/25/2000) gkh
+ * Fixed bug in visor_unthrottle that should help with the disconnect in PPP
+ * bug that people have been reporting.
+ *
* (06/23/2000) gkh
* Cleaned up debugging statements in a quest to find UHCI timeout bug.
*
@@ -137,7 +141,7 @@ static void visor_unthrottle (struct usb_serial_port *port)
{
dbg(__FUNCTION__ " - port %d", port->number);
- if (usb_unlink_urb (port->read_urb))
+ if (usb_submit_urb (port->read_urb))
dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
return;
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
new file mode 100644
index 000000000..c3dd30dee
--- /dev/null
+++ b/drivers/usb/storage/Makefile
@@ -0,0 +1,32 @@
+#
+# Makefile for the USB Mass Storage device drivers.
+#
+
+O_TARGET := usb-storage.o
+M_OBJS := usb-storage.o
+O_OBJS := scsiglue.o protocol.o transport.o debug.o usb.o
+MOD_LIST_NAME := USB_STORAGE_MODULES
+
+CFLAGS_scsiglue.o:= -I../../scsi/
+CFLAGS_protocol.o:= -I../../scsi/
+CFLAGS_transport.o:= -I../../scsi/
+CFLAGS_debug.o:= -I../../scsi/
+CFLAGS_usb.o:= -I../../scsi/
+
+ifeq ($(CONFIG_USB_STORAGE_DEBUG),y)
+ O_OBJS += debug.o
+endif
+
+ifeq ($(CONFIG_USB_STORAGE_FREECOM),y)
+ O_OBJS += freecom.o
+endif
+
+ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA),y)
+ O_OBJS += shuttle_sm.o
+endif
+
+ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y)
+ O_OBJS += shuttle_cf.o
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
new file mode 100644
index 000000000..d8845d8c2
--- /dev/null
+++ b/drivers/usb/storage/debug.c
@@ -0,0 +1,185 @@
+/* Driver for USB Mass Storage compliant devices
+ * Debugging Functions Source Code File
+ *
+ * $Id: debug.c,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "debug.h"
+
+void usb_stor_show_command(Scsi_Cmnd *srb)
+{
+ char *what = NULL;
+
+ switch (srb->cmnd[0]) {
+ case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+ case REZERO_UNIT: what = "REZERO_UNIT"; break;
+ case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+ case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+ case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+ case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+ case READ_6: what = "READ_6"; break;
+ case WRITE_6: what = "WRITE_6"; break;
+ case SEEK_6: what = "SEEK_6"; break;
+ case READ_REVERSE: what = "READ_REVERSE"; break;
+ case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+ case SPACE: what = "SPACE"; break;
+ case INQUIRY: what = "INQUIRY"; break;
+ case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+ case MODE_SELECT: what = "MODE_SELECT"; break;
+ case RESERVE: what = "RESERVE"; break;
+ case RELEASE: what = "RELEASE"; break;
+ case COPY: what = "COPY"; break;
+ case ERASE: what = "ERASE"; break;
+ case MODE_SENSE: what = "MODE_SENSE"; break;
+ case START_STOP: what = "START_STOP"; break;
+ case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+ case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+ case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+ case SET_WINDOW: what = "SET_WINDOW"; break;
+ case READ_CAPACITY: what = "READ_CAPACITY"; break;
+ case READ_10: what = "READ_10"; break;
+ case WRITE_10: what = "WRITE_10"; break;
+ case SEEK_10: what = "SEEK_10"; break;
+ case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+ case VERIFY: what = "VERIFY"; break;
+ case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+ case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+ case SEARCH_LOW: what = "SEARCH_LOW"; break;
+ case SET_LIMITS: what = "SET_LIMITS"; break;
+ case READ_POSITION: what = "READ_POSITION"; break;
+ case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+ case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+ case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+ case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+ case COMPARE: what = "COMPARE"; break;
+ case COPY_VERIFY: what = "COPY_VERIFY"; break;
+ case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+ case READ_BUFFER: what = "READ_BUFFER"; break;
+ case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+ case READ_LONG: what = "READ_LONG"; break;
+ case WRITE_LONG: what = "WRITE_LONG"; break;
+ case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+ case WRITE_SAME: what = "WRITE_SAME"; break;
+ case READ_TOC: what = "READ_TOC"; break;
+ case LOG_SELECT: what = "LOG_SELECT"; break;
+ case LOG_SENSE: what = "LOG_SENSE"; break;
+ case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+ case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+ case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
+ case READ_12: what = "READ_12"; break;
+ case WRITE_12: what = "WRITE_12"; break;
+ case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+ case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+ case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+ case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+ case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+ case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+ case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+ default: break;
+ }
+ US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len);
+ US_DEBUGP("%02x %02x %02x %02x "
+ "%02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n",
+ srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3],
+ srb->cmnd[4], srb->cmnd[5], srb->cmnd[6], srb->cmnd[7],
+ srb->cmnd[8], srb->cmnd[9], srb->cmnd[10],
+ srb->cmnd[11]);
+}
+
+void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd )
+{
+ int i=0, bufferSize = cmd->request_bufflen;
+ u8* buffer = cmd->request_buffer;
+ struct scatterlist* sg = (struct scatterlist*)cmd->request_buffer;
+
+ US_DEBUGP("Dumping information about %p.\n", cmd );
+ US_DEBUGP("cmd->cmnd[0] value is %d.\n", cmd->cmnd[0] );
+ US_DEBUGP("(MODE_SENSE is %d and MODE_SENSE_10 is %d)\n",
+ MODE_SENSE, MODE_SENSE_10 );
+
+ US_DEBUGP("buffer is %p with length %d.\n", buffer, bufferSize );
+ for ( i=0; i<bufferSize; i+=16 )
+ {
+ US_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x\n"
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buffer[i],
+ buffer[i+1],
+ buffer[i+2],
+ buffer[i+3],
+ buffer[i+4],
+ buffer[i+5],
+ buffer[i+6],
+ buffer[i+7],
+ buffer[i+8],
+ buffer[i+9],
+ buffer[i+10],
+ buffer[i+11],
+ buffer[i+12],
+ buffer[i+13],
+ buffer[i+14],
+ buffer[i+15] );
+ }
+
+ US_DEBUGP("Buffer has %d scatterlists.\n", cmd->use_sg );
+ for ( i=0; i<cmd->use_sg; i++ )
+ {
+ US_DEBUGP("Length of scatterlist %d is %d.\n",i,sg[i].length);
+ US_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x\n"
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ sg[i].address[0],
+ sg[i].address[1],
+ sg[i].address[2],
+ sg[i].address[3],
+ sg[i].address[4],
+ sg[i].address[5],
+ sg[i].address[6],
+ sg[i].address[7],
+ sg[i].address[8],
+ sg[i].address[9],
+ sg[i].address[10],
+ sg[i].address[11],
+ sg[i].address[12],
+ sg[i].address[13],
+ sg[i].address[14],
+ sg[i].address[15]);
+ }
+}
+
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
new file mode 100644
index 000000000..ab5bef0ac
--- /dev/null
+++ b/drivers/usb/storage/debug.h
@@ -0,0 +1,66 @@
+/* Driver for USB Mass Storage compliant devices
+ * Debugging Functions Header File
+ *
+ * $Id: debug.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/blk.h>
+#include "scsi.h"
+
+#define USB_STORAGE "usb-storage: "
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+void usb_stor_show_command(Scsi_Cmnd *srb);
+void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd );
+#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE ## x )
+#define US_DEBUGPX(x...) printk( ## x )
+#define US_DEBUG(x) x
+#else
+#define US_DEBUGP(x...)
+#define US_DEBUGPX(x...)
+#define US_DEBUG(x)
+#endif
+
+#endif
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
new file mode 100644
index 000000000..d3624dc76
--- /dev/null
+++ b/drivers/usb/storage/protocol.c
@@ -0,0 +1,304 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * $Id: protocol.c,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "scsiglue.h"
+#include "transport.h"
+
+/***********************************************************************
+ * Protocol routines
+ ***********************************************************************/
+
+void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int old_cmnd = 0;
+
+ /* Fix some commands -- this is a form of mode translation
+ * ATAPI devices only accept 12 byte long commands
+ *
+ * NOTE: This only works because a Scsi_Cmnd struct field contains
+ * a unsigned char cmnd[12], so we know we have storage available
+ */
+
+ /* set command length to 12 bytes */
+ srb->cmd_len = 12;
+
+ /* determine the correct (or minimum) data length for these commands */
+ switch (srb->cmnd[0]) {
+
+ /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+ case MODE_SENSE:
+ case MODE_SELECT:
+ /* save the command so we can tell what it was */
+ old_cmnd = srb->cmnd[0];
+
+ srb->cmnd[11] = 0;
+ srb->cmnd[10] = 0;
+ srb->cmnd[9] = 0;
+ srb->cmnd[8] = srb->cmnd[4];
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = 0;
+ srb->cmnd[4] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = srb->cmnd[2];
+ srb->cmnd[1] = srb->cmnd[1];
+ srb->cmnd[0] = srb->cmnd[0] | 0x40;
+ break;
+
+ /* change READ_6/WRITE_6 to READ_10/WRITE_10, which
+ * are ATAPI commands */
+ case WRITE_6:
+ case READ_6:
+ srb->cmnd[11] = 0;
+ srb->cmnd[10] = 0;
+ srb->cmnd[9] = 0;
+ srb->cmnd[8] = srb->cmnd[4];
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = srb->cmnd[3];
+ srb->cmnd[4] = srb->cmnd[2];
+ srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+ srb->cmnd[2] = 0;
+ srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+ srb->cmnd[0] = srb->cmnd[0] | 0x20;
+ break;
+ } /* end switch on cmnd[0] */
+
+ /* convert MODE_SELECT data here */
+ if (old_cmnd == MODE_SELECT)
+ usb_stor_scsiSense6to10(srb);
+
+ /* send the command to the transport layer */
+ usb_stor_invoke_transport(srb, us);
+
+ /* Fix the MODE_SENSE data if we translated the command */
+ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
+ usb_stor_scsiSense10to6(srb);
+
+ /* Fix-up the return data from an INQUIRY command to show
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ */
+ if (srb->cmnd[0] == INQUIRY) {
+ ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+ }
+}
+
+
+void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int old_cmnd = 0;
+
+ /* fix some commands -- this is a form of mode translation
+ * UFI devices only accept 12 byte long commands
+ *
+ * NOTE: This only works because a Scsi_Cmnd struct field contains
+ * a unsigned char cmnd[12], so we know we have storage available
+ */
+
+ /* set command length to 12 bytes (this affects the transport layer) */
+ srb->cmd_len = 12;
+
+ /* determine the correct (or minimum) data length for these commands */
+ switch (srb->cmnd[0]) {
+
+ /* for INQUIRY, UFI devices only ever return 36 bytes */
+ case INQUIRY:
+ srb->cmnd[4] = 36;
+ break;
+
+ /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+ case MODE_SENSE:
+ case MODE_SELECT:
+ /* save the command so we can tell what it was */
+ old_cmnd = srb->cmnd[0];
+
+ srb->cmnd[11] = 0;
+ srb->cmnd[10] = 0;
+ srb->cmnd[9] = 0;
+
+ /* if we're sending data, we send all. If getting data,
+ * get the minimum */
+ if (srb->cmnd[0] == MODE_SELECT)
+ srb->cmnd[8] = srb->cmnd[4];
+ else
+ srb->cmnd[8] = 8;
+
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = 0;
+ srb->cmnd[4] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = srb->cmnd[2];
+ srb->cmnd[1] = srb->cmnd[1];
+ srb->cmnd[0] = srb->cmnd[0] | 0x40;
+ break;
+
+ /* again, for MODE_SENSE_10, we get the minimum (8) */
+ case MODE_SENSE_10:
+ srb->cmnd[7] = 0;
+ srb->cmnd[8] = 8;
+ break;
+
+ /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
+ case REQUEST_SENSE:
+ srb->cmnd[4] = 18;
+ break;
+
+ /* change READ_6/WRITE_6 to READ_10/WRITE_10, which
+ * are UFI commands */
+ case WRITE_6:
+ case READ_6:
+ srb->cmnd[11] = 0;
+ srb->cmnd[10] = 0;
+ srb->cmnd[9] = 0;
+ srb->cmnd[8] = srb->cmnd[4];
+ srb->cmnd[7] = 0;
+ srb->cmnd[6] = 0;
+ srb->cmnd[5] = srb->cmnd[3];
+ srb->cmnd[4] = srb->cmnd[2];
+ srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+ srb->cmnd[2] = 0;
+ srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+ srb->cmnd[0] = srb->cmnd[0] | 0x20;
+ break;
+ } /* end switch on cmnd[0] */
+
+ /* convert MODE_SELECT data here */
+ if (old_cmnd == MODE_SELECT)
+ usb_stor_scsiSense6to10(srb);
+
+ /* send the command to the transport layer */
+ usb_stor_invoke_transport(srb, us);
+
+ /* Fix the MODE_SENSE data if we translated the command */
+ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
+ usb_stor_scsiSense10to6(srb);
+
+ /* Fix-up the return data from an INQUIRY command to show
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ */
+ if (srb->cmnd[0] == INQUIRY) {
+ ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+ }
+}
+
+void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+ /* This code supports devices which do not support {READ|WRITE}_6
+ * Apparently, neither Windows or MacOS will use these commands,
+ * so some devices do not support them
+ */
+ if (us->flags & US_FL_MODE_XLATE) {
+
+ /* translate READ_6 to READ_10 */
+ if (srb->cmnd[0] == 0x08) {
+
+ /* get the control */
+ srb->cmnd[9] = us->srb->cmnd[5];
+
+ /* get the length */
+ srb->cmnd[8] = us->srb->cmnd[6];
+ srb->cmnd[7] = 0;
+
+ /* set the reserved area to 0 */
+ srb->cmnd[6] = 0;
+
+ /* get LBA */
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
+
+ /* LUN and other info in cmnd[1] can stay */
+
+ /* fix command code */
+ srb->cmnd[0] = 0x28;
+
+ US_DEBUGP("Changing READ_6 to READ_10\n");
+ US_DEBUG(usb_stor_show_command(srb));
+ }
+
+ /* translate WRITE_6 to WRITE_10 */
+ if (srb->cmnd[0] == 0x0A) {
+
+ /* get the control */
+ srb->cmnd[9] = us->srb->cmnd[5];
+
+ /* get the length */
+ srb->cmnd[8] = us->srb->cmnd[4];
+ srb->cmnd[7] = 0;
+
+ /* set the reserved area to 0 */
+ srb->cmnd[6] = 0;
+
+ /* get LBA */
+ srb->cmnd[5] = us->srb->cmnd[3];
+ srb->cmnd[4] = us->srb->cmnd[2];
+ srb->cmnd[3] = 0;
+ srb->cmnd[2] = 0;
+
+ /* LUN and other info in cmnd[1] can stay */
+
+ /* fix command code */
+ srb->cmnd[0] = 0x2A;
+
+ US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
+ US_DEBUG(usb_stor_show_command(us->srb));
+ }
+ } /* if (us->flags & US_FL_MODE_XLATE) */
+
+ /* send the command to the transport layer */
+ usb_stor_invoke_transport(srb, us);
+
+ /* fix the results of an INQUIRY */
+ if (srb->cmnd[0] == INQUIRY) {
+ US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
+ ((unsigned char*)us->srb->request_buffer)[2] |= 2;
+ }
+}
+
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
new file mode 100644
index 000000000..1a343af41
--- /dev/null
+++ b/drivers/usb/storage/protocol.h
@@ -0,0 +1,63 @@
+/* Driver for USB Mass Storage compliant devices
+ * Protocol Functions Header File
+ *
+ * $Id: protocol.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PROTOCOL_H_
+#define _PROTOCOL_H_
+
+#include <linux/blk.h>
+#include "scsi.h"
+#include "usb.h"
+
+/* Sub Classes */
+
+#define US_SC_RBC 0x01 /* Typically, flash devices */
+#define US_SC_8020 0x02 /* CD-ROM */
+#define US_SC_QIC 0x03 /* QIC-157 Tapes */
+#define US_SC_UFI 0x04 /* Floppy */
+#define US_SC_8070 0x05 /* Removable media */
+#define US_SC_SCSI 0x06 /* Transparent */
+#define US_SC_MIN US_SC_RBC
+#define US_SC_MAX US_SC_SCSI
+
+extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*);
+extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*);
+extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*);
+
+#endif
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
new file mode 100644
index 000000000..71487235d
--- /dev/null
+++ b/drivers/usb/storage/scsiglue.c
@@ -0,0 +1,824 @@
+/* Driver for USB Mass Storage compliant devices
+ * SCSI layer glue code
+ *
+ * $Id: scsiglue.c,v 1.2 2000/06/27 10:20:39 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "scsiglue.h"
+#include "usb.h"
+#include "debug.h"
+
+#include <linux/malloc.h>
+
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
+/* FIXME: we need to use the new direction indicators in the Scsi_Cmnd
+ * structure, not this table. First we need to evaluate if it's being set
+ * correctly for us, though
+ */
+unsigned char us_direction[256/8] = {
+ 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+ 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+/*
+ * kernel thread actions
+ */
+
+#define US_ACT_COMMAND 1
+#define US_ACT_DEVICE_RESET 2
+#define US_ACT_BUS_RESET 3
+#define US_ACT_HOST_RESET 4
+#define US_ACT_EXIT 5
+
+/***********************************************************************
+ * Host functions
+ ***********************************************************************/
+
+static const char* host_info(struct Scsi_Host *host)
+{
+ return "SCSI emulation for USB Mass Storage devices";
+}
+
+/* detect a virtual adapter (always works) */
+static int detect(struct SHT *sht)
+{
+ struct us_data *us;
+ char local_name[32];
+
+ /* This is not nice at all, but how else are we to get the
+ * data here? */
+ us = (struct us_data *)sht->proc_dir;
+
+ /* set up the name of our subdirectory under /proc/scsi/ */
+ sprintf(local_name, "usb-storage-%d", us->host_number);
+ sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
+ if (!sht->proc_name)
+ return 0;
+ strcpy(sht->proc_name, local_name);
+
+ /* we start with no /proc directory entry */
+ sht->proc_dir = NULL;
+
+ /* register the host */
+ us->host = scsi_register(sht, sizeof(us));
+ if (us->host) {
+ us->host->hostdata[0] = (unsigned long)us;
+ us->host_no = us->host->host_no;
+ return 1;
+ }
+
+ /* odd... didn't register properly. Abort and free pointers */
+ kfree(sht->proc_name);
+ sht->proc_name = NULL;
+ return 0;
+}
+
+/* Release all resources used by the virtual host
+ *
+ * NOTE: There is no contention here, because we're allready deregistered
+ * the driver and we're doing each virtual host in turn, not in parallel
+ */
+static int release(struct Scsi_Host *psh)
+{
+ struct us_data *us = (struct us_data *)psh->hostdata[0];
+
+ US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
+
+ /* Kill the control threads
+ *
+ * Enqueue the command, wake up the thread, and wait for
+ * notification that it's exited.
+ */
+ US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
+ us->action = US_ACT_EXIT;
+ up(&(us->sleeper));
+ down(&(us->notify));
+
+ /* free the data structure we were using */
+ US_DEBUGP("-- freeing URB\n");
+ kfree(us->current_urb);
+ (struct us_data*)psh->hostdata[0] = NULL;
+
+ /* we always have a successful release */
+ return 0;
+}
+
+/* run command */
+static int command( Scsi_Cmnd *srb )
+{
+ US_DEBUGP("Bad use of us_command\n");
+
+ return DID_BAD_TARGET << 16;
+}
+
+/* run command */
+static int queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
+{
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+ US_DEBUGP("queuecommand() called\n");
+ srb->host_scribble = (unsigned char *)us;
+
+ /* get exclusive access to the structures we want */
+ down(&(us->queue_exclusion));
+
+ /* enqueue the command */
+ us->queue_srb = srb;
+ srb->scsi_done = done;
+ us->action = US_ACT_COMMAND;
+
+ /* wake up the process task */
+ up(&(us->queue_exclusion));
+ up(&(us->sleeper));
+
+ return 0;
+}
+
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command abort
+ *
+ * Note that this is really only meaningful right now for CBI transport
+ * devices which have failed to give us the command completion interrupt
+ */
+static int command_abort( Scsi_Cmnd *srb )
+{
+ struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+ api_wrapper_data *awd = (api_wrapper_data *)us->current_urb->context;
+
+ US_DEBUGP("command_abort() called\n");
+
+ /* if we're stuck waiting for an IRQ, simulate it */
+ if (us->ip_wanted) {
+ US_DEBUGP("-- simulating missing IRQ\n");
+ up(&(us->ip_waitq));
+ return SUCCESS;
+ }
+
+ /* if we have an urb pending, let's wake the control thread up */
+ if (us->current_urb->status == -EINPROGRESS) {
+ /* cancel the URB */
+ usb_unlink_urb(us->current_urb);
+
+ /* wake the control thread up */
+ if (waitqueue_active(awd->wakeup))
+ wake_up(awd->wakeup);
+
+ /* wait for us to be done */
+ down(&(us->notify));
+ return SUCCESS;
+ }
+
+ US_DEBUGP ("-- nothing to abort\n");
+ return FAILED;
+}
+
+/* FIXME: this doesn't do anything right now */
+static int bus_reset( Scsi_Cmnd *srb )
+{
+ // struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+ printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
+ US_DEBUGP("Bus reset requested\n");
+ // us->transport_reset(us);
+ return FAILED;
+}
+
+/* FIXME: This doesn't actually reset anything */
+static int host_reset( Scsi_Cmnd *srb )
+{
+ printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
+ return FAILED;
+}
+
+/***********************************************************************
+ * /proc/scsi/ functions
+ ***********************************************************************/
+
+/* we use this macro to help us write into the buffer */
+#undef SPRINTF
+#define SPRINTF(args...) \
+ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
+
+static int proc_info (char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
+{
+ struct us_data *us;
+ char *pos = buffer;
+
+ /* if someone is sending us data, just throw it away */
+ if (inout)
+ return length;
+
+ /* lock the data structures */
+ down(&us_list_semaphore);
+
+ /* find our data from hostno */
+ us = us_list;
+ while (us) {
+ if (us->host_no == hostno)
+ break;
+ us = us->next;
+ }
+
+ /* if we couldn't find it, we return an error */
+ if (!us) {
+ up(&us_list_semaphore);
+ return -ESRCH;
+ }
+
+ /* print the controler name */
+ SPRINTF(" Host scsi%d: usb-storage\n", hostno);
+
+ /* print product, vendor, and serial number strings */
+ SPRINTF(" Vendor: %s\n", us->vendor);
+ SPRINTF(" Product: %s\n", us->product);
+ SPRINTF("Serial Number: %s\n", us->serial);
+
+ /* show the protocol and transport */
+ SPRINTF(" Protocol: %s\n", us->protocol_name);
+ SPRINTF(" Transport: %s\n", us->transport_name);
+
+ /* show the GUID of the device */
+ SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
+
+ /* release our lock on the data structures */
+ up(&us_list_semaphore);
+
+ /*
+ * Calculate start of next buffer, and return value.
+ */
+ *start = buffer + offset;
+
+ if ((pos - buffer) < offset)
+ return (0);
+ else if ((pos - buffer - offset) < length)
+ return (pos - buffer - offset);
+ else
+ return (length);
+}
+
+/*
+ * this defines our 'host'
+ */
+
+Scsi_Host_Template usb_stor_host_template = {
+ name: "usb-storage",
+ proc_info: proc_info,
+ info: host_info,
+
+ detect: detect,
+ release: release,
+ command: command,
+ queuecommand: queuecommand,
+
+ eh_abort_handler: command_abort,
+ eh_device_reset_handler:bus_reset,
+ eh_bus_reset_handler: bus_reset,
+ eh_host_reset_handler: host_reset,
+
+ can_queue: 1,
+ this_id: -1,
+
+ sg_tablesize: SG_ALL,
+ cmd_per_lun: 1,
+ present: 0,
+ unchecked_isa_dma: FALSE,
+ use_clustering: TRUE,
+ use_new_eh_code: TRUE,
+ emulated: TRUE
+};
+
+unsigned char usb_stor_sense_notready[12] = {
+ [0] = 0x70, /* current error */
+ [2] = 0x02, /* not ready */
+ [5] = 0x0a, /* additional length */
+ [10] = 0x04, /* not ready */
+ [11] = 0x03 /* manual intervention */
+};
+
+#define USB_STOR_SCSI_SENSE_HDRSZ 4
+#define USB_STOR_SCSI_SENSE_10_HDRSZ 8
+
+struct usb_stor_scsi_sense_hdr
+{
+ __u8* dataLength;
+ __u8* mediumType;
+ __u8* devSpecParms;
+ __u8* blkDescLength;
+};
+
+typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr;
+
+union usb_stor_scsi_sense_hdr_u
+{
+ Usb_Stor_Scsi_Sense_Hdr hdr;
+ __u8* array[USB_STOR_SCSI_SENSE_HDRSZ];
+};
+
+typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u;
+
+struct usb_stor_scsi_sense_hdr_10
+{
+ __u8* dataLengthMSB;
+ __u8* dataLengthLSB;
+ __u8* mediumType;
+ __u8* devSpecParms;
+ __u8* reserved1;
+ __u8* reserved2;
+ __u8* blkDescLengthMSB;
+ __u8* blkDescLengthLSB;
+};
+
+typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10;
+
+union usb_stor_scsi_sense_hdr_10_u
+{
+ Usb_Stor_Scsi_Sense_Hdr_10 hdr;
+ __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ];
+};
+
+typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u;
+
+void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*,
+ Usb_Stor_Scsi_Sense_Hdr_10_u*, int* );
+
+int usb_stor_scsiSense10to6( Scsi_Cmnd* the10 )
+{
+ __u8 *buffer=0;
+ int outputBufferSize = 0;
+ int length=0;
+ struct scatterlist *sg = 0;
+ int i=0, j=0, element=0;
+ Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
+ Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
+ int sb=0,si=0,db=0,di=0;
+ int sgLength=0;
+
+ US_DEBUGP("-- converting 10 byte sense data to 6 byte\n");
+ the10->cmnd[0] = the10->cmnd[0] & 0xBF;
+
+ /* Determine buffer locations */
+ usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations,
+ &length );
+
+ /* Work out minimum buffer to output */
+ outputBufferSize = *the10Locations.hdr.dataLengthLSB;
+ outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ;
+
+ /* Check to see if we need to trucate the output */
+ if ( outputBufferSize > length )
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" );
+ printk( KERN_WARNING USB_STORAGE
+ "outputBufferSize is %d and length is %d.\n",
+ outputBufferSize, length );
+ }
+ outputBufferSize = length;
+
+ /* Data length */
+ if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Command will be truncated to fit in SENSE6 buffer.\n" );
+ *the6Locations.hdr.dataLength = 0xff;
+ }
+ else
+ {
+ *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB;
+ }
+
+ /* Medium type and DevSpecific parms */
+ *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType;
+ *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms;
+
+ /* Block descriptor length */
+ if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Command will be truncated to fit in SENSE6 buffer.\n" );
+ *the6Locations.hdr.blkDescLength = 0xff;
+ }
+ else
+ {
+ *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB;
+ }
+
+ if ( the10->use_sg == 0 )
+ {
+ buffer = the10->request_buffer;
+ /* Copy the rest of the data */
+ memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
+ &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ );
+ /* initialise last bytes left in buffer due to smaller header */
+ memset( &(buffer[outputBufferSize
+ -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]),
+ 0,
+ USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
+ }
+ else
+ {
+ sg = (struct scatterlist *) the10->request_buffer;
+ /* scan through this scatterlist and figure out starting positions */
+ for ( i=0; i < the10->use_sg; i++)
+ {
+ sgLength = sg[i].length;
+ for ( j=0; j<sgLength; j++ )
+ {
+ /* get to end of header */
+ if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ db=i;
+ di=j;
+ }
+ if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ sb=i;
+ si=j;
+ /* we've found both sets now, exit loops */
+ j=sgLength;
+ i=the10->use_sg;
+ }
+ element++;
+ }
+ }
+
+ /* Now we know where to start the copy from */
+ element = USB_STOR_SCSI_SENSE_HDRSZ;
+ while ( element < outputBufferSize
+ -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
+ {
+ /* check limits */
+ if ( sb >= the10->use_sg ||
+ si >= sg[sb].length ||
+ db >= the10->use_sg ||
+ di >= sg[db].length )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ /* copy one byte */
+ sg[db].address[di] = sg[sb].address[si];
+
+ /* get next destination */
+ if ( sg[db].length-1 == di )
+ {
+ db++;
+ di=0;
+ }
+ else
+ {
+ di++;
+ }
+
+ /* get next source */
+ if ( sg[sb].length-1 == si )
+ {
+ sb++;
+ si=0;
+ }
+ else
+ {
+ si++;
+ }
+
+ element++;
+ }
+ /* zero the remaining bytes */
+ while ( element < outputBufferSize )
+ {
+ /* check limits */
+ if ( db >= the10->use_sg ||
+ di >= sg[db].length )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ sg[db].address[di] = 0;
+
+ /* get next destination */
+ if ( sg[db].length-1 == di )
+ {
+ db++;
+ di=0;
+ }
+ else
+ {
+ di++;
+ }
+ element++;
+ }
+ }
+
+ /* All done any everything was fine */
+ return 0;
+}
+
+int usb_stor_scsiSense6to10( Scsi_Cmnd* the6 )
+{
+ /* will be used to store part of buffer */
+ __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ],
+ *buffer=0;
+ int outputBufferSize = 0;
+ int length=0;
+ struct scatterlist *sg = 0;
+ int i=0, j=0, element=0;
+ Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
+ Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
+ int sb=0,si=0,db=0,di=0;
+ int lsb=0,lsi=0,ldb=0,ldi=0;
+
+ US_DEBUGP("-- converting 6 byte sense data to 10 byte\n");
+ the6->cmnd[0] = the6->cmnd[0] | 0x40;
+
+ /* Determine buffer locations */
+ usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations,
+ &length );
+
+ /* Work out minimum buffer to output */
+ outputBufferSize = *the6Locations.hdr.dataLength;
+ outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ;
+
+ /* Check to see if we need to trucate the output */
+ if ( outputBufferSize > length )
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" );
+ printk( KERN_WARNING USB_STORAGE
+ "outputBufferSize is %d and length is %d.\n",
+ outputBufferSize, length );
+ }
+ outputBufferSize = length;
+
+ /* Block descriptor length - save these before overwriting */
+ tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB;
+ tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB;
+ *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength;
+ *the10Locations.hdr.blkDescLengthMSB = 0;
+
+ /* reserved - save these before overwriting */
+ tempBuffer[0] = *the10Locations.hdr.reserved1;
+ tempBuffer[1] = *the10Locations.hdr.reserved2;
+ *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0;
+
+ /* Medium type and DevSpecific parms */
+ *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms;
+ *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType;
+
+ /* Data length */
+ *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength;
+ *the10Locations.hdr.dataLengthMSB = 0;
+
+ if ( !the6->use_sg )
+ {
+ buffer = the6->request_buffer;
+ /* Copy the rest of the data */
+ memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
+ outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ );
+ /* Put the first four bytes (after header) in place */
+ memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ tempBuffer,
+ USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
+ }
+ else
+ {
+ sg = (struct scatterlist *) the6->request_buffer;
+ /* scan through this scatterlist and figure out ending positions */
+ for ( i=0; i < the6->use_sg; i++)
+ {
+ for ( j=0; j<sg[i].length; j++ )
+ {
+ /* get to end of header */
+ if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ ldb=i;
+ ldi=j;
+ }
+ if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ lsb=i;
+ lsi=j;
+ /* we've found both sets now, exit loops */
+ j=sg[i].length;
+ i=the6->use_sg;
+ break;
+ }
+ element++;
+ }
+ }
+ /* scan through this scatterlist and figure out starting positions */
+ element = length-1;
+ /* destination is the last element */
+ db=the6->use_sg-1;
+ di=sg[db].length-1;
+ for ( i=the6->use_sg-1; i >= 0; i--)
+ {
+ for ( j=sg[i].length-1; j>=0; j-- )
+ {
+ /* get to end of header and find source for copy */
+ if ( element == length - 1
+ - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
+ {
+ sb=i;
+ si=j;
+ /* we've found both sets now, exit loops */
+ j=-1;
+ i=-1;
+ }
+ element--;
+ }
+ }
+ /* Now we know where to start the copy from */
+ element = length-1
+ - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ);
+ while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* check limits */
+ if ( ( sb <= lsb && si < lsi ) ||
+ ( db <= ldb && di < ldi ) )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ /* copy one byte */
+ sg[db].address[di] = sg[sb].address[si];
+
+ /* get next destination */
+ if ( di == 0 )
+ {
+ db--;
+ di=sg[db].length-1;
+ }
+ else
+ {
+ di--;
+ }
+
+ /* get next source */
+ if ( si == 0 )
+ {
+ sb--;
+ si=sg[sb].length-1;
+ }
+ else
+ {
+ si--;
+ }
+
+ element--;
+ }
+ /* copy the remaining four bytes */
+ while ( element >= USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ /* check limits */
+ if ( db <= ldb && di < ldi )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ sg[db].address[di] = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ];
+
+ /* get next destination */
+ if ( di == 0 )
+ {
+ db--;
+ di=sg[db].length-1;
+ }
+ else
+ {
+ di--;
+ }
+ element--;
+ }
+ }
+
+ /* All done and everything was fine */
+ return 0;
+}
+
+void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6,
+ Usb_Stor_Scsi_Sense_Hdr_10_u* the10,
+ int* length_p )
+
+{
+ int i = 0, j=0, element=0;
+ struct scatterlist *sg = 0;
+ int length = 0;
+ __u8* buffer=0;
+
+ /* are we scatter-gathering? */
+ if ( srb->use_sg != 0 )
+ {
+ /* loop over all the scatter gather structures and
+ * get pointer to the data members in the headers
+ * (also work out the length while we're here)
+ */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ {
+ length += sg[i].length;
+ /* We only do the inner loop for the headers */
+ if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* scan through this scatterlist */
+ for ( j=0; j<sg[i].length; j++ )
+ {
+ if ( element < USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ /* fill in the pointers for both header types */
+ the6->array[element] = &(sg[i].address[j]);
+ the10->array[element] = &(sg[i].address[j]);
+ }
+ else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* only the longer headers still cares now */
+ the10->array[element] = &(sg[i].address[j]);
+ }
+ /* increase element counter */
+ element++;
+ }
+ }
+ }
+ }
+ else
+ {
+ length = srb->request_bufflen;
+ buffer = srb->request_buffer;
+ if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ printk( KERN_ERR USB_STORAGE
+ "Buffer length smaller than header!!" );
+ for( i=0; i<USB_STOR_SCSI_SENSE_10_HDRSZ; i++ )
+ {
+ if ( i < USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ the6->array[i] = &(buffer[i]);
+ the10->array[i] = &(buffer[i]);
+ }
+ else
+ {
+ the10->array[i] = &(buffer[i]);
+ }
+ }
+ }
+
+ /* Set value of length passed in */
+ *length_p = length;
+}
+
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
new file mode 100644
index 000000000..ea8a34504
--- /dev/null
+++ b/drivers/usb/storage/scsiglue.h
@@ -0,0 +1,54 @@
+/* Driver for USB Mass Storage compliant devices
+ * SCSI Connecting Glue Header File
+ *
+ * $Id: scsiglue.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SCSIGLUE_H_
+#define _SCSIGLUE_H_
+
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+
+extern unsigned char usb_stor_sense_notready[12];
+extern unsigned char us_direction[256/8];
+extern Scsi_Host_Template usb_stor_host_template;
+extern int usb_stor_scsiSense10to6(Scsi_Cmnd*);
+extern int usb_stor_scsiSense6to10(Scsi_Cmnd*);
+
+#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
new file mode 100644
index 000000000..c83a7512d
--- /dev/null
+++ b/drivers/usb/storage/transport.c
@@ -0,0 +1,904 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * $Id: transport.c,v 1.2 2000/06/27 10:20:39 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+/* This is the completion handler which will wake us up when an URB
+ * completes.
+ */
+static void usb_stor_blocking_completion(urb_t *urb)
+{
+ api_wrapper_data *awd = (api_wrapper_data *)urb->context;
+
+ if (waitqueue_active(awd->wakeup))
+ wake_up(awd->wakeup);
+}
+
+/* This is our function to emulate usb_control_msg() but give us enough
+ * access to make aborts/resets work
+ */
+int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ void *data, u16 size)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAIT_QUEUE_HEAD(wqh);
+ api_wrapper_data awd;
+ int status;
+ devrequest *dr;
+
+ /* allocate the device request structure */
+ dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ /* fill in the structure */
+ dr->requesttype = requesttype;
+ dr->request = request;
+ dr->value = cpu_to_le16(value);
+ dr->index = cpu_to_le16(index);
+ dr->length = cpu_to_le16(size);
+
+ /* set up data structures for the wakeup system */
+ awd.wakeup = &wqh;
+ awd.handler = 0;
+ init_waitqueue_head(&wqh);
+ add_wait_queue(&wqh, &wait);
+
+ /* lock the URB */
+ down(&(us->current_urb_sem));
+
+ /* fill the URB */
+ FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe,
+ (unsigned char*) dr, data, size,
+ usb_stor_blocking_completion, &awd);
+
+ /* submit the URB */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ status = usb_submit_urb(us->current_urb);
+ if (status) {
+ /* something went wrong */
+ up(&(us->current_urb_sem));
+ remove_wait_queue(&wqh, &wait);
+ kfree(dr);
+ return status;
+ }
+
+ /* wait for the completion of the URB */
+ up(&(us->current_urb_sem));
+ if (us->current_urb->status == -EINPROGRESS)
+ schedule();
+ down(&(us->current_urb_sem));
+
+ /* we either timed out or got woken up -- clean up either way */
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wqh, &wait);
+
+ /* return the actual length of the data transferred if no error*/
+ status = us->current_urb->status;
+ if (status >= 0)
+ status = us->current_urb->actual_length;
+
+ /* release the lock and return status */
+ up(&(us->current_urb_sem));
+ kfree(dr);
+ return status;
+}
+
+/* This is our function to emulate usb_bulk_msg() but give us enough
+ * access to make aborts/resets work
+ */
+int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+ unsigned int len, unsigned int *act_len)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAIT_QUEUE_HEAD(wqh);
+ api_wrapper_data awd;
+ int status;
+
+ /* set up data structures for the wakeup system */
+ awd.wakeup = &wqh;
+ awd.handler = 0;
+ init_waitqueue_head(&wqh);
+ add_wait_queue(&wqh, &wait);
+
+ /* lock the URB */
+ down(&(us->current_urb_sem));
+
+ /* fill the URB */
+ FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
+ usb_stor_blocking_completion, &awd);
+
+ /* submit the URB */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ status = usb_submit_urb(us->current_urb);
+ if (status) {
+ /* something went wrong */
+ up(&(us->current_urb_sem));
+ remove_wait_queue(&wqh, &wait);
+ return status;
+ }
+
+ /* wait for the completion of the URB */
+ up(&(us->current_urb_sem));
+ if (us->current_urb->status == -EINPROGRESS)
+ schedule();
+ down(&(us->current_urb_sem));
+
+ /* we either timed out or got woken up -- clean up either way */
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wqh, &wait);
+
+ /* return the actual length of the data transferred */
+ *act_len = us->current_urb->actual_length;
+
+ /* release the lock and return status */
+ up(&(us->current_urb_sem));
+ return us->current_urb->status;
+}
+
+/*
+ * Transfer one SCSI scatter-gather buffer via bulk transfer
+ *
+ * Note that this function is necessary because we want the ability to
+ * use scatter-gather memory. Good performance is achieved by a combination
+ * of scatter-gather and clustering (which makes each chunk bigger).
+ *
+ * Note that the lower layer will always retry when a NAK occurs, up to the
+ * timeout limit. Thus we don't have to worry about it for individual
+ * packets.
+ */
+static int us_transfer_partial(struct us_data *us, char *buf, int length)
+{
+ int result;
+ int partial;
+ int pipe;
+
+ /* calculate the appropriate pipe information */
+ if (US_DIRECTION(us->srb->cmnd[0]))
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ /* transfer the data */
+ US_DEBUGP("us_transfer_partial(): xfer %d bytes\n", length);
+ result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
+ US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
+ result, partial, length);
+
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
+
+ /* did we send all the data? */
+ if (partial == length) {
+ US_DEBUGP("us_transfer_partial(): transfer complete\n");
+ return US_BULK_TRANSFER_GOOD;
+ }
+
+ /* uh oh... we have an error code, so something went wrong. */
+ if (result) {
+ /* NAK - that means we've retried a few times allready */
+ if (result == -ETIMEDOUT) {
+ US_DEBUGP("us_transfer_partial(): device NAKed\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
+
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ /* the catch-all case */
+ US_DEBUGP("us_transfer_partial(): unknown error\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
+
+ /* no error code, so we must have transferred some data,
+ * just not all of it */
+ return US_BULK_TRANSFER_SHORT;
+}
+
+/*
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+ *
+ * Note that this uses us_transfer_partial to achieve it's goals -- this
+ * function simply determines if we're going to use scatter-gather or not,
+ * and acts appropriately. For now, it also re-interprets the error codes.
+ */
+static void us_transfer(Scsi_Cmnd *srb, struct us_data* us, int dir_in)
+{
+ int i;
+ int result = -1;
+ struct scatterlist *sg;
+
+ /* are we scatter-gathering? */
+ if (srb->use_sg) {
+
+ /* loop over all the scatter gather structures and
+ * make the appropriate requests for each, until done
+ */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++) {
+ result = us_transfer_partial(us, sg[i].address,
+ sg[i].length);
+ if (result)
+ break;
+ }
+ }
+ else
+ /* no scatter-gather, just make the request */
+ result = us_transfer_partial(us, srb->request_buffer,
+ srb->request_bufflen);
+
+ /* return the result in the data structure itself */
+ srb->result = result;
+}
+
+/* Calculate the length of the data transfer (not the command) for any
+ * given SCSI command
+ */
+static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int i;
+ unsigned int total = 0;
+ struct scatterlist *sg;
+
+ /* support those devices which need the length calculated
+ * differently
+ */
+ if (us->flags & US_FL_ALT_LENGTH) {
+ if (srb->cmnd[0] == INQUIRY) {
+ srb->cmnd[4] = 36;
+ }
+
+ if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
+ return srb->cmnd[4];
+
+ if (srb->cmnd[0] == TEST_UNIT_READY)
+ return 0;
+ }
+
+ /* Are we going to scatter gather? */
+ if (srb->use_sg) {
+ /* Add up the sizes of all the scatter-gather segments */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ total += sg[i].length;
+
+ return total;
+ }
+ else
+ /* Just return the length of the buffer */
+ return srb->request_bufflen;
+}
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+/* Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and recieve the response.
+ */
+void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int need_auto_sense;
+ int result;
+
+ /* send the command to the transport layer */
+ result = us->transport(srb, us);
+
+ /* if the command gets aborted by the higher layers, we need to
+ * short-circuit all other processing
+ */
+ if (result == USB_STOR_TRANSPORT_ABORTED) {
+ US_DEBUGP("-- transport indicates command was aborted\n");
+ srb->result = DID_ABORT << 16;
+ return;
+ }
+
+ /* Determine if we need to auto-sense
+ *
+ * I normally don't use a flag like this, but it's almost impossible
+ * to understand what's going on here if I don't.
+ */
+ need_auto_sense = 0;
+
+ /*
+ * If we're running the CB transport, which is incapable
+ * of determining status on it's own, we need to auto-sense almost
+ * every time.
+ */
+ if (us->protocol == US_PR_CB) {
+ US_DEBUGP("-- CB transport device requiring auto-sense\n");
+ need_auto_sense = 1;
+
+ /* There are some exceptions to this. Notably, if this is
+ * a UFI device and the command is REQUEST_SENSE or INQUIRY,
+ * then it is impossible to truly determine status.
+ */
+ if (us->subclass == US_SC_UFI &&
+ ((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY))) {
+ US_DEBUGP("** no auto-sense for a special command\n");
+ need_auto_sense = 0;
+ }
+ }
+
+ /*
+ * If we have an error, we're going to do a REQUEST_SENSE
+ * automatically. Note that we differentiate between a command
+ * "failure" and an "error" in the transport mechanism.
+ */
+ if (result == USB_STOR_TRANSPORT_FAILED) {
+ US_DEBUGP("-- transport indicates command failure\n");
+ need_auto_sense = 1;
+ }
+ if (result == USB_STOR_TRANSPORT_ERROR) {
+ /* FIXME: we need to invoke a transport reset here */
+ US_DEBUGP("-- transport indicates transport failure\n");
+ need_auto_sense = 0;
+ srb->result = DID_ERROR << 16;
+ return;
+ }
+
+ /*
+ * Also, if we have a short transfer on a command that can't have
+ * a short transfer, we're going to do this.
+ */
+ if ((srb->result == US_BULK_TRANSFER_SHORT) &&
+ !((srb->cmnd[0] == REQUEST_SENSE) ||
+ (srb->cmnd[0] == INQUIRY) ||
+ (srb->cmnd[0] == MODE_SENSE) ||
+ (srb->cmnd[0] == LOG_SENSE) ||
+ (srb->cmnd[0] == MODE_SENSE_10))) {
+ US_DEBUGP("-- unexpectedly short transfer\n");
+ need_auto_sense = 1;
+ }
+
+ /* Now, if we need to do the auto-sense, let's do it */
+ if (need_auto_sense) {
+ int temp_result;
+ void* old_request_buffer;
+ int old_sg;
+ int old_request_bufflen;
+ unsigned char old_cmnd[MAX_COMMAND_SIZE];
+
+ US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
+
+ /* save the old command */
+ memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
+
+ /* set the command and the LUN */
+ srb->cmnd[0] = REQUEST_SENSE;
+ srb->cmnd[1] = old_cmnd[1] & 0xE0;
+ srb->cmnd[2] = 0;
+ srb->cmnd[3] = 0;
+ srb->cmnd[4] = 18;
+ srb->cmnd[5] = 0;
+
+ /* set the buffer length for transfer */
+ old_request_buffer = srb->request_buffer;
+ old_request_bufflen = srb->request_bufflen;
+ old_sg = srb->use_sg;
+ srb->use_sg = 0;
+ srb->request_bufflen = 18;
+ srb->request_buffer = srb->sense_buffer;
+
+ /* issue the auto-sense command */
+ temp_result = us->transport(us->srb, us);
+ if (temp_result != USB_STOR_TRANSPORT_GOOD) {
+ /* FIXME: we need to invoke a transport reset here */
+ US_DEBUGP("-- auto-sense failure\n");
+ srb->result = DID_ERROR << 16;
+ return;
+ }
+
+ US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+ US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+ srb->sense_buffer[0],
+ srb->sense_buffer[2] & 0xf,
+ srb->sense_buffer[12],
+ srb->sense_buffer[13]);
+
+ /* set the result so the higher layers expect this data */
+ srb->result = CHECK_CONDITION;
+
+ /* we're done here, let's clean up */
+ srb->request_buffer = old_request_buffer;
+ srb->request_bufflen = old_request_bufflen;
+ srb->use_sg = old_sg;
+ memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+
+ /* If things are really okay, then let's show that */
+ if ((srb->sense_buffer[2] & 0xf) == 0x0)
+ srb->result = GOOD;
+ } else /* if (need_auto_sense) */
+ srb->result = GOOD;
+
+ /* Regardless of auto-sense, if we _know_ we have an error
+ * condition, show that in the result code
+ */
+ if (result == USB_STOR_TRANSPORT_FAILED)
+ srb->result = CHECK_CONDITION;
+
+ /* If we think we're good, then make sure the sense data shows it.
+ * This is necessary because the auto-sense for some devices always
+ * sets byte 0 == 0x70, even if there is no error
+ */
+ if ((us->protocol == US_PR_CB) &&
+ (result == USB_STOR_TRANSPORT_GOOD) &&
+ ((srb->sense_buffer[2] & 0xf) == 0x0))
+ srb->sense_buffer[0] = 0x0;
+}
+
+/*
+ * Control/Bulk/Interrupt transport
+ */
+
+/* The interrupt handler for CBI devices */
+void usb_stor_CBI_irq(struct urb *urb)
+{
+ struct us_data *us = (struct us_data *)urb->context;
+
+ US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+ US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
+ US_DEBUGP("-- IRQ state is %d\n", urb->status);
+
+ /* is the device removed? */
+ if (urb->status != -ENOENT) {
+ /* save the data for interpretation later */
+ US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
+ ((unsigned char*)urb->transfer_buffer)[0],
+ ((unsigned char*)urb->transfer_buffer)[1]);
+
+
+ /* was this a wanted interrupt? */
+ if (us->ip_wanted) {
+ us->ip_wanted = 0;
+ up(&(us->ip_waitq));
+ } else
+ US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+ } else
+ US_DEBUGP("-- device has been removed\n");
+}
+
+int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+
+ /* COMMAND STAGE */
+ /* let's send the command via the control pipe */
+ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len);
+
+ /* check the return code for the command */
+ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
+ if (result < 0) {
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* STALL must be cleared when they are detected */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* Set up for status notification */
+ us->ip_wanted = 1;
+
+ /* DATA STAGE */
+ /* transfer the data payload for this command, if one exists*/
+ if (us_transfer_length(srb, us)) {
+ us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
+ US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
+
+ /* if it was aborted, we need to indicate that */
+ if (srb->result == USB_STOR_TRANSPORT_ABORTED)
+ return USB_STOR_TRANSPORT_ABORTED;
+ }
+
+ /* STATUS STAGE */
+
+ /* go to sleep until we get this interrupt */
+ down(&(us->ip_waitq));
+
+ /* if we were woken up by an abort instead of the actual interrupt */
+ if (us->ip_wanted) {
+ US_DEBUGP("Did not get interrupt on CBI\n");
+ us->ip_wanted = 0;
+ return USB_STOR_TRANSPORT_ABORTED;
+ }
+
+ US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
+ ((unsigned char*)us->irq_urb->transfer_buffer)[0],
+ ((unsigned char*)us->irq_urb->transfer_buffer)[1]);
+
+ /* UFI gives us ASC and ASCQ, like a request sense
+ *
+ * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
+ * devices, so we ignore the information for those commands. Note
+ * that this means we could be ignoring a real error on these
+ * commands, but that can't be helped.
+ */
+ if (us->subclass == US_SC_UFI) {
+ if (srb->cmnd[0] == REQUEST_SENSE ||
+ srb->cmnd[0] == INQUIRY)
+ return USB_STOR_TRANSPORT_GOOD;
+ else
+ if (((unsigned char*)us->irq_urb->transfer_buffer)[0])
+ return USB_STOR_TRANSPORT_FAILED;
+ else
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* If not UFI, we interpret the data as a result code
+ * The first byte should always be a 0x0
+ * The second byte & 0x0F should be 0x0 for good, otherwise error
+ */
+ if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) {
+ US_DEBUGP("CBI IRQ data showed reserved bType\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ switch (((unsigned char*)us->irq_urb->transfer_buffer)[1] & 0x0F) {
+ case 0x00:
+ return USB_STOR_TRANSPORT_GOOD;
+ case 0x01:
+ return USB_STOR_TRANSPORT_FAILED;
+ default:
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* we should never get here, but if we do, we're in trouble */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Control/Bulk transport
+ */
+int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+
+ /* COMMAND STAGE */
+ /* let's send the command via the control pipe */
+ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
+ us->ifnum, srb->cmnd, srb->cmd_len);
+
+ /* check the return code for the command */
+ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
+ if (result < 0) {
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* a stall is a fatal condition from the device */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* DATA STAGE */
+ /* transfer the data payload for this command, if one exists*/
+ if (us_transfer_length(srb, us)) {
+ us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
+ US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
+
+ /* if it was aborted, we need to indicate that */
+ if (srb->result == USB_STOR_TRANSPORT_ABORTED)
+ return USB_STOR_TRANSPORT_ABORTED;
+ }
+
+ /* STATUS STAGE */
+ /* NOTE: CB does not have a status stage. Silly, I know. So
+ * we have to catch this at a higher level.
+ */
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Bulk only transport
+ */
+
+/* Determine what the maximum LUN supported is */
+int usb_stor_Bulk_max_lun(struct us_data *us)
+{
+ unsigned char data;
+ int result;
+ int pipe;
+
+ /* issue the command */
+ pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
+ result = usb_control_msg(us->pusb_dev, pipe,
+ US_BULK_GET_MAX_LUN,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ 0, us->ifnum, &data, sizeof(data), HZ);
+
+ US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
+ result, data);
+
+ /* if we have a successful request, return the result */
+ if (result == 1)
+ return data;
+
+ /* if we get a STALL, clear the stall */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
+
+ /* return the default -- no LUNs */
+ return 0;
+}
+
+int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ struct bulk_cb_wrap bcb;
+ struct bulk_cs_wrap bcs;
+ int result;
+ int pipe;
+ int partial;
+
+ /* set up the command wrapper */
+ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us));
+ bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+ bcb.Tag = srb->serial_number;
+ bcb.Lun = srb->cmnd[1] >> 5;
+ bcb.Length = srb->cmd_len;
+
+ /* construct the pipe handle */
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ /* copy the command payload */
+ memset(bcb.CDB, 0, sizeof(bcb.CDB));
+ memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+
+ /* send it to out endpoint */
+ US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
+ le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun,
+ bcb.DataTransferLength, bcb.Flags, bcb.Length);
+ result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN,
+ &partial);
+ US_DEBUGP("Bulk command transfer result=%d\n", result);
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+ } else if (result) {
+ /* unknown error -- we've got a problem */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* if the command transfered well, then we go to the data stage */
+ if (result == 0) {
+ /* send/receive data payload, if there is any */
+ if (bcb.DataTransferLength) {
+ us_transfer(srb, us, bcb.Flags);
+ US_DEBUGP("Bulk data transfer result 0x%x\n",
+ srb->result);
+
+ /* if it was aborted, we need to indicate that */
+ if (srb->result == USB_STOR_TRANSPORT_ABORTED)
+ return USB_STOR_TRANSPORT_ABORTED;
+ }
+ }
+
+ /* See flow chart on pg 15 of the Bulk Only Transport spec for
+ * an explanation of how this code works.
+ */
+
+ /* construct the pipe handle */
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+
+ /* get CSW for device status */
+ US_DEBUGP("Attempting to get CSW...\n");
+ result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN,
+ &partial);
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* did the attempt to read the CSW fail? */
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+
+ /* get the status again */
+ US_DEBUGP("Attempting to get CSW (2nd try)...\n");
+ result = usb_stor_bulk_msg(us, &bcs, pipe,
+ US_BULK_CS_WRAP_LEN, &partial);
+
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* if it fails again, we need a reset and return an error*/
+ if (result == -EPIPE) {
+ US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
+ usb_clear_halt(us->pusb_dev, pipe);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+
+ /* if we still have a failure at this point, we're in trouble */
+ US_DEBUGP("Bulk status result = %d\n", result);
+ if (result) {
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* check bulk status */
+ US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+ le32_to_cpu(bcs.Signature), bcs.Tag,
+ bcs.Residue, bcs.Status);
+ if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) ||
+ bcs.Tag != bcb.Tag ||
+ bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+ US_DEBUGP("Bulk logical error\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* based on the status code, we report good or bad */
+ switch (bcs.Status) {
+ case US_BULK_STAT_OK:
+ /* command good -- note that we could be short on data */
+ return USB_STOR_TRANSPORT_GOOD;
+
+ case US_BULK_STAT_FAIL:
+ /* command failed */
+ return USB_STOR_TRANSPORT_FAILED;
+
+ case US_BULK_STAT_PHASE:
+ /* phase error */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* we should never get here, but if we do, we're in trouble */
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+
+/* This issues a CB[I] Reset to the device in question
+ */
+int usb_stor_CB_reset(struct us_data *us)
+{
+ unsigned char cmd[12];
+ int result;
+
+ US_DEBUGP("CB_reset() called\n");
+
+ memset(cmd, 0xFF, sizeof(cmd));
+ cmd[0] = SEND_DIAGNOSTIC;
+ cmd[1] = 4;
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+ US_CBI_ADSC,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
+
+ /* long wait for reset */
+ schedule_timeout(HZ*6);
+
+ US_DEBUGP("CB_reset: clearing endpoint halt\n");
+ usb_clear_halt(us->pusb_dev,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ usb_clear_halt(us->pusb_dev,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+
+ US_DEBUGP("CB_reset done\n");
+ return 0;
+}
+
+/* FIXME: Does this work? */
+int usb_stor_Bulk_reset(struct us_data *us)
+{
+ int result;
+
+ result = usb_control_msg(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ US_BULK_RESET_REQUEST,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, NULL, 0, HZ*5);
+
+ if (result < 0)
+ US_DEBUGP("Bulk hard reset failed %d\n", result);
+
+ usb_clear_halt(us->pusb_dev,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ usb_clear_halt(us->pusb_dev,
+ usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+
+ /* long wait for reset */
+ schedule_timeout(HZ*6);
+
+ return result;
+}
+
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
new file mode 100644
index 000000000..fb8699781
--- /dev/null
+++ b/drivers/usb/storage/transport.h
@@ -0,0 +1,132 @@
+/* Driver for USB Mass Storage compliant devices
+ * Transport Functions Header File
+ *
+ * $Id: transport.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include <linux/blk.h>
+#include "usb.h"
+#include "scsi.h"
+
+/* bit set if input */
+extern unsigned char us_direction[256/8];
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+/* Protocols */
+
+#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */
+#define US_PR_CB 0x01 /* Control/Bulk w/o interrupt */
+#define US_PR_BULK 0x50 /* bulk only */
+
+/*
+ * Bulk only data structures
+ */
+
+/* command block wrapper */
+struct bulk_cb_wrap {
+ __u32 Signature; /* contains 'USBC' */
+ __u32 Tag; /* unique per command id */
+ __u32 DataTransferLength; /* size of data */
+ __u8 Flags; /* direction in bit 0 */
+ __u8 Lun; /* LUN normally 0 */
+ __u8 Length; /* of of the CDB */
+ __u8 CDB[16]; /* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN 31
+#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */
+#define US_BULK_FLAG_IN 1
+#define US_BULK_FLAG_OUT 0
+
+/* command status wrapper */
+struct bulk_cs_wrap {
+ __u32 Signature; /* should = 'USBS' */
+ __u32 Tag; /* same as original command */
+ __u32 Residue; /* amount not transferred */
+ __u8 Status; /* see below */
+ __u8 Filler[18];
+};
+
+#define US_BULK_CS_WRAP_LEN 13
+#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
+#define US_BULK_STAT_OK 0
+#define US_BULK_STAT_FAIL 1
+#define US_BULK_STAT_PHASE 2
+
+/* bulk-only class specific requests */
+#define US_BULK_RESET_REQUEST 0xff
+#define US_BULK_GET_MAX_LUN 0xfe
+
+/*
+ * us_bulk_transfer() return codes
+ */
+#define US_BULK_TRANSFER_GOOD 0 /* good transfer */
+#define US_BULK_TRANSFER_SHORT 1 /* transfered less than expected */
+#define US_BULK_TRANSFER_FAILED 2 /* transfer died in the middle */
+#define US_BULK_TRANSFER_ABORTED 3 /* transfer canceled */
+
+/*
+ * Transport return codes
+ */
+
+#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
+#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
+#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */
+#define USB_STOR_TRANSPORT_ABORTED 3 /* Transport aborted */
+
+/*
+ * CBI accept device specific command
+ */
+
+#define US_CBI_ADSC 0
+
+extern void usb_stor_CBI_irq(struct urb*);
+extern int usb_stor_CBI_transport(Scsi_Cmnd*, struct us_data*);
+
+extern int usb_stor_CB_transport(Scsi_Cmnd*, struct us_data*);
+extern int usb_stor_CB_reset(struct us_data*);
+
+extern int usb_stor_Bulk_transport(Scsi_Cmnd*, struct us_data*);
+extern int usb_stor_Bulk_max_lun(struct us_data*);
+extern int usb_stor_Bulk_reset(struct us_data*);
+
+void usb_stor_invoke_transport(Scsi_Cmnd *, struct us_data *);
+
+#endif
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
new file mode 100644
index 000000000..d493bc695
--- /dev/null
+++ b/drivers/usb/storage/usb.c
@@ -0,0 +1,803 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * $Id: usb.c,v 1.3 2000/06/27 10:20:39 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+
+#include <linux/module.h>
+ /*FIXME: note that this next include is needed for the new sleeping system
+ * which is not implemented yet
+ */
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+
+/*
+ * Per device data
+ */
+
+static int my_host_number;
+
+/*
+ * kernel thread actions
+ */
+
+#define US_ACT_COMMAND 1
+#define US_ACT_DEVICE_RESET 2
+#define US_ACT_BUS_RESET 3
+#define US_ACT_HOST_RESET 4
+#define US_ACT_EXIT 5
+
+/* The list of structures and the protective lock for them */
+struct us_data *us_list;
+struct semaphore us_list_semaphore;
+
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
+static void storage_disconnect(struct usb_device *dev, void *ptr);
+static struct usb_driver storage_driver = {
+ name: "usb-storage",
+ probe: storage_probe,
+ disconnect: storage_disconnect,
+};
+
+static int usb_stor_control_thread(void * __us)
+{
+ struct us_data *us = (struct us_data *)__us;
+ int action;
+
+ lock_kernel();
+
+ /*
+ * This thread doesn't need any user-level access,
+ * so get rid of all our resources..
+ */
+ daemonize();
+
+ /* set our name for identification purposes */
+ sprintf(current->comm, "usb-storage-%d", us->host_number);
+
+ unlock_kernel();
+
+ /* signal that we've started the thread */
+ up(&(us->notify));
+
+ for(;;) {
+ US_DEBUGP("*** thread sleeping.\n");
+ down(&(us->sleeper));
+ down(&(us->queue_exclusion));
+ US_DEBUGP("*** thread awakened.\n");
+
+ /* take the command off the queue */
+ action = us->action;
+ us->action = 0;
+ us->srb = us->queue_srb;
+
+ /* release the queue lock as fast as possible */
+ up(&(us->queue_exclusion));
+
+ switch (action) {
+ case US_ACT_COMMAND:
+ /* reject if target != 0 or if LUN is higher than
+ * the maximum known LUN
+ */
+ if (us->srb->target || (us->srb->lun > us->max_lun)) {
+ US_DEBUGP("Bad device number (%d/%d)\n",
+ us->srb->target, us->srb->lun);
+
+ us->srb->result = DID_BAD_TARGET << 16;
+
+ us->srb->scsi_done(us->srb);
+ us->srb = NULL;
+ break;
+ }
+
+ /* handle those devices which can't do a START_STOP */
+ if ((us->srb->cmnd[0] == START_STOP) &&
+ (us->flags & US_FL_START_STOP)) {
+ us->srb->result = GOOD;
+ us->srb->scsi_done(us->srb);
+ us->srb = NULL;
+ break;
+ }
+
+ /* lock the device pointers */
+ down(&(us->dev_semaphore));
+
+ /* our device has gone - pretend not ready */
+ if (!us->pusb_dev) {
+ US_DEBUGP("Request is for removed device\n");
+ /* For REQUEST_SENSE, it's the data. But
+ * for anything else, it should look like
+ * we auto-sensed for it.
+ */
+ if (us->srb->cmnd[0] == REQUEST_SENSE) {
+ memcpy(us->srb->request_buffer,
+ usb_stor_sense_notready,
+ sizeof(usb_stor_sense_notready));
+ us->srb->result = GOOD;
+ } else {
+ memcpy(us->srb->sense_buffer,
+ usb_stor_sense_notready,
+ sizeof(usb_stor_sense_notready));
+ us->srb->result = CHECK_CONDITION;
+ }
+ } else { /* !us->pusb_dev */
+ /* we've got a command, let's do it! */
+ US_DEBUG(usb_stor_show_command(us->srb));
+ us->proto_handler(us->srb, us);
+ }
+
+ /* unlock the device pointers */
+ up(&(us->dev_semaphore));
+
+ /* indicate that the command is done */
+ if (us->srb->result != DID_ABORT << 16) {
+ US_DEBUGP("scsi cmd done, result=0x%x\n",
+ us->srb->result);
+ us->srb->scsi_done(us->srb);
+ } else {
+ US_DEBUGP("scsi command aborted\n");
+ up(&(us->notify));
+ }
+ us->srb = NULL;
+ break;
+
+ case US_ACT_DEVICE_RESET:
+ break;
+
+ case US_ACT_BUS_RESET:
+ break;
+
+ case US_ACT_HOST_RESET:
+ break;
+
+ } /* end switch on action */
+
+ /* exit if we get a signal to exit */
+ if (action == US_ACT_EXIT) {
+ US_DEBUGP("-- US_ACT_EXIT command recieved\n");
+ break;
+ }
+ } /* for (;;) */
+
+ /* notify the exit routine that we're actually exiting now */
+ up(&(us->notify));
+
+ return 0;
+}
+
+/* This is the list of devices we recognize, along with their flag data */
+static struct us_unusual_dev us_unusual_dev_list[] = {
+ { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus",
+ US_SC_8070, US_PR_CB, 0},
+ { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120",
+ US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30/S70",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
+ US_FL_MODE_XLATE | US_FL_ALT_LENGTH | US_FL_ALT_LENGTH},
+ { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
+ US_FL_MODE_XLATE | US_FL_ALT_LENGTH},
+ { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U",
+ US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
+ { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U",
+ US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN},
+ { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-01)",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP},
+ { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)",
+ US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER},
+ { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech USB-SCSI-DB25",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge",
+ US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate",
+ US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
+ { 0 }};
+
+/* Search our ususual device list, based on vendor/product combinations
+ * to see if we can support this device. Returns a pointer to a structure
+ * defining how we should support this device, or NULL if it's not in the
+ * list
+ */
+static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
+ u16 bcdDevice)
+{
+ struct us_unusual_dev* ptr;
+
+ US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n",
+ idVendor, idProduct, bcdDevice);
+
+ ptr = us_unusual_dev_list;
+ while ((ptr->idVendor != 0x0000) &&
+ !((ptr->idVendor == idVendor) &&
+ (ptr->idProduct == idProduct) &&
+ (ptr->bcdDeviceMin <= bcdDevice) &&
+ (ptr->bcdDeviceMax >= bcdDevice)))
+ ptr++;
+
+ /* if the search ended because we hit the end record, we failed */
+ if (ptr->idVendor == 0x0000) {
+ US_DEBUGP("-- did not find a matching device\n");
+ return NULL;
+ }
+
+ /* otherwise, we found one! */
+ US_DEBUGP("-- found matching device: %s\n", ptr->name);
+ return ptr;
+}
+
+/* Set up the IRQ pipe and handler
+ * Note that this function assumes that all the data in the us_data
+ * strucuture is current. This includes the ep_int field, which gives us
+ * the endpoint for the interrupt.
+ * Returns non-zero on failure, zero on success
+ */
+static int usb_stor_allocate_irq(struct us_data *ss)
+{
+ unsigned int pipe;
+ int maxp;
+ int result;
+
+ US_DEBUGP("Allocating IRQ for CBI transport\n");
+
+ /* lock access to the data structure */
+ down(&(ss->irq_urb_sem));
+
+ /* allocate the URB */
+ ss->irq_urb = usb_alloc_urb(0);
+ if (!ss->irq_urb) {
+ up(&(ss->irq_urb_sem));
+ US_DEBUGP("couldn't allocate interrupt URB");
+ return 1;
+ }
+
+ /* calculate the pipe and max packet size */
+ pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK);
+ maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
+ if (maxp > sizeof(ss->irqbuf))
+ maxp = sizeof(ss->irqbuf);
+
+ /* fill in the URB with our data */
+ FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp,
+ usb_stor_CBI_irq, ss, ss->ep_int->bInterval);
+
+ /* submit the URB for processing */
+ result = usb_submit_urb(ss->irq_urb);
+ US_DEBUGP("usb_submit_urb() returns %d\n", result);
+ if (result) {
+ usb_free_urb(ss->irq_urb);
+ up(&(ss->irq_urb_sem));
+ return 2;
+ }
+
+ /* unlock the data structure and return success */
+ up(&(ss->irq_urb_sem));
+ return 0;
+}
+
+/* Probe to see if a new device is actually a SCSI device */
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ int i;
+ char mf[USB_STOR_STRING_LEN]; /* manufacturer */
+ char prod[USB_STOR_STRING_LEN]; /* product */
+ char serial[USB_STOR_STRING_LEN]; /* serial number */
+ GUID(guid); /* Global Unique Identifier */
+ unsigned int flags;
+ struct us_unusual_dev *unusual_dev;
+ struct us_data *ss = NULL;
+ int result;
+
+ /* these are temporary copies -- we test on these, then put them
+ * in the us-data structure
+ */
+ struct usb_endpoint_descriptor *ep_in = NULL;
+ struct usb_endpoint_descriptor *ep_out = NULL;
+ struct usb_endpoint_descriptor *ep_int = NULL;
+ u8 subclass = 0;
+ u8 protocol = 0;
+
+ /* the altsettting 0 on the interface we're probing */
+ struct usb_interface_descriptor *altsetting =
+ &(dev->actconfig->interface[ifnum].altsetting[0]);
+
+ /* clear the temporary strings */
+ memset(mf, 0, sizeof(mf));
+ memset(prod, 0, sizeof(prod));
+ memset(serial, 0, sizeof(serial));
+
+ /* search for this device in our unusual device list */
+ unusual_dev = us_find_dev(dev->descriptor.idVendor,
+ dev->descriptor.idProduct,
+ dev->descriptor.bcdDevice);
+
+ /*
+ * Can we support this device, either because we know about it
+ * from our unusual device list, or because it advertises that it's
+ * compliant to the specification?
+ */
+ if (!unusual_dev &&
+ !(dev->descriptor.bDeviceClass == 0 &&
+ altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+ altsetting->bInterfaceSubClass >= US_SC_MIN &&
+ altsetting->bInterfaceSubClass <= US_SC_MAX)) {
+ /* if it's not a mass storage, we go no further */
+ return NULL;
+ }
+
+ /* At this point, we know we've got a live one */
+ US_DEBUGP("USB Mass Storage device detected\n");
+
+ /* Determine subclass and protocol, or copy from the interface */
+ if (unusual_dev) {
+ subclass = unusual_dev->useProtocol;
+ protocol = unusual_dev->useTransport;
+ flags = unusual_dev->flags;
+ } else {
+ subclass = altsetting->bInterfaceSubClass;
+ protocol = altsetting->bInterfaceProtocol;
+ flags = 0;
+ }
+
+ /*
+ * Find the endpoints we need
+ * We are expecting a minimum of 2 endpoints - in and out (bulk).
+ * An optional interrupt is OK (necessary for CBI protocol).
+ * We will ignore any others.
+ */
+ for (i = 0; i < altsetting->bNumEndpoints; i++) {
+ /* is it an BULK endpoint? */
+ if ((altsetting->endpoint[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+ /* BULK in or out? */
+ if (altsetting->endpoint[i].bEndpointAddress &
+ USB_DIR_IN)
+ ep_in = &altsetting->endpoint[i];
+ else
+ ep_out = &altsetting->endpoint[i];
+ }
+
+ /* is it an interrupt endpoint? */
+ if ((altsetting->endpoint[i].bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+ ep_int = &altsetting->endpoint[i];
+ }
+ }
+ US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
+ ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
+
+ /* set the interface -- STALL is an acceptable response here */
+ result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
+ US_DEBUGP("Result from usb_set_interface is %d\n", result);
+ if (result == -EPIPE) {
+ US_DEBUGP("-- clearing stall on control interface\n");
+ usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+ } else if (result != 0) {
+ /* it's not a stall, but another error -- time to bail */
+ US_DEBUGP("-- Unknown error. Rejecting device\n");
+ return NULL;
+ }
+
+ /* Do some basic sanity checks, and bail if we find a problem */
+ if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
+ US_DEBUGP("Sanity check failed. Rejecting device.\n");
+ return NULL;
+ }
+
+ /* At this point, we're committed to using the device */
+
+ /* clear the GUID and fetch the strings */
+ GUID_CLEAR(guid);
+ if (dev->descriptor.iManufacturer)
+ usb_string(dev, dev->descriptor.iManufacturer,
+ mf, sizeof(mf));
+ if (dev->descriptor.iProduct)
+ usb_string(dev, dev->descriptor.iProduct,
+ prod, sizeof(prod));
+ if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER))
+ usb_string(dev, dev->descriptor.iSerialNumber,
+ serial, sizeof(serial));
+
+ /* Create a GUID for this device */
+ if (dev->descriptor.iSerialNumber && serial[0]) {
+ /* If we have a serial number, and it's a non-NULL string */
+ make_guid(guid, dev->descriptor.idVendor,
+ dev->descriptor.idProduct, serial);
+ } else {
+ /* We don't have a serial number, so we use 0 */
+ make_guid(guid, dev->descriptor.idVendor,
+ dev->descriptor.idProduct, "0");
+ }
+
+ /* lock access to the data structures */
+ down(&us_list_semaphore);
+
+ /*
+ * Now check if we have seen this GUID before
+ * We're looking for a device with a matching GUID that isn't
+ * allready on the system
+ */
+ ss = us_list;
+ while ((ss != NULL) &&
+ ((ss->pusb_dev) || !GUID_EQUAL(guid, ss->guid)))
+ ss = ss->next;
+
+ if (ss != NULL) {
+ /* Existing device -- re-connect */
+ US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
+ GUID_ARGS(guid));
+
+ /* establish the connection to the new device upon reconnect */
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+
+ /* copy over the endpoint data */
+ if (ep_in)
+ ss->ep_in = ep_in->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ if (ep_out)
+ ss->ep_out = ep_out->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->ep_int = ep_int;
+
+ /* allocate an IRQ callback if one is needed */
+ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+ return NULL;
+ } else {
+ /* New device -- allocate memory and initialize */
+ US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+
+ if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data),
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_WARNING USB_STORAGE "Out of memory\n");
+ up(&us_list_semaphore);
+ return NULL;
+ }
+ memset(ss, 0, sizeof(struct us_data));
+
+ /* allocate the URB we're going to use */
+ ss->current_urb = usb_alloc_urb(0);
+ if (!ss->current_urb) {
+ kfree(ss);
+ return NULL;
+ }
+
+ /* Initialize the mutexes only when the struct is new */
+ init_MUTEX_LOCKED(&(ss->sleeper));
+ init_MUTEX_LOCKED(&(ss->notify));
+ init_MUTEX_LOCKED(&(ss->ip_waitq));
+ init_MUTEX(&(ss->queue_exclusion));
+ init_MUTEX(&(ss->irq_urb_sem));
+ init_MUTEX(&(ss->current_urb_sem));
+ init_MUTEX(&(ss->dev_semaphore));
+
+ /* copy over the subclass and protocol data */
+ ss->subclass = subclass;
+ ss->protocol = protocol;
+ ss->flags = flags;
+
+ /* copy over the endpoint data */
+ if (ep_in)
+ ss->ep_in = ep_in->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ if (ep_out)
+ ss->ep_out = ep_out->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ ss->ep_int = ep_int;
+
+ /* establish the connection to the new device */
+ ss->ifnum = ifnum;
+ ss->pusb_dev = dev;
+
+ /* copy over the identifiying strings */
+ strncpy(ss->vendor, mf, USB_STOR_STRING_LEN);
+ strncpy(ss->product, prod, USB_STOR_STRING_LEN);
+ strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
+ if (strlen(ss->vendor) == 0)
+ strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN);
+ if (strlen(ss->product) == 0)
+ strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN);
+ if (strlen(ss->serial) == 0)
+ strncpy(ss->serial, "None", USB_STOR_STRING_LEN);
+
+ /* copy the GUID we created before */
+ memcpy(ss->guid, guid, sizeof(guid));
+
+ /*
+ * Set the handler pointers based on the protocol
+ * Again, this data is persistant across reattachments
+ */
+ switch (ss->protocol) {
+ case US_PR_CB:
+ ss->transport_name = "Control/Bulk";
+ ss->transport = usb_stor_CB_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ ss->max_lun = 7;
+ break;
+
+ case US_PR_CBI:
+ ss->transport_name = "Control/Bulk/Interrupt";
+ ss->transport = usb_stor_CBI_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ ss->max_lun = 7;
+ break;
+
+ case US_PR_BULK:
+ ss->transport_name = "Bulk";
+ ss->transport = usb_stor_Bulk_transport;
+ ss->transport_reset = usb_stor_Bulk_reset;
+ ss->max_lun = usb_stor_Bulk_max_lun(ss);
+ break;
+
+ default:
+ ss->transport_name = "Unknown";
+ up(&us_list_semaphore);
+ kfree(ss->current_urb);
+ kfree(ss);
+ return NULL;
+ break;
+ }
+ US_DEBUGP("Transport: %s\n", ss->transport_name);
+
+ /* fix for single-lun devices */
+ if (ss->flags & US_FL_SINGLE_LUN)
+ ss->max_lun = 0;
+
+ switch (ss->subclass) {
+ case US_SC_RBC:
+ ss->protocol_name = "Reduced Block Commands (RBC)";
+ ss->proto_handler = usb_stor_transparent_scsi_command;
+ break;
+
+ case US_SC_8020:
+ ss->protocol_name = "8020i";
+ ss->proto_handler = usb_stor_ATAPI_command;
+ break;
+
+ case US_SC_QIC:
+ ss->protocol_name = "QIC-157";
+ US_DEBUGP("Sorry, device not supported. Please\n");
+ US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
+ US_DEBUGP("if you see this message.\n");
+ up(&us_list_semaphore);
+ kfree(ss->current_urb);
+ kfree(ss);
+ return NULL;
+ break;
+
+ case US_SC_8070:
+ ss->protocol_name = "8070i";
+ ss->proto_handler = usb_stor_ATAPI_command;
+ break;
+
+ case US_SC_SCSI:
+ ss->protocol_name = "Transparent SCSI";
+ ss->proto_handler = usb_stor_transparent_scsi_command;
+ break;
+
+ case US_SC_UFI:
+ ss->protocol_name = "Uniform Floppy Interface (UFI)";
+ ss->proto_handler = usb_stor_ufi_command;
+ break;
+
+ default:
+ ss->protocol_name = "Unknown";
+ up(&us_list_semaphore);
+ kfree(ss->current_urb);
+ kfree(ss);
+ return NULL;
+ break;
+ }
+ US_DEBUGP("Protocol: %s\n", ss->protocol_name);
+
+ /* allocate an IRQ callback if one is needed */
+ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+ return NULL;
+
+ /*
+ * Since this is a new device, we need to generate a scsi
+ * host definition, and register with the higher SCSI layers
+ */
+
+ /* Initialize the host template based on the default one */
+ memcpy(&(ss->htmplt), &usb_stor_host_template,
+ sizeof(usb_stor_host_template));
+
+ /* Grab the next host number */
+ ss->host_number = my_host_number++;
+
+ /* We abuse this pointer so we can pass the ss pointer to
+ * the host controler thread in us_detect. But how else are
+ * we to do it?
+ */
+ (struct us_data *)ss->htmplt.proc_dir = ss;
+
+ /* start up our control thread */
+ ss->pid = kernel_thread(usb_stor_control_thread, ss,
+ CLONE_FS | CLONE_FILES |
+ CLONE_SIGHAND);
+ if (ss->pid < 0) {
+ printk(KERN_WARNING USB_STORAGE
+ "Unable to start control thread\n");
+ kfree(ss->current_urb);
+ kfree(ss);
+ return NULL;
+ }
+
+ /* wait for the thread to start */
+ down(&(ss->notify));
+
+ /* now register - our detect function will be called */
+ ss->htmplt.module = THIS_MODULE;
+ scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
+
+ /* put us in the list */
+ ss->next = us_list;
+ us_list = ss;
+ }
+
+ /* release the data structure lock */
+ up(&us_list_semaphore);
+
+ printk(KERN_DEBUG
+ "WARNING: USB Mass Storage data integrity not assured\n");
+ printk(KERN_DEBUG
+ "USB Mass Storage device found at %d\n", dev->devnum);
+
+ /* return a pointer for the disconnect function */
+ return ss;
+}
+
+/* Handle a disconnect event from the USB core */
+static void storage_disconnect(struct usb_device *dev, void *ptr)
+{
+ struct us_data *ss = ptr;
+ int result;
+
+ US_DEBUGP("storage_disconnect() called\n");
+
+ /* this is the odd case -- we disconnected but weren't using it */
+ if (!ss) {
+ US_DEBUGP("-- device was not in use\n");
+ return;
+ }
+
+ /* lock access to the device data structure */
+ down(&(ss->dev_semaphore));
+
+ /* release the IRQ, if we have one */
+ down(&(ss->irq_urb_sem));
+ if (ss->irq_urb) {
+ US_DEBUGP("-- releasing irq handle\n");
+ result = usb_unlink_urb(ss->irq_urb);
+ ss->irq_urb = NULL;
+ US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+ usb_free_urb(ss->irq_urb);
+ }
+ up(&(ss->irq_urb_sem));
+
+ /* mark the device as gone */
+ ss->pusb_dev = NULL;
+
+ /* lock access to the device data structure */
+ up(&(ss->dev_semaphore));
+}
+
+/***********************************************************************
+ * Initialization and registration
+ ***********************************************************************/
+
+int __init usb_stor_init(void)
+{
+ /* initialize internal global data elements */
+ us_list = NULL;
+ init_MUTEX(&us_list_semaphore);
+ my_host_number = 0;
+
+ /* register the driver, return -1 if error */
+ if (usb_register(&storage_driver) < 0)
+ return -1;
+
+ /* we're all set */
+ printk(KERN_INFO "USB Mass Storage support registered.\n");
+ return 0;
+}
+
+void __exit usb_stor_exit(void)
+{
+ struct us_data *next;
+
+ US_DEBUGP("usb_stor_exit() called\n");
+
+ /* Deregister the driver
+ * This eliminates races with probes and disconnects
+ */
+ US_DEBUGP("-- calling usb_deregister()\n");
+ usb_deregister(&storage_driver) ;
+
+ /* lock access to the data structures */
+ down(&us_list_semaphore);
+
+ /* While there are still virtual hosts, unregister them
+ *
+ * Note that the us_release() routine will destroy the local data
+ * structure. So we have to peel these off the top of the list
+ * and keep updating the head pointer as we go.
+ */
+ while (us_list) {
+ /* keep track of where the next one is */
+ next = us_list->next;
+
+ US_DEBUGP("-- calling scsi_unregister_module()\n");
+ scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+
+ /* Now that scsi_unregister_module is done with the host
+ * template, we can free the us_data structure (the host
+ * template is inline in this structure). */
+ kfree (us_list);
+
+ /* advance the list pointer */
+ us_list = next;
+ }
+
+ /* unlock the data structures */
+ up(&us_list_semaphore);
+}
+
+module_init(usb_stor_init) ;
+module_exit(usb_stor_exit) ;
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
new file mode 100644
index 000000000..f18b6c868
--- /dev/null
+++ b/drivers/usb/storage/usb.h
@@ -0,0 +1,182 @@
+/* Driver for USB Mass Storage compliant devices
+ * Main Header File
+ *
+ * $Id: usb.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ *
+ * Current development and maintainance by:
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices. Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document. The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#include <linux/usb.h>
+#include <linux/blk.h>
+#include <linux/smp_lock.h>
+#include "scsi.h"
+#include "hosts.h"
+
+/*
+ * GUID definitions
+ */
+
+#define GUID(x) __u32 x[3]
+#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2])
+#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0;
+#define GUID_NONE(x) (!x[0] && !x[1] && !x[2])
+#define GUID_FORMAT "%08x%08x%08x"
+#define GUID_ARGS(x) x[0], x[1], x[2]
+
+static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial)
+{
+ pg[0] = (vendor << 16) | product;
+ pg[1] = pg[2] = 0;
+ while (*serial) {
+ pg[1] <<= 4;
+ pg[1] |= pg[2] >> 28;
+ pg[2] <<= 4;
+ if (*serial >= 'a')
+ *serial -= 'a' - 'A';
+ pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0'
+ : *serial - 'A' + 10;
+ serial++;
+ }
+}
+
+/*
+ * Unusual device list definitions
+ */
+
+struct us_unusual_dev {
+ /* we search the list based on these parameters */
+ __u16 idVendor;
+ __u16 idProduct;
+ __u16 bcdDeviceMin;
+ __u16 bcdDeviceMax;
+
+ /* the list specifies these parameters */
+ const char* name;
+ __u8 useProtocol;
+ __u8 useTransport;
+ unsigned int flags;
+};
+
+/* Flag definitions */
+#define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */
+#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for
+ Win/MacOS compatibility */
+#define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */
+#define US_FL_ALT_LENGTH 0x00000008 /* use the alternate algorithm for
+ us_transfer_length() */
+#define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */
+
+#define USB_STOR_STRING_LEN 32
+
+struct us_data;
+
+typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
+typedef int (*trans_reset)(struct us_data*);
+typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
+
+/* we allocate one of these for every device that we remember */
+struct us_data {
+ struct us_data *next; /* next device */
+
+ /* the device we're working with */
+ struct semaphore dev_semaphore; /* protect pusb_dev */
+ struct usb_device *pusb_dev; /* this usb_device */
+
+ unsigned int flags; /* from filter initially */
+
+ /* information about the device -- always good */
+ char vendor[USB_STOR_STRING_LEN];
+ char product[USB_STOR_STRING_LEN];
+ char serial[USB_STOR_STRING_LEN];
+ char *transport_name;
+ char *protocol_name;
+ u8 subclass;
+ u8 protocol;
+ u8 max_lun;
+
+ /* information about the device -- only good if device is attached */
+ u8 ifnum; /* interface number */
+ u8 ep_in; /* bulk in endpoint */
+ u8 ep_out; /* bulk out endpoint */
+ struct usb_endpoint_descriptor *ep_int; /* interrupt endpoint */
+
+ /* function pointers for this device */
+ trans_cmnd transport; /* transport function */
+ trans_reset transport_reset; /* transport device reset */
+ proto_cmnd proto_handler; /* protocol handler */
+
+ /* SCSI interfaces */
+ GUID(guid); /* unique dev id */
+ struct Scsi_Host *host; /* our dummy host data */
+ Scsi_Host_Template htmplt; /* own host template */
+ int host_number; /* to find us */
+ int host_no; /* allocated by scsi */
+ Scsi_Cmnd *srb; /* current srb */
+
+ /* thread information */
+ Scsi_Cmnd *queue_srb; /* the single queue slot */
+ int action; /* what to do */
+ int pid; /* control thread */
+
+ /* interrupt info for CBI devices -- only good if attached */
+ struct semaphore ip_waitq; /* for CBI interrupts */
+ int ip_wanted; /* is an IRQ expected? */
+
+ /* interrupt communications data */
+ struct semaphore irq_urb_sem; /* to protect irq_urb */
+ struct urb *irq_urb; /* for USB int requests */
+ unsigned char irqbuf[2]; /* buffer for USB IRQ */
+
+ /* control and bulk communications data */
+ struct semaphore current_urb_sem; /* to protect irq_urb */
+ struct urb *current_urb; /* non-int USB requests */
+
+ /* mutual exclusion structures */
+ struct semaphore notify; /* thread begin/end */
+ struct semaphore sleeper; /* to sleep the thread on */
+ struct semaphore queue_exclusion; /* to protect data structs */
+};
+
+/* The list of structures and the protective lock for them */
+extern struct us_data *us_list;
+extern struct semaphore us_list_semaphore;
+
+#endif
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 08ef79fe4..3fba783e0 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -1683,8 +1683,9 @@ int usb_new_device(struct usb_device *dev)
usb_set_maxpacket(dev);
/* we set the default configuration here */
- if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
- err("failed to set default configuration");
+ err = usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+ if (err) {
+ err("failed to set default configuration (error=%d)", err);
return -1;
}
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 864e30f0c..3707b611a 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -292,19 +292,27 @@ fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
struct fb_fix_screeninfo fix;
- char *base_addr;
- ssize_t copy_size;
if (! fb || ! info->disp)
return -ENODEV;
fb->fb_get_fix(&fix,PROC_CONSOLE(info), info);
- base_addr=info->disp->screen_base;
- copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
- if (copy_to_user(buf, base_addr+p, copy_size))
- return -EFAULT;
- *ppos += copy_size;
- return copy_size;
+ if (p >= fix.smem_len)
+ return 0;
+ if (count >= fix.smem_len)
+ count = fix.smem_len;
+ if (count + p > fix.smem_len)
+ count = fix.smem_len - p;
+ if (count) {
+ char *base_addr;
+
+ base_addr = info->disp->screen_base;
+ count -= copy_to_user(buf, base_addr+p, count);
+ if (!count)
+ return -EFAULT;
+ *ppos += count;
+ }
+ return count;
}
static ssize_t
@@ -316,19 +324,32 @@ fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
struct fb_fix_screeninfo fix;
- char *base_addr;
- ssize_t copy_size;
+ int err;
if (! fb || ! info->disp)
return -ENODEV;
fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);
- base_addr=info->disp->screen_base;
- copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
- if (copy_from_user(base_addr+p, buf, copy_size))
- return -EFAULT;
- file->f_pos += copy_size;
- return copy_size;
+ if (p > fix.smem_len)
+ return -ENOSPC;
+ if (count >= fix.smem_len)
+ count = fix.smem_len;
+ err = 0;
+ if (count + p > fix.smem_len) {
+ count = fix.smem_len - p;
+ err = -ENOSPC;
+ }
+ if (count) {
+ char *base_addr;
+
+ base_addr = info->disp->screen_base;
+ count -= copy_from_user(base_addr+p, buf, count);
+ *ppos += count;
+ err = -EFAULT;
+ }
+ if (count)
+ return count;
+ return err;
}
#ifdef CONFIG_KMOD
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 91dfca4ab..4c2a13791 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -1,7 +1,9 @@
/*
* linux/drivers/video/rivafb.c - nVidia RIVA 128/TNT/TNT2 fb driver
*
- * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
+ *
+ * Copyright 1999-2000 Jeff Garzik
*
* Contributors:
*
@@ -20,7 +22,7 @@
*/
/* version number of this driver */
-#define RIVAFB_VERSION "0.7.1"
+#define RIVAFB_VERSION "0.7.2"
#include <linux/config.h>
#include <linux/module.h>
@@ -208,10 +210,10 @@ struct rivafb_info {
static struct rivafb_info *riva_boards = NULL;
/* command line data, set in rivafb_setup() */
-static char fontname[40] __initdata;
+static char fontname[40] __initdata = { 0 };
#ifndef MODULE
-static char noaccel __initdata; /* unused */
-static const char *mode_option __initdata;
+static char noaccel __initdata = 0; /* unused */
+static const char *mode_option __initdata = NULL;
#endif
static struct fb_var_screeninfo rivafb_default_var = {
@@ -253,14 +255,14 @@ static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
struct fb_info *info);
static int riva_get_cmap_len (const struct fb_var_screeninfo *var);
-static int riva_pci_register (struct pci_dev *pd,
- const struct riva_chip_info *rci);
static int riva_set_fbinfo (struct rivafb_info *rinfo);
static void riva_save_state (struct rivafb_info *rinfo, struct riva_regs *regs);
static void riva_load_state (struct rivafb_info *rinfo, struct riva_regs *regs);
static struct rivafb_info *riva_board_list_add (struct rivafb_info *board_list,
struct rivafb_info *new_node);
+static struct rivafb_info *riva_board_list_del (struct rivafb_info *board_list,
+ struct rivafb_info *del_node);
static void riva_wclut (unsigned char regnum, unsigned char red,
unsigned char green, unsigned char blue);
@@ -286,7 +288,7 @@ static struct fb_ops riva_fb_ops = {
static const struct riva_regs reg_template = {
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x01, 0x0F, 0x13, 0x00},
+ 0x41, 0x01, 0x0F, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CRT */
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, /* 0x10 */
@@ -378,9 +380,6 @@ static int riva_init_disp_var (struct rivafb_info *rinfo)
if (mode_option)
fb_find_mode (&rinfo->disp.var, &rinfo->info, mode_option,
NULL, 0, NULL, 8);
- else
- fb_find_mode (&rinfo->disp.var, &rinfo->info,
- "640x480-8@60", NULL, 0, NULL, 8);
#endif /* !MODULE */
return 0;
}
@@ -447,13 +446,13 @@ static int __devinit riva_set_fbinfo (struct rivafb_info *rinfo)
info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &riva_fb_ops;
-#warning FIXME: set monspecs to what???
+ /* FIXME: set monspecs to what??? */
- info->display_fg = NULL; /* FIXME: correct? */
+ info->display_fg = NULL;
strncpy (info->fontname, fontname, sizeof (info->fontname));
info->fontname[sizeof (info->fontname) - 1] = 0;
- info->changevar = NULL; /* FIXME: needed? */
+ info->changevar = NULL;
info->switch_con = rivafb_switch;
info->updatevar = rivafb_updatevar;
info->blank = rivafb_blank;
@@ -472,32 +471,6 @@ static int __devinit riva_set_fbinfo (struct rivafb_info *rinfo)
-static void __devinit riva_init_clut (struct rivafb_info *fb_info)
-{
- int j, k, red, green, blue;
-
- for (j = 0; j < 256; j++) {
- if (j < 16) {
- /* use default fbcon colors for first 16 */
- k = color_table[j];
- red = default_red[k];
- green = default_grn[k];
- blue = default_blu[k];
- } else {
- /* grey ramp for rest of colors */
- red = green = blue = j;
- }
-
- riva_wclut (j, red, green, blue);
-
- fb_info->palette[j].red = red;
- fb_info->palette[j].green = green;
- fb_info->palette[j].blue = blue;
- }
-}
-
-
-
static int __devinit rivafb_init_one (struct pci_dev *pd,
const struct pci_device_id *ent)
{
@@ -597,7 +570,7 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
riva_set_fbinfo (rinfo);
- riva_init_clut (rinfo);
+ fb_memset (rinfo->fb_base, 0, rinfo->ram_amount);
riva_load_video_mode (rinfo, &rinfo->disp.var);
@@ -607,6 +580,8 @@ static int __devinit rivafb_init_one (struct pci_dev *pd,
goto err_out_iounmap_fb;
}
+ riva_boards = riva_board_list_add(riva_boards, rinfo);
+
pd->driver_data = rinfo;
printk ("PCI Riva NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
@@ -640,6 +615,8 @@ static void __devexit rivafb_remove_one (struct pci_dev *pd)
if (!board)
return;
+ riva_boards = riva_board_list_del(riva_boards, board);
+
riva_load_state (board, &board->initial_state);
unregister_framebuffer ((struct fb_info *) board);
@@ -1355,6 +1332,7 @@ static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
{
struct rivafb_info *rivainfo = (struct rivafb_info *) info;
struct display *p;
+ unsigned shift = 8;
DPRINTK ("ENTER\n");
@@ -1370,11 +1348,22 @@ static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
red = green = blue =
(red * 77 + green * 151 + blue * 28) >> 8;
}
+
+ switch (rivainfo->riva.Architecture) {
+ case 3:
+ shift = 10;
+ break;
+ case 4:
+ case 5:
+ shift = 8;
+ break;
+ }
+
#ifdef FBCON_HAS_CFB8
switch (p->var.bits_per_pixel) {
case 8:
/* "transparent" stuff is completely ignored. */
- riva_wclut (regno, red >> 10, green >> 10, blue >> 10);
+ riva_wclut (regno, red >> shift, green >> shift, blue >> shift);
break;
default:
/* do nothing */
@@ -1469,24 +1458,24 @@ static void riva_load_video_mode (struct rivafb_info *rinfo,
newmode.crtc[0x0] = Set8Bits (hTotal - 4);
newmode.crtc[0x1] = Set8Bits (hDisplay);
newmode.crtc[0x2] = Set8Bits (hDisplay);
- newmode.crtc[0x3] = SetBitField (hTotal, 4: 0, 4:0) | SetBit (7);
+ newmode.crtc[0x3] = SetBitField (hTotal, 4: 0, 4:0) | SetBit (7);
newmode.crtc[0x4] = Set8Bits (hStart);
- newmode.crtc[0x5] = SetBitField (hTotal, 5: 5, 7:7)
- | SetBitField (hEnd, 4: 0, 4:0);
- newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
- newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
- | SetBitField (vDisplay, 8: 8, 1:1)
- | SetBitField (vStart, 8: 8, 2:2)
- | SetBitField (vDisplay, 8: 8, 3:3)
- | SetBit (4)
- | SetBitField (vTotal, 9: 9, 5:5)
- | SetBitField (vDisplay, 9: 9, 6:6)
- | SetBitField (vStart, 9: 9, 7:7);
- newmode.crtc[0x9] = SetBitField (vDisplay, 9: 9, 5:5)
- | SetBit (6);
+ newmode.crtc[0x5] = SetBitField (hTotal, 5: 5, 7:7)
+ | SetBitField (hEnd, 4: 0, 4:0);
+ newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
+ newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
+ | SetBitField (vDisplay, 8: 8, 1:1)
+ | SetBitField (vStart, 8: 8, 2:2)
+ | SetBitField (vDisplay, 8: 8, 3:3)
+ | SetBit (4)
+ | SetBitField (vTotal, 9: 9, 5:5)
+ | SetBitField (vDisplay, 9: 9, 6:6)
+ | SetBitField (vStart, 9: 9, 7:7);
+ newmode.crtc[0x9] = SetBitField (vDisplay, 9: 9, 5:5)
+ | SetBit (6);
newmode.crtc[0x10] = Set8Bits (vStart);
- newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
- | SetBit (5);
+ newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
+ | SetBit (5);
newmode.crtc[0x12] = Set8Bits (vDisplay);
newmode.crtc[0x13] = ((width / 8) * (bpp / 8)) & 0xFF;
newmode.crtc[0x15] = Set8Bits (vDisplay);
@@ -1538,7 +1527,7 @@ module_init(rivafb_init);
#endif /* MODULE */
module_exit(rivafb_exit);
-MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR("Ani Joshi, maintainer");
MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2");
@@ -1644,7 +1633,7 @@ void riva_load_state (struct rivafb_info *rinfo, struct riva_regs *regs)
for (i = 0; i < NUM_ATC_REGS; i++) {
io_out8 (i, 0x3C0);
- io_out8 (regs->attr[i], 0x3C1);
+ io_out8 (regs->attr[i], 0x3C0);
}
for (i = 0; i < NUM_GRC_REGS; i++) {
@@ -1689,3 +1678,33 @@ struct rivafb_info *riva_board_list_add (struct rivafb_info *board_list,
return board_list;
}
+
+
+
+/**
+ * riva_board_list_del
+ * @board_list: Root node of list of boards
+ * @del_node: Node to be removed
+ *
+ * DESCRIPTION:
+ * Removes @del_node from the list referenced by @board_list
+ *
+ * RETURNS:
+ * New root node
+ */
+static
+struct rivafb_info *riva_board_list_del (struct rivafb_info *board_list,
+ struct rivafb_info *del_node)
+{
+ struct rivafb_info *i_p = board_list;
+
+ if (board_list == del_node)
+ return del_node->next;
+
+ while (i_p->next != del_node)
+ i_p = i_p->next;
+ i_p->next = del_node->next;
+
+ return board_list;
+}
+
diff --git a/drivers/video/sisfb.c b/drivers/video/sisfb.c
index d42448fbf..019a86a8e 100644
--- a/drivers/video/sisfb.c
+++ b/drivers/video/sisfb.c
@@ -175,9 +175,9 @@ static struct board {
const char *name;
} dev_list[] = {
{
- PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, {
- PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540, "SIS 540"}, {
- PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, "SIS 630"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300, "SIS 300"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5300, "SIS 540"}, {
+ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_6300, "SIS 630"}, {
0, 0, NULL}
};
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 473f5019a..499d8fef7 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -1994,7 +1994,7 @@ int __init tdfxfb_init(void) {
fb_info.iobase = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
#else
- fb_info.regbase_phys = pdev->resource[0].start;
+ fb_info.regbase_phys = pci_resource_start(pdev, 0);
fb_info.regbase_size = 1 << 24;
fb_info.regbase_virt =
(unsigned long)ioremap_nocache(fb_info.regbase_phys, 1 << 24);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 9fd867d0e..7f0e51187 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -674,9 +674,8 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
interpreter,
&interp_load_addr);
- lock_kernel();
+ allow_write_access(interpreter);
fput(interpreter);
- unlock_kernel();
kfree(elf_interpreter);
if (elf_entry == ~0UL) {
@@ -763,9 +762,8 @@ out:
/* error cleanup */
out_free_dentry:
- lock_kernel();
+ allow_write_access(interpreter);
fput(interpreter);
- unlock_kernel();
out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 1b18094eb..95c24a70a 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -17,6 +17,7 @@
#include <linux/binfmts.h>
#include <linux/elf.h>
#include <linux/init.h>
+#include <linux/file.h>
#define EM86_INTERP "/usr/bin/em86"
@@ -43,6 +44,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
}
bprm->sh_bang++; /* Well, the bang-shell is implicit... */
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 0d44c3d4e..f9c30df1b 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -201,6 +201,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (!fmt)
goto _ret;
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index dc78f8389..3d5023e2d 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -29,6 +29,7 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
*/
bprm->sh_bang++;
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index c455a735d..29972c8ca 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -313,7 +313,7 @@ ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
* since the vma has no handle.
*/
-static int block_fsync(struct file *filp, struct dentry *dentry)
+static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
{
return fsync_dev(dentry->d_inode->i_rdev);
}
@@ -597,6 +597,8 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind)
ret = bdev->bd_op->open(fake_inode, &fake_file);
if (!ret)
atomic_inc(&bdev->bd_openers);
+ else if (!atomic_read(&bdev->bd_openers))
+ bdev->bd_op = NULL;
iput(fake_inode);
}
}
@@ -617,6 +619,8 @@ int blkdev_open(struct inode * inode, struct file * filp)
ret = bdev->bd_op->open(inode,filp);
if (!ret)
atomic_inc(&bdev->bd_openers);
+ else if (!atomic_read(&bdev->bd_openers))
+ bdev->bd_op = NULL;
}
up(&bdev->bd_sem);
return ret;
diff --git a/fs/buffer.c b/fs/buffer.c
index 47d690fa4..b1e1c33b7 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -323,7 +323,7 @@ asmlinkage long sys_sync(void)
* filp may be NULL if called via the msync of a vma.
*/
-int file_fsync(struct file *filp, struct dentry *dentry)
+int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
{
struct inode * inode = dentry->d_inode;
struct super_block * sb;
@@ -332,7 +332,7 @@ int file_fsync(struct file *filp, struct dentry *dentry)
lock_kernel();
/* sync the inode to buffers */
- write_inode_now(inode);
+ write_inode_now(inode, 0);
/* sync the superblock to buffers */
sb = inode->i_sb;
@@ -360,12 +360,7 @@ asmlinkage long sys_fsync(unsigned int fd)
goto out;
dentry = file->f_dentry;
- if (!dentry)
- goto out_putf;
-
inode = dentry->d_inode;
- if (!inode)
- goto out_putf;
err = -EINVAL;
if (!file->f_op || !file->f_op->fsync)
@@ -373,7 +368,7 @@ asmlinkage long sys_fsync(unsigned int fd)
/* We need to protect against concurrent writers.. */
down(&inode->i_sem);
- err = file->f_op->fsync(file, dentry);
+ err = file->f_op->fsync(file, dentry, 0);
up(&inode->i_sem);
out_putf:
@@ -395,20 +390,14 @@ asmlinkage long sys_fdatasync(unsigned int fd)
goto out;
dentry = file->f_dentry;
- if (!dentry)
- goto out_putf;
-
inode = dentry->d_inode;
- if (!inode)
- goto out_putf;
err = -EINVAL;
if (!file->f_op || !file->f_op->fsync)
goto out_putf;
- /* this needs further work, at the moment it is identical to fsync() */
down(&inode->i_sem);
- err = file->f_op->fsync(file, dentry);
+ err = file->f_op->fsync(file, dentry, 1);
up(&inode->i_sem);
out_putf:
@@ -2101,6 +2090,7 @@ static int grow_buffers(int size)
spin_unlock(&free_list[isize].lock);
page->buffers = bh;
+ page->flags &= ~(1 << PG_referenced);
lru_cache_add(page);
atomic_inc(&buffermem_pages);
return 1;
@@ -2499,7 +2489,7 @@ asmlinkage long sys_bdflush(int func, long data)
* the syscall above, but now we launch it ourselves internally with
* kernel_thread(...) directly after the first thread in init/main.c
*/
-int bdflush(void * unused)
+int bdflush(void *sem)
{
struct task_struct *tsk = current;
int flushed;
@@ -2521,6 +2511,8 @@ int bdflush(void * unused)
recalc_sigpending(tsk);
spin_unlock_irq(&tsk->sigmask_lock);
+ up((struct semaphore *)sem);
+
for (;;) {
CHECK_EMERGENCY_SYNC
@@ -2555,7 +2547,7 @@ int bdflush(void * unused)
* You don't need to change your userspace configuration since
* the userspace `update` will do_exit(0) at the first sys_bdflush().
*/
-int kupdate(void * unused)
+int kupdate(void *sem)
{
struct task_struct * tsk = current;
int interval;
@@ -2571,6 +2563,8 @@ int kupdate(void * unused)
recalc_sigpending(tsk);
spin_unlock_irq(&tsk->sigmask_lock);
+ up((struct semaphore *)sem);
+
for (;;) {
/* update interval */
interval = bdf_prm.b_un.interval;
@@ -2604,8 +2598,11 @@ int kupdate(void * unused)
static int __init bdflush_init(void)
{
- kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
- kernel_thread(kupdate, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ DECLARE_MUTEX_LOCKED(sem);
+ kernel_thread(bdflush, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ down(&sem);
+ kernel_thread(kupdate, &sem, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ down(&sem);
return 0;
}
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index e949f7986..0e6fa5625 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -55,7 +55,7 @@ static void coda_prepare_fakefile(struct inode *coda_inode,
struct dentry *open_dentry);
static int coda_venus_readdir(struct file *filp, void *dirent,
filldir_t filldir);
-int coda_fsync(struct file *, struct dentry *dentry);
+int coda_fsync(struct file *, struct dentry *dentry, int datasync);
int coda_hasmknod = 0;
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 9aecd716a..128b07d44 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -40,7 +40,7 @@ coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
}
/* exported from this file (used for dirs) */
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
+int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
{
struct inode *inode = coda_dentry->d_inode;
struct dentry cont_dentry;
@@ -60,7 +60,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
cont_dentry.d_inode = (struct inode *)inode->i_mapping->host;
down(&cont_dentry.d_inode->i_sem);
- result = file_fsync(NULL, &cont_dentry);
+ result = file_fsync(NULL, &cont_dentry, datasync);
up(&cont_dentry.d_inode->i_sem);
if ( result == 0 ) {
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 45025e871..14fe68ad4 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -109,7 +109,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
ssize_t retval = 0, count = 0;
int error;
- if ( !coda_upc_comm.vc_pid )
+ if ( !coda_upc_comm.vc_inuse )
return -EIO;
/* Peek at the opcode, uniquefier */
if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
@@ -291,29 +291,14 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
struct venus_comm *vcp = &coda_upc_comm;
ENTRY;
- /* first opener: must be lento. Initialize & take its pid */
- if ( (file->f_flags & O_ACCMODE) == O_RDWR ) {
- if ( vcp->vc_pid ) {
- printk("Venus pid already set to %d!!\n", vcp->vc_pid);
- return -1;
- }
- if ( vcp->vc_inuse ) {
- printk("psdev_open: Cannot O_RDWR while open.\n");
- return -1;
- }
- }
-
- vcp->vc_inuse++;
-
- if ( (file->f_flags & O_ACCMODE) == O_RDWR ) {
- vcp->vc_pid = current->pid;
- vcp->vc_seq = 0;
- INIT_LIST_HEAD(&vcp->vc_pending);
- INIT_LIST_HEAD(&vcp->vc_processing);
+ /* first opener, initialize */
+ if (!vcp->vc_inuse++) {
+ INIT_LIST_HEAD(&vcp->vc_pending);
+ INIT_LIST_HEAD(&vcp->vc_processing);
+ vcp->vc_seq = 0;
}
- CDEBUG(D_PSDEV, "inuse: %d, vc_pid %d, caller %d\n",
- vcp->vc_inuse, vcp->vc_pid, current->pid);
+ CDEBUG(D_PSDEV, "inuse: %d\n", vcp->vc_inuse);
EXIT;
return 0;
@@ -332,17 +317,9 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
return -1;
}
- vcp->vc_inuse--;
- CDEBUG(D_PSDEV, "inuse: %d, vc_pid %d, caller %d\n",
- vcp->vc_inuse, vcp->vc_pid, current->pid);
-
- if ( vcp->vc_pid != current->pid ) {
- /* FIXME: this is broken. If venus does fork(), accounting goes wrong */
- printk( "Closed by someone else than caller?\n" );
- return 0;
- }
+ CDEBUG(D_PSDEV, "psdev_release: inuse %d\n", vcp->vc_inuse);
+ if (--vcp->vc_inuse) return 0;
- vcp->vc_pid = 0;
/* Wakeup clients so they can return. */
CDEBUG(D_PSDEV, "wake up pending clients\n");
lh = vcp->vc_pending.next;
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 674c8cb3b..206c9d8b0 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -625,7 +625,7 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
set_current_state(TASK_UNINTERRUPTIBLE);
/* venus died */
- if ( !coda_upc_comm.vc_pid )
+ if ( !coda_upc_comm.vc_inuse )
break;
/* got a reply */
@@ -688,7 +688,7 @@ static int coda_upcall(struct coda_sb_info *sbi,
ENTRY;
vcommp = &coda_upc_comm;
- if ( !vcommp->vc_pid ) {
+ if ( !vcommp->vc_inuse ) {
printk("No pseudo device in upcall comms at %p\n", vcommp);
return -ENXIO;
}
@@ -733,7 +733,7 @@ ENTRY;
CDEBUG(D_UPCALL,
"..process %d woken up by Venus for req at %p, data at %p\n",
current->pid, req, req->uc_data);
- if (vcommp->vc_pid) { /* i.e. Venus is still alive */
+ if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
/* Op went through, interrupt or not... */
if (req->uc_flags & REQ_WRITE) {
out = (union outputArgs *)req->uc_data;
diff --git a/fs/exec.c b/fs/exec.c
index 2ab337341..ce1031e3b 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -101,37 +101,54 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
*/
asmlinkage long sys_uselib(const char * library)
{
- int fd, retval;
struct file * file;
+ struct nameidata nd;
+ int error;
- fd = sys_open(library, 0, 0);
- if (fd < 0)
- return fd;
- file = fget(fd);
- retval = -ENOEXEC;
- if (file) {
- if(file->f_op && file->f_op->read) {
- struct linux_binfmt * fmt;
+ error = user_path_walk(library, &nd);
+ if (error)
+ goto out;
- read_lock(&binfmt_lock);
- for (fmt = formats ; fmt ; fmt = fmt->next) {
- if (!fmt->load_shlib)
- continue;
- if (!try_inc_mod_count(fmt->module))
- continue;
- read_unlock(&binfmt_lock);
- retval = fmt->load_shlib(file);
- read_lock(&binfmt_lock);
- put_binfmt(fmt);
- if (retval != -ENOEXEC)
- break;
- }
+ error = -EINVAL;
+ if (!S_ISREG(nd.dentry->d_inode->i_mode))
+ goto exit;
+
+ error = permission(nd.dentry->d_inode, MAY_READ | MAY_EXEC);
+ if (error)
+ goto exit;
+
+ lock_kernel();
+ file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
+ unlock_kernel();
+ error = PTR_ERR(file);
+ if (IS_ERR(file))
+ goto out;
+
+ error = -ENOEXEC;
+ if(file->f_op && file->f_op->read) {
+ struct linux_binfmt * fmt;
+
+ read_lock(&binfmt_lock);
+ for (fmt = formats ; fmt ; fmt = fmt->next) {
+ if (!fmt->load_shlib)
+ continue;
+ if (!try_inc_mod_count(fmt->module))
+ continue;
read_unlock(&binfmt_lock);
+ error = fmt->load_shlib(file);
+ read_lock(&binfmt_lock);
+ put_binfmt(fmt);
+ if (error != -ENOEXEC)
+ break;
}
- fput(file);
+ read_unlock(&binfmt_lock);
}
- sys_close(fd);
- return retval;
+ fput(file);
+out:
+ return error;
+exit:
+ path_release(&nd);
+ goto out;
}
/*
@@ -319,6 +336,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
struct file *open_exec(const char *name)
{
struct nameidata nd;
+ struct inode *inode;
struct file *file;
int err = 0;
@@ -328,14 +346,22 @@ struct file *open_exec(const char *name)
unlock_kernel();
file = ERR_PTR(err);
if (!err) {
+ inode = nd.dentry->d_inode;
file = ERR_PTR(-EACCES);
- if (S_ISREG(nd.dentry->d_inode->i_mode)) {
- int err = permission(nd.dentry->d_inode, MAY_EXEC);
+ if (!IS_NOEXEC(inode) && S_ISREG(inode->i_mode)) {
+ int err = permission(inode, MAY_EXEC);
file = ERR_PTR(err);
if (!err) {
lock_kernel();
file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
unlock_kernel();
+ if (!IS_ERR(file)) {
+ err = deny_write_access(file);
+ if (err) {
+ fput(file);
+ file = ERR_PTR(err);
+ }
+ }
out:
return file;
}
@@ -540,23 +566,13 @@ static inline int must_not_trace_exec(struct task_struct * p)
int prepare_binprm(struct linux_binprm *bprm)
{
int mode;
- int retval,id_change,cap_raised;
+ int id_change,cap_raised;
struct inode * inode = bprm->file->f_dentry->d_inode;
mode = inode->i_mode;
- if (!S_ISREG(mode)) /* must be regular file */
- return -EACCES;
- if (!(mode & 0111)) /* with at least _one_ execute bit set */
+ /* Huh? We had already checked for MAY_EXEC, WTF do we check this? */
+ if (!(mode & 0111)) /* with at least _one_ execute bit set */
return -EACCES;
- if (IS_NOEXEC(inode)) /* FS mustn't be mounted noexec */
- return -EACCES;
- if (!inode->i_sb)
- return -EACCES;
- if ((retval = permission(inode, MAY_EXEC)) != 0)
- return retval;
- /* better not execute files which are being written to */
- if (atomic_read(&inode->i_writecount) > 0)
- return -ETXTBSY;
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
@@ -728,6 +744,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
char * dynloader[] = { "/sbin/loader" };
struct file * file;
+ allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
@@ -761,6 +778,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
retval = fn(bprm, regs);
if (retval >= 0) {
put_binfmt(fmt);
+ allow_write_access(bprm->file);
if (bprm->file)
fput(bprm->file);
bprm->file = NULL;
@@ -822,11 +840,13 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
+ allow_write_access(file);
fput(file);
return bprm.envc;
}
@@ -855,6 +875,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
out:
/* Something went wrong, return the inode and free the argument pages*/
+ allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 52ffd6138..1e4478cc7 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -124,7 +124,7 @@ static int sync_tindirect(struct inode * inode, u32 * tiblock, int wait)
* even pass file to fsync ?
*/
-int ext2_sync_file(struct file * file, struct dentry *dentry)
+int ext2_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
int wait, err = 0;
struct inode *inode = dentry->d_inode;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 7e5263fb1..d999b2b4f 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -904,7 +904,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
return err;
}
-void ext2_write_inode (struct inode * inode)
+void ext2_write_inode (struct inode * inode, int wait)
{
lock_kernel();
ext2_update_inode (inode, 0);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index aa6a599fc..d3af3b992 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -593,7 +593,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
/*
* set up enough so that it can read an inode
*/
- sb->s_dev = dev;
sb->s_op = &ext2_sops;
sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
if (!sb->s_root) {
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 85cc4e1a6..bd8d0ae26 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -837,7 +837,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
MSDOS_I(inode)->i_ctime_ms = de->ctime_ms;
}
-void fat_write_inode(struct inode *inode)
+void fat_write_inode(struct inode *inode, int wait)
{
struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index f6e4e1651..37e32a012 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -252,8 +252,8 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
err = sock_fcntl (filp, cmd, arg);
break;
}
- fput(filp);
unlock_kernel();
+ fput(filp);
out:
return err;
}
diff --git a/fs/file_table.c b/fs/file_table.c
index ecaa46896..5c722143d 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -16,9 +16,7 @@
static kmem_cache_t *filp_cache;
/* sysctl tunables... */
-int nr_files; /* read only */
-int nr_free_files; /* read only */
-int max_files = NR_FILE;/* tunable */
+struct files_stat_struct files_stat = {0, 0, NR_FILE};
/* Here the new files go */
static LIST_HEAD(anon_list);
@@ -53,11 +51,11 @@ struct file * get_empty_filp(void)
struct file * f;
file_list_lock();
- if (nr_free_files > NR_RESERVED_FILES) {
+ if (files_stat.nr_free_files > NR_RESERVED_FILES) {
used_one:
f = list_entry(free_list.next, struct file, f_list);
list_del(&f->f_list);
- nr_free_files--;
+ files_stat.nr_free_files--;
new_one:
file_list_unlock();
memset(f, 0, sizeof(*f));
@@ -73,25 +71,25 @@ struct file * get_empty_filp(void)
/*
* Use a reserved one if we're the superuser
*/
- if (nr_free_files && !current->euid)
+ if (files_stat.nr_free_files && !current->euid)
goto used_one;
/*
* Allocate a new one if we're below the limit.
*/
- if (nr_files < max_files) {
+ if (files_stat.nr_files < files_stat.max_files) {
file_list_unlock();
f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
file_list_lock();
if (f) {
- nr_files++;
+ files_stat.nr_files++;
goto new_one;
}
/* Big problems... */
printk("VFS: filp allocation failed\n");
- } else if (max_files > old_max) {
- printk("VFS: file-max limit %d reached\n", max_files);
- old_max = max_files;
+ } else if (files_stat.max_files > old_max) {
+ printk("VFS: file-max limit %d reached\n", files_stat.max_files);
+ old_max = files_stat.max_files;
}
file_list_unlock();
return NULL;
@@ -148,7 +146,7 @@ void _fput(struct file *file)
file_list_lock();
list_del(&file->f_list);
list_add(&file->f_list, &free_list);
- nr_free_files++;
+ files_stat.nr_free_files++;
file_list_unlock();
}
@@ -160,7 +158,7 @@ void put_filp(struct file *file)
file_list_lock();
list_del(&file->f_list);
list_add(&file->f_list, &free_list);
- nr_free_files++;
+ files_stat.nr_free_files++;
file_list_unlock();
}
}
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index c0707b52c..4a301f593 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -23,7 +23,7 @@ int hpfs_file_release(struct inode *inode, struct file *file)
return 0;
}
-int hpfs_file_fsync(struct file *file, struct dentry *dentry)
+int hpfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
{
/*return file_fsync(file, dentry);*/
return 0; /* Don't fsync :-) */
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index a01140f1f..78341ca16 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -256,7 +256,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int);
int hpfs_file_release(struct inode *, struct file *);
int hpfs_open(struct inode *, struct file *);
-int hpfs_file_fsync(struct file *, struct dentry *);
+int hpfs_file_fsync(struct file *, struct dentry *, int);
secno hpfs_bmap(struct inode *, unsigned);
void hpfs_truncate(struct inode *);
int hpfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create);
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index b09ad98ea..5684801df 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -330,7 +330,15 @@ int hpfs_unlink(struct inode *dir, struct dentry *dentry)
struct iattr newattrs;
int err;
hpfs_unlock_2inodes(dir, inode);
- if (rep || dentry->d_count > 1 || permission(inode, MAY_WRITE) || get_write_access(inode)) goto ret;
+ if (rep)
+ goto ret;
+ d_drop(dentry);
+ if (dentry->d_count > 1 ||
+ permission(inode, MAY_WRITE) ||
+ get_write_access(inode)) {
+ d_rehash(dentry);
+ goto ret;
+ }
/*printk("HPFS: truncating file before delete.\n");*/
down(&inode->i_sem);
newattrs.ia_size = 0;
diff --git a/fs/inode.c b/fs/inode.c
index e46359b03..3dbd9f54e 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -162,10 +162,10 @@ static inline void wait_on_inode(struct inode *inode)
}
-static inline void write_inode(struct inode *inode)
+static inline void write_inode(struct inode *inode, int sync)
{
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
- inode->i_sb->s_op->write_inode(inode);
+ inode->i_sb->s_op->write_inode(inode, sync);
}
static inline void __iget(struct inode * inode)
@@ -182,7 +182,7 @@ static inline void __iget(struct inode * inode)
inodes_stat.nr_unused--;
}
-static inline void sync_one(struct inode *inode)
+static inline void sync_one(struct inode *inode, int sync)
{
if (inode->i_state & I_LOCK) {
__iget(inode);
@@ -199,7 +199,7 @@ static inline void sync_one(struct inode *inode)
inode->i_state ^= I_DIRTY | I_LOCK;
spin_unlock(&inode_lock);
- write_inode(inode);
+ write_inode(inode, sync);
spin_lock(&inode_lock);
inode->i_state &= ~I_LOCK;
@@ -212,7 +212,7 @@ static inline void sync_list(struct list_head *head)
struct list_head * tmp;
while ((tmp = head->prev) != head)
- sync_one(list_entry(tmp, struct inode, i_list));
+ sync_one(list_entry(tmp, struct inode, i_list), 0);
}
/**
@@ -266,14 +266,14 @@ static void sync_all_inodes(void)
* dirty. This is primarily needed by knfsd.
*/
-void write_inode_now(struct inode *inode)
+void write_inode_now(struct inode *inode, int sync)
{
struct super_block * sb = inode->i_sb;
if (sb) {
spin_lock(&inode_lock);
while (inode->i_state & I_DIRTY)
- sync_one(inode);
+ sync_one(inode, sync);
spin_unlock(&inode_lock);
}
else
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 16ad5ec26..f02d766bd 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -107,8 +107,8 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
else if (filp->f_op && filp->f_op->ioctl)
error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
}
- fput(filp);
unlock_kernel();
+ fput(filp);
out:
return error;
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index f89188d12..a3a4f072f 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -162,8 +162,7 @@ reclaimer(void *ptr)
{
struct nlm_host *host = (struct nlm_host *) ptr;
struct nlm_wait *block;
- struct file_lock *fl;
- struct inode *inode;
+ struct list_head *tmp;
/* This one ensures that our parent doesn't terminate while the
* reclaim is in progress */
@@ -171,19 +170,21 @@ reclaimer(void *ptr)
lockd_up();
/* First, reclaim all locks that have been granted previously. */
- do {
- for (fl = file_lock_table; fl; fl = fl->fl_nextlink) {
- inode = fl->fl_file->f_dentry->d_inode;
- if (inode->i_sb->s_magic == NFS_SUPER_MAGIC
- && nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr)
- && fl->fl_u.nfs_fl.state != host->h_state
- && (fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) {
- fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED;
- nlmclnt_reclaim(host, fl);
- break;
- }
+restart:
+ tmp = file_lock_list.next;
+ while (tmp != &file_lock_list) {
+ struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
+ struct inode *inode = fl->fl_file->f_dentry->d_inode;
+ if (inode->i_sb->s_magic == NFS_SUPER_MAGIC &&
+ nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr) &&
+ fl->fl_u.nfs_fl.state != host->h_state &&
+ (fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) {
+ fl->fl_u.nfs_fl.flags &= ~ NFS_LCK_GRANTED;
+ nlmclnt_reclaim(host, fl);
+ goto restart;
}
- } while (fl);
+ tmp = tmp->next;
+ }
host->h_reclaiming = 0;
wake_up(&host->h_gracewait);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 279fcc3c1..56c8d8173 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -347,7 +347,7 @@ again:
/* Append to list of blocked */
nlmsvc_insert_block(block, NLM_NEVER);
- if (!block->b_call.a_args.lock.fl.fl_prevblock) {
+ if (!list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
/* Now add block to block list of the conflicting lock
if we haven't done so. */
dprintk("lockd: blocking on this lock.\n");
diff --git a/fs/locks.c b/fs/locks.c
index 015b8e87a..6ce980735 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -108,57 +108,150 @@
#include <linux/malloc.h>
#include <linux/file.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
-static int flock_make_lock(struct file *filp, struct file_lock *fl,
- unsigned int cmd);
-static int posix_make_lock(struct file *filp, struct file_lock *fl,
- struct flock *l);
-static int flock_locks_conflict(struct file_lock *caller_fl,
- struct file_lock *sys_fl);
-static int posix_locks_conflict(struct file_lock *caller_fl,
- struct file_lock *sys_fl);
-static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
-static int flock_lock_file(struct file *filp, struct file_lock *caller,
- unsigned int wait);
-static int posix_locks_deadlock(struct file_lock *caller,
- struct file_lock *blocker);
-
-static struct file_lock *locks_empty_lock(void);
-static struct file_lock *locks_init_lock(struct file_lock *,
- struct file_lock *);
-static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
-static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait);
-static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx);
-
-static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter);
-static void locks_delete_block(struct file_lock *blocker, struct file_lock *waiter);
-static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait);
-
-struct file_lock *file_lock_table = NULL;
-
-/* Allocate a new lock, and initialize its fields from fl.
- * The lock is not inserted into any lists until locks_insert_lock() or
- * locks_insert_block() are called.
- */
-static inline struct file_lock *locks_alloc_lock(struct file_lock *fl)
+LIST_HEAD(file_lock_list);
+static LIST_HEAD(blocked_list);
+
+static kmem_cache_t *filelock_cache;
+
+/* Allocate an empty lock structure. */
+static struct file_lock *locks_alloc_lock(void)
{
- return locks_init_lock(locks_empty_lock(), fl);
+ struct file_lock *fl;
+ fl = kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
+ return fl;
}
-/* Free lock not inserted in any queue.
- */
+/* Free a lock which is not in use. */
static inline void locks_free_lock(struct file_lock *fl)
{
+ if (fl == NULL) {
+ BUG();
+ return;
+ }
+
if (waitqueue_active(&fl->fl_wait))
panic("Attempting to free lock with active wait queue");
- if (fl->fl_nextblock != NULL || fl->fl_prevblock != NULL)
+ if (!list_empty(&fl->fl_block))
panic("Attempting to free lock with active block list");
-
- kfree(fl);
- return;
+
+ if (!list_empty(&fl->fl_link))
+ panic("Attempting to free lock on active lock list");
+
+ kmem_cache_free(filelock_cache, fl);
+}
+
+/*
+ * Initialises the fields of the file lock which are invariant for
+ * free file_locks.
+ */
+static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags)
+{
+ struct file_lock *lock = (struct file_lock *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) !=
+ SLAB_CTOR_CONSTRUCTOR)
+ return;
+
+ lock->fl_next = NULL;
+ INIT_LIST_HEAD(&lock->fl_link);
+ INIT_LIST_HEAD(&lock->fl_block);
+ init_waitqueue_head(&lock->fl_wait);
+}
+
+/*
+ * Initialize a new lock from an existing file_lock structure.
+ */
+static void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
+{
+ new->fl_owner = fl->fl_owner;
+ new->fl_pid = fl->fl_pid;
+ new->fl_file = fl->fl_file;
+ new->fl_flags = fl->fl_flags;
+ new->fl_type = fl->fl_type;
+ new->fl_start = fl->fl_start;
+ new->fl_end = fl->fl_end;
+ new->fl_notify = fl->fl_notify;
+ new->fl_insert = fl->fl_insert;
+ new->fl_remove = fl->fl_remove;
+ new->fl_u = fl->fl_u;
+}
+
+/* Fill in a file_lock structure with an appropriate FLOCK lock. */
+static struct file_lock *flock_make_lock(struct file *filp, unsigned int type)
+{
+ struct file_lock *fl = locks_alloc_lock();
+ if (fl == NULL)
+ return NULL;
+
+ fl->fl_owner = NULL;
+ fl->fl_file = filp;
+ fl->fl_pid = current->pid;
+ fl->fl_flags = FL_FLOCK;
+ fl->fl_type = type;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+ fl->fl_notify = NULL;
+ fl->fl_insert = NULL;
+ fl->fl_remove = NULL;
+
+ return fl;
+}
+
+/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
+ * style lock.
+ */
+static int posix_make_lock(struct file *filp, struct file_lock *fl,
+ struct flock *l)
+{
+ loff_t start;
+
+ switch (l->l_whence) {
+ case 0: /*SEEK_SET*/
+ start = 0;
+ break;
+ case 1: /*SEEK_CUR*/
+ start = filp->f_pos;
+ break;
+ case 2: /*SEEK_END*/
+ start = filp->f_dentry->d_inode->i_size;
+ break;
+ default:
+ return (0);
+ }
+
+ if (((start += l->l_start) < 0) || (l->l_len < 0))
+ return (0);
+ fl->fl_end = start + l->l_len - 1;
+ if (l->l_len > 0 && fl->fl_end < 0)
+ return (0);
+ fl->fl_start = start; /* we record the absolute position */
+ if (l->l_len == 0)
+ fl->fl_end = OFFSET_MAX;
+
+ fl->fl_owner = current->files;
+ fl->fl_pid = current->pid;
+ fl->fl_file = filp;
+ fl->fl_flags = FL_POSIX;
+ fl->fl_notify = NULL;
+ fl->fl_insert = NULL;
+ fl->fl_remove = NULL;
+
+ switch (l->l_type) {
+ case F_RDLCK:
+ case F_WRLCK:
+ case F_UNLCK:
+ fl->fl_type = l->l_type;
+ break;
+ default:
+ return (0);
+ }
+
+ return (1);
}
/* Check if two locks overlap each other.
@@ -181,6 +274,17 @@ locks_same_owner(struct file_lock *fl1, struct file_lock *fl2)
(fl1->fl_pid == fl2->fl_pid);
}
+/* Remove waiter from blocker's block list.
+ * When blocker ends up pointing to itself then the list is empty.
+ */
+static void locks_delete_block(struct file_lock *waiter)
+{
+ list_del(&waiter->fl_block);
+ INIT_LIST_HEAD(&waiter->fl_block);
+ list_del(&waiter->fl_link);
+ INIT_LIST_HEAD(&waiter->fl_link);
+}
+
/* Insert waiter into blocker's block list.
* We use a circular list so that processes can be easily woken up in
* the order they blocked. The documentation doesn't require this but
@@ -189,71 +293,15 @@ locks_same_owner(struct file_lock *fl1, struct file_lock *fl2)
static void locks_insert_block(struct file_lock *blocker,
struct file_lock *waiter)
{
- struct file_lock *prevblock;
-
- if (waiter->fl_prevblock) {
- printk(KERN_ERR "locks_insert_block: remove duplicated lock "
- "(pid=%d %Ld-%Ld type=%d)\n",
- waiter->fl_pid, (long long)waiter->fl_start,
- (long long)waiter->fl_end, waiter->fl_type);
- locks_delete_block(waiter->fl_prevblock, waiter);
+ if (!list_empty(&waiter->fl_block)) {
+ printk(KERN_ERR "locks_insert_block: removing duplicated lock "
+ "(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid,
+ waiter->fl_start, waiter->fl_end, waiter->fl_type);
+ locks_delete_block(waiter);
}
-
- if (blocker->fl_prevblock == NULL)
- /* No previous waiters - list is empty */
- prevblock = blocker;
- else
- /* Previous waiters exist - add to end of list */
- prevblock = blocker->fl_prevblock;
-
- prevblock->fl_nextblock = waiter;
- blocker->fl_prevblock = waiter;
- waiter->fl_nextblock = blocker;
- waiter->fl_prevblock = prevblock;
-
- return;
-}
-
-/* Remove waiter from blocker's block list.
- * When blocker ends up pointing to itself then the list is empty.
- */
-static void locks_delete_block(struct file_lock *blocker,
- struct file_lock *waiter)
-{
- struct file_lock *nextblock;
- struct file_lock *prevblock;
-
- nextblock = waiter->fl_nextblock;
- prevblock = waiter->fl_prevblock;
-
- if (nextblock == NULL)
- return;
-
- nextblock->fl_prevblock = prevblock;
- prevblock->fl_nextblock = nextblock;
-
- waiter->fl_prevblock = waiter->fl_nextblock = NULL;
- if (blocker->fl_nextblock == blocker)
- /* No more locks on blocker's blocked list */
- blocker->fl_prevblock = blocker->fl_nextblock = NULL;
- return;
-}
-
-/* The following two are for the benefit of lockd.
- */
-void
-posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
-{
- locks_insert_block(blocker, waiter);
- return;
-}
-
-void
-posix_unblock_lock(struct file_lock *waiter)
-{
- if (waiter->fl_prevblock)
- locks_delete_block(waiter->fl_prevblock, waiter);
- return;
+ list_add_tail(&waiter->fl_block, &blocker->fl_block);
+// list_add(&waiter->fl_link, &blocked_list);
+// waiter->fl_next = blocker;
}
/* Wake up processes blocked waiting for blocker.
@@ -262,9 +310,8 @@ posix_unblock_lock(struct file_lock *waiter)
*/
static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
{
- struct file_lock *waiter;
-
- while ((waiter = blocker->fl_nextblock) != NULL) {
+ while (!list_empty(&blocker->fl_block)) {
+ struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_block);
/* N.B. Is it possible for the notify function to block?? */
if (waiter->fl_notify)
waiter->fl_notify(waiter);
@@ -279,262 +326,105 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
/* Remove waiter from the block list, because by the
* time it wakes up blocker won't exist any more.
*/
- locks_delete_block(blocker, waiter);
+ locks_delete_block(waiter);
}
}
- return;
}
-/* flock() system call entry point. Apply a FL_FLOCK style lock to
- * an open file descriptor.
+/* Insert file lock fl into an inode's lock list at the position indicated
+ * by pos. At the same time add the lock to the global file lock list.
*/
-asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
+static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
{
- struct file_lock file_lock;
- struct file *filp;
- int error;
+ list_add(&fl->fl_link, &file_lock_list);
- lock_kernel();
- error = -EBADF;
- filp = fget(fd);
- if (!filp)
- goto out;
- error = -EINVAL;
- if (!flock_make_lock(filp, &file_lock, cmd))
- goto out_putf;
- error = -EBADF;
- if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
- goto out_putf;
- error = flock_lock_file(filp, &file_lock,
- (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
-out_putf:
- fput(filp);
-out:
- unlock_kernel();
- return (error);
+ /* insert into file's list */
+ fl->fl_next = *pos;
+ *pos = fl;
+
+ if (fl->fl_insert)
+ fl->fl_insert(fl);
}
-/* Report the first existing lock that would conflict with l.
- * This implements the F_GETLK command of fcntl().
+/* Delete a lock and free it.
+ * First remove our lock from the active lock lists. Then call
+ * locks_wake_up_blocks() to wake up processes that are blocked
+ * waiting for this lock. Finally free the lock structure.
*/
-int fcntl_getlk(unsigned int fd, struct flock *l)
+static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
{
- struct file *filp;
- struct file_lock *fl,file_lock;
- struct flock flock;
- int error;
+ int (*lock)(struct file *, int, struct file_lock *);
+ struct file_lock *fl = *thisfl_p;
- error = -EFAULT;
- if (copy_from_user(&flock, l, sizeof(flock)))
- goto out;
- error = -EINVAL;
- if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
- goto out;
+ *thisfl_p = fl->fl_next;
+ fl->fl_next = NULL;
- error = -EBADF;
- filp = fget(fd);
- if (!filp)
- goto out;
+ list_del(&fl->fl_link);
+ INIT_LIST_HEAD(&fl->fl_link);
- if (!posix_make_lock(filp, &file_lock, &flock))
- goto out_putf;
+ if (fl->fl_remove)
+ fl->fl_remove(fl);
- if (filp->f_op->lock) {
- error = filp->f_op->lock(filp, F_GETLK, &file_lock);
- if (error < 0)
- goto out_putf;
- else if (error == LOCK_USE_CLNT)
- /* Bypass for NFS with no locking - 2.0.36 compat */
- fl = posix_test_lock(filp, &file_lock);
- else
- fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
- } else {
- fl = posix_test_lock(filp, &file_lock);
- }
-
- flock.l_type = F_UNLCK;
- if (fl != NULL) {
- flock.l_pid = fl->fl_pid;
- flock.l_start = fl->fl_start;
- flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
- fl->fl_end - fl->fl_start + 1;
- flock.l_whence = 0;
- flock.l_type = fl->fl_type;
+ locks_wake_up_blocks(fl, wait);
+ lock = fl->fl_file->f_op->lock;
+ if (lock) {
+ fl->fl_type = F_UNLCK;
+ lock(fl->fl_file, F_SETLK, fl);
}
- error = -EFAULT;
- if (!copy_to_user(l, &flock, sizeof(flock)))
- error = 0;
-
-out_putf:
- fput(filp);
-out:
- return error;
+ locks_free_lock(fl);
}
-/* Apply the lock described by l to an open file descriptor.
- * This implements both the F_SETLK and F_SETLKW commands of fcntl().
+/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
+ * checks for overlapping locks and shared/exclusive status.
*/
-int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
+static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
{
- struct file *filp;
- struct file_lock file_lock;
- struct flock flock;
- struct inode *inode;
- int error;
-
- /*
- * This might block, so we do it before checking the inode.
- */
- error = -EFAULT;
- if (copy_from_user(&flock, l, sizeof(flock)))
- goto out;
-
- /* Get arguments and validate them ...
- */
-
- error = -EBADF;
- filp = fget(fd);
- if (!filp)
- goto out;
-
- error = -EINVAL;
- inode = filp->f_dentry->d_inode;
-
- /* Don't allow mandatory locks on files that may be memory mapped
- * and shared.
- */
- if (IS_MANDLOCK(inode) &&
- (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
- struct vm_area_struct *vma;
- struct address_space *mapping = inode->i_mapping;
- spin_lock(&mapping->i_shared_lock);
- for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) {
- if (!(vma->vm_flags & VM_MAYSHARE))
- continue;
- spin_unlock(&mapping->i_shared_lock);
- error = -EAGAIN;
- goto out_putf;
- }
- spin_unlock(&mapping->i_shared_lock);
- }
+ if (!locks_overlap(caller_fl, sys_fl))
+ return (0);
- error = -EINVAL;
- if (!posix_make_lock(filp, &file_lock, &flock))
- goto out_putf;
-
- error = -EBADF;
- switch (flock.l_type) {
+ switch (caller_fl->fl_type) {
case F_RDLCK:
- if (!(filp->f_mode & FMODE_READ))
- goto out_putf;
- break;
+ return (sys_fl->fl_type == F_WRLCK);
+
case F_WRLCK:
- if (!(filp->f_mode & FMODE_WRITE))
- goto out_putf;
- break;
- case F_UNLCK:
- break;
- case F_SHLCK:
- case F_EXLCK:
-#ifdef __sparc__
-/* warn a bit for now, but don't overdo it */
-{
- static int count = 0;
- if (!count) {
- count=1;
- printk(KERN_WARNING
- "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n",
- current->pid, current->comm);
- }
-}
- if (!(filp->f_mode & 3))
- goto out_putf;
- break;
-#endif
- default:
- error = -EINVAL;
- goto out_putf;
- }
+ return (1);
- if (filp->f_op->lock != NULL) {
- error = filp->f_op->lock(filp, cmd, &file_lock);
- if (error < 0)
- goto out_putf;
+ default:
+ printk("locks_conflict(): impossible lock type - %d\n",
+ caller_fl->fl_type);
+ break;
}
- error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW);
-
-out_putf:
- fput(filp);
-out:
- return error;
+ return (0); /* This should never happen */
}
-/*
- * This function is called when the file is being removed
- * from the task's fd array.
+/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific
+ * checking before calling the locks_conflict().
*/
-void locks_remove_posix(struct file *filp, fl_owner_t owner)
+static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
{
- struct inode * inode = filp->f_dentry->d_inode;
- struct file_lock file_lock, *fl;
- struct file_lock **before;
-
- /*
- * For POSIX locks we free all locks on this file for the given task.
+ /* POSIX locks owned by the same process do not conflict with
+ * each other.
*/
-repeat:
- before = &inode->i_flock;
- while ((fl = *before) != NULL) {
- if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {
- int (*lock)(struct file *, int, struct file_lock *);
- lock = filp->f_op->lock;
- if (lock) {
- file_lock = *fl;
- file_lock.fl_type = F_UNLCK;
- }
- locks_delete_lock(before, 0);
- if (lock) {
- lock(filp, F_SETLK, &file_lock);
- /* List may have changed: */
- goto repeat;
- }
- continue;
- }
- before = &fl->fl_next;
- }
+ if (!(sys_fl->fl_flags & FL_POSIX) ||
+ locks_same_owner(caller_fl, sys_fl))
+ return (0);
+
+ return (locks_conflict(caller_fl, sys_fl));
}
-/*
- * This function is called on the last close of an open file.
+/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
+ * checking before calling the locks_conflict().
*/
-void locks_remove_flock(struct file *filp)
+static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
{
- struct inode * inode = filp->f_dentry->d_inode;
- struct file_lock file_lock, *fl;
- struct file_lock **before;
+ /* FLOCK locks referring to the same filp do not conflict with
+ * each other.
+ */
+ if (!(sys_fl->fl_flags & FL_FLOCK) ||
+ (caller_fl->fl_file == sys_fl->fl_file))
+ return (0);
-repeat:
- before = &inode->i_flock;
- while ((fl = *before) != NULL) {
- if ((fl->fl_flags & FL_FLOCK) && fl->fl_file == filp) {
- int (*lock)(struct file *, int, struct file_lock *);
- lock = NULL;
- if (filp->f_op)
- lock = filp->f_op->lock;
- if (lock) {
- file_lock = *fl;
- file_lock.fl_type = F_UNLCK;
- }
- locks_delete_lock(before, 0);
- if (lock) {
- lock(filp, F_SETLK, &file_lock);
- /* List may have changed: */
- goto repeat;
- }
- continue;
- }
- before = &fl->fl_next;
- }
+ return (locks_conflict(caller_fl, sys_fl));
}
struct file_lock *
@@ -552,6 +442,57 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
return (cfl);
}
+/* This function tests for deadlock condition before putting a process to
+ * sleep. The detection scheme is no longer recursive. Recursive was neat,
+ * but dangerous - we risked stack corruption if the lock data was bad, or
+ * if the recursion was too deep for any other reason.
+ *
+ * We rely on the fact that a task can only be on one lock's wait queue
+ * at a time. When we find blocked_task on a wait queue we can re-search
+ * with blocked_task equal to that queue's owner, until either blocked_task
+ * isn't found, or blocked_task is found on a queue owned by my_task.
+ *
+ * Note: the above assumption may not be true when handling lock requests
+ * from a broken NFS client. But broken NFS clients have a lot more to
+ * worry about than proper deadlock detection anyway... --okir
+ */
+static int posix_locks_deadlock(struct file_lock *caller_fl,
+ struct file_lock *block_fl)
+{
+ struct list_head *tmp;
+ void *caller_owner, *blocked_owner;
+ unsigned int caller_pid, blocked_pid;
+
+ caller_owner = caller_fl->fl_owner;
+ caller_pid = caller_fl->fl_pid;
+ blocked_owner = block_fl->fl_owner;
+ blocked_pid = block_fl->fl_pid;
+
+next_task:
+ if (caller_owner == blocked_owner && caller_pid == blocked_pid)
+ return 1;
+ list_for_each(tmp, &file_lock_list) {
+ struct list_head *btmp;
+ struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
+ if (fl->fl_owner == NULL || list_empty(&fl->fl_block))
+ continue;
+ list_for_each(btmp, &fl->fl_block) {
+ struct file_lock *bfl = list_entry(tmp, struct file_lock, fl_block);
+ if (bfl->fl_owner == blocked_owner &&
+ bfl->fl_pid == blocked_pid) {
+ if (fl->fl_owner == caller_owner &&
+ fl->fl_pid == caller_pid) {
+ return (1);
+ }
+ blocked_owner = fl->fl_owner;
+ blocked_pid = fl->fl_pid;
+ goto next_task;
+ }
+ }
+ }
+ return 0;
+}
+
int locks_mandatory_locked(struct inode *inode)
{
fl_owner_t owner = current->files;
@@ -576,19 +517,16 @@ int locks_mandatory_area(int read_write, struct inode *inode,
size_t count)
{
struct file_lock *fl;
- struct file_lock tfl;
+ struct file_lock *new_fl = locks_alloc_lock();
int error;
- memset(&tfl, 0, sizeof(tfl));
-
- tfl.fl_file = filp;
- tfl.fl_flags = FL_POSIX | FL_ACCESS;
- tfl.fl_owner = current->files;
- tfl.fl_pid = current->pid;
- init_waitqueue_head(&tfl.fl_wait);
- tfl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
- tfl.fl_start = offset;
- tfl.fl_end = offset + count - 1;
+ new_fl->fl_owner = current->files;
+ new_fl->fl_pid = current->pid;
+ new_fl->fl_file = filp;
+ new_fl->fl_flags = FL_POSIX | FL_ACCESS;
+ new_fl->fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
+ new_fl->fl_start = offset;
+ new_fl->fl_end = offset + count - 1;
error = 0;
lock_kernel();
@@ -606,7 +544,7 @@ repeat:
/* Block for writes against a "read" lock,
* and both reads and writes against a "write" lock.
*/
- if (posix_locks_conflict(&tfl, fl)) {
+ if (posix_locks_conflict(new_fl, fl)) {
error = -EAGAIN;
if (filp && (filp->f_flags & O_NONBLOCK))
break;
@@ -614,12 +552,12 @@ repeat:
if (signal_pending(current))
break;
error = -EDEADLK;
- if (posix_locks_deadlock(&tfl, fl))
+ if (posix_locks_deadlock(new_fl, fl))
break;
- locks_insert_block(fl, &tfl);
- interruptible_sleep_on(&tfl.fl_wait);
- locks_delete_block(fl, &tfl);
+ locks_insert_block(fl, new_fl);
+ interruptible_sleep_on(&new_fl->fl_wait);
+ locks_delete_block(new_fl);
/*
* If we've been sleeping someone might have
@@ -631,202 +569,15 @@ repeat:
}
}
unlock_kernel();
+ locks_free_lock(new_fl);
return error;
}
-/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
- * style lock.
- */
-static int posix_make_lock(struct file *filp, struct file_lock *fl,
- struct flock *l)
-{
- loff_t start;
-
- memset(fl, 0, sizeof(*fl));
-
- init_waitqueue_head(&fl->fl_wait);
- fl->fl_flags = FL_POSIX;
-
- switch (l->l_type) {
- case F_RDLCK:
- case F_WRLCK:
- case F_UNLCK:
- fl->fl_type = l->l_type;
- break;
- default:
- return (0);
- }
-
- switch (l->l_whence) {
- case 0: /*SEEK_SET*/
- start = 0;
- break;
- case 1: /*SEEK_CUR*/
- start = filp->f_pos;
- break;
- case 2: /*SEEK_END*/
- start = filp->f_dentry->d_inode->i_size;
- break;
- default:
- return (0);
- }
-
- if (((start += l->l_start) < 0) || (l->l_len < 0))
- return (0);
- fl->fl_end = start + l->l_len - 1;
- if (l->l_len > 0 && fl->fl_end < 0)
- return (0);
- fl->fl_start = start; /* we record the absolute position */
- if (l->l_len == 0)
- fl->fl_end = OFFSET_MAX;
-
- fl->fl_file = filp;
- fl->fl_owner = current->files;
- fl->fl_pid = current->pid;
-
- return (1);
-}
-
-/* Verify a call to flock() and fill in a file_lock structure with
- * an appropriate FLOCK lock.
- */
-static int flock_make_lock(struct file *filp, struct file_lock *fl,
- unsigned int cmd)
-{
- memset(fl, 0, sizeof(*fl));
-
- init_waitqueue_head(&fl->fl_wait);
-
- switch (cmd & ~LOCK_NB) {
- case LOCK_SH:
- fl->fl_type = F_RDLCK;
- break;
- case LOCK_EX:
- fl->fl_type = F_WRLCK;
- break;
- case LOCK_UN:
- fl->fl_type = F_UNLCK;
- break;
- default:
- return (0);
- }
-
- fl->fl_flags = FL_FLOCK;
- fl->fl_start = 0;
- fl->fl_end = OFFSET_MAX;
- fl->fl_file = filp;
- fl->fl_owner = NULL;
-
- return (1);
-}
-
-/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific
- * checking before calling the locks_conflict().
- */
-static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
-{
- /* POSIX locks owned by the same process do not conflict with
- * each other.
- */
- if (!(sys_fl->fl_flags & FL_POSIX) ||
- locks_same_owner(caller_fl, sys_fl))
- return (0);
-
- return (locks_conflict(caller_fl, sys_fl));
-}
-
-/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
- * checking before calling the locks_conflict().
- */
-static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
-{
- /* FLOCK locks referring to the same filp do not conflict with
- * each other.
- */
- if (!(sys_fl->fl_flags & FL_FLOCK) ||
- (caller_fl->fl_file == sys_fl->fl_file))
- return (0);
-
- return (locks_conflict(caller_fl, sys_fl));
-}
-
-/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
- * checks for overlapping locks and shared/exclusive status.
- */
-static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
-{
- if (!locks_overlap(caller_fl, sys_fl))
- return (0);
-
- switch (caller_fl->fl_type) {
- case F_RDLCK:
- return (sys_fl->fl_type == F_WRLCK);
-
- case F_WRLCK:
- return (1);
-
- default:
- printk("locks_conflict(): impossible lock type - %d\n",
- caller_fl->fl_type);
- break;
- }
- return (0); /* This should never happen */
-}
-
-/* This function tests for deadlock condition before putting a process to
- * sleep. The detection scheme is no longer recursive. Recursive was neat,
- * but dangerous - we risked stack corruption if the lock data was bad, or
- * if the recursion was too deep for any other reason.
- *
- * We rely on the fact that a task can only be on one lock's wait queue
- * at a time. When we find blocked_task on a wait queue we can re-search
- * with blocked_task equal to that queue's owner, until either blocked_task
- * isn't found, or blocked_task is found on a queue owned by my_task.
- *
- * Note: the above assumption may not be true when handling lock requests
- * from a broken NFS client. But broken NFS clients have a lot more to
- * worry about than proper deadlock detection anyway... --okir
- */
-static int posix_locks_deadlock(struct file_lock *caller_fl,
- struct file_lock *block_fl)
-{
- struct file_lock *fl;
- struct file_lock *bfl;
- void *caller_owner, *blocked_owner;
- unsigned int caller_pid, blocked_pid;
-
- caller_owner = caller_fl->fl_owner;
- caller_pid = caller_fl->fl_pid;
- blocked_owner = block_fl->fl_owner;
- blocked_pid = block_fl->fl_pid;
-
-next_task:
- if (caller_owner == blocked_owner && caller_pid == blocked_pid)
- return (1);
- for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) {
- if (fl->fl_owner == NULL || fl->fl_nextblock == NULL)
- continue;
- for (bfl = fl->fl_nextblock; bfl != fl; bfl = bfl->fl_nextblock) {
- if (bfl->fl_owner == blocked_owner &&
- bfl->fl_pid == blocked_pid) {
- if (fl->fl_owner == caller_owner &&
- fl->fl_pid == caller_pid) {
- return (1);
- }
- blocked_owner = fl->fl_owner;
- blocked_pid = fl->fl_pid;
- goto next_task;
- }
- }
- }
- return (0);
-}
-
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks at
* the head of the list, but that's secret knowledge known only to the next
* two functions.
*/
-static int flock_lock_file(struct file *filp, struct file_lock *caller,
+static int flock_lock_file(struct file *filp, unsigned int lock_type,
unsigned int wait)
{
struct file_lock *fl;
@@ -834,14 +585,14 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller,
struct file_lock **before;
struct inode * inode = filp->f_dentry->d_inode;
int error, change;
- int unlock = (caller->fl_type == F_UNLCK);
+ int unlock = (lock_type == F_UNLCK);
/*
* If we need a new lock, get it in advance to avoid races.
*/
if (!unlock) {
error = -ENOLCK;
- new_fl = locks_alloc_lock(caller);
+ new_fl = flock_make_lock(filp, lock_type);
if (!new_fl)
goto out;
}
@@ -851,8 +602,8 @@ search:
change = 0;
before = &inode->i_flock;
while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) {
- if (caller->fl_file == fl->fl_file) {
- if (caller->fl_type == fl->fl_type)
+ if (filp == fl->fl_file) {
+ if (lock_type == fl->fl_type)
goto out;
change = 1;
break;
@@ -888,7 +639,7 @@ repeat:
goto out;
locks_insert_block(fl, new_fl);
interruptible_sleep_on(&new_fl->fl_wait);
- locks_delete_block(fl, new_fl);
+ locks_delete_block(new_fl);
goto repeat;
}
locks_insert_lock(&inode->i_flock, new_fl);
@@ -928,8 +679,8 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
* We may need two file_lock structures for this operation,
* so we get them in advance to avoid races.
*/
- new_fl = locks_empty_lock();
- new_fl2 = locks_empty_lock();
+ new_fl = locks_alloc_lock();
+ new_fl2 = locks_alloc_lock();
error = -ENOLCK; /* "no luck" */
if (!(new_fl && new_fl2))
goto out;
@@ -952,7 +703,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
goto out;
locks_insert_block(fl, caller);
interruptible_sleep_on(&caller->fl_wait);
- locks_delete_block(fl, caller);
+ locks_delete_block(caller);
goto repeat;
}
}
@@ -1058,7 +809,7 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
if (!added) {
if (caller->fl_type == F_UNLCK)
goto out;
- locks_init_lock(new_fl, caller);
+ locks_copy_lock(new_fl, caller);
locks_insert_lock(before, new_fl);
new_fl = NULL;
}
@@ -1068,8 +819,9 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
* so we have to use the second new lock (in this
* case, even F_UNLCK may fail!).
*/
- left = locks_init_lock(new_fl2, right);
+ locks_copy_lock(new_fl2, right);
locks_insert_lock(before, left);
+ left = new_fl2;
new_fl2 = NULL;
}
right->fl_start = caller->fl_end + 1;
@@ -1081,101 +833,288 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
}
out:
/*
- * Free any unused locks. (They haven't
- * ever been used, so we use kfree().)
+ * Free any unused locks.
*/
if (new_fl)
- kfree(new_fl);
+ locks_free_lock(new_fl);
if (new_fl2)
- kfree(new_fl2);
+ locks_free_lock(new_fl2);
return error;
}
-/*
- * Allocate an empty lock structure. We can use GFP_KERNEL now that
- * all allocations are done in advance.
+static inline int flock_translate_cmd(int cmd) {
+ switch (cmd &~ LOCK_NB) {
+ case LOCK_SH:
+ return F_RDLCK;
+ case LOCK_EX:
+ return F_WRLCK;
+ case LOCK_UN:
+ return F_UNLCK;
+ }
+ return -EINVAL;
+}
+
+/* flock() system call entry point. Apply a FL_FLOCK style lock to
+ * an open file descriptor.
*/
-static struct file_lock *locks_empty_lock(void)
+asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
{
- /* Okay, let's make a new file_lock structure... */
- return ((struct file_lock *) kmalloc(sizeof(struct file_lock),
- GFP_KERNEL));
+ struct file *filp;
+ int error, type;
+
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ error = flock_translate_cmd(cmd);
+ if (error < 0)
+ goto out_putf;
+ type = error;
+
+ error = -EBADF;
+ if ((type != F_UNLCK) && !(filp->f_mode & 3))
+ goto out_putf;
+
+ lock_kernel();
+ error = flock_lock_file(filp, type,
+ (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+ unlock_kernel();
+
+out_putf:
+ fput(filp);
+out:
+ return error;
}
-/*
- * Initialize a new lock from an existing file_lock structure.
+/* Report the first existing lock that would conflict with l.
+ * This implements the F_GETLK command of fcntl().
*/
-static struct file_lock *locks_init_lock(struct file_lock *new,
- struct file_lock *fl)
+int fcntl_getlk(unsigned int fd, struct flock *l)
{
- if (new) {
- memset(new, 0, sizeof(*new));
- new->fl_owner = fl->fl_owner;
- new->fl_pid = fl->fl_pid;
- init_waitqueue_head(&new->fl_wait);
- new->fl_file = fl->fl_file;
- new->fl_flags = fl->fl_flags;
- new->fl_type = fl->fl_type;
- new->fl_start = fl->fl_start;
- new->fl_end = fl->fl_end;
- new->fl_notify = fl->fl_notify;
- new->fl_insert = fl->fl_insert;
- new->fl_remove = fl->fl_remove;
- new->fl_u = fl->fl_u;
+ struct file *filp;
+ struct file_lock *fl, *file_lock = locks_alloc_lock();
+ struct flock flock;
+ int error;
+
+ error = -EFAULT;
+ if (copy_from_user(&flock, l, sizeof(flock)))
+ goto out;
+ error = -EINVAL;
+ if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
+ goto out;
+
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ if (!posix_make_lock(filp, file_lock, &flock))
+ goto out_putf;
+
+ if (filp->f_op->lock) {
+ error = filp->f_op->lock(filp, F_GETLK, file_lock);
+ if (error < 0)
+ goto out_putf;
+ else if (error == LOCK_USE_CLNT)
+ /* Bypass for NFS with no locking - 2.0.36 compat */
+ fl = posix_test_lock(filp, file_lock);
+ else
+ fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock);
+ } else {
+ fl = posix_test_lock(filp, file_lock);
}
- return new;
+
+ flock.l_type = F_UNLCK;
+ if (fl != NULL) {
+ flock.l_pid = fl->fl_pid;
+ flock.l_start = fl->fl_start;
+ flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
+ fl->fl_end - fl->fl_start + 1;
+ flock.l_whence = 0;
+ flock.l_type = fl->fl_type;
+ }
+ error = -EFAULT;
+ if (!copy_to_user(l, &flock, sizeof(flock)))
+ error = 0;
+
+out_putf:
+ fput(filp);
+out:
+ locks_free_lock(file_lock);
+ return error;
}
-/* Insert file lock fl into an inode's lock list at the position indicated
- * by pos. At the same time add the lock to the global file lock list.
+/* Apply the lock described by l to an open file descriptor.
+ * This implements both the F_SETLK and F_SETLKW commands of fcntl().
*/
-static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
+int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
{
- fl->fl_nextlink = file_lock_table;
- fl->fl_prevlink = NULL;
- if (file_lock_table != NULL)
- file_lock_table->fl_prevlink = fl;
- file_lock_table = fl;
- fl->fl_next = *pos; /* insert into file's list */
- *pos = fl;
+ struct file *filp;
+ struct file_lock *file_lock = locks_alloc_lock();
+ struct flock flock;
+ struct inode *inode;
+ int error;
- if (fl->fl_insert)
- fl->fl_insert(fl);
+ /*
+ * This might block, so we do it before checking the inode.
+ */
+ error = -EFAULT;
+ if (copy_from_user(&flock, l, sizeof(flock)))
+ goto out;
- return;
+ /* Get arguments and validate them ...
+ */
+
+ error = -EBADF;
+ filp = fget(fd);
+ if (!filp)
+ goto out;
+
+ error = -EINVAL;
+ inode = filp->f_dentry->d_inode;
+
+ /* Don't allow mandatory locks on files that may be memory mapped
+ * and shared.
+ */
+ if (IS_MANDLOCK(inode) &&
+ (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+ struct vm_area_struct *vma;
+ struct address_space *mapping = inode->i_mapping;
+ spin_lock(&mapping->i_shared_lock);
+ for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) {
+ if (!(vma->vm_flags & VM_MAYSHARE))
+ continue;
+ spin_unlock(&mapping->i_shared_lock);
+ error = -EAGAIN;
+ goto out_putf;
+ }
+ spin_unlock(&mapping->i_shared_lock);
+ }
+
+ error = -EINVAL;
+ if (!posix_make_lock(filp, file_lock, &flock))
+ goto out_putf;
+
+ error = -EBADF;
+ switch (flock.l_type) {
+ case F_RDLCK:
+ if (!(filp->f_mode & FMODE_READ))
+ goto out_putf;
+ break;
+ case F_WRLCK:
+ if (!(filp->f_mode & FMODE_WRITE))
+ goto out_putf;
+ break;
+ case F_UNLCK:
+ break;
+ case F_SHLCK:
+ case F_EXLCK:
+#ifdef __sparc__
+/* warn a bit for now, but don't overdo it */
+{
+ static int count = 0;
+ if (!count) {
+ count=1;
+ printk(KERN_WARNING
+ "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n",
+ current->pid, current->comm);
+ }
}
+ if (!(filp->f_mode & 3))
+ goto out_putf;
+ break;
+#endif
+ default:
+ error = -EINVAL;
+ goto out_putf;
+ }
-/* Delete a lock and free it.
- * First remove our lock from the active lock lists. Then call
- * locks_wake_up_blocks() to wake up processes that are blocked
- * waiting for this lock. Finally free the lock structure.
+ if (filp->f_op->lock != NULL) {
+ error = filp->f_op->lock(filp, cmd, file_lock);
+ if (error < 0)
+ goto out_putf;
+ }
+ error = posix_lock_file(filp, file_lock, cmd == F_SETLKW);
+
+out_putf:
+ fput(filp);
+out:
+ locks_free_lock(file_lock);
+ return error;
+}
+
+/*
+ * This function is called when the file is being removed
+ * from the task's fd array.
*/
-static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
+void locks_remove_posix(struct file *filp, fl_owner_t owner)
{
- struct file_lock *thisfl;
- struct file_lock *prevfl;
- struct file_lock *nextfl;
-
- thisfl = *thisfl_p;
- *thisfl_p = thisfl->fl_next;
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct file_lock *fl;
+ struct file_lock **before;
- prevfl = thisfl->fl_prevlink;
- nextfl = thisfl->fl_nextlink;
+ /*
+ * For POSIX locks we free all locks on this file for the given task.
+ */
+repeat:
+ before = &inode->i_flock;
+ while ((fl = *before) != NULL) {
+ if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {
+ locks_delete_lock(before, 0);
+ goto repeat;
+ }
+ before = &fl->fl_next;
+ }
+}
- if (nextfl != NULL)
- nextfl->fl_prevlink = prevfl;
+/*
+ * This function is called on the last close of an open file.
+ */
+void locks_remove_flock(struct file *filp)
+{
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct file_lock file_lock, *fl;
+ struct file_lock **before;
- if (prevfl != NULL)
- prevfl->fl_nextlink = nextfl;
- else
- file_lock_table = nextfl;
+repeat:
+ before = &inode->i_flock;
+ while ((fl = *before) != NULL) {
+ if ((fl->fl_flags & FL_FLOCK) && fl->fl_file == filp) {
+ int (*lock)(struct file *, int, struct file_lock *);
+ lock = NULL;
+ if (filp->f_op)
+ lock = filp->f_op->lock;
+ if (lock) {
+ file_lock = *fl;
+ file_lock.fl_type = F_UNLCK;
+ }
+ locks_delete_lock(before, 0);
+ if (lock) {
+ lock(filp, F_SETLK, &file_lock);
+ /* List may have changed: */
+ goto repeat;
+ }
+ continue;
+ }
+ before = &fl->fl_next;
+ }
+}
- if (thisfl->fl_remove)
- thisfl->fl_remove(thisfl);
-
- locks_wake_up_blocks(thisfl, wait);
- locks_free_lock(thisfl);
+/* The following two are for the benefit of lockd.
+ */
+void
+posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
+{
+ lock_kernel();
+ locks_insert_block(blocker, waiter);
+ unlock_kernel();
+}
+void
+posix_unblock_lock(struct file_lock *waiter)
+{
+ locks_delete_block(waiter);
return;
}
@@ -1202,8 +1141,8 @@ static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
kdevname(inode->i_dev), inode->i_ino,
(long long)fl->fl_start, (long long)fl->fl_end);
sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n",
- (long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
- (long)fl->fl_next, (long)fl->fl_nextblock);
+ (long)fl, (long)fl->fl_link.prev, (long)fl->fl_link.next,
+ (long)fl->fl_next, (long)fl->fl_block.next);
}
static void move_lock_status(char **p, off_t* pos, off_t offset)
@@ -1230,35 +1169,46 @@ static void move_lock_status(char **p, off_t* pos, off_t offset)
int get_locks_status(char *buffer, char **start, off_t offset, int length)
{
- struct file_lock *fl;
- struct file_lock *bfl;
+ struct list_head *tmp;
char *q = buffer;
off_t pos = 0;
- int i;
+ int i = 0;
- for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
- lock_get_status(q, fl, i, "");
+ lock_kernel();
+ list_for_each(tmp, &file_lock_list) {
+ struct list_head *btmp;
+ struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link);
+ lock_get_status(q, fl, ++i, "");
move_lock_status(&q, &pos, offset);
if(pos >= offset+length)
goto done;
- if ((bfl = fl->fl_nextblock) == NULL)
- continue;
- do {
+ list_for_each(btmp, &fl->fl_block) {
+ struct file_lock *bfl = list_entry(btmp,
+ struct file_lock, fl_block);
lock_get_status(q, bfl, i, " ->");
move_lock_status(&q, &pos, offset);
if(pos >= offset+length)
goto done;
- } while ((bfl = bfl->fl_nextblock) != fl);
+ }
}
done:
+ unlock_kernel();
*start = buffer;
if(q-buffer < length)
return (q-buffer);
return length;
}
+static int __init filelock_init(void)
+{
+ filelock_cache = kmem_cache_create("file lock cache",
+ sizeof(struct file_lock), 0, 0, init_once, NULL);
+ if (!filelock_cache)
+ panic("cannot create file lock slab cache");
+ return 0;
+}
-
+module_init(filelock_init)
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 075574876..ca30b7753 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -276,16 +276,13 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
mark_inode_dirty(inode);
unlock_super(sb);
-printk("m_n_i: allocated inode ");
if(DQUOT_ALLOC_INODE(sb, inode)) {
-printk("fails quota test\n");
sb->dq_op->drop(inode);
inode->i_nlink = 0;
iput(inode);
*error = -EDQUOT;
return NULL;
}
-printk("is within quota\n");
*error = 0;
return inode;
diff --git a/fs/minix/fsync.c b/fs/minix/fsync.c
index 30794d27a..96e1ffa86 100644
--- a/fs/minix/fsync.c
+++ b/fs/minix/fsync.c
@@ -329,7 +329,7 @@ static int V2_minix_sync_file(struct inode * inode, struct file * file)
* NULL
*/
-int minix_sync_file(struct file * file, struct dentry *dentry)
+int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
struct inode *inode = dentry->d_inode;
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 6ddc278aa..fac903800 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -28,7 +28,7 @@
#include <linux/minix_fs.h>
static void minix_read_inode(struct inode * inode);
-static void minix_write_inode(struct inode * inode);
+static void minix_write_inode(struct inode * inode, int wait);
static int minix_statfs(struct super_block *sb, struct statfs *buf);
static int minix_remount (struct super_block * sb, int * flags, char * data);
@@ -1232,7 +1232,7 @@ static struct buffer_head *minix_update_inode(struct inode *inode)
return V2_minix_update_inode(inode);
}
-static void minix_write_inode(struct inode * inode)
+static void minix_write_inode(struct inode * inode, int wait)
{
struct buffer_head *bh;
diff --git a/fs/namei.c b/fs/namei.c
index 501000381..fcda2fd61 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -89,6 +89,12 @@
* if the pathname has trailing slashes - follow.
* otherwise - don't follow.
* (applied in that order).
+ *
+ * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT
+ * restored for 2.4. This is the last surviving part of old 4.2BSD bug.
+ * During the 2.4 we need to fix the userland stuff depending on it -
+ * hopefully we will be able to get rid of that wart in 2.5. So far only
+ * XEmacs seems to be relying on it...
*/
/* In order to reduce some races, while at the same time doing additional
@@ -191,21 +197,35 @@ int permission(struct inode * inode,int mask)
* < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
* > 0: (i_writecount) users are writing to the file.
*
- * WARNING: as soon as we will move get_write_access(), do_mmap() or
- * prepare_binfmt() out of the big lock we will need a spinlock protecting
- * the checks in all 3. For the time being it is not needed.
+ * Normally we operate on that counter with atomic_{inc,dec} and it's safe
+ * except for the cases where we don't hold i_writecount yet. Then we need to
+ * use {get,deny}_write_access() - these functions check the sign and refuse
+ * to do the change if sign is wrong. Exclusion between them is provided by
+ * spinlock (arbitration_lock) and I'll rip the second arsehole to the first
+ * who will try to move it in struct inode - just leave it here.
*/
+static spinlock_t arbitration_lock = SPIN_LOCK_UNLOCKED;
int get_write_access(struct inode * inode)
{
- if (atomic_read(&inode->i_writecount) < 0)
+ spin_lock(&arbitration_lock);
+ if (atomic_read(&inode->i_writecount) < 0) {
+ spin_unlock(&arbitration_lock);
return -ETXTBSY;
+ }
atomic_inc(&inode->i_writecount);
+ spin_unlock(&arbitration_lock);
return 0;
}
-
-void put_write_access(struct inode * inode)
+int deny_write_access(struct file * file)
{
- atomic_dec(&inode->i_writecount);
+ spin_lock(&arbitration_lock);
+ if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
+ spin_unlock(&arbitration_lock);
+ return -ETXTBSY;
+ }
+ atomic_dec(&file->f_dentry->d_inode->i_writecount);
+ spin_unlock(&arbitration_lock);
+ return 0;
}
void path_release(struct nameidata *nd)
@@ -337,7 +357,34 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry)
{
return __follow_down(mnt,dentry);
}
-
+
+static inline void follow_dotdot(struct nameidata *nd)
+{
+ while(1) {
+ struct vfsmount *parent;
+ struct dentry *dentry;
+ if (nd->dentry == current->fs->root &&
+ nd->mnt == current->fs->rootmnt) {
+ break;
+ }
+ if (nd->dentry != nd->mnt->mnt_root) {
+ dentry = dget(nd->dentry->d_parent);
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ break;
+ }
+ parent=nd->mnt->mnt_parent;
+ if (parent == nd->mnt) {
+ break;
+ }
+ mntget(parent);
+ dentry=dget(nd->mnt->mnt_mountpoint);
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ mntput(nd->mnt);
+ nd->mnt = parent;
+ }
+}
/*
* Name resolution.
*
@@ -403,19 +450,7 @@ int path_walk(const char * name, struct nameidata *nd)
case 2:
if (this.name[1] != '.')
break;
- while (1) {
- if (nd->dentry == current->fs->root &&
- nd->mnt == current->fs->rootmnt)
- break;
- if (nd->dentry != nd->mnt->mnt_root) {
- dentry = dget(nd->dentry->d_parent);
- dput(nd->dentry);
- nd->dentry = dentry;
- break;
- }
- if (!__follow_up(&nd->mnt, &nd->dentry))
- break;
- }
+ follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
@@ -483,19 +518,7 @@ last_component:
case 2:
if (this.name[1] != '.')
break;
- while (1) {
- if (nd->dentry == current->fs->root &&
- nd->mnt == current->fs->rootmnt)
- break;
- if (nd->dentry != nd->mnt->mnt_root) {
- dentry = dget(nd->dentry->d_parent);
- dput(nd->dentry);
- nd->dentry = dentry;
- break;
- }
- if (!__follow_up(&nd->mnt, &nd->dentry))
- break;
- }
+ follow_dotdot(nd);
inode = nd->dentry->d_inode;
/* fallthrough */
case 1:
@@ -771,8 +794,6 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir)
int error;
if (!victim->d_inode || victim->d_parent->d_inode != dir)
return -ENOENT;
- if (IS_DEADDIR(dir))
- return -ENOENT;
error = permission(dir,MAY_WRITE | MAY_EXEC);
if (error)
return error;
@@ -786,8 +807,6 @@ static inline int may_delete(struct inode *dir,struct dentry *victim, int isdir)
return -ENOTDIR;
if (IS_ROOT(victim))
return -EBUSY;
- if (d_mountpoint(victim))
- return -EBUSY;
} else if (S_ISDIR(victim->d_inode->i_mode))
return -EISDIR;
return 0;
@@ -872,83 +891,92 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
int acc_mode, error = 0;
struct inode *inode;
struct dentry *dentry;
+ struct dentry *dir;
+ int count = 0;
acc_mode = ACC_MODE(flag);
+
+ /*
+ * The simplest case - just a plain lookup.
+ */
if (!(flag & O_CREAT)) {
if (path_init(pathname, lookup_flags(flag), nd))
error = path_walk(pathname, nd);
if (error)
return error;
-
dentry = nd->dentry;
- } else {
- struct dentry *dir;
+ goto ok;
+ }
- if (path_init(pathname, LOOKUP_PARENT, nd))
- error = path_walk(pathname, nd);
+ /*
+ * Create - we need to know the parent.
+ */
+ if (path_init(pathname, LOOKUP_PARENT, nd))
+ error = path_walk(pathname, nd);
+ if (error)
+ return error;
+
+ /*
+ * We have the parent and last component. First of all, check
+ * that we are not asked to creat(2) an obvious directory - that
+ * will not do.
+ */
+ error = -EISDIR;
+ if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len])
+ goto exit;
+
+ dir = nd->dentry;
+ down(&dir->d_inode->i_sem);
+ dentry = lookup_hash(&nd->last, nd->dentry);
+
+do_last:
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry)) {
+ up(&dir->d_inode->i_sem);
+ goto exit;
+ }
+
+ /* Negative dentry, just create the file */
+ if (!dentry->d_inode) {
+ error = vfs_create(dir->d_inode, dentry, mode);
+ up(&dir->d_inode->i_sem);
+ dput(nd->dentry);
+ nd->dentry = dentry;
if (error)
- return error;
- /*
- * It's not obvious that open(".", O_CREAT, foo) should
- * fail, but it's even less obvious that it should succeed.
- * Since O_CREAT means an intention to create the thing and
- * open(2) had never created directories, count it as caller's
- * luserdom and let him sod off - -EISDIR it is.
- */
- error = -EISDIR;
- if (nd->last_type != LAST_NORM)
- goto exit;
- /* same for foo/ */
- if (nd->last.name[nd->last.len])
goto exit;
+ /* Don't check for write permission, don't truncate */
+ acc_mode = 0;
+ flag &= ~O_TRUNC;
+ goto ok;
+ }
- dir = nd->dentry;
- down(&dir->d_inode->i_sem);
+ /*
+ * It already exists.
+ */
+ up(&dir->d_inode->i_sem);
- dentry = lookup_hash(&nd->last, nd->dentry);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry)) {
- up(&dir->d_inode->i_sem);
- goto exit;
- }
+ error = -EEXIST;
+ if (flag & O_EXCL)
+ goto exit_dput;
- if (dentry->d_inode) {
- up(&dir->d_inode->i_sem);
- error = -EEXIST;
- if (flag & O_EXCL)
- goto exit_dput;
- if (dentry->d_inode->i_op &&
- dentry->d_inode->i_op->follow_link) {
- /*
- * With O_EXCL it would be -EEXIST.
- * If symlink is a dangling one it's -ENOENT.
- * Otherwise we open the object it points to.
- */
- error = do_follow_link(dentry, nd);
- dput(dentry);
- if (error)
- return error;
- dentry = nd->dentry;
- } else {
- dput(nd->dentry);
- nd->dentry = dentry;
- }
- error = -EISDIR;
- if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
- goto exit;
- } else {
- error = vfs_create(dir->d_inode, dentry, mode);
- up(&dir->d_inode->i_sem);
- /* Don't check for write permission, don't truncate */
- acc_mode = 0;
- flag &= ~O_TRUNC;
- dput(nd->dentry);
- nd->dentry = dentry;
- if (error)
- goto exit;
- }
+ if (d_mountpoint(dentry)) {
+ error = -ELOOP;
+ if (flag & O_NOFOLLOW)
+ goto exit_dput;
+ do __follow_down(&nd->mnt,&dentry); while(d_mountpoint(dentry));
}
+ error = -ENOENT;
+ if (!dentry->d_inode)
+ goto exit_dput;
+ if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)
+ goto do_link;
+ dput(nd->dentry);
+ nd->dentry = dentry;
+ error = -EISDIR;
+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
+ goto exit;
+ok:
error = -ENOENT;
inode = dentry->d_inode;
if (!inode)
@@ -1023,6 +1051,47 @@ exit_dput:
exit:
path_release(nd);
return error;
+
+do_link:
+ error = -ELOOP;
+ if (flag & O_NOFOLLOW)
+ goto exit_dput;
+ /*
+ * This is subtle. Instead of calling do_follow_link() we do the
+ * thing by hands. The reason is that this way we have zero link_count
+ * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT.
+ * After that we have the parent and last component, i.e.
+ * we are in the same situation as after the first path_walk().
+ * Well, almost - if the last component is normal we get its copy
+ * stored in nd->last.name and we will have to putname() it when we
+ * are done. Procfs-like symlinks just set LAST_BIND.
+ */
+ UPDATE_ATIME(dentry->d_inode);
+ error = dentry->d_inode->i_op->follow_link(dentry, nd);
+ dput(dentry);
+ if (error)
+ return error;
+ if (nd->last_type == LAST_BIND) {
+ dentry = nd->dentry;
+ goto ok;
+ }
+ error = -EISDIR;
+ if (nd->last_type != LAST_NORM)
+ goto exit;
+ if (nd->last.name[nd->last.len]) {
+ putname(nd->last.name);
+ goto exit;
+ }
+ if (count++==32) {
+ dentry = nd->dentry;
+ putname(nd->last.name);
+ goto ok;
+ }
+ dir = nd->dentry;
+ down(&dir->d_inode->i_sem);
+ dentry = lookup_hash(&nd->last, nd->dentry);
+ putname(nd->last.name);
+ goto do_last;
}
static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
@@ -1213,9 +1282,15 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
d_unhash(dentry);
- error = dir->i_op->rmdir(dir, dentry);
- if (!error)
- dentry->d_inode->i_flags |= S_DEAD;
+ if (IS_DEADDIR(dir))
+ error = -ENOENT;
+ else if (d_mountpoint(dentry))
+ error = -EBUSY;
+ else {
+ error = dir->i_op->rmdir(dir, dentry);
+ if (!error)
+ dentry->d_inode->i_flags |= S_DEAD;
+ }
double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
if (!error)
d_delete(dentry);
@@ -1275,9 +1350,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
error = -EPERM;
if (dir->i_op && dir->i_op->unlink) {
DQUOT_INIT(dir);
- error = dir->i_op->unlink(dir, dentry);
- if (!error)
- d_delete(dentry);
+ if (d_mountpoint(dentry))
+ error = -EBUSY;
+ else {
+ error = dir->i_op->unlink(dir, dentry);
+ if (!error)
+ d_delete(dentry);
+ }
}
}
up(&dir->i_zombie);
@@ -1555,7 +1634,12 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
} else
double_down(&old_dir->i_zombie,
&new_dir->i_zombie);
- error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+ if (IS_DEADDIR(old_dir)||IS_DEADDIR(new_dir))
+ error = -ENOENT;
+ else if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
+ error = -EBUSY;
+ else
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
if (target) {
if (!error)
target->i_flags |= S_DEAD;
@@ -1603,7 +1687,10 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
DQUOT_INIT(old_dir);
DQUOT_INIT(new_dir);
double_down(&old_dir->i_zombie, &new_dir->i_zombie);
- error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+ if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
+ error = -EBUSY;
+ else
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
double_up(&old_dir->i_zombie, &new_dir->i_zombie);
if (error)
return error;
@@ -1734,6 +1821,8 @@ out:
static inline int
__vfs_follow_link(struct nameidata *nd, const char *link)
{
+ int res = 0;
+ char *name;
if (IS_ERR(link))
goto fail;
@@ -1741,10 +1830,25 @@ __vfs_follow_link(struct nameidata *nd, const char *link)
path_release(nd);
if (!walk_init_root(link, nd))
/* weird __emul_prefix() stuff did it */
- return 0;
+ goto out;
}
- return path_walk(link, nd);
-
+ res = path_walk(link, nd);
+out:
+ if (current->link_count || res || nd->last_type!=LAST_NORM)
+ return res;
+ /*
+ * If it is an iterative symlinks resolution in open_namei() we
+ * have to copy the last component. And all that crap because of
+ * bloody create() on broken symlinks. Furrfu...
+ */
+ name = __getname();
+ if (IS_ERR(name))
+ goto fail_name;
+ strcpy(name, nd->last.name);
+ nd->last.name = name;
+ return 0;
+fail_name:
+ link = name;
fail:
path_release(nd);
return PTR_ERR(link);
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 55daea198..11694e79b 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -973,7 +973,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
/*
* Check whether to close the file ...
*/
- if (inode && NCP_FINFO(inode)->opened) {
+ if (inode) {
PPRINTK("ncp_unlink: closing file\n");
ncp_make_closed(inode);
}
@@ -982,7 +982,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
#ifdef CONFIG_NCPFS_STRONG
/* 9C is Invalid path.. It should be 8F, 90 - read only, but
it is not :-( */
- if (error == 0x9C && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
+ if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
error = ncp_force_unlink(dir, dentry);
}
#endif
@@ -1051,7 +1051,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
new_dir, __new_name);
#ifdef CONFIG_NCPFS_STRONG
- if ((error == 0x90 || error == -EACCES) &&
+ if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
server->m.flags & NCP_MOUNT_STRONG) { /* RO */
error = ncp_force_rename(old_dir, old_dentry, __old_name,
new_dir, new_dentry, __new_name);
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 6f8fd2d63..3442c3f9f 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -26,7 +26,7 @@ static inline unsigned int min(unsigned int a, unsigned int b)
return a < b ? a : b;
}
-static int ncp_fsync(struct file *file, struct dentry *dentry)
+static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync)
{
return 0;
}
@@ -46,12 +46,12 @@ int ncp_make_open(struct inode *inode, int right)
}
DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
- NCP_FINFO(inode)->opened,
+ atomic_read(&NCP_FINFO(inode)->opened),
NCP_FINFO(inode)->volNumber,
NCP_FINFO(inode)->dirEntNum);
error = -EACCES;
- lock_super(inode->i_sb);
- if (!NCP_FINFO(inode)->opened) {
+ down(&NCP_FINFO(inode)->open_sem);
+ if (!atomic_read(&NCP_FINFO(inode)->opened)) {
struct ncp_entry_info finfo;
int result;
@@ -88,15 +88,18 @@ int ncp_make_open(struct inode *inode, int right)
*/
update:
ncp_update_inode(inode, &finfo);
+ atomic_set(&NCP_FINFO(inode)->opened, 1);
}
access = NCP_FINFO(inode)->access;
PPRINTK("ncp_make_open: file open, access=%x\n", access);
- if (access == right || access == O_RDWR)
+ if (access == right || access == O_RDWR) {
+ atomic_inc(&NCP_FINFO(inode)->opened);
error = 0;
+ }
out_unlock:
- unlock_super(inode->i_sb);
+ up(&NCP_FINFO(inode)->open_sem);
out:
return error;
}
@@ -153,7 +156,7 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
freelen = ncp_read_bounce_size(bufsize);
freepage = kmalloc(freelen, GFP_NFS);
if (!freepage)
- goto out;
+ goto outrel;
error = 0;
/* First read in as much as possible for each bufsize. */
while (already_read < count) {
@@ -166,9 +169,8 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
pos, to_read, buf, &read_this_time,
freepage, freelen);
if (error) {
- kfree(freepage);
- error = -EIO; /* This is not exact, i know.. */
- goto out;
+ error = -EIO; /* NW errno -> Linux errno */
+ break;
}
pos += read_this_time;
buf += read_this_time;
@@ -188,6 +190,8 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
DPRINTK("ncp_file_read: exit %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
+outrel:
+ ncp_inode_close(inode);
out:
return already_read ? already_read : error;
}
@@ -236,8 +240,10 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
already_written = 0;
bouncebuffer = kmalloc(bufsize, GFP_NFS);
- if (!bouncebuffer)
- return -EIO; /* -ENOMEM */
+ if (!bouncebuffer) {
+ errno = -EIO; /* -ENOMEM */
+ goto outrel;
+ }
while (already_written < count) {
int written_this_time;
size_t to_write = min(bufsize - (pos % bufsize),
@@ -271,15 +277,15 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
}
DPRINTK("ncp_file_write: exit %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
+outrel:
+ ncp_inode_close(inode);
out:
return already_written ? already_written : errno;
}
static int ncp_release(struct inode *inode, struct file *file) {
- if (NCP_FINFO(inode)->opened) {
- if (ncp_make_closed(inode)) {
- DPRINTK("ncp_release: failed to close\n");
- }
+ if (ncp_make_closed(inode)) {
+ DPRINTK("ncp_release: failed to close\n");
}
return 0;
}
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index e885aed47..b6104831e 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -61,7 +61,6 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
#ifdef CONFIG_NCPFS_STRONG
NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
#endif
- NCP_FINFO(inode)->opened = nwinfo->opened;
NCP_FINFO(inode)->access = nwinfo->access;
NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
@@ -76,7 +75,7 @@ void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
struct nw_info_struct *nwi = &nwinfo->i;
struct ncp_server *server = NCP_SERVER(inode);
- if (!NCP_FINFO(inode)->opened) {
+ if (!atomic_read(&NCP_FINFO(inode)->opened)) {
#ifdef CONFIG_NCPFS_STRONG
NCP_FINFO(inode)->nwattr = nwi->attributes;
#endif
@@ -216,6 +215,9 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
inode = get_empty_inode();
if (inode) {
+ init_MUTEX(&NCP_FINFO(inode)->open_sem);
+ atomic_set(&NCP_FINFO(inode)->opened, info->opened);
+
inode->i_sb = sb;
inode->i_dev = sb->s_dev;
inode->i_ino = info->ino;
@@ -245,7 +247,7 @@ ncp_delete_inode(struct inode *inode)
DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
}
- if (NCP_FINFO(inode)->opened && ncp_make_closed(inode) != 0) {
+ if (ncp_make_closed(inode) != 0) {
/* We can't do anything but complain. */
printk(KERN_ERR "ncp_delete_inode: could not close\n");
}
@@ -259,7 +261,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
struct ncp_server *server;
struct file *ncp_filp;
struct inode *root_inode;
- kdev_t dev = sb->s_dev;
int error;
#ifdef CONFIG_NCPFS_PACKET_SIGNING
int options;
@@ -318,7 +319,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
sb->s_blocksize = 1024; /* Eh... Is this correct? */
sb->s_blocksize_bits = 10;
sb->s_magic = NCP_SUPER_MAGIC;
- sb->s_dev = dev;
sb->s_op = &ncp_sops;
server = NCP_SBP(sb);
@@ -676,6 +676,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
/* According to ndir, the changes only take effect after
closing the file */
+ ncp_inode_close(inode);
result = ncp_make_closed(inode);
if (!result)
vmtruncate(inode, attr->ia_size);
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 26c95fc8f..24e616396 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -335,18 +335,12 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
{
return result;
}
+ result = -EIO;
if (!ncp_conn_valid(server))
- {
- return -EIO;
- }
+ goto outrel;
+ result = -EISDIR;
if (!S_ISREG(inode->i_mode))
- {
- return -EISDIR;
- }
- if (!NCP_FINFO(inode)->opened)
- {
- return -EBADFD;
- }
+ goto outrel;
if (rqdata.cmd == NCP_LOCK_CLEAR)
{
result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
@@ -373,6 +367,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
rqdata.timeout);
if (result > 0) result = -EAGAIN;
}
+outrel:
+ ncp_inode_close(inode);
return result;
}
#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 752ae1e1e..08d28d895 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -82,6 +82,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
break;
}
}
+ ncp_inode_close(inode);
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 73afd107a..0353882b9 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -221,20 +221,23 @@ ncp_close_file(struct ncp_server *server, const char *file_id)
return result;
}
-/*
- * Called with the superblock locked.
- */
int
ncp_make_closed(struct inode *inode)
{
int err;
- NCP_FINFO(inode)->opened = 0;
- err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
- if (!err)
- PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
- NCP_FINFO(inode)->volNumber,
- NCP_FINFO(inode)->dirEntNum, err);
+ err = 0;
+ down(&NCP_FINFO(inode)->open_sem);
+ if (atomic_read(&NCP_FINFO(inode)->opened) == 1) {
+ atomic_set(&NCP_FINFO(inode)->opened, 0);
+ err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
+
+ if (!err)
+ PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
+ NCP_FINFO(inode)->volNumber,
+ NCP_FINFO(inode)->dirEntNum, err);
+ }
+ up(&NCP_FINFO(inode)->open_sem);
return err;
}
@@ -613,7 +616,8 @@ int ncp_open_create_file_or_subdir(struct ncp_server *server,
if ((result = ncp_request(server, 87)) != 0)
goto out;
- target->opened = 1;
+ if (!(create_attributes & aDIR))
+ target->opened = 1;
target->server_file_handle = ncp_reply_dword(server, 0);
target->open_create_action = ncp_reply_byte(server, 4);
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 8b33a5c2e..31797a3c3 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -57,6 +57,10 @@ int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16,
int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16,
const char *, int *);
+static inline void ncp_inode_close(struct inode *inode) {
+ atomic_dec(&NCP_FINFO(inode)->opened);
+}
+
int ncp_obtain_info(struct ncp_server *server, struct inode *, char *,
struct nw_info_struct *target);
int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *);
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index 46925eb6d..0962593da 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -50,10 +50,6 @@ static int ncp_symlink_readpage(struct file *file, struct page *page)
char *link;
char *buf = (char*)kmap(page);
- error = -EIO;
- if (ncp_make_open(inode,O_RDONLY))
- goto fail;
-
error = -ENOMEM;
for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) {
if (cnt > 10)
@@ -61,20 +57,22 @@ static int ncp_symlink_readpage(struct file *file, struct page *page)
schedule();
}
+ if (ncp_make_open(inode,O_RDONLY))
+ goto failEIO;
+
error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
0,NCP_MAX_SYMLINK_SIZE,link,&length);
- if (error) {
- kfree(link);
- goto fail;
- }
+ ncp_inode_close(inode);
+ /* Close file handle if no other users... */
+ ncp_make_closed(inode);
+ if (error)
+ goto failEIO;
+
if (length<NCP_MIN_SYMLINK_SIZE ||
((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||
- ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
- error = -EIO;
- kfree(link);
- goto fail;
- }
+ ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1)
+ goto failEIO;
len = NCP_MAX_SYMLINK_SIZE;
error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link+8, length-8, 0);
@@ -86,6 +84,9 @@ static int ncp_symlink_readpage(struct file *file, struct page *page)
UnlockPage(page);
return 0;
+failEIO:
+ error = -EIO;
+ kfree(link);
fail:
SetPageError(page);
kunmap(page);
@@ -120,13 +121,15 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL)
return -ENOMEM;
- if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN)) {
- kfree(link);
- return -EIO;
- }
+ err = -EIO;
+ if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN))
+ goto failfree;
inode=dentry->d_inode;
+ if (ncp_make_open(inode, O_WRONLY))
+ goto failfree;
+
((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0;
((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1;
@@ -134,19 +137,26 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
symlink can point out of ncp filesystem */
length += 1;
err = ncp_io2vol(NCP_SERVER(inode),link+8,&length,symname,length-1,0);
- if (err) {
- kfree(link);
- return err;
- }
+ if (err)
+ goto fail;
if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
0, length+8, link, &i) || i!=length+8) {
- kfree(link);
- return -EIO;
+ err = -EIO;
+ goto fail;
}
+ ncp_inode_close(inode);
+ ncp_make_closed(inode);
kfree(link);
return 0;
+
+fail:
+ ncp_inode_close(inode);
+ ncp_make_closed(inode);
+failfree:
+ kfree(link);
+ return err;
}
#endif
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 62b37c8cf..06f067eea 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -38,7 +38,7 @@ static int nfs_file_mmap(struct file *, struct vm_area_struct *);
static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *);
static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
static int nfs_file_flush(struct file *);
-static int nfs_fsync(struct file *, struct dentry *dentry);
+static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
struct file_operations nfs_file_operations = {
read: nfs_file_read,
@@ -123,7 +123,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
* whether any write errors occurred for this process.
*/
static int
-nfs_fsync(struct file *file, struct dentry *dentry)
+nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
struct inode *inode = dentry->d_inode;
int status;
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index dee52dd8a..df2532048 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -9,8 +9,6 @@
* creates a client control block and adds it to the hash
* table. Then, you call NFSCTL_EXPORT for each fs.
*
- * You cannot currently read the export information from the
- * kernel. It would be nice to have a /proc file though.
*
* Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
*/
@@ -388,12 +386,10 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
err = -EPERM;
if (path) {
- err = 0;
- if (path_init(path, LOOKUP_POSITIVE, &nd))
- err = path_walk(path, &nd);
- if (err) {
+ if (path_init(path, LOOKUP_POSITIVE, &nd) &&
+ path_walk(path, &nd)) {
printk("nfsd: exp_rootfh path not found %s", path);
- return -EPERM;
+ return err;
}
dev = nd.dentry->d_inode->i_dev;
ino = nd.dentry->d_inode->i_ino;
@@ -438,7 +434,8 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
fh_put(&fh);
out:
- path_release(&nd);
+ if (path)
+ path_release(&nd);
return err;
}
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 357a297f6..f5795583b 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -174,8 +174,9 @@ int
nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
{
struct svc_cacherep *rh, *rp;
- struct svc_client *clp = rqstp->rq_client;
u32 xid = rqstp->rq_xid,
+ proto = rqstp->rq_prot,
+ vers = rqstp->rq_vers,
proc = rqstp->rq_proc;
unsigned long age;
@@ -189,7 +190,9 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
while ((rp = rp->c_hash_next) != rh) {
if (rp->c_state != RC_UNUSED &&
xid == rp->c_xid && proc == rp->c_proc &&
- exp_checkaddr(clp, rp->c_client)) {
+ proto == rp->c_prot && vers == rp->c_vers &&
+ time_before(jiffies, rp->c_timestamp + 120*HZ) &&
+ memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, rqstp->rq_addrlen)==0) {
nfsdstats.rchits++;
goto found_entry;
}
@@ -226,7 +229,11 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
rp->c_state = RC_INPROG;
rp->c_xid = xid;
rp->c_proc = proc;
- rp->c_client = rqstp->rq_addr.sin_addr;
+ rp->c_addr = rqstp->rq_addr;
+ rp->c_prot = proto;
+ rp->c_vers = vers;
+ rp->c_timestamp = jiffies;
+
hash_refile(rp);
/* release any buffer */
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c4e456185..913cbf5f8 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -5,7 +5,6 @@
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
-#define NFS_GETFH_NEW
#include <linux/config.h>
#include <linux/module.h>
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 85a98c874..78f399bd3 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -495,17 +495,15 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
- if (!fhp->fh_dverified) {
+ if (!fhp->fh_dentry) {
kdev_t xdev;
ino_t xino;
__u32 *datap=NULL;
int data_left = fh->fh_size/4;
int nfsdev;
error = nfserr_stale;
-#if CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
error = nfserr_badhandle;
-#endif
if (fh->fh_version == 1) {
datap = fh->fh_auth;
@@ -562,10 +560,8 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
* Look up the dentry using the NFS file handle.
*/
error = nfserr_stale;
-#if CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
error = nfserr_badhandle;
-#endif
if (fh->fh_version == 1) {
/* if fileid_type != 0, and super_operations provide fh_to_dentry lookup,
@@ -611,7 +607,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
fhp->fh_dentry = dentry;
fhp->fh_export = exp;
- fhp->fh_dverified = 1;
nfsd_nr_verified++;
} else {
/* just rechecking permissions
@@ -731,7 +726,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0));
- if (fhp->fh_dverified || fhp->fh_locked || fhp->fh_dentry) {
+ if (fhp->fh_locked || fhp->fh_dentry) {
printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
parent->d_name.name, dentry->d_name.name);
}
@@ -757,8 +752,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4;
- /* We stuck it there, we know it's good. */
- fhp->fh_dverified = 1;
nfsd_nr_verified++;
if (fhp->fh_handle.fh_fileid_type == 255)
return nfserr_opnotsupp;
@@ -775,7 +768,7 @@ fh_update(struct svc_fh *fhp)
struct dentry *dentry;
__u32 *datap;
- if (!fhp->fh_dverified)
+ if (!fhp->fh_dentry)
goto out_bad;
dentry = fhp->fh_dentry;
@@ -811,10 +804,9 @@ void
fh_put(struct svc_fh *fhp)
{
struct dentry * dentry = fhp->fh_dentry;
- if (fhp->fh_dverified) {
+ if (dentry) {
fh_unlock(fhp);
fhp->fh_dentry = NULL;
- fhp->fh_dverified = 0;
dput(dentry);
nfsd_nr_put++;
}
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 763970736..b5057d57b 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -239,7 +239,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
* whether the file exists or not. Time to bail ...
*/
nfserr = nfserr_acces;
- if (!newfhp->fh_dverified) {
+ if (!newfhp->fh_dentry) {
printk(KERN_WARNING
"nfsd_proc_create: file handle not verified\n");
goto out_unlock;
@@ -415,7 +415,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
dprintk("nfsd: MKDIR %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
- if (resp->fh.fh_dverified) {
+ if (resp->fh.fh_dentry) {
printk(KERN_WARNING
"nfsd_proc_mkdir: response already verified??\n");
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index fb3b32f8d..9a4d12a7d 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -275,7 +275,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
/* Encode result.
* For NFSv2, additional info is never returned in case of an error.
*/
-#ifdef CONFIG_NFSD_V3
if (!(nfserr && rqstp->rq_vers == 2)) {
xdr = proc->pc_encode;
if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
@@ -286,17 +285,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
return 1;
}
}
-#else
- xdr = proc->pc_encode;
- if (!nfserr && xdr
- && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
- /* Failed to encode result. Release cache entry */
- dprintk("nfsd: failed to encode result!\n");
- nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
- *statp = rpc_system_err;
- return 1;
- }
-#endif /* CONFIG_NFSD_V3 */
/* Store reply in cache. */
nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 40f1ab85a..7a144d707 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -165,6 +165,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dentry = mounts;
} else
dput(mounts);
+ mntput(mnt);
}
}
/*
@@ -253,8 +254,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
goto out_nfserr;
err = locks_verify_truncate(inode, NULL, iap->ia_size);
- if (err)
+ if (err) {
+ put_write_access(inode);
goto out_nfserr;
+ }
DQUOT_INIT(inode);
}
@@ -314,11 +317,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (err)
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export))
- write_inode_now(inode);
+ write_inode_now(inode, 0);
err = 0;
-
- /* Don't unlock inode; the nfssvc_release functions are supposed
- * to do this. */
out:
return err;
@@ -413,7 +413,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access)
out:
return error;
}
-#endif
+#endif /* CONFIG_NFSD_V3 */
@@ -512,7 +512,7 @@ nfsd_sync(struct file *filp)
{
dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);
down(&filp->f_dentry->d_inode->i_sem);
- filp->f_op->fsync(filp, filp->f_dentry);
+ filp->f_op->fsync(filp, filp->f_dentry, 0);
up(&filp->f_dentry->d_inode->i_sem);
}
@@ -520,10 +520,10 @@ void
nfsd_sync_dir(struct dentry *dp)
{
struct inode *inode = dp->d_inode;
- int (*fsync) (struct file *, struct dentry *);
+ int (*fsync) (struct file *, struct dentry *, int);
if (inode->i_fop && (fsync = inode->i_fop->fsync)) {
- fsync(NULL, dp);
+ fsync(NULL, dp, 0);
}
}
@@ -598,7 +598,6 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
oldfs = get_fs(); set_fs(KERNEL_DS);
err = file.f_op->read(&file, buf, *count, &file.f_pos);
set_fs(oldfs);
- nfsdstats.io_read += *count;
/* Write back readahead params */
if (ra != NULL) {
@@ -614,6 +613,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
}
if (err >= 0) {
+ nfsdstats.io_read += err;
*count = err;
err = 0;
} else
@@ -665,19 +665,16 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
* When gathered writes have been configured for this volume,
* flushing the data to disk is handled separately below.
*/
-#ifdef CONFIG_NFSD_V3
+
if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */
stable = 2;
*stablep = 2; /* FILE_SYNC */
}
+
if (!EX_ISSYNC(exp))
stable = 0;
if (stable && !EX_WGATHER(exp))
file.f_flags |= O_SYNC;
-#else
- if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
- file.f_flags |= O_SYNC;
-#endif /* CONFIG_NFSD_V3 */
file.f_pos = offset; /* set write offset */
@@ -692,7 +689,8 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
#else
err = file.f_op->write(&file, buf, cnt, &file.f_pos);
#endif
- nfsdstats.io_write += cnt;
+ if (err >= 0)
+ nfsdstats.io_write += cnt;
set_fs(oldfs);
/* clear setuid/setgid flag after write */
@@ -734,7 +732,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
#else
dprintk("nfsd: write defer %d\n", current->pid);
/* FIXME: Olaf commented this out [gam3] */
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((HZ+99)/100);
+ current->state = TASK_RUNNING;
dprintk("nfsd: write resume %d\n", current->pid);
#endif
}
@@ -743,7 +743,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
dprintk("nfsd: write sync %d\n", current->pid);
nfsd_sync(&file);
}
+#if 0
wake_up(&inode->i_wait);
+#endif
last_ino = inode->i_ino;
last_dev = inode->i_dev;
}
@@ -762,11 +764,12 @@ out:
#ifdef CONFIG_NFSD_V3
/*
- * Commit all pendig writes to stable storage.
- * Strictly speaking, we could sync just indicated the file region here,
+ * Commit all pending writes to stable storage.
+ * Strictly speaking, we could sync just the indicated file region here,
* but there's currently no way we can ask the VFS to do so.
*
- * We lock the file to make sure we return full WCC data to the client.
+ * Unfortunately we cannot lock the file to make sure we return full WCC
+ * data to the client, as locking happens lower down in the filesystem.
*/
int
nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -828,7 +831,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
* Check whether the response file handle has been verified yet.
* If it has, the parent directory should already be locked.
*/
- if (!resfhp->fh_dverified) {
+ if (!resfhp->fh_dentry) {
/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
fh_lock(fhp);
dchild = lookup_one(fname, dentry);
@@ -891,7 +894,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (EX_ISSYNC(fhp->fh_export)) {
nfsd_sync_dir(dentry);
- write_inode_now(dchild->d_inode);
+ write_inode_now(dchild->d_inode, 0);
}
@@ -928,6 +931,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct dentry *dentry, *dchild;
struct inode *dirp;
int err;
+ __u32 v_mtime=0, v_atime=0;
+ int v_mode=0;
err = nfserr_perm;
if (!flen)
@@ -963,6 +968,19 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (err)
goto out;
+ if (createmode == NFS3_CREATE_EXCLUSIVE) {
+ /* while the verifier would fit in mtime+atime,
+ * solaris7 gets confused (bugid 4218508) if these have
+ * the high bit set, so we use the mode as well
+ */
+ v_mtime = verifier[0]&0x7fffffff;
+ v_atime = verifier[1]&0x7fffffff;
+ v_mode = S_IFREG
+ | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */
+ | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */
+ ;
+ }
+
if (dchild->d_inode) {
err = 0;
@@ -976,10 +994,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
break;
case NFS3_CREATE_EXCLUSIVE:
- if ( dchild->d_inode->i_mtime == verifier[0]
- && dchild->d_inode->i_atime == verifier[1]
- && dchild->d_inode->i_mode == S_IFREG
- && dchild->d_inode->i_size == 0 )
+ if ( dchild->d_inode->i_mtime == v_mtime
+ && dchild->d_inode->i_atime == v_atime
+ && dchild->d_inode->i_mode == v_mode
+ && dchild->d_inode->i_size == 0 )
break;
/* fallthru */
case NFS3_CREATE_GUARDED:
@@ -1005,19 +1023,23 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out;
if (createmode == NFS3_CREATE_EXCLUSIVE) {
- /* Cram the verifier into atime/mtime */
- iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET;
- iap->ia_mtime = verifier[0];
- iap->ia_atime = verifier[1];
+ /* Cram the verifier into atime/mtime/mode */
+ iap->ia_valid = ATTR_MTIME|ATTR_ATIME
+ | ATTR_MTIME_SET|ATTR_ATIME_SET
+ | ATTR_MODE;
+ iap->ia_mtime = v_mtime;
+ iap->ia_atime = v_atime;
+ iap->ia_mode = v_mode;
}
- /* Set file attributes. Mode has already been set and
- * setting uid/gid works only for root. Irix appears to
- * send along the gid when it tries to implement setgid
- * directories via NFS. Clear out all that cruft.
+ /* Set file attributes.
+ * Mode has already been set but we might need to reset it
+ * for CREATE_EXCLUSIVE
+ * Irix appears to send along the gid when it tries to
+ * implement setgid directories via NFS. Clear out all that cruft.
*/
set_attr:
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0)
err = nfsd_setattr(rqstp, resfhp, iap);
out:
@@ -1118,7 +1140,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
| S_IFLNK;
err = notify_change(dnew, iap);
if (!err && EX_ISSYNC(fhp->fh_export))
- write_inode_now(dentry->d_inode);
+ write_inode_now(dentry->d_inode, 0);
}
}
} else
@@ -1178,7 +1200,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
if (!err) {
if (EX_ISSYNC(ffhp->fh_export)) {
nfsd_sync_dir(ddir);
- write_inode_now(dest);
+ write_inode_now(dest, 0);
}
} else {
if (err == -EXDEV && rqstp->rq_vers == 2)
@@ -1230,7 +1252,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))
goto out;
+ /* cannot use fh_lock as we need deadlock protective ordering
+ * so do it by hand */
double_down(&tdir->i_sem, &fdir->i_sem);
+ ffhp->fh_locked = tfhp->fh_locked = 1;
+ fill_pre_wcc(ffhp);
+ fill_pre_wcc(tfhp);
+
odentry = lookup_one(fname, fdentry);
err = PTR_ERR(odentry);
if (IS_ERR(odentry))
@@ -1245,39 +1273,31 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (IS_ERR(ndentry))
goto out_dput_old;
-#ifdef CONFIG_NFSD_V3
- /* Fill in the pre-op attr for the wcc data for both
- * tdir and fdir
- */
- fill_pre_wcc(ffhp);
- fill_pre_wcc(tfhp);
-#endif /* CONFIG_NFSD_V3 */
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
nfsd_sync_dir(tdentry);
nfsd_sync_dir(fdentry);
}
-#ifdef CONFIG_NFSD_V3
- /* Fill in the post-op attr for the wcc data for both
- * tdir and fdir
- */
- fill_post_wcc(ffhp);
- fill_post_wcc(tfhp);
-#endif /* CONFIG_NFSD_V3 */
- double_up(&tdir->i_sem, &fdir->i_sem);
dput(ndentry);
-out_dput_old:
+ out_dput_old:
dput(odentry);
+ out_nfserr:
if (err)
- goto out_nfserr;
+ err = nfserrno(err);
+
+ /* we cannot reply on fh_unlock on the two filehandles,
+ * as that would do the wrong thing if the two directories
+ * were the same, so again we do it by hand
+ */
+ fill_post_wcc(ffhp);
+ fill_post_wcc(tfhp);
+ double_up(&tdir->i_sem, &fdir->i_sem);
+ ffhp->fh_locked = tfhp->fh_locked = 0;
+
out:
return err;
-
-out_nfserr:
- err = nfserrno(err);
- goto out;
}
/*
@@ -1320,17 +1340,13 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
err = vfs_rmdir(dirp, rdentry);
}
- fh_unlock(fhp);
-
dput(rdentry);
if (err)
goto out_nfserr;
- if (EX_ISSYNC(fhp->fh_export)) {
- down(&dentry->d_inode->i_sem);
+ if (EX_ISSYNC(fhp->fh_export))
nfsd_sync_dir(dentry);
- up(&dentry->d_inode->i_sem);
- }
+
out:
return err;
@@ -1353,13 +1369,11 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
struct file file;
struct readdir_cd cd;
- err = 0;
- if (offset > ~(u32) 0)
- goto out;
-
err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);
if (err)
goto out;
+ if (offset > ~(u32) 0)
+ goto out_close;
err = nfserr_notdir;
if (!file.f_op->readdir)
@@ -1402,11 +1416,9 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
eof = !cd.eob;
if (cd.offset) {
-#ifdef CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
(void)xdr_encode_hyper(cd.offset, file.f_pos);
else
-#endif /* CONFIG_NFSD_V3 */
*cd.offset = htonl(file.f_pos);
}
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index e0649ec7b..470f15c90 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -546,6 +546,7 @@ _linux_ntfs_mkdir(struct inode *dir, struct dentry* d, int mode)
}
#endif
+#if 0
static int
ntfs_bmap(struct inode *ino,int block)
{
@@ -554,6 +555,7 @@ ntfs_bmap(struct inode *ino,int block)
ino->i_ino,block,ret);
return (ret==-1) ? 0:ret;
}
+#endif
/* It's fscking broken. */
diff --git a/fs/pipe.c b/fs/pipe.c
index b97851fab..a30985a53 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -607,6 +607,8 @@ static struct super_block * pipefs_read_super(struct super_block *sb, void *data
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
+ root->i_sb = sb;
+ root->i_dev = sb->s_dev;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = PIPEFS_MAGIC;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index fb63722d5..01f5b22ea 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -408,6 +408,7 @@ static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
goto out;
error = inode->u.proc_i.op.proc_get_link(inode, &nd->dentry, &nd->mnt);
+ nd->last_type = LAST_BIND;
out:
#ifdef NULL_VFSMNT
mntput(dummy);
@@ -706,6 +707,7 @@ static struct dentry_operations pid_base_dentry_operations =
};
/* Lookups */
+#define MAX_MULBY10 ((~0U-9)/10)
static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
{
@@ -726,10 +728,10 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
name++;
if (c > 9)
goto out;
+ if (fd >= MAX_MULBY10)
+ goto out;
fd *= 10;
fd += c;
- if (fd & 0xffff8000)
- goto out;
}
inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_FD_DIR+fd);
@@ -940,12 +942,12 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
name++;
if (c > 9)
goto out;
+ if (pid >= MAX_MULBY10)
+ goto out;
pid *= 10;
pid += c;
if (!pid)
goto out;
- if (pid & 0xffff0000)
- goto out;
}
read_lock(&tasklist_lock);
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 60393eb91..3576482ca 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -340,7 +340,6 @@ static struct super_block *qnx4_read_super(struct super_block *s,
set_blocksize(dev, QNX4_BLOCK_SIZE);
s->s_blocksize = QNX4_BLOCK_SIZE;
s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS;
- s->s_dev = dev;
/* Check the boot signature. Since the qnx4 code is
dangerous, we should leave as quickly as possible
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index f87d30e0b..9bb7611c1 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -298,15 +298,9 @@ static struct inode_operations ramfs_dir_inode_operations = {
rename: ramfs_rename,
};
-static void ramfs_put_super(struct super_block *sb)
-{
- d_genocide(sb->s_root);
- shrink_dcache_parent(sb->s_root);
-}
-
static struct super_operations ramfs_ops = {
- put_super: ramfs_put_super,
statfs: ramfs_statfs,
+ put_inode: force_delete,
};
static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent)
@@ -331,7 +325,7 @@ static struct super_block *ramfs_read_super(struct super_block * sb, void * data
return sb;
}
-static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, 0);
+static DECLARE_FSTYPE(ramfs_fs_type, "ramfs", ramfs_read_super, FS_LITTER);
static int __init init_ramfs_fs(void)
{
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index b47e236b0..49d47afa7 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -27,7 +27,7 @@
/* #define pr_debug printk */
static int
-smb_fsync(struct file *file, struct dentry * dentry)
+smb_fsync(struct file *file, struct dentry * dentry, int datasync)
{
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_fsync: sync file %s/%s\n",
diff --git a/fs/super.c b/fs/super.c
index 5b8974e5b..8def1c9c4 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -260,7 +260,7 @@ int get_filesystem_list(char * buf)
return len;
}
-static struct file_system_type *get_fs_type(const char *name)
+struct file_system_type *get_fs_type(const char *name)
{
struct file_system_type *fs;
@@ -281,14 +281,28 @@ static struct file_system_type *get_fs_type(const char *name)
static LIST_HEAD(vfsmntlist);
-static struct vfsmount *add_vfsmnt(struct super_block *sb,
- struct dentry *mountpoint,
+/**
+ * add_vfsmnt - add a new mount node
+ * @nd: location of mountpoint or %NULL if we want a root node
+ * @root: root of (sub)tree to be mounted
+ * @dev_name: device name to show in /proc/mounts
+ *
+ * This is VFS idea of mount. New node is allocated, bound to a tree
+ * we are mounting and optionally (OK, usually) registered as mounted
+ * on a given mountpoint. Returns a pointer to new node or %NULL in
+ * case of failure.
+ *
+ * Potential reason for failure (aside of trivial lack of memory) is a
+ * deleted mountpoint. Caller must hold ->i_zombie on mountpoint
+ * dentry (if any).
+ */
+
+static struct vfsmount *add_vfsmnt(struct nameidata *nd,
struct dentry *root,
- struct vfsmount *parent,
- const char *dev_name,
- const char *dir_name)
+ const char *dev_name)
{
struct vfsmount *mnt;
+ struct super_block *sb = root->d_inode->i_sb;
char *name;
mnt = kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
@@ -296,13 +310,7 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb,
goto out;
memset(mnt, 0, sizeof(struct vfsmount));
- atomic_set(&mnt->mnt_count,1);
- mnt->mnt_sb = sb;
- mnt->mnt_mountpoint = dget(mountpoint);
- mnt->mnt_root = dget(root);
- mnt->mnt_parent = parent ? mntget(parent) : mnt;
-
- /* N.B. Is it really OK to have a vfsmount without names? */
+ /* It may be NULL, but who cares? */
if (dev_name) {
name = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
if (name) {
@@ -310,51 +318,53 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb,
mnt->mnt_devname = name;
}
}
- name = kmalloc(strlen(dir_name)+1, GFP_KERNEL);
- if (name) {
- strcpy(name, dir_name);
- mnt->mnt_dirname = name;
- }
mnt->mnt_owner = current->uid;
+ atomic_set(&mnt->mnt_count,1);
+ mnt->mnt_sb = sb;
- if (parent)
- list_add(&mnt->mnt_child, &parent->mnt_mounts);
- else
+ if (nd && !IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))
+ goto fail;
+ mnt->mnt_root = dget(root);
+ mnt->mnt_mountpoint = nd ? dget(nd->dentry) : dget(root);
+ mnt->mnt_parent = nd ? mntget(nd->mnt) : mnt;
+
+ if (nd) {
+ list_add(&mnt->mnt_child, &nd->mnt->mnt_mounts);
+ list_add(&mnt->mnt_clash, &nd->dentry->d_vfsmnt);
+ } else {
INIT_LIST_HEAD(&mnt->mnt_child);
+ INIT_LIST_HEAD(&mnt->mnt_clash);
+ }
INIT_LIST_HEAD(&mnt->mnt_mounts);
list_add(&mnt->mnt_instances, &sb->s_mounts);
- list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
list_add(&mnt->mnt_list, vfsmntlist.prev);
out:
return mnt;
+fail:
+ kfree(mnt->mnt_devname);
+ kfree(mnt);
+ return NULL;
}
static void move_vfsmnt(struct vfsmount *mnt,
struct dentry *mountpoint,
struct vfsmount *parent,
- const char *dev_name,
- const char *dir_name)
+ const char *dev_name)
{
- struct dentry *old_mountpoint = mnt->mnt_mountpoint;
- struct vfsmount *old_parent = mnt->mnt_parent;
- char *new_devname = NULL, *new_dirname = NULL;
+ struct dentry *old_mountpoint;
+ struct vfsmount *old_parent;
+ char *new_devname = NULL;
if (dev_name) {
new_devname = kmalloc(strlen(dev_name)+1, GFP_KERNEL);
if (new_devname)
strcpy(new_devname, dev_name);
}
- if (dir_name) {
- new_dirname = kmalloc(strlen(dir_name)+1, GFP_KERNEL);
- if (new_dirname)
- strcpy(new_dirname, dir_name);
- }
+
+ old_mountpoint = mnt->mnt_mountpoint;
+ old_parent = mnt->mnt_parent;
/* flip names */
- if (new_dirname) {
- kfree(mnt->mnt_dirname);
- mnt->mnt_dirname = new_dirname;
- }
if (new_devname) {
kfree(mnt->mnt_devname);
mnt->mnt_devname = new_devname;
@@ -365,11 +375,13 @@ static void move_vfsmnt(struct vfsmount *mnt,
mnt->mnt_parent = parent ? mntget(parent) : mnt;
list_del(&mnt->mnt_clash);
list_del(&mnt->mnt_child);
- list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
- if (parent)
+ if (parent) {
list_add(&mnt->mnt_child, &parent->mnt_mounts);
- else
+ list_add(&mnt->mnt_clash, &mountpoint->d_vfsmnt);
+ } else {
INIT_LIST_HEAD(&mnt->mnt_child);
+ INIT_LIST_HEAD(&mnt->mnt_clash);
+ }
/* put the old stuff */
dput(old_mountpoint);
@@ -391,7 +403,6 @@ static void remove_vfsmnt(struct vfsmount *mnt)
dput(mnt->mnt_mountpoint);
dput(mnt->mnt_root);
kfree(mnt->mnt_devname);
- kfree(mnt->mnt_dirname);
kfree(mnt);
}
@@ -738,10 +749,6 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
/* Done with lookups, semaphore down */
down(&mount_sem);
dev = to_kdev_t(bdev->bd_dev);
- check_disk_change(dev);
- error = -EACCES;
- if (!(flags & MS_RDONLY) && is_read_only(dev))
- goto out;
sb = get_super(dev);
if (sb) {
if (fs_type == sb->s_type) {
@@ -755,6 +762,10 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
error = blkdev_get(bdev, mode, 0, BDEV_FS);
if (error)
goto out;
+ check_disk_change(dev);
+ error = -EACCES;
+ if (!(flags & MS_RDONLY) && is_read_only(dev))
+ goto out1;
error = -EINVAL;
sb = read_super(dev, bdev, fs_type, flags, data, 0);
if (sb) {
@@ -762,6 +773,7 @@ static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
path_release(&nd);
return sb;
}
+out1:
blkdev_put(bdev, BDEV_FS);
}
out:
@@ -812,8 +824,14 @@ static struct block_device *kill_super(struct super_block *sb, int umount_root)
{
struct block_device *bdev;
kdev_t dev;
- dput(sb->s_root);
+ struct dentry *root = sb->s_root;
sb->s_root = NULL;
+ /* Need to clean after the sucker */
+ if (sb->s_type->fs_flags & FS_LITTER)
+ d_genocide(root);
+ if (sb->s_type->fs_flags & (FS_SINGLE|FS_LITTER))
+ shrink_dcache_parent(root);
+ dput(root);
lock_super(sb);
if (sb->s_op) {
if (sb->s_op->write_super && sb->s_dirt)
@@ -895,7 +913,7 @@ struct vfsmount *kern_mount(struct file_system_type *type)
put_unnamed_dev(dev);
return ERR_PTR(-EINVAL);
}
- mnt = add_vfsmnt(sb, sb->s_root, sb->s_root, NULL, "none", type->name);
+ mnt = add_vfsmnt(NULL, sb->s_root, "none");
if (!mnt) {
kill_super(sb, 0);
return ERR_PTR(-ENOMEM);
@@ -909,10 +927,7 @@ struct vfsmount *kern_mount(struct file_system_type *type)
void kern_umount(struct vfsmount *mnt)
{
struct super_block *sb = mnt->mnt_sb;
- struct dentry *root = sb->s_root;
remove_vfsmnt(mnt);
- dput(root);
- sb->s_root = NULL;
kill_super(sb, 0);
}
@@ -932,6 +947,16 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
{
struct super_block * sb = mnt->mnt_sb;
+ /*
+ * No sense to grab the lock for this test, but test itself looks
+ * somewhat bogus. Suggestions for better replacement?
+ * Ho-hum... In principle, we might treat that as umount + switch
+ * to rootfs. GC would eventually take care of the old vfsmount.
+ * The problem being: we have to implement rootfs and GC for that ;-)
+ * Actually it makes sense, especially if rootfs would contain a
+ * /reboot - static binary that would close all descriptors and
+ * call reboot(9). Then init(8) could umount root and exec /reboot.
+ */
if (mnt == current->fs->rootmnt && !umount_root) {
int retval = 0;
/*
@@ -952,6 +977,7 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
if (mnt->mnt_instances.next != mnt->mnt_instances.prev) {
if (sb->s_type->fs_flags & FS_SINGLE)
put_filesystem(sb->s_type);
+ /* We hold two references, so mntput() is safe */
mntput(mnt);
remove_vfsmnt(mnt);
return 0;
@@ -988,14 +1014,14 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
shrink_dcache_sb(sb);
fsync_dev(sb->s_dev);
- /* Something might grab it again - redo checks */
-
- if (atomic_read(&mnt->mnt_count) > 2) {
+ if (sb->s_root->d_inode->i_state) {
mntput(mnt);
return -EBUSY;
}
- if (sb->s_root->d_inode->i_state) {
+ /* Something might grab it again - redo checks */
+
+ if (atomic_read(&mnt->mnt_count) > 2) {
mntput(mnt);
return -EBUSY;
}
@@ -1067,6 +1093,8 @@ static int mount_is_safe(struct nameidata *nd)
{
if (capable(CAP_SYS_ADMIN))
return 0;
+ return -EPERM;
+#ifdef notyet
if (S_ISLNK(nd->dentry->d_inode->i_mode))
return -EPERM;
if (nd->dentry->d_inode->i_mode & S_ISVTX) {
@@ -1076,6 +1104,7 @@ static int mount_is_safe(struct nameidata *nd)
if (permission(nd->dentry->d_inode, MAY_WRITE))
return -EPERM;
return 0;
+#endif
}
/*
@@ -1102,22 +1131,22 @@ static int do_loopback(char *old_name, char *new_name)
if (S_ISDIR(new_nd.dentry->d_inode->i_mode) !=
S_ISDIR(old_nd.dentry->d_inode->i_mode))
goto out2;
-
- down(&mount_sem);
- err = -ENOENT;
- if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
- goto out3;
- if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
- goto out3;
- /* there we go */
+
err = -ENOMEM;
if (old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
get_filesystem(old_nd.mnt->mnt_sb->s_type);
- if (add_vfsmnt(old_nd.mnt->mnt_sb, new_nd.dentry, old_nd.dentry,
- new_nd.mnt, old_nd.mnt->mnt_devname, new_name))
+
+ down(&mount_sem);
+ /* there we go */
+ down(&new_nd.dentry->d_inode->i_zombie);
+ if (IS_DEADDIR(new_nd.dentry->d_inode))
+ err = -ENOENT;
+ else if (add_vfsmnt(&new_nd, old_nd.dentry, old_nd.mnt->mnt_devname))
err = 0;
-out3:
+ up(&new_nd.dentry->d_inode->i_zombie);
up(&mount_sem);
+ if (err && old_nd.mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
+ put_filesystem(old_nd.mnt->mnt_sb->s_type);
out2:
path_release(&new_nd);
out1:
@@ -1215,7 +1244,7 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
{
struct file_system_type * fstype;
struct nameidata nd;
- struct vfsmount *mnt;
+ struct vfsmount *mnt = NULL;
struct super_block *sb;
int retval = 0;
unsigned long flags = 0;
@@ -1224,8 +1253,6 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
return -EINVAL;
- if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
- return -EINVAL;
if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
return -EINVAL;
@@ -1239,6 +1266,11 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
flags = new_flags & ~MS_MGC_MSK;
+ /* For the rest we need the type */
+
+ if (!type_page || !memchr(type_page, 0, PAGE_SIZE))
+ return -EINVAL;
+
/* loopback mount? This is special - requires fewer capabilities */
if (strcmp(type_page, "bind")==0)
return do_loopback(dev_name, dir_name);
@@ -1272,16 +1304,18 @@ long do_mount(char * dev_name, char * dir_name, char *type_page,
if (IS_ERR(sb))
goto dput_out;
- retval = -ENOENT;
- if (d_unhashed(nd.dentry) && !IS_ROOT(nd.dentry))
- goto fail;
-
/* Something was mounted here while we slept */
while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry))
;
-
- retval = -ENOMEM;
- mnt = add_vfsmnt(sb, nd.dentry, sb->s_root, nd.mnt, dev_name, dir_name);
+ retval = -ENOENT;
+ if (!nd.dentry->d_inode)
+ goto fail;
+ down(&nd.dentry->d_inode->i_zombie);
+ if (!IS_DEADDIR(nd.dentry->d_inode)) {
+ retval = -ENOMEM;
+ mnt = add_vfsmnt(&nd, sb->s_root, dev_name);
+ }
+ up(&nd.dentry->d_inode->i_zombie);
if (!mnt)
goto fail;
retval = 0;
@@ -1312,15 +1346,6 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
if (retval < 0)
return retval;
- /* copy_mount_options allows a NULL user pointer,
- * and just returns zero in that case. But if we
- * allow the type to be NULL we will crash.
- * Previously we did not check this case.
- */
- if (type_page == 0)
- return -EINVAL;
-
- lock_kernel();
dir_page = getname(dir_name);
retval = PTR_ERR(dir_page);
if (IS_ERR(dir_page))
@@ -1331,8 +1356,10 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
goto out2;
retval = copy_mount_options (data, &data_page);
if (retval >= 0) {
+ lock_kernel();
retval = do_mount((char*)dev_page,dir_page,(char*)type_page,
new_flags, (void*)data_page);
+ unlock_kernel();
free_page(data_page);
}
free_page(dev_page);
@@ -1340,7 +1367,6 @@ out2:
putname(dir_page);
out1:
free_page(type_page);
- unlock_kernel();
return retval;
}
@@ -1490,12 +1516,11 @@ mount_it:
path + 5 + path_start, 0,
NULL, NULL);
memcpy (path + path_start, "/dev/", 5);
- vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
- path + path_start, "/");
+ vfsmnt = add_vfsmnt(NULL, sb->s_root, path + path_start);
}
else
- vfsmnt = add_vfsmnt (sb, sb->s_root, sb->s_root, NULL,
- "/dev/root", "/");
+ vfsmnt = add_vfsmnt(NULL, sb->s_root, "/dev/root");
+ /* FIXME: if something will try to umount us right now... */
if (vfsmnt) {
set_fs_root(current->fs, vfsmnt, sb->s_root);
set_fs_pwd(current->fs, vfsmnt, sb->s_root);
@@ -1516,6 +1541,7 @@ static void chroot_fs_refs(struct dentry *old_root,
read_lock(&tasklist_lock);
for_each_task(p) {
+ /* FIXME - unprotected usage of ->fs + (harmless) race */
if (!p->fs) continue;
if (p->fs->root == old_root && p->fs->rootmnt == old_rootmnt)
set_fs_root(p->fs, new_rootmnt, new_root);
@@ -1576,7 +1602,10 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
root_mnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
down(&mount_sem);
+ down(&old_nd.dentry->d_inode->i_zombie);
error = -ENOENT;
+ if (IS_DEADDIR(new_nd.dentry->d_inode))
+ goto out2;
if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
goto out2;
if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
@@ -1599,19 +1628,12 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
} else if (!is_subdir(old_nd.dentry, new_nd.dentry))
goto out2;
- error = -ENOMEM;
- name = __getname();
- if (!name)
- goto out2;
-
- move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL, "/");
- move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL,
- __d_path(old_nd.dentry, old_nd.mnt, new_nd.dentry,
- new_nd.mnt, name, PAGE_SIZE));
- putname(name);
+ move_vfsmnt(new_nd.mnt, new_nd.dentry, NULL, NULL);
+ move_vfsmnt(root_mnt, old_nd.dentry, old_nd.mnt, NULL);
chroot_fs_refs(root,root_mnt,new_nd.dentry,new_nd.mnt);
error = 0;
out2:
+ up(&old_nd.dentry->d_inode->i_zombie);
up(&mount_sem);
dput(root);
mntput(root_mnt);
@@ -1629,10 +1651,11 @@ out0:
int __init change_root(kdev_t new_root_dev,const char *put_old)
{
kdev_t old_root_dev = ROOT_DEV;
- struct vfsmount *old_rootmnt = mntget(current->fs->rootmnt);
+ struct vfsmount *old_rootmnt;
struct nameidata devfs_nd, nd;
int error = 0;
+ old_rootmnt = mntget(current->fs->rootmnt);
/* First unmount devfs if mounted */
if (path_init("/dev", LOOKUP_FOLLOW|LOOKUP_POSITIVE, &devfs_nd))
error = path_walk("/dev", &devfs_nd);
@@ -1675,7 +1698,8 @@ int __init change_root(kdev_t new_root_dev,const char *put_old)
printk(KERN_ERR "error %ld\n",blivet);
return error;
}
- move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old", put_old);
+ /* FIXME: we should hold i_zombie on nd.dentry */
+ move_vfsmnt(old_rootmnt, nd.dentry, nd.mnt, "/dev/root.old");
mntput(old_rootmnt);
path_release(&nd);
return 0;
diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c
index 3c9871be6..091605cd1 100644
--- a/fs/sysv/fsync.c
+++ b/fs/sysv/fsync.c
@@ -178,7 +178,7 @@ static int sync_tindirect(struct inode *inode, u32 *tiblockp, int convert,
return err;
}
-int sysv_sync_file(struct file * file, struct dentry *dentry)
+int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
int wait, err = 0;
struct inode *inode = dentry->d_inode;
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index d7cc12187..bbd88336c 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -142,7 +142,7 @@ struct inode * sysv_new_inode(const struct inode * dir)
/* Change directory entry: */
inode->i_mode = 0; /* for sysv_write_inode() */
inode->i_size = 0; /* ditto */
- sysv_write_inode(inode); /* ensure inode not allocated again */
+ sysv_write_inode(inode, 0); /* ensure inode not allocated again */
/* FIXME: caller may call this too. */
mark_inode_dirty(inode); /* cleared by sysv_write_inode() */
/* That's it. */
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 455818959..9ac81643b 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -496,7 +496,6 @@ static struct super_block *sysv_read_super(struct super_block *sb,
sb->s_blocksize = sb->sv_block_size;
sb->s_blocksize_bits = sb->sv_block_size_bits;
/* set up enough so that it can read an inode */
- sb->s_dev = dev;
sb->s_op = &sysv_sops;
root_inode = iget(sb,SYSV_ROOT_INO);
sb->s_root = d_alloc_root(root_inode);
@@ -1154,7 +1153,7 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
return bh;
}
-void sysv_write_inode(struct inode * inode)
+void sysv_write_inode(struct inode * inode, int wait)
{
struct buffer_head *bh;
bh = sysv_update_inode(inode);
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
index e7d067e62..bc107046d 100644
--- a/fs/udf/fsync.c
+++ b/fs/udf/fsync.c
@@ -96,7 +96,7 @@ static int sync_all_extents(struct inode * inode, int wait)
* even pass file to fsync ?
*/
-int udf_sync_file(struct file * file, struct dentry *dentry)
+int udf_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
int wait, err = 0;
struct inode *inode = dentry->d_inode;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 8c38883c0..360c12ba0 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1213,10 +1213,10 @@ udf_convert_permissions(struct FileEntry *fe)
* Written, tested, and released.
*/
-void udf_write_inode(struct inode * inode)
+void udf_write_inode(struct inode * inode, int sync)
{
lock_kernel();
- udf_update_inode(inode, 0);
+ udf_update_inode(inode, sync);
unlock_kernel();
}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 5f76abbb0..f3f575d7e 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1419,7 +1419,6 @@ udf_read_super(struct super_block *sb, void *options, int silent)
return sb;
error_out:
- sb->s_dev = NODEV;
if (UDF_SB_VAT(sb))
iput(UDF_SB_VAT(sb));
if (!(sb->s_flags & MS_RDONLY))
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 7dd00bc19..22cdd2c43 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -134,7 +134,7 @@ extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
extern void udf_read_inode(struct inode *);
extern void udf_put_inode(struct inode *);
extern void udf_delete_inode(struct inode *);
-extern void udf_write_inode(struct inode *);
+extern void udf_write_inode(struct inode *, int);
extern long udf_locked_block_map(struct inode *, long);
extern long udf_block_map(struct inode *, long);
extern int inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **);
@@ -184,7 +184,7 @@ extern int udf_prealloc_blocks(const struct inode *, Uint16, Uint32, Uint32);
extern int udf_new_block(const struct inode *, Uint16, Uint32, int *);
/* fsync.c */
-extern int udf_sync_file(struct file *, struct dentry *);
+extern int udf_sync_file(struct file *, struct dentry *, int);
/* directory.c */
extern Uint8 * udf_filead_read(struct inode *, Uint8 *, Uint8, lb_addr, int *, int *, struct buffer_head **, int *);
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 7801add9a..eb1d86d18 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -136,6 +136,7 @@ int ufs_frag_map(struct inode *inode, int frag)
ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
sb->s_blocksize),
frag & uspi->s_apbmask, uspi, swab));
+ goto out;
}
frag -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
if (frag < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
@@ -744,9 +745,9 @@ static int ufs_update_inode(struct inode * inode, int do_sync)
return 0;
}
-void ufs_write_inode (struct inode * inode)
+void ufs_write_inode (struct inode * inode, int wait)
{
- ufs_update_inode (inode, 0);
+ ufs_update_inode (inode, wait);
}
int ufs_sync_inode (struct inode *inode)
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 14b23467d..8820a49dd 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -293,11 +293,11 @@ out:
/*
* Update the disk with the inode content
*/
-void UMSDOS_write_inode (struct inode *inode)
+void UMSDOS_write_inode (struct inode *inode, int wait)
{
struct iattr newattrs;
- fat_write_inode (inode);
+ fat_write_inode (inode, wait);
newattrs.ia_mtime = inode->i_mtime;
newattrs.ia_atime = inode->i_atime;
newattrs.ia_ctime = inode->i_ctime;
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index a74290f55..86d1db58c 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -51,10 +51,7 @@ struct pci_controler {
#define PCIBIOS_MIN_IO alpha_mv.min_io_address
#define PCIBIOS_MIN_MEM alpha_mv.min_mem_address
-extern inline void pcibios_set_master(struct pci_dev *dev)
-{
- /* No special bus mastering setup handling */
-}
+extern void pcibios_set_master(struct pci_dev *dev);
extern inline void pcibios_penalize_isa_irq(int irq)
{
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index 4c2f70170..6328750e1 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -14,16 +14,17 @@
* We leave one page for the initial stack page, and one page for
* the initial process structure. Also, the console eats 3 MB for
* the initial bootloader (one of which we can reclaim later).
- * With a few other pages for various reasons, we'll use an initial
- * load address of PAGE_OFFSET+0x310000UL
*/
#define BOOT_PCB 0x20000000
#define BOOT_ADDR 0x20000000
/* Remove when official MILO sources have ELF support: */
#define BOOT_SIZE (16*1024)
-
+#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
+#define KERNEL_START_PHYS 0x300000 /* Old bootloaders hardcoded this. */
+#else
#define KERNEL_START_PHYS 0x800000 /* Wildfire has a huge console */
+#endif
#define KERNEL_START (PAGE_OFFSET+KERNEL_START_PHYS)
#define SWAPPER_PGD KERNEL_START
diff --git a/include/asm-arm/arch-arc/ide.h b/include/asm-arm/arch-arc/ide.h
index bccbe3f50..39f91b60b 100644
--- a/include/asm-arm/arch-arc/ide.h
+++ b/include/asm-arm/arch-arc/ide.h
@@ -20,7 +20,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
@@ -30,7 +30,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
@@ -44,7 +45,8 @@ static __inline__ void ide_init_default_hwifs(void)
memset(&hw, 0, sizeof(hw));
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = IRQ_HARDDISK;
ide_register_hw(&hw, NULL);
#endif
}
diff --git a/include/asm-arm/arch-cl7500/ide.h b/include/asm-arm/arch-cl7500/ide.h
index 590579747..53daa0969 100644
--- a/include/asm-arm/arch-cl7500/ide.h
+++ b/include/asm-arm/arch-cl7500/ide.h
@@ -13,7 +13,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
@@ -25,7 +25,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
diff --git a/include/asm-arm/arch-ebsa285/ide.h b/include/asm-arm/arch-ebsa285/ide.h
index 1a09f1827..dbdeb1fab 100644
--- a/include/asm-arm/arch-ebsa285/ide.h
+++ b/include/asm-arm/arch-ebsa285/ide.h
@@ -13,7 +13,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
@@ -23,7 +23,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
diff --git a/include/asm-arm/arch-l7200/ide.h b/include/asm-arm/arch-l7200/ide.h
index 0cfcf3aac..aff8aaf9c 100644
--- a/include/asm-arm/arch-l7200/ide.h
+++ b/include/asm-arm/arch-l7200/ide.h
@@ -13,7 +13,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
}
diff --git a/include/asm-arm/arch-nexuspci/ide.h b/include/asm-arm/arch-nexuspci/ide.h
index cb1eac75a..4a4d1b20c 100644
--- a/include/asm-arm/arch-nexuspci/ide.h
+++ b/include/asm-arm/arch-nexuspci/ide.h
@@ -13,7 +13,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
@@ -23,7 +23,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
diff --git a/include/asm-arm/arch-rpc/ide.h b/include/asm-arm/arch-rpc/ide.h
index ccbc7cf76..827d81c2b 100644
--- a/include/asm-arm/arch-rpc/ide.h
+++ b/include/asm-arm/arch-rpc/ide.h
@@ -13,7 +13,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
@@ -25,7 +25,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
@@ -37,6 +38,7 @@ ide_init_default_hwifs(void)
{
hw_regs_t hw;
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = IRQ_HARDDISK;
ide_register_hw(&hw, NULL);
}
diff --git a/include/asm-arm/arch-sa1100/ide.h b/include/asm-arm/arch-sa1100/ide.h
index 3a1f00e3d..3a9935c0b 100644
--- a/include/asm-arm/arch-sa1100/ide.h
+++ b/include/asm-arm/arch-sa1100/ide.h
@@ -17,7 +17,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg;
int i;
@@ -37,7 +37,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
reg += (1 << IO_SHIFT);
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) (ctrl_port << IO_SHIFT);
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
@@ -73,9 +74,11 @@ ide_init_default_hwifs(void)
/* MAC 23/4/1999, swap these round so that the left hand
hard disk is hda when viewed from the front. This
doesn't match the silkscreen however. */
- ide_init_hwif_ports(&hw,0x10,0x1e,EMPEG_IRQ_IDE2);
+ ide_init_hwif_ports(&hw,0x10,0x1e,NULL);
+ hw.irq = EMPEG_IRQ_IDE2;
ide_register_hw(&hw, NULL);
- ide_init_hwif_ports(&hw,0x00,0x0e,EMPEG_IRQ_IDE1);
+ ide_init_hwif_ports(&hw,0x00,0x0e,NULL);
+ hw.irq = EMPEG_IRQ_IDE1;
ide_register_hw(&hw, NULL);
#elif defined( CONFIG_SA1100_VICTOR )
@@ -87,7 +90,8 @@ ide_init_default_hwifs(void)
/* set the pcmcia interface timing */
MECR = 0x00060006;
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_GPIO7);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = IRQ_GPIO7;
ide_register_hw(&hw, NULL);
#else
#error Missing IDE interface definition in include/asm/arch/ide.h
diff --git a/include/asm-arm/arch-sa1100/irq.h b/include/asm-arm/arch-sa1100/irq.h
index 6f447f497..2f1e63d82 100644
--- a/include/asm-arm/arch-sa1100/irq.h
+++ b/include/asm-arm/arch-sa1100/irq.h
@@ -15,6 +15,7 @@
* 26-05-2000 JD SA-1111 support added
*/
#include <linux/config.h>
+#include <asm/irq.h>
#define fixup_irq(x) (x)
@@ -73,7 +74,7 @@ static int GPIO_11_27_spurious; /* GPIOs that triggered when masked */
static void sa1100_GPIO11_27_demux(int irq, void *dev_id,
struct pt_regs *regs)
{
- int i, irq, spurious;
+ int i, spurious;
while( (irq = (GEDR & 0xfffff800)) ){
/*
diff --git a/include/asm-arm/arch-shark/hardware.h b/include/asm-arm/arch-shark/hardware.h
index 1fb25abd1..fc38d57aa 100644
--- a/include/asm-arm/arch-shark/hardware.h
+++ b/include/asm-arm/arch-shark/hardware.h
@@ -10,7 +10,7 @@
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
/*
* Mapping areas
diff --git a/include/asm-arm/arch-shark/ide.h b/include/asm-arm/arch-shark/ide.h
index a9e373e98..2ef90b558 100644
--- a/include/asm-arm/arch-shark/ide.h
+++ b/include/asm-arm/arch-shark/ide.h
@@ -15,7 +15,7 @@
* This should follow whatever the default interface uses.
*/
static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
+ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
ide_ioreg_t reg = (ide_ioreg_t) data_port;
int i;
@@ -27,7 +27,8 @@ ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
reg += 1;
}
hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
- hw->irq = irq;
+ if (irq)
+ *irq = 0;
}
/*
@@ -39,7 +40,8 @@ ide_init_default_hwifs(void)
{
hw_regs_t hw;
- ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, 14);
+ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
+ hw.irq = 14;
ide_register_hw(&hw, NULL);
}
diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
index d5dfe4f91..94fd17170 100644
--- a/include/asm-arm/atomic.h
+++ b/include/asm-arm/atomic.h
@@ -36,36 +36,36 @@ static __inline__ void atomic_add(int i, volatile atomic_t *v)
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter += i;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ void atomic_sub(int i, volatile atomic_t *v)
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter -= i;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ void atomic_inc(volatile atomic_t *v)
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter += 1;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ void atomic_dec(volatile atomic_t *v)
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter -= 1;
- restore_flags (flags);
+ __restore_flags(flags);
}
static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
@@ -73,10 +73,10 @@ static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
unsigned long flags;
int result;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
v->counter -= 1;
result = (v->counter == 0);
- restore_flags (flags);
+ __restore_flags(flags);
return result;
}
@@ -86,10 +86,10 @@ extern __inline__ int atomic_add_negative(int i, volatile atomic_t *v)
unsigned long flags;
int result;
- save_flags_cli(flags);
+ __save_flags_cli(flags);
v->counter += i;
result = (v->counter < 0);
- restore_flags(flags);
+ __restore_flags(flags);
return result;
}
@@ -98,9 +98,9 @@ static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *addr
{
unsigned long flags;
- save_flags_cli (flags);
+ __save_flags_cli(flags);
*addr &= ~mask;
- restore_flags (flags);
+ __restore_flags(flags);
}
#endif
diff --git a/include/asm-arm/cpu-multi26.h b/include/asm-arm/cpu-multi26.h
index c09edf8b1..50639037d 100644
--- a/include/asm-arm/cpu-multi26.h
+++ b/include/asm-arm/cpu-multi26.h
@@ -20,7 +20,6 @@ extern struct processor {
void (*_set_pgd)(pgd_t *pgd);
/* XCHG */
unsigned long (*_xchg_1)(unsigned long x, volatile void *ptr);
- unsigned long (*_xchg_2)(unsigned long x, volatile void *ptr);
unsigned long (*_xchg_4)(unsigned long x, volatile void *ptr);
} processor;
@@ -34,7 +33,6 @@ extern const struct processor arm3_processor_functions;
#define cpu_do_idle() do { } while (0)
#define cpu_switch_mm(pgd,tsk) processor._set_pgd(pgd)
#define cpu_xchg_1(x,ptr) processor._xchg_1(x,ptr)
-#define cpu_xchg_2(x,ptr) processor._xchg_2(x,ptr)
#define cpu_xchg_4(x,ptr) processor._xchg_4(x,ptr)
extern void cpu_memc_update_all(pgd_t *pgd);
diff --git a/include/asm-arm/dma.h b/include/asm-arm/dma.h
index b67e33a9d..67db9ab90 100644
--- a/include/asm-arm/dma.h
+++ b/include/asm-arm/dma.h
@@ -6,7 +6,8 @@ typedef unsigned int dmach_t;
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
-#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/memory.h>
#include <asm/arch/dma.h>
/*
diff --git a/include/asm-arm/floppy.h b/include/asm-arm/floppy.h
index 9d9848644..05a94a2e6 100644
--- a/include/asm-arm/floppy.h
+++ b/include/asm-arm/floppy.h
@@ -1,7 +1,9 @@
/*
* linux/include/asm-arm/floppy.h
*
- * (C) 1996 Russell King
+ * (C) 1996-2000 Russell King
+ *
+ * Note that we don't touch FLOPPY_DMA nor FLOPPY_IRQ here
*/
#ifndef __ASM_ARM_FLOPPY_H
#define __ASM_ARM_FLOPPY_H
@@ -24,14 +26,14 @@
#define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK)
#define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK)
-#define fd_request_dma() request_dma(FLOPPY_DMA,"floppy")
-#define fd_free_dma() free_dma(FLOPPY_DMA)
-#define fd_disable_dma() disable_dma(FLOPPY_DMA)
-#define fd_enable_dma() enable_dma(FLOPPY_DMA)
-#define fd_clear_dma_ff() clear_dma_ff(FLOPPY_DMA)
-#define fd_set_dma_mode(mode) set_dma_mode(FLOPPY_DMA, (mode))
-#define fd_set_dma_addr(addr) set_dma_addr(FLOPPY_DMA, virt_to_bus((addr)))
-#define fd_set_dma_count(len) set_dma_count(FLOPPY_DMA, (len))
+#define fd_request_dma() request_dma(DMA_FLOPPY,"floppy")
+#define fd_free_dma() free_dma(DMA_FLOPPY)
+#define fd_disable_dma() disable_dma(DMA_FLOPPY)
+#define fd_enable_dma() enable_dma(DMA_FLOPPY)
+#define fd_clear_dma_ff() clear_dma_ff(DMA_FLOPPY)
+#define fd_set_dma_mode(mode) set_dma_mode(DMA_FLOPPY, (mode))
+#define fd_set_dma_addr(addr) set_dma_addr(DMA_FLOPPY, virt_to_bus((addr)))
+#define fd_set_dma_count(len) set_dma_count(DMA_FLOPPY, (len))
#define fd_cacheflush(addr,sz)
/* need to clean up dma.h */
@@ -109,13 +111,12 @@ extern __inline__ void fd_scandrives (void)
}
#define FDC1 (0x3f0)
-static int FDC2 = -1;
#define FLOPPY0_TYPE 4
#define FLOPPY1_TYPE 4
#define N_FDC 1
-#define N_DRIVE 8
+#define N_DRIVE 4
#define FLOPPY_MOTOR_MASK 0xf0
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 871e50a65..fad9e7412 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -1,7 +1,7 @@
/*
* linux/include/asm-arm/io.h
*
- * Copyright (C) 1996-1999 Russell King
+ * Copyright (C) 1996-2000 Russell King
*
* Modifications:
* 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both
@@ -11,6 +11,7 @@
* 27-Mar-1999 PJB Second parameter of memcpy_toio is const..
* 04-Apr-1999 PJB Added check_signature.
* 12-Dec-1999 RMK More cleanups
+ * 18-Jun-2000 RMK Removed virt_to_* and friends definitions
*/
#ifndef __ASM_ARM_IO_H
#define __ASM_ARM_IO_H
@@ -43,23 +44,7 @@ extern void insl(unsigned int port, void *from, int len);
#ifdef __KERNEL__
-#include <asm/arch/memory.h>
-
-extern __inline__ unsigned long virt_to_phys(volatile void *x)
-{
- return __virt_to_phys((unsigned long)(x));
-}
-
-extern __inline__ void *phys_to_virt(unsigned long x)
-{
- return (void *)(__phys_to_virt((unsigned long)(x)));
-}
-
-/*
- * Virtual <-> DMA view memory address translations
- */
-#define virt_to_bus(x) (__virt_to_bus((unsigned long)(x)))
-#define bus_to_virt(x) ((void *)(__bus_to_virt((unsigned long)(x))))
+#include <asm/memory.h>
/* the following macro is depreciated */
#define ioaddr(port) __ioaddr((port))
diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h
new file mode 100644
index 000000000..837ea199a
--- /dev/null
+++ b/include/asm-arm/memory.h
@@ -0,0 +1,31 @@
+/*
+ * linux/include/asm-arm/memory.h
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * Note: this file should not be included by non-asm/.h files
+ *
+ * Modifications:
+ */
+#ifndef __ASM_ARM_MEMORY_H
+#define __ASM_ARM_MEMORY_H
+
+#include <asm/arch/memory.h>
+
+extern __inline__ unsigned long virt_to_phys(volatile void *x)
+{
+ return __virt_to_phys((unsigned long)(x));
+}
+
+extern __inline__ void *phys_to_virt(unsigned long x)
+{
+ return (void *)(__phys_to_virt((unsigned long)(x)));
+}
+
+/*
+ * Virtual <-> DMA view memory address translations
+ */
+#define virt_to_bus(x) (__virt_to_bus((unsigned long)(x)))
+#define bus_to_virt(x) ((void *)(__bus_to_virt((unsigned long)(x))))
+
+#endif
diff --git a/include/asm-arm/proc-armo/system.h b/include/asm-arm/proc-armo/system.h
index bc113ae6e..36a3515e7 100644
--- a/include/asm-arm/proc-armo/system.h
+++ b/include/asm-arm/proc-armo/system.h
@@ -7,20 +7,16 @@
#ifndef __ASM_PROC_SYSTEM_H
#define __ASM_PROC_SYSTEM_H
-extern const char xchg_str[];
-
-#include <linux/config.h>
#include <asm/proc-fns.h>
extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
- extern void arm_invalidptr(const char *, int);
+ extern void __bad_xchg(volatile void *, int);
switch (size) {
case 1: return cpu_xchg_1(x, ptr);
- case 2: return cpu_xchg_2(x, ptr);
case 4: return cpu_xchg_4(x, ptr);
- default: arm_invalidptr(xchg_str, size);
+ default: __bad_xchg(ptr, size);
}
return 0;
}
@@ -108,22 +104,4 @@ extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int
: "memory"); \
} while (0)
-/* For spinlocks etc */
-#define local_irq_save(x) __save_flags_cli(x)
-#define local_irq_restore(x) __restore_flags(x)
-#define local_irq_disable() __cli()
-#define local_irq_enable() __sti()
-
-#ifdef CONFIG_SMP
-#error SMP not supported
-#else
-
-#define cli() __cli()
-#define sti() __sti()
-#define save_flags(x) __save_flags(x)
-#define restore_flags(x) __restore_flags(x)
-#define save_flags_cli(x) __save_flags_cli(x)
-
-#endif
-
#endif
diff --git a/include/asm-arm/proc-armv/system.h b/include/asm-arm/proc-armv/system.h
index 3b35be309..d9ef8ffd9 100644
--- a/include/asm-arm/proc-armv/system.h
+++ b/include/asm-arm/proc-armv/system.h
@@ -7,20 +7,16 @@
#ifndef __ASM_PROC_SYSTEM_H
#define __ASM_PROC_SYSTEM_H
-#include <linux/config.h>
-
-extern const char xchg_str[];
-
extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
- extern void arm_invalidptr(const char *, int);
+ extern void __bad_xchg(volatile void *, int);
switch (size) {
case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" : "=r" (x) : "r" (x), "r" (ptr) : "memory");
break;
case 4: __asm__ __volatile__ ("swp %0, %1, [%2]" : "=r" (x) : "r" (x), "r" (ptr) : "memory");
break;
- default: arm_invalidptr(xchg_str, size);
+ default: __bad_xchg(ptr, size);
}
return x;
}
@@ -102,22 +98,4 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */
: "r" (x) \
: "memory")
-/* For spinlocks etc */
-#define local_irq_save(x) __save_flags_cli(x)
-#define local_irq_restore(x) __restore_flags(x)
-#define local_irq_disable() __cli()
-#define local_irq_enable() __sti()
-
-#ifdef CONFIG_SMP
-#error SMP not supported
-#else
-
-#define cli() __cli()
-#define sti() __sti()
-#define save_flags(x) __save_flags(x)
-#define restore_flags(x) __restore_flags(x)
-#define save_flags_cli(x) __save_flags_cli(x)
-
-#endif
-
#endif
diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
index 961363cc7..3126767a4 100644
--- a/include/asm-arm/ptrace.h
+++ b/include/asm-arm/ptrace.h
@@ -17,6 +17,10 @@
#ifdef __KERNEL__
extern void show_regs(struct pt_regs *);
+
+#define predicate(x) (x & 0xf0000000)
+#define PREDICATE_ALWAYS 0xe0000000
+
#endif
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index b75a88411..94073475d 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -381,7 +381,6 @@ extern unsigned int __machine_arch_type;
#define tas(ptr) (xchg((ptr),1))
-extern void arm_malalignedptr(const char *, void *, volatile void *);
extern asmlinkage void __backtrace(void);
/*
@@ -411,4 +410,22 @@ extern struct task_struct *__switch_to(struct task_struct *prev, struct task_str
#endif
+/* For spinlocks etc */
+#define local_irq_save(x) __save_flags_cli(x)
+#define local_irq_restore(x) __restore_flags(x)
+#define local_irq_disable() __cli()
+#define local_irq_enable() __sti()
+
+#ifdef CONFIG_SMP
+#error SMP not supported
+#else
+
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(x) __save_flags(x)
+#define restore_flags(x) __restore_flags(x)
+#define save_flags_cli(x) __save_flags_cli(x)
+
+#endif
+
#endif
diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
index d4609a9a8..4c64c151a 100644
--- a/include/asm-ppc/unistd.h
+++ b/include/asm-ppc/unistd.h
@@ -194,7 +194,7 @@
#define __NR_getpmsg 187 /* some people actually want streams */
#define __NR_putpmsg 188 /* some people actually want streams */
#define __NR_vfork 189
-#define __NR_ugetrlimit 191 /* SuS compliant getrlimit */
+#define __NR_ugetrlimit 190 /* SuS compliant getrlimit */
#define __NR_mmap2 192
#define __NR_truncate64 193
#define __NR_ftruncate64 194
diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h
index 60af0d40c..8a09cd72d 100644
--- a/include/linux/affs_fs.h
+++ b/include/linux/affs_fs.h
@@ -84,7 +84,7 @@ extern int affs_add_entry(struct inode *dir, struct inode *link,
extern void affs_put_inode(struct inode *inode);
extern void affs_delete_inode(struct inode *inode);
extern void affs_read_inode(struct inode *inode);
-extern void affs_write_inode(struct inode *inode);
+extern void affs_write_inode(struct inode *inode, int);
/* super.c */
diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h
index b5a9999a5..d2334ba95 100644
--- a/include/linux/arcdevice.h
+++ b/include/linux/arcdevice.h
@@ -241,11 +241,13 @@ struct arcnet_local {
setup2, /* Contents of setup2 register */
intmask; /* current value of INTMASK register */
uint8_t default_proto[256]; /* default encap to use for each host */
- int cur_tx, /* buffer used by current transmit, or -1 */
+ int cur_tx, /* buffer used by current transmit, or -1 */
next_tx, /* buffer where a packet is ready to send */
cur_rx; /* current receive buffer */
- int lastload_dest, /* can last loaded packet be acked? */
+ int lastload_dest, /* can last loaded packet be acked? */
lasttrans_dest; /* can last TX'd packet be acked? */
+ int timed_out; /* need to process TX timeout and drop packet */
+ unsigned long last_timeout; /* time of last reported timeout */
char *card_name; /* card ident string */
int card_flags; /* special card features */
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index 2b6bbadd7..73757bb53 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -11,9 +11,8 @@ extern struct coda_sb_info coda_super_info;
struct coda_sb_info
{
struct inode * sbi_psdev; /* /dev/cfs? Venus/kernel device */
- struct inode * sbi_ctlcp; /* control magic file */
int sbi_refct;
- struct venus_comm * sbi_vcomm;
+ struct venus_comm * sbi_vcomm;
struct inode * sbi_root;
struct super_block *sbi_sb;
struct list_head sbi_cchead;
@@ -27,7 +26,6 @@ struct venus_comm {
struct list_head vc_pending;
struct list_head vc_processing;
int vc_inuse;
- pid_t vc_pid; /* Venus pid */
};
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 25178b66b..af962e94f 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -548,7 +548,7 @@ extern int ext2_read (struct inode *, struct file *, char *, int);
extern int ext2_write (struct inode *, struct file *, char *, int);
/* fsync.c */
-extern int ext2_sync_file (struct file *, struct dentry *);
+extern int ext2_sync_file (struct file *, struct dentry *, int);
/* ialloc.c */
extern struct inode * ext2_new_inode (const struct inode *, int, int *);
@@ -562,7 +562,7 @@ extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
extern void ext2_read_inode (struct inode *);
-extern void ext2_write_inode (struct inode *);
+extern void ext2_write_inode (struct inode *, int);
extern void ext2_put_inode (struct inode *);
extern void ext2_delete_inode (struct inode *);
extern int ext2_sync_inode (struct inode *);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8a1f8e9b6..b30bb8a08 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -47,7 +47,12 @@ struct poll_table_struct;
#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
/* And dynamically-tunable limits and defaults: */
-extern int max_files, nr_files, nr_free_files;
+struct files_stat_struct {
+ int nr_files; /* read only */
+ int nr_free_files; /* read only */
+ int max_files; /* tunable */
+};
+extern struct files_stat_struct files_stat;
extern int max_super_blocks, nr_super_blocks;
#define NR_FILE 8192 /* this can well be larger on a larger system */
@@ -84,6 +89,7 @@ extern int max_super_blocks, nr_super_blocks;
* kernel-wide vfsmnt is kept in ->kern_mnt.
*/
#define FS_NOMOUNT 16 /* Never mount from userland */
+#define FS_LITTER 32 /* Keeps the tree in dcache */
/*
* These are the fs-independent mount-flags: up to 16 flags are supported
*/
@@ -504,10 +510,8 @@ typedef struct files_struct *fl_owner_t;
struct file_lock {
struct file_lock *fl_next; /* singly linked list for this inode */
- struct file_lock *fl_nextlink; /* doubly linked list of all locks */
- struct file_lock *fl_prevlink; /* used to simplify lock removal */
- struct file_lock *fl_nextblock; /* circular list of blocked processes */
- struct file_lock *fl_prevblock;
+ struct list_head fl_link; /* doubly linked list of all locks */
+ struct list_head fl_block; /* circular list of blocked processes */
fl_owner_t fl_owner;
unsigned int fl_pid;
wait_queue_head_t fl_wait;
@@ -532,7 +536,7 @@ struct file_lock {
#define OFFSET_MAX INT_LIMIT(loff_t)
#endif
-extern struct file_lock *file_lock_table;
+extern struct list_head file_lock_list;
#include <linux/fcntl.h>
@@ -721,7 +725,7 @@ struct file_operations {
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
- int (*fsync) (struct file *, struct dentry *);
+ int (*fsync) (struct file *, struct dentry *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
@@ -754,7 +758,7 @@ struct inode_operations {
*/
struct super_operations {
void (*read_inode) (struct inode *);
- void (*write_inode) (struct inode *);
+ void (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
@@ -859,7 +863,8 @@ static inline int locks_verify_truncate(struct inode *inode,
return locks_mandatory_area(
FLOCK_VERIFY_WRITE, inode, filp,
size < inode->i_size ? size : inode->i_size,
- abs(inode->i_size - size)
+ (size < inode->i_size ? inode->i_size - size
+ : size - inode->i_size)
);
return 0;
}
@@ -989,7 +994,7 @@ extern void invalidate_inode_pages(struct inode *);
#define destroy_buffers(dev) __invalidate_buffers((dev), 1)
extern void __invalidate_buffers(kdev_t dev, int);
extern void sync_inodes(kdev_t);
-extern void write_inode_now(struct inode *);
+extern void write_inode_now(struct inode *, int);
extern void sync_dev(kdev_t);
extern int fsync_dev(kdev_t);
extern void sync_supers(kdev_t);
@@ -997,7 +1002,16 @@ extern int bmap(struct inode *, int);
extern int notify_change(struct dentry *, struct iattr *);
extern int permission(struct inode *, int);
extern int get_write_access(struct inode *);
-extern void put_write_access(struct inode *);
+extern int deny_write_access(struct file *);
+static inline void put_write_access(struct inode * inode)
+{
+ atomic_dec(&inode->i_writecount);
+}
+static inline void allow_write_access(struct file *file)
+{
+ if (file)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
+}
extern int do_pipe(int *);
extern int open_namei(const char *, int, int, struct nameidata *);
@@ -1037,7 +1051,7 @@ extern ino_t find_inode_number(struct dentry *, struct qstr *);
/*
* Type of the last component on LOOKUP_PARENT
*/
-enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT };
+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
/*
* "descriptor" for what we're up to with a read for sendfile().
@@ -1148,6 +1162,7 @@ extern struct inode_operations page_symlink_inode_operations;
extern int vfs_readdir(struct file *, filldir_t, void *);
extern int dcache_readdir(struct file *, void *, filldir_t);
+extern struct file_system_type *get_fs_type(const char *name);
extern struct super_block *get_super(kdev_t);
struct super_block *get_empty_super(void);
extern void put_super(kdev_t);
@@ -1172,7 +1187,7 @@ extern int read_ahead[];
extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
-extern int file_fsync(struct file *, struct dentry *);
+extern int file_fsync(struct file *, struct dentry *, int);
extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx);
extern int inode_change_ok(struct inode *, struct iattr *);
@@ -1186,20 +1201,6 @@ extern void inode_setattr(struct inode *, struct iattr *);
*/
/*
- * We need to do a check-parent every time
- * after we have locked the parent - to verify
- * that the parent is still our parent and
- * that we are still hashed onto it..
- *
- * This is required in case two processes race
- * on removing (or moving) the same entry: the
- * parent lock will serialize them, but the
- * other process will be too late..
- */
-#define check_parent(dir, dentry) \
- ((dir) == (dentry)->d_parent && !d_unhashed(dentry))
-
-/*
* Locking the parent is needed to:
* - serialize directory operations
* - make sure the parent doesn't change from
diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h
index 250191081..b9efcb696 100644
--- a/include/linux/kernelcapi.h
+++ b/include/linux/kernelcapi.h
@@ -58,12 +58,8 @@
#ifndef __KERNELCAPI_H__
#define __KERNELCAPI_H__
-#define CAPI_MAXAPPL 20 /*
- * maximum number of applications
- */
-#define CAPI_MAXCONTR 10 /*
- * maximum number of controller
- */
+#define CAPI_MAXAPPL 128 /* maximum number of applications */
+#define CAPI_MAXCONTR 16 /* maximum number of controller */
#define CAPI_MAXDATAWINDOW 8
diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h
index 1eca767b4..99cd63717 100644
--- a/include/linux/minix_fs.h
+++ b/include/linux/minix_fs.h
@@ -101,7 +101,7 @@ extern struct buffer_head * minix_bread(struct inode *, int, int);
extern void minix_truncate(struct inode *);
extern int minix_sync_inode(struct inode *);
-extern int minix_sync_file(struct file *, struct dentry *);
+extern int minix_sync_file(struct file *, struct dentry *, int);
extern struct address_space_operations minix_aops;
extern struct inode_operations minix_file_inode_operations;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 37cb9664e..e6325a298 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -185,6 +185,7 @@ typedef struct page {
#define ClearPageUptodate(page) clear_bit(PG_uptodate, &(page)->flags)
#define PageDirty(page) test_bit(PG_dirty, &(page)->flags)
#define SetPageDirty(page) set_bit(PG_dirty, &(page)->flags)
+#define ClearPageDirty(page) clear_bit(PG_dirty, &(page)->flags)
#define PageLocked(page) test_bit(PG_locked, &(page)->flags)
#define LockPage(page) set_bit(PG_locked, &(page)->flags)
#define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags)
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 61ab19b1f..adb571de2 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -26,7 +26,6 @@ struct vfsmount
atomic_t mnt_count;
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
- char *mnt_dirname; /* Name of directory mounted on */
struct list_head mnt_list;
uid_t mnt_owner;
};
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 4897f2ec9..cbbf78528 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -248,7 +248,7 @@ extern struct inode *fat_build_inode(struct super_block*,struct msdos_dir_entry*
extern struct super_block *fat_read_super(struct super_block *s, void *data, int silent, struct inode_operations *dir_ops);
extern void msdos_put_super(struct super_block *sb);
extern int fat_statfs(struct super_block *sb,struct statfs *buf);
-extern void fat_write_inode(struct inode *inode);
+extern void fat_write_inode(struct inode *inode, int);
/* dir.c */
extern struct file_operations fat_dir_operations;
diff --git a/include/linux/ncp_fs_i.h b/include/linux/ncp_fs_i.h
index 96728bcdd..ffdf49f4c 100644
--- a/include/linux/ncp_fs_i.h
+++ b/include/linux/ncp_fs_i.h
@@ -19,7 +19,8 @@ struct ncp_inode_info {
__u32 DosDirNum __attribute__((packed));
__u32 volNumber __attribute__((packed));
__u32 nwattr;
- int opened;
+ struct semaphore open_sem;
+ atomic_t opened;
int access;
__u32 server_file_handle __attribute__((packed));
__u8 open_create_action __attribute__((packed));
diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
index 8e675705e..ae2da13be 100644
--- a/include/linux/nfsd/cache.h
+++ b/include/linux/nfsd/cache.h
@@ -25,9 +25,11 @@ struct svc_cacherep {
unsigned char c_state, /* unused, inprog, done */
c_type, /* status, buffer */
c_secure : 1; /* req came from port < 1024 */
- struct in_addr c_client;
+ struct sockaddr_in c_addr;
u32 c_xid;
+ u32 c_prot;
u32 c_proc;
+ u32 c_vers;
unsigned long c_timestamp;
union {
struct svc_buf u_buffer;
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 06a21296f..5fb55c738 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -95,18 +95,6 @@ int nfserrno(int errno);
void exp_nlmdetach(void);
-extern __inline__ int
-exp_checkaddr(struct svc_client *clp, struct in_addr addr)
-{
- struct in_addr *ap = clp->cl_addr;
- int i;
-
- for (i = clp->cl_naddr; i--; ap++)
- if (ap->s_addr == addr.s_addr)
- return 1;
- return 0;
-}
-
#endif /* __KERNEL__ */
#endif /* NFSD_EXPORT_H */
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 42663e79b..26e8edd22 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -80,19 +80,19 @@ int nfsd_racache_init(int);
void nfsd_racache_shutdown(void);
int nfsd_lookup(struct svc_rqst *, struct svc_fh *,
const char *, int, struct svc_fh *);
-#ifdef CONFIG_NFSD_V3
-int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *);
-#endif /* CONFIG_NFSD_V3 */
int nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct iattr *);
int nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
int type, dev_t rdev, struct svc_fh *res);
#ifdef CONFIG_NFSD_V3
+int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *);
int nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
struct svc_fh *res, int createmode,
u32 *verifier);
+int nfsd_commit(struct svc_rqst *, struct svc_fh *,
+ off_t, unsigned long);
#endif /* CONFIG_NFSD_V3 */
int nfsd_open(struct svc_rqst *, struct svc_fh *, int,
int, struct file *);
@@ -122,10 +122,7 @@ int nfsd_readdir(struct svc_rqst *, struct svc_fh *,
u32 *buffer, int *countp, u32 *verf);
int nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct statfs *);
-#ifdef CONFIG_NFSD_V3
-int nfsd_commit(struct svc_rqst *, struct svc_fh *,
- off_t, unsigned long);
-#endif /* CONFIG_NFSD_V3 */
+
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index 83320b810..39ab97f14 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -90,7 +90,7 @@ struct nfs_fhbase_new {
};
struct knfsd_fh {
- int fh_size; /* significant for NFSv3.
+ unsigned int fh_size; /* significant for NFSv3.
* Points to the current size while building
* a new file handle
*/
@@ -149,14 +149,13 @@ typedef struct svc_fh {
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
int fh_maxsize; /* max size for fh_handle */
+
+ unsigned char fh_locked; /* inode locked by us */
+
#ifdef CONFIG_NFSD_V3
unsigned char fh_post_saved; /* post-op attrs saved */
unsigned char fh_pre_saved; /* pre-op attrs saved */
-#endif /* CONFIG_NFSD_V3 */
- unsigned char fh_locked; /* inode locked by us */
- unsigned char fh_dverified; /* dentry has been checked */
-#ifdef CONFIG_NFSD_V3
/* Pre-op attributes saved during fh_lock */
__u64 fh_pre_size; /* size before operation */
time_t fh_pre_mtime; /* mtime before oper */
@@ -207,7 +206,7 @@ void fh_put(struct svc_fh *);
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
{
- if (src->fh_dverified || src->fh_locked) {
+ if (src->fh_dentry || src->fh_locked) {
struct dentry *dentry = src->fh_dentry;
printk(KERN_ERR "fh_copy: copying %s/%s, already verified!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -241,7 +240,6 @@ fill_pre_wcc(struct svc_fh *fhp)
fhp->fh_pre_size = inode->i_size;
fhp->fh_pre_saved = 1;
}
- fhp->fh_locked = 1;
}
/*
@@ -273,13 +271,18 @@ fill_post_wcc(struct svc_fh *fhp)
fhp->fh_post_mtime = inode->i_mtime;
fhp->fh_post_ctime = inode->i_ctime;
fhp->fh_post_saved = 1;
- fhp->fh_locked = 0;
}
+#else
+#define fill_pre_wcc(ignored)
+#define fill_post_wcc(notused)
#endif /* CONFIG_NFSD_V3 */
/*
* Lock a file handle/inode
+ * NOTE: both fh_lock and fh_unlock are done "by hand" in
+ * vfs.c:nfsd_rename as it needs to grab 2 i_sem's at once
+ * so, any changes here should be reflected there.
*/
static inline void
fh_lock(struct svc_fh *fhp)
@@ -290,7 +293,7 @@ fh_lock(struct svc_fh *fhp)
dfprintk(FILEOP, "nfsd: fh_lock(%s) locked = %d\n",
SVCFH_fmt(fhp), fhp->fh_locked);
- if (!fhp->fh_dverified) {
+ if (!fhp->fh_dentry) {
printk(KERN_ERR "fh_lock: fh not verified!\n");
return;
}
@@ -302,11 +305,8 @@ fh_lock(struct svc_fh *fhp)
inode = dentry->d_inode;
down(&inode->i_sem);
-#ifdef CONFIG_NFSD_V3
fill_pre_wcc(fhp);
-#else
fhp->fh_locked = 1;
-#endif /* CONFIG_NFSD_V3 */
}
/*
@@ -315,20 +315,13 @@ fh_lock(struct svc_fh *fhp)
static inline void
fh_unlock(struct svc_fh *fhp)
{
- if (!fhp->fh_dverified)
+ if (!fhp->fh_dentry)
printk(KERN_ERR "fh_unlock: fh not verified!\n");
if (fhp->fh_locked) {
-#ifdef CONFIG_NFSD_V3
fill_post_wcc(fhp);
up(&fhp->fh_dentry->d_inode->i_sem);
-#else
- struct dentry *dentry = fhp->fh_dentry;
- struct inode *inode = dentry->d_inode;
-
fhp->fh_locked = 0;
- up(&inode->i_sem);
-#endif /* CONFIG_NFSD_V3 */
}
}
#endif /* __KERNEL__ */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 5512d2a51..04ae938be 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -330,13 +330,14 @@
#define PCI_DEVICE_ID_SI_6205 0x0205
#define PCI_DEVICE_ID_SI_501 0x0406
#define PCI_DEVICE_ID_SI_496 0x0496
-#define PCI_DEVICE_ID_SI_300 0x0300
+#define PCI_DEVICE_ID_SI_300 0x0300
#define PCI_DEVICE_ID_SI_530 0x0530
-#define PCI_DEVICE_ID_SI_540 0x5300
+#define PCI_DEVICE_ID_SI_540 0x0540
#define PCI_DEVICE_ID_SI_601 0x0601
#define PCI_DEVICE_ID_SI_620 0x0620
-#define PCI_DEVICE_ID_SI_630 0x6300
+#define PCI_DEVICE_ID_SI_630 0x0630
#define PCI_DEVICE_ID_SI_5107 0x5107
+#define PCI_DEVICE_ID_SI_5300 0x5300
#define PCI_DEVICE_ID_SI_5511 0x5511
#define PCI_DEVICE_ID_SI_5513 0x5513
#define PCI_DEVICE_ID_SI_5571 0x5571
@@ -344,6 +345,7 @@
#define PCI_DEVICE_ID_SI_5597 0x5597
#define PCI_DEVICE_ID_SI_5598 0x5598
#define PCI_DEVICE_ID_SI_5600 0x5600
+#define PCI_DEVICE_ID_SI_6300 0x6300
#define PCI_DEVICE_ID_SI_6306 0x6306
#define PCI_DEVICE_ID_SI_6326 0x6326
#define PCI_DEVICE_ID_SI_7001 0x7001
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
index ad5ca5543..dd9b7cb6e 100644
--- a/include/linux/qnx4_fs.h
+++ b/include/linux/qnx4_fs.h
@@ -116,7 +116,7 @@ extern void qnx4_truncate(struct inode *inode);
extern void qnx4_free_inode(struct inode *inode);
extern int qnx4_unlink(struct inode *dir, struct dentry *dentry);
extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry);
-extern int qnx4_sync_file(struct file *file, struct dentry *dentry);
+extern int qnx4_sync_file(struct file *file, struct dentry *dentry, int);
extern int qnx4_sync_inode(struct inode *inode);
extern int qnx4_get_block(struct inode *inode, long iblock, struct buffer_head *bh, int create);
diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h
index d9c2557e5..4cff4260c 100644
--- a/include/linux/sysv_fs.h
+++ b/include/linux/sysv_fs.h
@@ -377,9 +377,9 @@ extern unsigned long sysv_count_free_blocks(struct super_block *sb);
extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
extern void sysv_truncate(struct inode *);
-extern void sysv_write_inode(struct inode *);
+extern void sysv_write_inode(struct inode *, int);
extern int sysv_sync_inode(struct inode *);
-extern int sysv_sync_file(struct file *, struct dentry *);
+extern int sysv_sync_file(struct file *, struct dentry *, int);
extern int sysv_notify_change(struct dentry *, struct iattr *);
extern struct inode_operations sysv_file_inode_operations;
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 2de8050ea..9d6b8c3a2 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -52,9 +52,10 @@ struct timer_list {
unsigned long expires;
unsigned long data;
void (*function)(unsigned long);
- volatile int running;
+ unsigned long sequence;
};
+extern volatile unsigned long timer_sequence;
extern void add_timer(struct timer_list * timer);
extern int del_timer(struct timer_list * timer);
@@ -71,7 +72,7 @@ static inline void init_timer(struct timer_list * timer)
{
timer->list.next = timer->list.prev = NULL;
#ifdef CONFIG_SMP
- timer->running = 0;
+ timer->sequence = timer_sequence-1;
#endif
}
@@ -81,17 +82,17 @@ static inline int timer_pending (const struct timer_list * timer)
}
#ifdef CONFIG_SMP
-#define timer_exit(t) do { (t)->running = 0; mb(); } while (0)
-#define timer_set_running(t) do { (t)->running = 1; mb(); } while (0)
-#define timer_is_running(t) ((t)->running != 0)
+#define timer_enter(t) do { (t)->sequence = timer_sequence; mb(); } while (0)
+#define timer_exit() do { timer_sequence++; } while (0)
+#define timer_is_running(t) ((t)->sequence == timer_sequence)
#define timer_synchronize(t) while (timer_is_running(t)) barrier()
extern int del_timer_sync(struct timer_list * timer);
#else
-#define timer_exit(t) (void)(t)
-#define timer_set_running(t) (void)(t)
-#define timer_is_running(t) (0)
-#define timer_synchronize(t) do { (void)(t); barrier(); } while(0)
-#define del_timer_sync(t) del_timer(t)
+#define timer_enter(t) do { } while (0)
+#define timer_exit() do { } while (0)
+#define timer_is_running(t) (0)
+#define timer_synchronize(t) do { (void)(t); barrier(); } while(0)
+#define del_timer_sync(t) del_timer(t)
#endif
/*
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index 96cb38e67..3c8f1d415 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -560,9 +560,8 @@ extern struct inode * ufs_new_inode (const struct inode *, int, int *);
extern int ufs_frag_map (struct inode *, int);
extern void ufs_read_inode (struct inode *);
extern void ufs_put_inode (struct inode *);
-extern void ufs_write_inode (struct inode *);
+extern void ufs_write_inode (struct inode *, int);
extern int ufs_sync_inode (struct inode *);
-extern void ufs_write_inode (struct inode *);
extern void ufs_delete_inode (struct inode *);
extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p
index 76436a479..677bee22e 100644
--- a/include/linux/umsdos_fs.p
+++ b/include/linux/umsdos_fs.p
@@ -48,7 +48,7 @@ int umsdos_isempty (struct dentry *);
/* inode.c 12/06/95 09.49.40 */
void fill_new_filp (struct file *filp, struct dentry *dentry);
void UMSDOS_read_inode (struct inode *);
-void UMSDOS_write_inode (struct inode *);
+void UMSDOS_write_inode (struct inode *, int);
int UMSDOS_notify_change (struct dentry *, struct iattr *attr);
int umsdos_notify_change_locked(struct dentry *, struct iattr *attr);
void UMSDOS_put_inode (struct inode *);
diff --git a/ipc/shm.c b/ipc/shm.c
index f1b638acf..a76860ca1 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -52,7 +52,7 @@ static struct super_block *shm_read_super(struct super_block *,void *, int);
static void shm_put_super (struct super_block *);
static int shm_remount_fs (struct super_block *, int *, char *);
static void shm_read_inode (struct inode *);
-static void shm_write_inode(struct inode *);
+static void shm_write_inode(struct inode *, int);
static int shm_statfs (struct super_block *, struct statfs *);
static int shm_create (struct inode *,struct dentry *,int);
static struct dentry *shm_lookup (struct inode *,struct dentry *);
@@ -371,7 +371,7 @@ static int shm_statfs(struct super_block *sb, struct statfs *buf)
return 0;
}
-static void shm_write_inode(struct inode * inode)
+static void shm_write_inode(struct inode * inode, int sync)
{
}
@@ -1490,7 +1490,7 @@ static int shm_swap_core(struct shmid_kernel *shp, unsigned long idx, swp_entry_
return RETRY;
if (shp->id != zero_id) swap_attempts++;
- if (--counter < 0) /* failed */
+ if (--*counter < 0) /* failed */
return FAILED;
if (page_count(page_map) != 1)
return RETRY;
diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c
index 3f3b5fc16..1daf64cc1 100644
--- a/kernel/exec_domain.c
+++ b/kernel/exec_domain.c
@@ -104,32 +104,37 @@ int unregister_exec_domain(struct exec_domain *it)
void __set_personality(unsigned long personality)
{
- struct exec_domain *it;
+ struct exec_domain *it, *prev;
it = lookup_exec_domain(personality);
- if (it) {
- if (atomic_read(&current->fs->count) != 1) {
- struct fs_struct *new = copy_fs_struct(current->fs);
- struct fs_struct *old;
- if (!new) {
- put_exec_domain(it);
- return;
- }
- task_lock(current);
- old = current->fs;
- current->fs = new;
- task_unlock(current);
- put_fs_struct(old);
- }
- /*
- * At that point we are guaranteed to be the sole owner of
- * current->fs.
- */
+ if (it == current->exec_domain) {
current->personality = personality;
- current->exec_domain = it;
- set_fs_altroot();
- put_exec_domain(current->exec_domain);
+ return;
+ }
+ if (!it)
+ return;
+ if (atomic_read(&current->fs->count) != 1) {
+ struct fs_struct *new = copy_fs_struct(current->fs);
+ struct fs_struct *old;
+ if (!new) {
+ put_exec_domain(it);
+ return;
+ }
+ task_lock(current);
+ old = current->fs;
+ current->fs = new;
+ task_unlock(current);
+ put_fs_struct(old);
}
+ /*
+ * At that point we are guaranteed to be the sole owner of
+ * current->fs.
+ */
+ current->personality = personality;
+ prev = current->exec_domain;
+ current->exec_domain = it;
+ set_fs_altroot();
+ put_exec_domain(prev);
}
asmlinkage long sys_personality(unsigned long personality)
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 6c38477be..79d58220c 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -103,7 +103,6 @@ void it_real_fn(unsigned long __data)
p->real_timer.expires = jiffies + interval;
add_timer(&p->real_timer);
}
- timer_exit(&p->real_timer);
}
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index f1032de30..2189d87a4 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -130,6 +130,7 @@ EXPORT_SYMBOL(highmem_start_page);
/* filesystem internal functions */
EXPORT_SYMBOL(def_blk_fops);
EXPORT_SYMBOL(update_atime);
+EXPORT_SYMBOL(get_fs_type);
EXPORT_SYMBOL(get_super);
EXPORT_SYMBOL(get_empty_super);
EXPORT_SYMBOL(getname);
@@ -205,7 +206,7 @@ EXPORT_SYMBOL(generic_ro_fops);
EXPORT_SYMBOL(generic_buffer_fdatasync);
EXPORT_SYMBOL(page_hash_bits);
EXPORT_SYMBOL(page_hash_table);
-EXPORT_SYMBOL(file_lock_table);
+EXPORT_SYMBOL(file_lock_list);
EXPORT_SYMBOL(posix_lock_file);
EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL(posix_block_lock);
@@ -213,7 +214,6 @@ EXPORT_SYMBOL(posix_unblock_lock);
EXPORT_SYMBOL(locks_mandatory_area);
EXPORT_SYMBOL(dput);
EXPORT_SYMBOL(have_submounts);
-EXPORT_SYMBOL(d_genocide);
EXPORT_SYMBOL(d_find_alias);
EXPORT_SYMBOL(d_prune_aliases);
EXPORT_SYMBOL(prune_dcache);
@@ -502,7 +502,6 @@ EXPORT_SYMBOL(disk_name); /* for md.c */
/* binfmt_aout */
EXPORT_SYMBOL(get_write_access);
-EXPORT_SYMBOL(put_write_access);
/* dynamic registering of consoles */
EXPORT_SYMBOL(register_console);
diff --git a/kernel/module.c b/kernel/module.c
index c0c5c9053..5e5fbfe1b 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -326,10 +326,11 @@ sys_init_module(const char *name_user, struct module *mod_user)
/* Initialize the module. */
mod->flags |= MOD_INITIALIZING;
atomic_set(&mod->uc.usecount,1);
- if (mod->init && mod->init() != 0) {
+ if (mod->init && (error = mod->init()) != 0) {
atomic_set(&mod->uc.usecount,0);
mod->flags &= ~MOD_INITIALIZING;
- error = -EBUSY;
+ if (error > 0) /* Buggy module */
+ error = -EBUSY;
goto err0;
}
atomic_dec(&mod->uc.usecount);
diff --git a/kernel/sched.c b/kernel/sched.c
index f85cc4213..fa30b0645 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -60,8 +60,8 @@ struct task_struct * init_tasks[NR_CPUS] = {&init_task, };
* The run-queue lock locks the parts that actually access
* and change the run-queues, and have to be interrupt-safe.
*/
-__cacheline_aligned spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED; /* second */
-__cacheline_aligned rwlock_t tasklist_lock = RW_LOCK_UNLOCKED; /* third */
+spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; /* second */
+rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* third */
static LIST_HEAD(runqueue_head);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 5fc0418f9..ab62787d1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -255,9 +255,9 @@ static ctl_table fs_table[] = {
0444, NULL, &proc_dointvec},
{FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
0444, NULL, &proc_dointvec},
- {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
+ {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
0444, NULL, &proc_dointvec},
- {FS_MAXFILE, "file-max", &max_files, sizeof(int),
+ {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
0644, NULL, &proc_dointvec},
{FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
0444, NULL, &proc_dointvec},
diff --git a/kernel/timer.c b/kernel/timer.c
index 9fa35a63b..873fef479 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -160,7 +160,9 @@ static inline void internal_add_timer(struct timer_list *timer)
list_add(&timer->list, vec->prev);
}
+/* Initialize both explicitly - let's try to have them in the same cache line */
spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
+volatile unsigned long timer_sequence = 0xfee1bad;
void add_timer(struct timer_list *timer)
{
@@ -233,11 +235,12 @@ int del_timer_sync(struct timer_list * timer)
spin_lock_irqsave(&timerlist_lock, flags);
ret += detach_timer(timer);
timer->list.next = timer->list.prev = 0;
- running = timer->running;
+ running = timer_is_running(timer);
spin_unlock_irqrestore(&timerlist_lock, flags);
if (!running)
- return ret;
+ break;
+
timer_synchronize(timer);
}
@@ -295,10 +298,11 @@ repeat:
detach_timer(timer);
timer->list.next = timer->list.prev = NULL;
- timer_set_running(timer);
+ timer_enter(timer);
spin_unlock_irq(&timerlist_lock);
fn(data);
spin_lock_irq(&timerlist_lock);
+ timer_exit();
goto repeat;
}
++timer_jiffies;
@@ -577,27 +581,32 @@ void update_one_process(struct task_struct *p,
do_it_prof(p, ticks);
}
-static void update_process_times(unsigned long ticks, unsigned long system)
+/*
+ * Called from the timer interrupt handler to charge one tick to the current
+ * process. user_tick is 1 if the tick is user time, 0 for system.
+ */
+static void update_process_times(int user_tick)
{
/*
* SMP does this on a per-CPU basis elsewhere
*/
#ifndef CONFIG_SMP
- struct task_struct * p = current;
- unsigned long user = ticks - system;
+ struct task_struct *p = current;
+ int system = !user_tick;
+
if (p->pid) {
- p->counter -= ticks;
- if (p->counter <= 0) {
+ if (--p->counter <= 0) {
p->counter = 0;
p->need_resched = 1;
}
if (p->priority < DEF_PRIORITY)
- kstat.cpu_nice += user;
+ kstat.cpu_nice += user_tick;
else
- kstat.cpu_user += user;
+ kstat.cpu_user += user_tick;
kstat.cpu_system += system;
- }
- update_one_process(p, ticks, user, system, 0);
+ } else if (local_bh_count(0) || local_irq_count(0) > 1)
+ kstat.cpu_system += system;
+ update_one_process(p, 1, user_tick, system, 0);
#endif
}
@@ -643,7 +652,6 @@ static inline void calc_load(unsigned long ticks)
}
volatile unsigned long lost_ticks;
-static unsigned long lost_ticks_system;
/*
* This spinlock protect us from races in SMP while playing with xtime. -arca
@@ -665,17 +673,10 @@ static inline void update_times(void)
lost_ticks = 0;
if (ticks) {
- unsigned long system;
- system = xchg(&lost_ticks_system, 0);
-
calc_load(ticks);
update_wall_time(ticks);
- write_unlock_irq(&xtime_lock);
-
- update_process_times(ticks, system);
-
- } else
- write_unlock_irq(&xtime_lock);
+ }
+ write_unlock_irq(&xtime_lock);
}
void timer_bh(void)
@@ -685,13 +686,12 @@ void timer_bh(void)
run_timer_list();
}
-void do_timer(struct pt_regs * regs)
+void do_timer(struct pt_regs *regs)
{
(*(unsigned long *)&jiffies)++;
lost_ticks++;
+ update_process_times(user_mode(regs));
mark_bh(TIMER_BH);
- if (!user_mode(regs))
- lost_ticks_system++;
if (tq_timer)
mark_bh(TQUEUE_BH);
}
diff --git a/mm/filemap.c b/mm/filemap.c
index b1e2b8547..74eb0ef83 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -195,6 +195,7 @@ repeat:
* to it causing all sorts of fun problems ...
*/
remove_inode_page(page);
+ ClearPageDirty(page);
UnlockPage(page);
page_cache_release(page);
@@ -500,7 +501,7 @@ void add_to_page_cache_locked(struct page * page, struct address_space *mapping,
/*
* This adds a page to the page cache, starting out as locked,
- * owned by us, referenced, but not uptodate and with no errors.
+ * owned by us, but unreferenced, not uptodate and with no errors.
*/
static inline void __add_to_page_cache(struct page * page,
struct address_space *mapping, unsigned long offset,
@@ -512,8 +513,8 @@ static inline void __add_to_page_cache(struct page * page,
if (PageLocked(page))
BUG();
- flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty));
- page->flags = flags | (1 << PG_locked) | (1 << PG_referenced);
+ flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ page->flags = flags | (1 << PG_locked);
page_cache_get(page);
page->index = offset;
add_page_to_inode_queue(mapping, page);
@@ -1744,7 +1745,7 @@ static int msync_interval(struct vm_area_struct * vma,
if (!error && (flags & MS_SYNC)) {
struct file * file = vma->vm_file;
if (file && file->f_op && file->f_op->fsync)
- error = file->f_op->fsync(file, file->f_dentry);
+ error = file->f_op->fsync(file, file->f_dentry, 1);
}
return error;
}
diff --git a/mm/mmap.c b/mm/mmap.c
index f5bb2599c..3d331a311 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -166,6 +166,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
{
struct mm_struct * mm = current->mm;
struct vm_area_struct * vma;
+ int correct_wcount = 0;
int error;
if (file && (!file->f_op || !file->f_op->mmap))
@@ -296,26 +297,15 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
goto free_vma;
if (file) {
- int correct_wcount = 0;
if (vma->vm_flags & VM_DENYWRITE) {
- if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
- error = -ETXTBSY;
+ error = deny_write_access(file);
+ if (error)
goto free_vma;
- }
- /* f_op->mmap might possibly sleep
- * (generic_file_mmap doesn't, but other code
- * might). In any case, this takes care of any
- * race that this might cause.
- */
- atomic_dec(&file->f_dentry->d_inode->i_writecount);
correct_wcount = 1;
}
vma->vm_file = file;
get_file(file);
error = file->f_op->mmap(file, vma);
- /* Fix up the count if necessary, then check for an error */
- if (correct_wcount)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
if (error)
goto unmap_and_free_vma;
} else if (flags & MAP_SHARED) {
@@ -332,6 +322,8 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
addr = vma->vm_start; /* can addr have changed?? */
vmlist_modify_lock(mm);
insert_vm_struct(mm, vma);
+ if (correct_wcount)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
merge_segments(mm, vma->vm_start, vma->vm_end);
vmlist_modify_unlock(mm);
@@ -343,6 +335,8 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
return addr;
unmap_and_free_vma:
+ if (correct_wcount)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
vma->vm_file = NULL;
fput(file);
/* Undo any partial mapping done by a device driver. */
@@ -694,9 +688,11 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
* so release them, and unmap the page range..
* If the one of the segments is only being partially unmapped,
* it will put new vm_area_struct(s) into the address space.
+ * In that case we have to be careful with VM_DENYWRITE.
*/
while ((mpnt = free) != NULL) {
unsigned long st, end, size;
+ struct file *file = NULL;
free = free->vm_next;
@@ -708,6 +704,11 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
if (mpnt->vm_ops && mpnt->vm_ops->unmap)
mpnt->vm_ops->unmap(mpnt, st, size);
+ if (mpnt->vm_flags & VM_DENYWRITE &&
+ (st != mpnt->vm_start || end != mpnt->vm_end) &&
+ (file = mpnt->vm_file) != NULL) {
+ atomic_dec(&file->f_dentry->d_inode->i_writecount);
+ }
remove_shared_vm_struct(mpnt);
mm->map_count--;
@@ -719,6 +720,8 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
* Fix the mapping, and free the old area if it wasn't reused.
*/
extra = unmap_fixup(mm, mpnt, st, size, extra);
+ if (file)
+ atomic_inc(&file->f_dentry->d_inode->i_writecount);
}
/* Release the extra vma struct if it wasn't used */
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 926364499..18a60fdbd 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -93,6 +93,8 @@ void __free_pages_ok (struct page *page, unsigned long order)
BUG();
if (PageDecrAfter(page))
BUG();
+ if (PageDirty(page))
+ BUG();
zone = page->zone;
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 2405aba2f..72f3eaca4 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -58,8 +58,8 @@ void add_to_swap_cache(struct page *page, swp_entry_t entry)
BUG();
if (page->mapping)
BUG();
- flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty));
- page->flags = flags | (1 << PG_referenced) | (1 << PG_uptodate);
+ flags = page->flags & ~((1 << PG_error) | (1 << PG_dirty) | (1 << PG_referenced));
+ page->flags = flags | (1 << PG_uptodate);
add_to_page_cache_locked(page, &swapper_space, entry.val);
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 55ef476a3..5d3a7f23e 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -407,11 +407,11 @@ asmlinkage long sys_swapoff(const char * specialfile)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- lock_kernel();
err = user_path_walk(specialfile, &nd);
if (err)
goto out;
+ lock_kernel();
prev = -1;
swap_list_lock();
for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
@@ -478,9 +478,9 @@ asmlinkage long sys_swapoff(const char * specialfile)
err = 0;
out_dput:
+ unlock_kernel();
path_release(&nd);
out:
- unlock_kernel();
return err;
}
@@ -555,7 +555,6 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
unsigned long maxpages;
int swapfilesize;
struct block_device *bdev = NULL;
- char *name;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -586,14 +585,7 @@ asmlinkage long sys_swapon(const char * specialfile, int swap_flags)
} else {
p->prio = --least_priority;
}
- name = getname(specialfile);
- error = PTR_ERR(name);
- if (IS_ERR(name))
- goto bad_swap_2;
- error = 0;
- if (path_init(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
- error = path_walk(name, &nd);
- putname(name);
+ error = user_path_walk(specialfile, &nd);
if (error)
goto bad_swap_2;
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index d99065efe..57718cf00 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -964,7 +964,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
return NULL;
}
- *ax25->digipeat = *osk->protinfo.ax25->digipeat;
+ memcpy(ax25->digipeat, osk->protinfo.ax25->digipeat, sizeof(ax25_digi));
}
sk->protinfo.ax25 = ax25;
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index f4b5e1a75..6efbc57f2 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -426,7 +426,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
}
} else {
/* Reverse the source SABM's path */
- *ax25->digipeat = reverse_dp;
+ memcpy(&ax25->digipeat, &reverse_dp, sizeof(ax25_digi));
}
if ((*skb->data & ~AX25_PF) == AX25_SABME) {
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
index 719059b21..e6b19f53b 100644
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -98,7 +98,7 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
ax25_free_cb(ax25);
return NULL;
}
- *ax25->digipeat = *digi;
+ memcpy(ax25->digipeat, digi, sizeof(ax25_digi));
}
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index e92a1b39e..6d58c5d04 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -373,7 +373,7 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
if (ax25_rt->digipeat != NULL) {
if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- *ax25->digipeat = *ax25_rt->digipeat;
+ memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
ax25_adjust_path(addr, ax25->digipeat);
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 5a3ccd062..88322c8d6 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -603,8 +603,6 @@ static void neigh_periodic_timer(unsigned long arg)
struct neigh_table *tbl = (struct neigh_table*)arg;
tasklet_schedule(&tbl->gc_task);
-
- timer_exit(&tbl->gc_timer);
}
#endif
@@ -676,7 +674,6 @@ static void neigh_timer_handler(unsigned long arg)
neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue));
atomic_inc(&neigh->probes);
- timer_exit(&neigh->timer);
return;
out:
@@ -685,7 +682,6 @@ out:
if (notify && neigh->parms->app_probes)
neigh_app_notify(neigh);
#endif
- timer_exit(&neigh->timer);
neigh_release(neigh);
}
@@ -1021,7 +1017,6 @@ static void neigh_proxy_process(unsigned long arg)
tbl->proxy_timer.expires = jiffies + sched_next;
add_timer(&tbl->proxy_timer);
}
- timer_exit(&tbl->proxy_timer);
}
void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 3ab33c220..bc9e2cb48 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -911,7 +911,6 @@ static void dn_dev_timer_func(unsigned long arg)
}
dn_dev_set_timer(dev);
- timer_exit(&dn_db->timer);
}
static void dn_dev_set_timer(struct net_device *dev)
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 1f52d293d..de4722707 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -241,7 +241,6 @@ static void tcp_delack_timer(unsigned long data)
TCP_CHECK_TIMER(sk);
out_unlock:
- timer_exit(&tp->delack_timer);
bh_unlock_sock(sk);
sock_put(sk);
}
@@ -299,7 +298,6 @@ static void tcp_probe_timer(unsigned long data)
TCP_CHECK_TIMER(sk);
}
out_unlock:
- timer_exit(&tp->probe_timer);
bh_unlock_sock(sk);
sock_put(sk);
}
@@ -611,7 +609,6 @@ static void tcp_retransmit_timer(unsigned long data)
TCP_CHECK_TIMER(sk);
out_unlock:
- timer_exit(&tp->retransmit_timer);
bh_unlock_sock(sk);
sock_put(sk);
}
@@ -806,7 +803,6 @@ death:
tcp_done(sk);
out:
- timer_exit(&sk->timer);
bh_unlock_sock(sk);
sock_put(sk);
}
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index fd36a887e..308e73af2 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -122,7 +122,7 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
kfree(nr_neigh);
return -ENOMEM;
}
- *nr_neigh->digipeat = *ax25_digi;
+ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
}
save_flags(flags);
@@ -402,7 +402,7 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net
kfree(nr_neigh);
return -ENOMEM;
}
- *nr_neigh->digipeat = *ax25_digi;
+ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
}
save_flags(flags);
diff --git a/net/netsyms.c b/net/netsyms.c
index c209ff991..cd4a2bdb9 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -196,7 +196,7 @@ EXPORT_SYMBOL(__scm_send);
/* Needed by unix.o */
EXPORT_SYMBOL(scm_fp_dup);
-EXPORT_SYMBOL(max_files);
+EXPORT_SYMBOL(files_stat);
EXPORT_SYMBOL(memcpy_toiovec);
EXPORT_SYMBOL(csum_partial);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index e0a13d725..f0f714ff0 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -32,6 +32,7 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
+#include <net/checksum.h>
#include <net/ip.h>
#include <asm/uaccess.h>
@@ -371,6 +372,16 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
dprintk("svc: recvfrom returned error %d\n", -err);
}
+ if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
+ unsigned int csum = skb->csum;
+ csum = csum_partial(skb->h.raw, skb->len, csum);
+ if ((unsigned short)csum_fold(csum)) {
+ skb_free_datagram(svsk->sk_sk, skb);
+ svc_sock_received(svsk, 0);
+ return 0;
+ }
+ }
+
/* There may be more data */
svsk->sk_data = 1;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d71a527fe..20e0fc8c7 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -445,7 +445,7 @@ static struct sock * unix_create1(struct socket *sock)
{
struct sock *sk;
- if (atomic_read(&unix_nr_socks) >= 2*max_files)
+ if (atomic_read(&unix_nr_socks) >= 2*files_stat.max_files)
return NULL;
MOD_INC_USE_COUNT;
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index f58867de7..649cb6cb3 100644
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -673,9 +673,9 @@ sub dump_function {
$args = $3;
# allow for up to fours args to function pointers
- $args =~ s/(\([^\),]+),/\1#/;
- $args =~ s/(\([^\),]+),/\1#/;
- $args =~ s/(\([^\),]+),/\1#/;
+ $args =~ s/(\([^\),]+),/\1#/g;
+ $args =~ s/(\([^\),]+),/\1#/g;
+ $args =~ s/(\([^\),]+),/\1#/g;
# print STDERR "ARGS = '$args'\n";
foreach $arg (split ',', $args) {