summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS32
-rw-r--r--Documentation/Changes4
-rw-r--r--Documentation/Configure.help145
-rw-r--r--Documentation/networking/decnet.txt10
-rw-r--r--Documentation/sound/Introduction2
-rw-r--r--Documentation/sound/Maestro3
-rw-r--r--Documentation/sound/OPL3-SA28
-rw-r--r--Documentation/sound/Opti4
-rw-r--r--Documentation/sound/README.OSS39
-rw-r--r--Documentation/sound/Wavefront30
-rw-r--r--Documentation/sound/via82cxxx.txt20
-rw-r--r--Makefile6
-rw-r--r--arch/alpha/config.in2
-rw-r--r--arch/alpha/defconfig4
-rw-r--r--arch/alpha/kernel/osf_sys.c15
-rw-r--r--arch/arm/Makefile1
-rw-r--r--arch/arm/config.in2
-rw-r--r--arch/i386/config.in8
-rw-r--r--arch/i386/defconfig10
-rw-r--r--arch/i386/kernel/acpi.c75
-rw-r--r--arch/i386/kernel/apm.c6
-rw-r--r--arch/i386/kernel/pci-pc.c23
-rw-r--r--arch/i386/kernel/process.c6
-rw-r--r--arch/ia64/Makefile8
-rw-r--r--arch/ia64/config.in4
-rw-r--r--arch/ia64/dig/iosapic.c146
-rw-r--r--arch/ia64/hp/hpsim_irq.c81
-rw-r--r--arch/ia64/ia32/binfmt_elf32.c4
-rw-r--r--arch/ia64/kernel/Makefile2
-rw-r--r--arch/ia64/kernel/acpi.c16
-rw-r--r--arch/ia64/kernel/efi.c4
-rw-r--r--arch/ia64/kernel/entry.S4
-rw-r--r--arch/ia64/kernel/fw-emu.c18
-rw-r--r--arch/ia64/kernel/gate.S4
-rw-r--r--arch/ia64/kernel/irq.c1291
-rw-r--r--arch/ia64/kernel/irq_default.c30
-rw-r--r--arch/ia64/kernel/irq_ia64.c247
-rw-r--r--arch/ia64/kernel/irq_internal.c63
-rw-r--r--arch/ia64/kernel/irq_lock.c4
-rw-r--r--arch/ia64/kernel/pci.c7
-rw-r--r--arch/ia64/kernel/perfmon.c117
-rw-r--r--arch/ia64/kernel/process.c20
-rw-r--r--arch/ia64/kernel/semaphore.c5
-rw-r--r--arch/ia64/kernel/setup.c2
-rw-r--r--arch/ia64/kernel/time.c32
-rw-r--r--arch/ia64/kernel/traps.c2
-rw-r--r--arch/ia64/lib/copy_page.S26
-rw-r--r--arch/ia64/lib/copy_user.S31
-rw-r--r--arch/ia64/lib/strncpy_from_user.S30
-rw-r--r--arch/ia64/mm/init.c4
-rw-r--r--arch/ia64/mm/tlb.c4
-rw-r--r--arch/mips/config.in4
-rw-r--r--arch/mips/defconfig6
-rw-r--r--arch/mips/defconfig-decstation8
-rw-r--r--arch/mips/defconfig-ip226
-rw-r--r--arch/mips/kernel/sysirix.c95
-rw-r--r--arch/mips64/config.in3
-rw-r--r--arch/mips64/defconfig8
-rw-r--r--arch/mips64/defconfig-ip278
-rw-r--r--arch/mips64/kernel/mips64_ksyms.c6
-rw-r--r--arch/ppc/boot/Makefile1
-rw-r--r--arch/ppc/chrpboot/Makefile1
-rw-r--r--arch/ppc/coffboot/Makefile4
-rw-r--r--arch/ppc/configs/common_defconfig81
-rw-r--r--arch/ppc/defconfig81
-rw-r--r--arch/ppc/kernel/chrp_time.c2
-rw-r--r--arch/ppc/kernel/irq.c2
-rw-r--r--arch/ppc/kernel/open_pic.c4
-rw-r--r--arch/ppc/kernel/prom.c3
-rw-r--r--arch/ppc/mbxboot/Makefile2
-rw-r--r--arch/ppc/treeboot/Makefile5
-rw-r--r--arch/ppc/xmon/xmon.c42
-rw-r--r--arch/sh/config.in2
-rw-r--r--arch/sh/defconfig4
-rw-r--r--arch/sparc/defconfig5
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c8
-rw-r--r--arch/sparc/kernel/sys_sunos.c2
-rw-r--r--arch/sparc/lib/Makefile6
-rw-r--r--arch/sparc/lib/irqlock.S122
-rw-r--r--arch/sparc/mm/init.c8
-rw-r--r--arch/sparc64/Makefile18
-rw-r--r--arch/sparc64/defconfig5
-rw-r--r--arch/sparc64/kernel/pci_iommu.c183
-rw-r--r--arch/sparc64/kernel/pci_psycho.c22
-rw-r--r--arch/sparc64/kernel/pci_sabre.c24
-rw-r--r--arch/sparc64/kernel/sbus.c205
-rw-r--r--arch/sparc64/kernel/smp.c1
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c2
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c2
-rw-r--r--arch/sparc64/mm/init.c4
-rw-r--r--arch/sparc64/solaris/fs.c20
-rw-r--r--drivers/block/DAC960.c5
-rw-r--r--drivers/block/Makefile4
-rw-r--r--drivers/block/aec6210.c4
-rw-r--r--drivers/block/cmd64x.c209
-rw-r--r--drivers/block/hpt34x.c5
-rw-r--r--drivers/block/hpt366.c21
-rw-r--r--drivers/block/ide-disk.c5
-rw-r--r--drivers/block/ide-geometry.c41
-rw-r--r--drivers/block/ide-pnp.c158
-rw-r--r--drivers/block/ide-probe.c15
-rw-r--r--drivers/block/ide-proc.c8
-rw-r--r--drivers/block/ide.c49
-rw-r--r--drivers/block/ide_modes.h4
-rw-r--r--drivers/block/ll_rw_blk.c13
-rw-r--r--drivers/block/nbd.c55
-rw-r--r--drivers/block/pdc202xx.c3
-rw-r--r--drivers/block/rd.c107
-rw-r--r--drivers/block/via82cxxx.c261
-rw-r--r--drivers/char/Config.in8
-rw-r--r--drivers/char/README.epca7
-rw-r--r--drivers/char/bttv.c1
-rw-r--r--drivers/char/dsp56k.c6
-rw-r--r--drivers/char/epca.c3
-rw-r--r--drivers/char/mem.c2
-rw-r--r--drivers/char/radio-miropcm20.c2
-rw-r--r--drivers/char/raw.c24
-rw-r--r--drivers/net/3c509.c8
-rw-r--r--drivers/net/aironet4500.h28
-rw-r--r--drivers/net/aironet4500_card.c35
-rw-r--r--drivers/net/aironet4500_core.c146
-rw-r--r--drivers/net/aironet4500_proc.c59
-rw-r--r--drivers/net/aironet4500_rid.c46
-rw-r--r--drivers/net/arlan.c21
-rw-r--r--drivers/net/pcmcia/Config.in2
-rw-r--r--drivers/net/pcmcia/aironet4500_cs.c1
-rw-r--r--drivers/net/ppp_generic.c2
-rw-r--r--drivers/net/setup.c2
-rw-r--r--drivers/net/tokenring/Makefile2
-rw-r--r--drivers/net/tokenring/tms380tr.c1
-rw-r--r--drivers/net/tulip/tulip_core.c16
-rw-r--r--drivers/net/wan/Config.in8
-rw-r--r--drivers/net/wan/cosa.c8
-rw-r--r--drivers/net/wavelan.c125
-rw-r--r--drivers/parport/ChangeLog10
-rw-r--r--drivers/parport/parport_pc.c345
-rw-r--r--drivers/pci/pci.ids118
-rw-r--r--drivers/pcmcia/i82365.c6
-rw-r--r--drivers/pcmcia/yenta.c26
-rw-r--r--drivers/pnp/quirks.c21
-rw-r--r--drivers/scsi/3w-xxxx.c4
-rw-r--r--drivers/scsi/Config.in4
-rw-r--r--drivers/scsi/aic7xxx.c2
-rw-r--r--drivers/scsi/scsi_dma.c2
-rw-r--r--drivers/sound/Config.in45
-rw-r--r--drivers/sound/Makefile17
-rw-r--r--drivers/sound/aci.c718
-rw-r--r--drivers/sound/ad1816.c2
-rw-r--r--drivers/sound/ad1848.c55
-rw-r--r--drivers/sound/aedsp16.c (renamed from drivers/sound/lowlevel/aedsp16.c)75
-rw-r--r--drivers/sound/awe_hw.h (renamed from drivers/sound/lowlevel/awe_hw.h)0
-rw-r--r--drivers/sound/awe_wave.c (renamed from drivers/sound/lowlevel/awe_wave.c)577
-rw-r--r--drivers/sound/awe_wave.h (renamed from drivers/sound/lowlevel/awe_config.h)45
-rw-r--r--drivers/sound/dev_table.c1
-rw-r--r--drivers/sound/dev_table.h2
-rw-r--r--drivers/sound/lowlevel/Config.in66
-rw-r--r--drivers/sound/lowlevel/Makefile24
-rw-r--r--drivers/sound/lowlevel/README22
-rw-r--r--drivers/sound/lowlevel/aci.c679
-rw-r--r--drivers/sound/lowlevel/awe_compat.h257
-rw-r--r--drivers/sound/lowlevel/awe_version.h35
-rw-r--r--drivers/sound/lowlevel/lowlevel.h5
-rw-r--r--drivers/sound/lowlevel/soundlow.c67
-rw-r--r--drivers/sound/mad16.c2
-rw-r--r--drivers/sound/miroaci.h (renamed from drivers/sound/lowlevel/miroaci.h)7
-rw-r--r--drivers/sound/sb_card.c24
-rw-r--r--drivers/sound/sb_common.c3
-rw-r--r--drivers/sound/sscape.c1
-rw-r--r--drivers/sound/wavfront.c1
-rw-r--r--drivers/sound/wf_midi.c1
-rw-r--r--drivers/usb/Config.in8
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/acm.c4
-rw-r--r--drivers/usb/audio.c2
-rw-r--r--drivers/usb/cpia.c2
-rw-r--r--drivers/usb/dabusb.c11
-rw-r--r--drivers/usb/dabusb.h2
-rw-r--r--drivers/usb/dc2xx.c4
-rw-r--r--drivers/usb/devices.c2
-rw-r--r--drivers/usb/devio.c2
-rw-r--r--drivers/usb/drivers.c2
-rw-r--r--drivers/usb/hid.c7
-rw-r--r--drivers/usb/hub.c5
-rw-r--r--drivers/usb/ibmcam.c2
-rw-r--r--drivers/usb/inode.c43
-rw-r--r--drivers/usb/mousedev.c2
-rw-r--r--drivers/usb/ov511.c2
-rw-r--r--drivers/usb/pegasus.c3
-rw-r--r--drivers/usb/plusb.c3
-rw-r--r--drivers/usb/printer.c4
-rw-r--r--drivers/usb/rio500.c3
-rw-r--r--drivers/usb/scanner.h4
-rw-r--r--drivers/usb/serial/.cvsignore5
-rw-r--r--drivers/usb/serial/Makefile66
-rw-r--r--drivers/usb/serial/Makefile-keyspan_pda_fw16
-rw-r--r--drivers/usb/serial/ezusb_convert.pl48
-rw-r--r--drivers/usb/serial/ftdi_sio.h (renamed from drivers/usb/ftdi_sio.h)0
-rw-r--r--drivers/usb/serial/keyspan_pda_fw.h (renamed from drivers/usb/keyspan_pda_fw.h)0
-rw-r--r--drivers/usb/serial/usb-serial.c (renamed from drivers/usb/usb-serial.c)4
-rw-r--r--drivers/usb/serial/usb-serial.h (renamed from drivers/usb/usb-serial.h)0
-rw-r--r--drivers/usb/serial/whiteheat.h (renamed from drivers/usb/whiteheat.h)0
-rw-r--r--drivers/usb/uhci.c948
-rw-r--r--drivers/usb/uhci.h43
-rw-r--r--drivers/usb/usb-core.c3
-rw-r--r--drivers/usb/usb-debug.c3
-rw-r--r--drivers/usb/usb-ohci.c24
-rw-r--r--drivers/usb/usb-storage.c2
-rw-r--r--drivers/usb/usb-uhci.c12
-rw-r--r--drivers/usb/usb.c56
-rw-r--r--drivers/usb/usbkbd.c2
-rw-r--r--drivers/usb/usbmouse.c2
-rw-r--r--drivers/usb/uss720.c3
-rw-r--r--drivers/usb/wacom.c383
-rw-r--r--drivers/usb/wmforce.c2
-rw-r--r--drivers/video/Config.in2
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/amifb.c130
-rw-r--r--drivers/video/aty128fb.c14
-rw-r--r--drivers/video/atyfb.c32
-rw-r--r--drivers/video/fbcon.c101
-rw-r--r--drivers/video/fbmem.c75
-rw-r--r--drivers/video/fbmon.c3
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c3
-rw-r--r--drivers/video/matrox/matroxfb_maven.c5
-rw-r--r--drivers/video/matrox/matroxfb_maven.h3
-rw-r--r--drivers/video/offb.c9
-rw-r--r--drivers/video/vgacon.c80
-rw-r--r--fs/adfs/super.c52
-rw-r--r--fs/affs/namei.c5
-rw-r--r--fs/affs/super.c33
-rw-r--r--fs/autofs/init.c7
-rw-r--r--fs/autofs/inode.c39
-rw-r--r--fs/autofs/root.c2
-rw-r--r--fs/autofs4/init.c7
-rw-r--r--fs/autofs4/inode.c40
-rw-r--r--fs/autofs4/root.c2
-rw-r--r--fs/bfs/dir.c6
-rw-r--r--fs/bfs/file.c2
-rw-r--r--fs/bfs/inode.c39
-rw-r--r--fs/buffer.c48
-rw-r--r--fs/coda/dir.c2
-rw-r--r--fs/coda/inode.c46
-rw-r--r--fs/cramfs/inode.c30
-rw-r--r--fs/devfs/base.c35
-rw-r--r--fs/devpts/inode.c54
-rw-r--r--fs/efs/super.c40
-rw-r--r--fs/ext2/balloc.c3
-rw-r--r--fs/ext2/ialloc.c3
-rw-r--r--fs/ext2/super.c45
-rw-r--r--fs/fat/inode.c33
-rw-r--r--fs/filesystems.c9
-rw-r--r--fs/hfs/dir.c2
-rw-r--r--fs/hfs/super.c44
-rw-r--r--fs/hpfs/hpfs_fn.h2
-rw-r--r--fs/hpfs/namei.c2
-rw-r--r--fs/hpfs/super.c36
-rw-r--r--fs/inode.c1
-rw-r--r--fs/iobuf.c36
-rw-r--r--fs/isofs/inode.c40
-rw-r--r--fs/lockd/lockd_syms.c11
-rw-r--r--fs/lockd/svc.c1
-rw-r--r--fs/lockd/svcsubs.c37
-rw-r--r--fs/lockd/xdr.c37
-rw-r--r--fs/lockd/xdr4.c8
-rw-r--r--fs/minix/inode.c43
-rw-r--r--fs/minix/namei.c5
-rw-r--r--fs/msdos/msdosfs_syms.c7
-rw-r--r--fs/msdos/namei.c15
-rw-r--r--fs/namei.c147
-rw-r--r--fs/ncpfs/dir.c3
-rw-r--r--fs/ncpfs/inode.c37
-rw-r--r--fs/nfs/dir.c25
-rw-r--r--fs/nfs/inode.c43
-rw-r--r--fs/nfsd/export.c12
-rw-r--r--fs/nfsd/lockd.c17
-rw-r--r--fs/nfsd/nfs3proc.c182
-rw-r--r--fs/nfsd/nfs3xdr.c37
-rw-r--r--fs/nfsd/nfsctl.c66
-rw-r--r--fs/nfsd/nfsfh.c201
-rw-r--r--fs/nfsd/nfsproc.c148
-rw-r--r--fs/nfsd/nfsxdr.c65
-rw-r--r--fs/nfsd/vfs.c201
-rw-r--r--fs/ntfs/fs.c59
-rw-r--r--fs/open.c21
-rw-r--r--fs/openpromfs/inode.c36
-rw-r--r--fs/proc/array.c5
-rw-r--r--fs/proc/inode.c24
-rw-r--r--fs/proc/procfs_syms.c7
-rw-r--r--fs/qnx4/inode.c41
-rw-r--r--fs/qnx4/namei.c2
-rw-r--r--fs/romfs/inode.c32
-rw-r--r--fs/smbfs/dir.c2
-rw-r--r--fs/smbfs/inode.c35
-rw-r--r--fs/super.c489
-rw-r--r--fs/sysv/inode.c59
-rw-r--r--fs/sysv/namei.c5
-rw-r--r--fs/udf/namei.c3
-rw-r--r--fs/udf/super.c57
-rw-r--r--fs/ufs/super.c39
-rw-r--r--fs/umsdos/inode.c12
-rw-r--r--fs/umsdos/namei.c2
-rw-r--r--fs/umsdos/rdir.c2
-rw-r--r--fs/vfat/namei.c24
-rw-r--r--fs/vfat/vfatfs_syms.c7
-rw-r--r--include/asm-i386/ide.h4
-rw-r--r--include/asm-i386/system.h2
-rw-r--r--include/asm-ia64/atomic.h1
-rw-r--r--include/asm-ia64/efi.h2
-rw-r--r--include/asm-ia64/hardirq.h77
-rw-r--r--include/asm-ia64/hw_irq.h76
-rw-r--r--include/asm-ia64/ide.h4
-rw-r--r--include/asm-ia64/irq.h95
-rw-r--r--include/asm-ia64/keyboard.h4
-rw-r--r--include/asm-ia64/machvec.h2
-rw-r--r--include/asm-ia64/pal.h17
-rw-r--r--include/asm-ia64/pgtable.h1
-rw-r--r--include/asm-ia64/ptrace_offsets.h4
-rw-r--r--include/asm-ia64/smp.h4
-rw-r--r--include/asm-ia64/socket.h12
-rw-r--r--include/asm-ia64/softirq.h8
-rw-r--r--include/asm-mips/ide.h6
-rw-r--r--include/asm-mips64/dma.h10
-rw-r--r--include/asm-mips64/ide.h12
-rw-r--r--include/asm-ppc/prom.h3
-rw-r--r--include/asm-sparc/ide.h7
-rw-r--r--include/asm-sparc/system.h44
-rw-r--r--include/asm-sparc64/pbm.h13
-rw-r--r--include/linux/adfs_fs.h2
-rw-r--r--include/linux/brlock.h2
-rw-r--r--include/linux/dcache.h5
-rw-r--r--include/linux/efs_fs.h2
-rw-r--r--include/linux/ext2_fs.h2
-rw-r--r--include/linux/fb.h8
-rw-r--r--include/linux/fs.h114
-rw-r--r--include/linux/ide.h1
-rw-r--r--include/linux/if_ec.h21
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--include/linux/iobuf.h9
-rw-r--r--include/linux/irq.h5
-rw-r--r--include/linux/kmod.h2
-rw-r--r--include/linux/lockd/bind.h3
-rw-r--r--include/linux/lockd/lockd.h3
-rw-r--r--include/linux/lockd/xdr.h13
-rw-r--r--include/linux/lockd/xdr4.h7
-rw-r--r--include/linux/module.h2
-rw-r--r--include/linux/msdos_fs.h2
-rw-r--r--include/linux/msdos_fs_sb.h1
-rw-r--r--include/linux/nbd.h18
-rw-r--r--include/linux/nfsd/export.h2
-rw-r--r--include/linux/nfsd/nfsd.h70
-rw-r--r--include/linux/nfsd/nfsfh.h127
-rw-r--r--include/linux/nfsd/syscall.h17
-rw-r--r--include/linux/nfsd/xdr.h1
-rw-r--r--include/linux/pci_ids.h8
-rw-r--r--include/linux/shm.h2
-rw-r--r--include/linux/sysctl.h3
-rw-r--r--include/linux/usb.h (renamed from drivers/usb/usb.h)25
-rw-r--r--include/linux/videodev.h2
-rw-r--r--include/net/dn_raw.h19
-rw-r--r--include/net/tcp.h6
-rw-r--r--init/main.c2
-rw-r--r--ipc/shm.c1167
-rw-r--r--ipc/util.c3
-rw-r--r--kernel/acct.c12
-rw-r--r--kernel/exit.c12
-rw-r--r--kernel/fork.c4
-rw-r--r--kernel/ksyms.c19
-rw-r--r--kernel/module.c35
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/sys.c46
-rw-r--r--kernel/sysctl.c28
-rw-r--r--mm/filemap.c6
-rw-r--r--mm/memory.c176
-rw-r--r--mm/mmap.c6
-rw-r--r--net/Config.in8
-rw-r--r--net/appletalk/aarp.c742
-rw-r--r--net/appletalk/ddp.c1218
-rw-r--r--net/decnet/Config.in3
-rw-r--r--net/decnet/Makefile4
-rw-r--r--net/decnet/TODO6
-rw-r--r--net/decnet/af_decnet.c38
-rw-r--r--net/decnet/dn_nsp_in.c7
-rw-r--r--net/decnet/dn_nsp_out.c5
-rw-r--r--net/decnet/dn_raw.c367
-rw-r--r--net/decnet/dn_route.c5
-rw-r--r--net/decnet/sysctl_net_decnet.c6
-rw-r--r--net/econet/Makefile13
-rw-r--r--net/econet/af_econet.c (renamed from net/econet/econet.c)278
-rw-r--r--net/econet/sysctl_net_ec.c43
-rw-r--r--net/ipv4/tcp.c39
-rw-r--r--net/ipv4/tcp_ipv4.c21
-rw-r--r--net/ipv6/tcp_ipv6.c21
-rw-r--r--net/netsyms.c4
-rw-r--r--net/sysctl_net.c7
394 files changed, 9929 insertions, 9090 deletions
diff --git a/CREDITS b/CREDITS
index af4d44bab..4e1d57242 100644
--- a/CREDITS
+++ b/CREDITS
@@ -258,6 +258,11 @@ P: 1024/77D50909 76 99 FD 31 91 E1 96 1C 90 BB 22 80 62 F6 BD 63
D: Author and maintainer of the QIC-02 tape driver
S: The Netherlands
+N: Tomas Berndtsson
+E: tomas@nocrew.org
+W: http://tomas.nocrew.org/
+D: dsp56k device driver
+
N: Ross Biro
E: bir7@leland.Stanford.Edu
D: Original author of the Linux networking code
@@ -350,6 +355,14 @@ S: 19. Wellington Road
S: Lancaster, LA1 4DN
S: UK, England
+N: Lars Brinkhoff
+E: lars@nocrew.org
+W: http://lars.nocrew.org/
+D: dsp56k device driver
+S: Kopmansg 2
+S: 411 13 Goteborg
+S: Sweden
+
N: Andries Brouwer
E: aeb@cwi.nl
D: random Linux hacker
@@ -940,6 +953,13 @@ S: Frankenstraße 33
S: 34131 Kassel
S: Germany
+N: Christoph Hellwig
+E: chhellwig@gmx.net
+D: Sound/OSS hacking
+S: Triftstraße 26
+S: 38644 Goslar
+S: Germany
+
N: Richard Henderson
E: rth@twiddle.net
E: rth@cygnus.com
@@ -1683,6 +1703,13 @@ S: 35706 Runckel Lane
S: Fremont, California 94536
S: USA
+N: Sam Mosel
+E: sam.mosel@computer.org
+D: Wacom Intuos USB Support
+S: 22 Seaview St
+S: Fullarton 5063
+S: South Australia
+
N: Ian A. Murdock
E: imurdock@gnu.ai.mit.edu
D: Creator of Debian distribution
@@ -1754,6 +1781,11 @@ S: 2364 Old Trail Drive
S: Reston, Virginia 20191
S: USA
+N: Fredrik Noring
+E: noring@nocrew.org
+W: http://www.lysator.liu.se/~noring/
+D: dsp56k device driver
+
N: Michael O'Reilly
E: michael@iinet.com.au
E: oreillym@tartarus.uwa.edu.au
diff --git a/Documentation/Changes b/Documentation/Changes
index ea01182b0..9be04dcd6 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -72,6 +72,10 @@ Upgrade notes
General Information
===================
+ To use System V shared memory, you have to mount the shm filesystem
+somewhere and put the mountpoint into /proc/sys/kernel/shmpath.
+Default is /var/shm.
+
<CTRL><ALT><DEL> now performs a cold reboot instead of a warm reboot
for increased hardware compatibility. If you want a warm reboot and
know it works on your hardware, add a "reboot=warm" command line option
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index dc7103e36..cee6bef35 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -648,7 +648,7 @@ CONFIG_IDEDMA_PCI_WIP
It is SAFEST to say N to this question.
-3ware Hardware ATA-RAID support (EXPERIMENTAL)
+3ware Hardware ATA-RAID support
CONFIG_BLK_DEV_3W_XXXX_RAID
3ware is the only hardware ATA-Raid product in Linux to date.
This card is 2,4, or 8 channel master mode support only.
@@ -745,9 +745,13 @@ CONFIG_BLK_DEV_HPT366
This is an Ultra DMA chipset for ATA-66.
This driver adds up to 4 more EIDE devices sharing a single
- interrupt. The HPT366 chipset in its current form is a non-bootable.
- This driver requires dynamic tuning of the chipset during the
- ide-probe at boot. It is reported to support DVD II drives, by the
+ interrupt. The HPT366 chipset in its current form is a non-bootable,
+ without special LILO commands for redirecting the reference to device 0x80.
+ The other solution is to include "CONFIG_BLK_DEV_OFFBOARD" unless your
+ mainboard has the chipset native mounted. Regardless one should use the
+ fore mentioned option and call at LILO or include in your append-line:
+ "ide=reverse". This driver requires dynamic tuning of the chipset during
+ the ide-probe at boot. It is reported to support DVD II drives, by the
manufacturer.
Please read the comments at the top of drivers/block/hpt366.c
@@ -2353,6 +2357,11 @@ CONFIG_FB_AMIGA
This is the frame buffer device driver for the builtin graphics
chipset found in Amigas.
+ The driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want). The
+ module will be called amifb.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
Amiga OCS chipset support
CONFIG_FB_AMIGA_OCS
This enables support for the original Agnus and Denise video chips,
@@ -3480,15 +3489,13 @@ CONFIG_DECNET_ROUTER
Add support for turning your DECnet Endnode into a level 1 or 2
router. This is an unfinished option for developers only. If you do
turn it on, then make sure that you also say Y to "Kernel/User
- network link driver" and "Routing messages", since rtnetlink is the
- only current method of configuration.
+ network link driver", "Routing messages" and "Network packet
+ filtering". The first two are required to allow configuration via
+ rtnetlink (currently you need Alexey Kuznetsov's iproute2 package
+ from ftp.inr.ac.ru). The "Network packet filtering" option will
+ be required for the forthcoming routing daemon to work.
-DECnet Raw Socket Support
-CONFIG_DECNET_RAW
- Add support for the SOCK_RAW type under DECnet. Used by userland
- routing programs to receive routing messages from the kernel and
- also as a general debugging aid to see what's going on "under the
- hood".
+ See Documentation/networking/decnet.txt for more information.
AppleTalk DDP
CONFIG_ATALK
@@ -11144,10 +11151,8 @@ CONFIG_MICROCODE
Intel processors in P6 family, e.g. Pentium Pro, Pentium II,
Pentium III, Xeon etc. You will obviously need the actual microcode
binary data itself which is not shipped with the Linux kernel.
- With this support compiled you can use dd(1) to write microcode,
- for example:
-
- # dd if=/etc/microcode of=/dev/cpu/microcode bs=98304 count=1
+ You also need to say Y to "/dev file system support" in 'File systems'
+ section of the kernel configuration menu.
You need to be superuser to do that. For latest news and information
on obtaining all the required ingredients for this driver, check:
@@ -11439,11 +11444,15 @@ CONFIG_SOUND_SGALAXY
This module initializes the older non Plug and Play sound galaxy
cards from Aztech. It supports the Waverider Pro 32 - 3D and the
Galaxy Washington 16.
+ If you compile the driver into the kernel, you have to add
+ "sgalaxy=<io>,<irq>,<dma>,<dma2>,<sgbase>" to the kernel command line.
Support for AD1816(A) based cards (EXPERIMENTAL)
CONFIG_SOUND_AD1816
Say M here if you have a sound card based on the Analog Devices
AD1816(A) chip.
+ If you compile the driver into the kernel, you have to add
+ "ad1816=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
NOTE: This driver is still EXPERIMENTAL.
See Documentation/sound/AD1816 for further information.
@@ -11453,6 +11462,9 @@ CONFIG_SOUND_OPL3SA1
Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
usually built into motherboards. Read Documentation/sound/OPL3-SA
for details.
+ If you compile the driver into the kernel, you have to add
+ "opl3sa=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
+ command line.
ProAudioSpectrum 16 support
CONFIG_SOUND_PAS
@@ -11460,6 +11472,9 @@ CONFIG_SOUND_PAS
16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
some other card made by Media Vision or Logitech since they are not
PAS16 compatible.
+ If you compile the driver into the kernel, you have to add
+ "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
+ to the kernel command line.
100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
CONFIG_SOUND_SB
@@ -11477,6 +11492,8 @@ CONFIG_SOUND_SB
Y here and also to "Additional lowlevel drivers" and to "SB32/AWE
support" below and read Documentation/sound/INSTALL.awe. If you have
an IBM Mwave card, say Y here and read Documentation/sound/mwave.
+ If you compile the driver into the kernel and don't want to use isapnp,
+ you have to add "sb=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
You can say M here to compile this driver as a module; the module is
called sb.o.
@@ -11492,6 +11509,8 @@ CONFIG_SOUND_GUS
Say Y here for any type of Gravis Ultrasound card, including
the GUS or GUS MAX. See also Documentation/sound/ultrasound for
more information on configuring this card with modules.
+ If you compile the driver into the kernel, you have to add
+ "gus=<io>,<irq>,<dma>,<dma2>" to the kernel command line.
MPU-401 support (NOT for SB16)
CONFIG_SOUND_MPU401
@@ -11503,12 +11522,16 @@ CONFIG_SOUND_MPU401
was in the list of supported cards, look at the card specific
instructions in the drivers/sound/Readme.cards file. It's safe to
answer Y if you have a true MPU401 MIDI interface card.
+ If you compile the driver into the kernel, you have to add
+ "mpu401=<io>,<irq>" to the kernel command line.
6850 UART support
CONFIG_SOUND_UART6850
This option enables support for MIDI interfaces based on the 6850
UART chip. This interface is rarely found on sound cards. It's safe
to answer N to this question.
+ If you compile the driver into the kernel, you have to add
+ "uart6850=<io>,<irq>" to the kernel command line.
VIDC Sound
CONFIG_VIDC_SOUND
@@ -11522,6 +11545,9 @@ CONFIG_SOUND_PSS
ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on
how to compile it into the kernel or as a module see the file
Documentation/sound/PSS.
+ If you compile the driver into the kernel, you have to add
+ "pss=<io>,<mssio>,<mssirq>,<mssdma>,<mpuio>,<mpuirq>" to the kernel
+ command line.
Enable PSS mixer (Beethoven ADSP-16 and other compatible)
CONFIG_PSS_MIXER
@@ -11580,6 +11606,8 @@ CONFIG_SOUND_MSS
specific instructions in drivers/sound/Readme.cards. Some drivers
have their own MSS support and saying Y to this option will cause a
conflict.
+ If you compile the driver into the kernel, you have to add
+ "ad1848=<io>,<irq>,<dma>,<dma2>[,<type>]" to the kernel command line.
SGI Visual Workstation on-board audio
CONFIG_SOUND_VWSND
@@ -11592,11 +11620,16 @@ CONFIG_SOUND_SSCAPE
Answer Y if you have a sound card based on the Ensoniq SoundScape
chipset. Such cards are being manufactured at least by Ensoniq, Spea
and Reveal (Reveal makes also other cards).
+ If you compile the driver into the kernel, you have to add
+ "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command line.
MediaTriX AudioTriX Pro support
CONFIG_SOUND_TRIX
Answer Y if you have the AudioTriX Pro sound card manufactured
by MediaTrix.
+ If you compile the driver into the kernel, you have to add
+ "trix=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<mpuio>,<mpuirq>"
+ to the kernel command line.
Have TRXPRO.HEX firmware file
CONFIG_TRIX_HAVE_BOOT
@@ -11621,6 +11654,9 @@ CONFIG_SOUND_MAD16
and Diamond (latest ones). Note however that the Tropez sound cards
have their own driver; if you have one of those, say N here and Y or
M to "Full support for Turtle Beach WaveFront", below.
+ If you compile the driver into the kernel, you have to add
+ "mad16=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the
+ kernel command line.
See also Documentation/sound/Opti and Documentation/sound/MAD16 for
more information on setting these cards up as modules.
@@ -11640,7 +11676,10 @@ CONFIG_MAD16_OLDCARD
Support for Crystal CS4232 based (PnP) cards
CONFIG_SOUND_CS4232
Say Y here if you have a card based on the Crystal CS4232 chip set,
- which uses its own Plug and Play protocol.
+ which uses its own Plug and Play protocol.
+ If you compile the driver into the kernel, you have to add
+ "cs4232=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
+ command line.
See Documentation/sound/CS4232 for more information on configuring
this card.
@@ -11650,11 +11689,16 @@ CONFIG_SOUND_OPL3SA2
Say Y or M if you have a card based on one of these Yamaha
sound chipsets. Read Documentation/sound/OPL3-SA2 for more
information on configuring these cards.
+ If you compile the driver into the kernel, you have to add
+ "opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>" to the kernel
+ command line.
Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
CONFIG_SOUND_MAUI
Say Y here if you have a Turtle Beach Wave Front, Maui, or Tropez
sound card.
+ If you compile the driver into the kernel, you have to add
+ "maui=<io>,<irq>" to the kernel command line.
Have OSWF.MOT firmware file
CONFIG_MAUI_HAVE_BOOT
@@ -11742,18 +11786,6 @@ CONFIG_MSND_FIFOSIZE
and Pinnacle). Larger values reduce the chance of data overruns at
the expense of overall latency. If unsure, use the default.
-/dev/dsp and /dev/audio support
-CONFIG_SOUND_AUDIO
- If you say Y here, you will get the /dev/dsp and /dev/audio devices;
- these are the analog-digital and digital-analog converter devices
- and are very useful, so say Y.
-
-MIDI interface support
-CONFIG_SOUND_MIDI
- Answering N disables /dev/midixx devices and access to any MIDI
- ports using /dev/sequencer and /dev/music. This option also affects
- any MPU401 and/or General MIDI compatible devices. Answer Y.
-
FM synthesizer (YM3812/OPL-3) support
CONFIG_SOUND_YM3812
Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
@@ -11763,6 +11795,8 @@ CONFIG_SOUND_YM3812
cards, however).
Please read the file Documentation/sound/OPL3 if your card has an
OPL3 chip.
+ If you compile the driver into the kernel, you have to add
+ "opl3=<io>" to the kernel command line.
If unsure, say Y.
@@ -11771,15 +11805,8 @@ CONFIG_SUN_AUDIO
This is support for the sound cards on Sun workstations. The code
does not exist yet, so you might as well say N here.
-Additional low level drivers
-CONFIG_LOWLEVEL_SOUND
- If you need additional low level sound drivers which have not yet
- appeared, say Y. The answer to this question does not directly
- affect the kernel; saying Y will simply cause this configure script
- to present you with more options. If unsure, say Y.
-
ACI mixer (miroPCM12/PCM20)
-CONFIG_ACI_MIXER
+CONFIG_SOUND_ACI_MIXER
ACI (Audio Command Interface) is a protocol used to communicate with
the microcontroller on some sound cards produced by miro, e.g. the
miroSOUND PCM12 and PCM20. The main function of the ACI is to
@@ -11791,7 +11818,7 @@ CONFIG_ACI_MIXER
radio-miropcm20 driver.
SB32/AWE support
-CONFIG_AWE32_SYNTH
+CONFIG_SOUND_AWE32_SYNTH
Say Y here if you have a Sound Blaster SB32, AWE32-PnP, SB AWE64 or
similar sound card. See Documentation/sound/README.awe,
Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO,
@@ -11799,7 +11826,7 @@ CONFIG_AWE32_SYNTH
info.
Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
-CONFIG_AEDSP16
+CONFIG_SOUND_AEDSP16
Answer Y if you have a Gallant's Audio Excel DSP 16 card. This
driver supports Audio Excel DSP 16 but not the III nor PnP versions
of this card.
@@ -11817,30 +11844,15 @@ CONFIG_AEDSP16
Documentation/sound/AudioExcelDSP16 to get more information about
this driver and its configuration.
-I/O base for Audio Excel DSP 16
-CONFIG_AEDSP16_BASE
- This is the base I/O address of the Audio Excel DSP 16 card. It must
- be 220 or 240. If you compiled aedsp16.o as a module you can specify
- this parameter as 'io=0xNNN'.
-
Audio Excel DSP 16 (SBPro emulation)
CONFIG_AEDSP16_SBPRO
Answer Y if you want your audio card to emulate Sound Blaster Pro.
You should then say Y to "100% Sound Blaster compatibles
(SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
emulation)".
-
-Audio Excel DSP 16 IRQ
-CONFIG_AEDSP16_SB_IRQ
- This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9,
- 10 or 11. If you compiled aedsp16.o as a module you can specify
- this parameter as 'irq=NN'.
-
-Audio Excel DSP 16 DMA
-CONFIG_AEDSP16_SB_DMA
- This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or
- 3. If you compiled aedsp16.o as a module you can specify this
- parameter as 'dma=NN'.
+ If you compile the driver into the kernel, you have to add
+ "aedsp16=<io>,<irq>,<dma>,<mssio>,<mpuio>,<mouirq>" to the kernel
+ command line.
Audio Excel DSP 16 (MSS emulation)
CONFIG_AEDSP16_MSS
@@ -11848,18 +11860,6 @@ CONFIG_AEDSP16_MSS
System. You should then say Y to "Microsoft Sound System support"
and say N to "Audio Excel DSP 16 (SBPro emulation)".
-Audio Excel DSP 16 IRQ
-CONFIG_AEDSP16_MSS_IRQ
- This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9,
- 10 or 11. If you compiled aedsp16.o as a module you can specify
- this parameter as 'irq=NN'.
-
-Audio Excel DSP 16 DMA
-CONFIG_AEDSP16_MSS_DMA
- This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1
- or 3. If you compiled aedsp16.o as a module you can specify this
- parameter as 'dma=NN'.
-
SC-6600 based audio cards (new Audio Excel DSP 16)
CONFIG_SC6600
The SC6600 is the new version of DSP mounted on the Audio Excel DSP
@@ -11887,13 +11887,6 @@ CONFIG_AEDSP16_MPU401
driver as a module you have to specify the MPU I/O base address with
the parameter 'mpu_base=0xNNN'.
-MPU401 IRQ for Audio Excel DSP 16
-CONFIG_AEDSP16_MPU_IRQ
- This is the IRQ of the MPU-401 emulation of your Audio Excel DSP 16
- card. It must be 5, 7, 9, 10 or 0 (to disable MPU-401 interface). If
- you compiled aedsp16.o as a module you can specify this parameter as
- 'mpu_irq=NN'.
-
Ensoniq ES1370 based PCI sound cards
CONFIG_SOUND_ES1370
Say Y or M if you have a PCI sound card utilizing the Ensoniq
diff --git a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt
index 2ceceecb6..e09832dca 100644
--- a/Documentation/networking/decnet.txt
+++ b/Documentation/networking/decnet.txt
@@ -30,10 +30,10 @@ Be sure to turn on the following options:
if you want to try out router support (not properly debugged yet)
you'll need the following options as well...
- CONFIG_DECNET_RAW (to receive routing packets)
CONFIG_DECNET_ROUTER (to be able to add/delete routes)
CONFIG_NETLINK (to allow rtnetlink)
CONFIG_RTNETLINK (for communication with the kernel routing layer)
+ CONFIG_NETFILTER (will be required for the DECnet routing daemon)
3) Command line options
@@ -93,7 +93,13 @@ a reduced functionality.
If you want to configure a DECnet router you'll need the iproute2 package
since its the _only_ way to add and delete routes currently. Eventually
there will be a routing daemon to send and receive routing messages for
-each interface and update the kernel routing tables accordingly.
+each interface and update the kernel routing tables accordingly. The
+routing daemon will use netfilter to listen to routing packets, and
+rtnetlink to update the kernels routing tables.
+
+The DECnet raw socket layer has been removed since it was there purely
+for use by the routing daemon which will now use netfilter (a much cleaner
+and more generic solution) instead.
5) How can I tell if its working ?
diff --git a/Documentation/sound/Introduction b/Documentation/sound/Introduction
index 2ab4867d9..f2ce25d67 100644
--- a/Documentation/sound/Introduction
+++ b/Documentation/sound/Introduction
@@ -160,8 +160,6 @@ Sound Status:
=============
The status of sound may be read/checked by:
- cat /proc/sound
- cat /dev/sndstat
cat (anyfile).au >/dev/audio
The status of the modules and which modules depend on
diff --git a/Documentation/sound/Maestro b/Documentation/sound/Maestro
index f3cc4ab77..8d0fd215d 100644
--- a/Documentation/sound/Maestro
+++ b/Documentation/sound/Maestro
@@ -30,8 +30,7 @@ Driver OSS Behavior
--------------------
This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec. This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
+mostly adhere to the OSS spec.
The /dev/dsp device exported behaves almost as expected. Playback is
supported in all the various lovely formats. 8/16bit stereo/mono from
diff --git a/Documentation/sound/OPL3-SA b/Documentation/sound/OPL3-SA
index 5e8f2f41c..0d91c8bf3 100644
--- a/Documentation/sound/OPL3-SA
+++ b/Documentation/sound/OPL3-SA
@@ -48,33 +48,5 @@ kernel.
If you chose to build it as a module, just insmod the resulting softoss2.o
-A 'cat /dev/sndstat' with all the above options should look similar to this:
-
- OSS/Free:3.8s2++-971130
- Load type: Driver loaded as a module
- Kernel: Linux iniquity 2.1.105 #145 Mon Jun 8 11:40:47 MST 1998 i586
- Config options: 0
-
- Installed drivers:
-
- Card config:
-
- Audio devices:
- 0: MSS audio codec (CS4231) (DUPLEX)
-
- Synth devices:
- 0: Yamaha OPL-3
- 1: SoftOSS
-
- Midi devices:
- 0: OPL3-SA (MPU401)
-
- Timers:
- 0: System clock
- 1: MSS audio codec (CS4231)
-
- Mixers:
- 0: MSS audio codec (CS4231)
-
Questions? Comments?
<stiker@northlink.com>
diff --git a/Documentation/sound/Opti b/Documentation/sound/Opti
index 07318d243..92f123313 100644
--- a/Documentation/sound/Opti
+++ b/Documentation/sound/Opti
@@ -99,9 +99,7 @@ alias synth0 opl3
When any sound device is opened the kernel requests auto-loading
of char-major-14. There is a built-in alias that translates this
-request to loading the main sound module. The main sound module
-contains only common code which is needed by all the sound drivers,
-and the driver for /dev/sndstat.
+request to loading the main sound module.
The sound module in its turn will request loading of a sub-driver
for mixer, audio, midi or synthesizer device. The first 3 are
diff --git a/Documentation/sound/README.OSS b/Documentation/sound/README.OSS
index 379dd3bd5..f594802e5 100644
--- a/Documentation/sound/README.OSS
+++ b/Documentation/sound/README.OSS
@@ -147,24 +147,9 @@ If you get an error message when trying to use the driver, please look
at /var/adm/messages for more verbose error message.
-In general the easiest way to diagnose problems is to do "cat /dev/sndstat".
-
-If you get an error message, there are some problems with the driver setup:
-
- - "No such file or directory" tells that the device files for
- the sound driver are missing. Use the script at the end of
- linux/drivers/sound/Readme.linux to create them.
-
- - "No such device" tells that the sound driver is not in the kernel.
- You have to reconfigure and recompile the kernel to have the sound
- driver. Compiling the driver doesn't help alone. You have to boot
- with the newly compiled one before the driver becomes active.
- The Linux-HOWTO should help in this step.
-
The following errors are likely with /dev/dsp and /dev/audio.
- - "No such device or address". This error message should not happen
- with /dev/sndstat but it's possible with the other sound devices.
+ - "No such device or address".
This error indicates that there are no suitable hardware for the
device file or the sound driver has been compiled without support for
this particular device. For example /dev/audio and /dev/dsp will not
@@ -180,10 +165,6 @@ The following errors are likely with /dev/dsp and /dev/audio.
with impossible parameters. Check that the application is
for sound driver version 2.X or later.
-In general the printout of /dev/sndstat should tell what is the problem.
-It's possible that there are bugs in the sound driver but 99% of the problems
-reported to me are caused by somehow incorrect setup during "make config".
-
Linux installation
==================
@@ -226,17 +207,6 @@ Readme of sound driver version 3.0.1 if you still want to use this method.
Problems
--------
-If you have any kind of problems, there is a debugging feature which
-could help you to solve the problem. To use it, just execute the
-command:
-
- cat /dev/sndstat
-
-and look at the output. It should display some useful info about the
-driver configuration. If there is no /dev/sndstat
-(/dev/sndstat: No such file or directory), ensure that you have executed the
-soundinstall script (at the end of this file).
-
Common error messages:
- /dev/???????: No such file or directory.
@@ -757,10 +727,6 @@ the kernel following instructions in the kernel README.
The sound driver configuration dialog
-------------------------------------
-If you already have the sound driver installed, consult a printout of
-"cat /dev/sndstat" when configuring the driver again. It gives the I/O,
-IRQ and DMA settings you used earlier.
-
Sound configuration starts by making some yes/no questions. Be careful
when answering to these questions since answering y to a question may
prevent some later ones from being asked. For example don't answer y to
@@ -1417,8 +1383,7 @@ Cards not supported yet
Please check the version of sound driver you are using before
complaining that your card is not supported. It's possible you are
using a driver version which was released months before your card was
-introduced. The driver's release date is listed after its version number in a
-"cat /dev/sndstat" printout and in the file linux/drivers/sound/soundvers.h.
+introduced.
First of all, there is an easy way to make most sound cards work with Linux.
Just use the DOS based driver to initialize the card to a known state, then use
diff --git a/Documentation/sound/Wavefront b/Documentation/sound/Wavefront
index f1dcf975f..5453af77f 100644
--- a/Documentation/sound/Wavefront
+++ b/Documentation/sound/Wavefront
@@ -293,36 +293,6 @@ warm reboots since the last firmware load).
The "available DRAM" line will vary depending on how much added RAM
your card has. Mine has 8MB.
-Next, check /dev/sndstat, which on my machine says:
----------------------------------------------------------------------
-OSS/Free:3.8s2++-971130
-Load type: Driver loaded as a module
-Kernel: Linux bd 2.1.106 #12 SMP Fri Jul 3 00:37:34 EDT 1998 i486
-Config options: 0
-
-Installed drivers:
-
-Card config:
-
-Audio devices:
-0: Crystal audio controller (CS4232) (DUPLEX)
-
-Synth devices:
-0: Turtle Beach WaveFront
-1: Yamaha OPL-3
-
-Midi devices:
-0: WaveFront Internal MIDI
-1: WaveFront External MIDI
-
-Timers:
-0: System clock
-1: Crystal audio controller (CS4232)
-
-Mixers:
-0: Crystal audio controller (CS4232)
------------------------------------------------------------
-
To check basically functionality, use play(1) or splay(1) to send a
.WAV or other audio file through the audio portion. Then use playmidi
to play a General MIDI file. Try the "-D 0" to hear the
diff --git a/Documentation/sound/via82cxxx.txt b/Documentation/sound/via82cxxx.txt
index 62877fd79..5bb587950 100644
--- a/Documentation/sound/via82cxxx.txt
+++ b/Documentation/sound/via82cxxx.txt
@@ -122,25 +122,7 @@ Native MIDI driver, as described above
Known bugs (patches/suggestions welcome)
------------------------------------------------------------------------
1) Two MIDI devices are loaded by the sound driver. Eliminate one of them.
-Sample /proc/sound output:
-
- Midi devices:
- 0: Sound Blaster
- 1: VIA 82Cxxx Audio driver 1.1.2
2) Two mixer devices are loaded by the sound driver. Eliminate one of
them. At least one bug report says that SB mixer does not work at all,
-only AC97 mixer. Sample /proc/sound output:
-
- Mixers:
- 0: via82cxxxAC97Mixer
- 1: Sound Blaster
-
-3) After unloading the driver, a SoundBlaster MIDI device is still
-listed in /proc/sound. Investigate what is not being unloaded,
-and fix it. Sample /proc/sound output, after 'rmmod via82cxxx':
-
- Midi devices:
- 0: Sound Blaster
-
-
+only AC97 mixer.
diff --git a/Makefile b/Makefile
index 3e88d8096..f7787297d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 3
-SUBLEVEL = 50
+SUBLEVEL = 51
EXTRAVERSION =
ARCH = mips
@@ -136,6 +136,10 @@ ifdef CONFIG_NET_FC
DRIVERS := $(DRIVERS) drivers/net/fc/fc.a
endif
+ifdef CONFIG_ATALK
+DRIVERS := $(DRIVERS) drivers/net/appletalk/appletalk.a
+endif
+
ifdef CONFIG_TR
DRIVERS := $(DRIVERS) drivers/net/tokenring/tr.a
endif
diff --git a/arch/alpha/config.in b/arch/alpha/config.in
index 1686fefbc..6e760c917 100644
--- a/arch/alpha/config.in
+++ b/arch/alpha/config.in
@@ -270,7 +270,7 @@ source drivers/char/Config.in
source drivers/usb/Config.in
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
source fs/Config.in
diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig
index 9365dc4e2..cc244e560 100644
--- a/arch/alpha/defconfig
+++ b/arch/alpha/defconfig
@@ -324,10 +324,6 @@ CONFIG_PSMOUSE=y
# CONFIG_USB is not set
#
-# Misc devices
-#
-
-#
# Filesystems
#
# CONFIG_QUOTA is not set
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 6a2ff8a9b..091edaf37 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -303,18 +303,9 @@ static int linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf
static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz)
{
struct statfs linux_stat;
- struct inode * inode = dentry->d_inode;
- struct super_block * sb = inode->i_sb;
- int error;
-
- error = -ENODEV;
- if (sb && sb->s_op && sb->s_op->statfs) {
- set_fs(KERNEL_DS);
- error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat));
- set_fs(USER_DS);
- if (!error)
- error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
- }
+ int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat);
+ if (!error)
+ error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
return error;
}
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index bb0a34f92..6b4033705 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -12,7 +12,6 @@
#
# Copyright (C) 1995-1999 by Russell King
-LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
CPP := $(CC) -E
PERL := perl
diff --git a/arch/arm/config.in b/arch/arm/config.in
index 5e9cc8bfc..4c7a5fe19 100644
--- a/arch/arm/config.in
+++ b/arch/arm/config.in
@@ -214,7 +214,7 @@ fi
source drivers/usb/Config.in
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
if [ "$CONFIG_VT" = "y" ]; then
mainmenu_option next_comment
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 11a98fc58..e1ba021e1 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -50,9 +50,7 @@ if [ "$CONFIG_MK7" = "y" ]; then
define_bool CONFIG_X86_PGE y
fi
-if [ "$CONFIG_DEVFS_FS" = "y" ]; then
- tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
-fi
+tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
choice 'High Memory Support' \
"off CONFIG_NOHIGHMEM \
@@ -142,7 +140,7 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
bool 'Power Management support' CONFIG_PM
-dep_bool ' ACPI support' CONFIG_ACPI $CONFIG_PM
+dep_tristate ' ACPI support' CONFIG_ACPI $CONFIG_PM
if [ "$CONFIG_ACPI" != "n" ]; then
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' Enter S1 for sleep (EXPERIMENTAL)' CONFIG_ACPI_S1_SLEEP
@@ -231,7 +229,7 @@ source drivers/char/Config.in
source drivers/usb/Config.in
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
source fs/Config.in
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index aa04c3685..813a2ecea 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -27,6 +27,7 @@ CONFIG_X86_POPAD_OK=y
CONFIG_X86_TSC=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_PGE=y
+# CONFIG_MICROCODE is not set
CONFIG_NOHIGHMEM=y
# CONFIG_HIGHMEM4G is not set
# CONFIG_HIGHMEM64G is not set
@@ -165,6 +166,7 @@ CONFIG_SKB_LARGE=y
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
#
# Telephony Support
@@ -197,6 +199,7 @@ CONFIG_SCSI_CONSTANTS=y
#
# SCSI low-level drivers
#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -334,7 +337,6 @@ CONFIG_PCMCIA_PCNET=y
# CONFIG_PCMCIA_NMCLAN is not set
# CONFIG_PCMCIA_SMC91C92 is not set
# CONFIG_PCMCIA_XIRC2PS is not set
-# CONFIG_AIRONET4500_CS is not set
# CONFIG_ARCNET_COM20020_CS is not set
# CONFIG_PCMCIA_3C575 is not set
# CONFIG_PCMCIA_TULIP is not set
@@ -342,6 +344,7 @@ CONFIG_NET_PCMCIA_RADIO=y
CONFIG_PCMCIA_RAYCS=y
# CONFIG_PCMCIA_NETWAVE is not set
# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_AIRONET4500_CS is not set
CONFIG_PCMCIA_NETCARD=y
#
@@ -402,7 +405,6 @@ CONFIG_PSMOUSE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
#
# Video For Linux
@@ -433,10 +435,6 @@ CONFIG_PCMCIA_SERIAL=y
# CONFIG_USB is not set
#
-# Misc devices
-#
-
-#
# File systems
#
# CONFIG_QUOTA is not set
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
index b19097420..d95bbe6b1 100644
--- a/arch/i386/kernel/acpi.c
+++ b/arch/i386/kernel/acpi.c
@@ -50,7 +50,6 @@
*/
extern unsigned long get_cmos_time(void);
-static int acpi_control_thread(void *context);
static int acpi_do_ulong(ctl_table *ctl,
int write,
struct file *file,
@@ -72,8 +71,6 @@ static int acpi_do_sleep(ctl_table *ctl,
void *buffer,
size_t *len);
-DECLARE_WAIT_QUEUE_HEAD(acpi_control_wait);
-
static struct ctl_table_header *acpi_sysctl = NULL;
static struct acpi_facp *acpi_facp = NULL;
@@ -105,7 +102,15 @@ static unsigned long acpi_p_blk = 0;
static int acpi_p_lvl2_tested = 0;
static int acpi_p_lvl3_tested = 0;
-static int acpi_disabled = 0;
+enum
+{
+ ACPI_ENABLED,
+ ACPI_TABLES_ONLY,
+ ACPI_CHIPSET_ONLY,
+ ACPI_DISABLED,
+};
+
+static int acpi_enabled = ACPI_ENABLED;
// bits 8-15 are SLP_TYPa, bits 0-7 are SLP_TYPb
static unsigned long acpi_slp_typ[] =
@@ -1296,13 +1301,21 @@ static int acpi_do_sleep(ctl_table *ctl,
*/
static int __init acpi_init(void)
{
- int pid;
-
- if (acpi_disabled)
- return -ENODEV;
-
- if (acpi_find_tables() && acpi_find_chipset()) {
- // no ACPI tables and not recognized chipset
+ switch(acpi_enabled)
+ {
+ case ACPI_ENABLED:
+ if (acpi_find_tables() && acpi_find_chipset())
+ return -ENODEV;
+ break;
+ case ACPI_TABLES_ONLY:
+ if (acpi_find_tables())
+ return -ENODEV;
+ break;
+ case ACPI_CHIPSET_ONLY:
+ if (acpi_find_chipset())
+ return -ENODEV;
+ break;
+ case ACPI_DISABLED:
return -ENODEV;
}
@@ -1342,10 +1355,6 @@ static int __init acpi_init(void)
acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);
- pid = kernel_thread(acpi_control_thread,
- NULL,
- CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-
pm_power_off = acpi_power_off;
pm_active = 1;
@@ -1379,6 +1388,7 @@ err_out:
static void __exit acpi_exit(void)
{
pm_idle = NULL;
+ pm_active = 0;
pm_power_off = NULL;
unregister_sysctl_table(acpi_sysctl);
@@ -1400,10 +1410,14 @@ static void __exit acpi_exit(void)
static int __init acpi_setup(char *str)
{
while (str && *str) {
- if (strncmp(str, "off", 3) == 0)
- acpi_disabled = 1;
- else if (strncmp(str, "on", 2) == 0)
- acpi_disabled = 0;
+ if (strncmp(str, "on", 2) == 0)
+ acpi_enabled = ACPI_ENABLED;
+ else if (strncmp(str, "tables", 6) == 0)
+ acpi_enabled = ACPI_TABLES_ONLY;
+ else if (strncmp(str, "chipset", 7) == 0)
+ acpi_enabled = ACPI_CHIPSET_ONLY;
+ else if (strncmp(str, "off", 3) == 0)
+ acpi_enabled = ACPI_DISABLED;
str = strpbrk(str, ",");
if (str)
str += strspn(str, ",");
@@ -1413,24 +1427,5 @@ static int __init acpi_setup(char *str)
__setup("acpi=", acpi_setup);
-/*
- * Manage idle devices
- */
-static int acpi_control_thread(void *context)
-{
- exit_mm(current);
- exit_files(current);
- strcpy(current->comm, "acpi");
-
- for(;;) {
- interruptible_sleep_on(&acpi_control_wait);
- if (signal_pending(current))
- break;
-
- // find all idle devices and set idle timer
- }
-
- return 0;
-}
-
-__initcall(acpi_init);
+module_init(acpi_init);
+module_exit(acpi_exit);
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 3d403b93c..99e258756 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -590,11 +590,11 @@ static void apm_cpu_idle(void)
continue;
if (hlt_counter)
continue;
- asm volatile("cli" : : : "memory");
+ __cli();
if (!current->need_resched)
- asm volatile("sti ; hlt" : : : "memory");
+ safe_halt();
else
- asm volatile("sti" : : : "memory");
+ __sti();
continue;
}
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index a76c92d25..e51e96e43 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -1044,17 +1044,17 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt)
printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
}
-static void set_level_irq(unsigned irq)
+static void ali_set_level_irq(unsigned irq)
{
unsigned char mask = 1 << (irq & 7);
unsigned int port = 0x4d0 + (irq >> 3);
unsigned char val = inb(port);
if (val & mask) {
- printk("PCI irq %d was level\n", irq);
+ DBG("PCI irq %d was level\n", irq);
return;
}
- printk("PCI irq %d was edge, turning into level-triggered\n", irq);
+ DBG("PCI irq %d was edge, turning into level-triggered\n", irq);
outb(val | mask, port);
}
@@ -1070,18 +1070,17 @@ static int ali_set_irq(struct pci_dev *router, unsigned pirq, unsigned irq)
unsigned offset = 0x48 + (pirq >> 1);
unsigned shift = (pirq & 1) << 2;
pci_read_config_byte(router, offset, &byte);
- printk("ALI: old %04x=%02x\n", offset, byte);
+ DBG("ALI: old %04x=%02x\n", offset, byte);
byte &= ~(0xf << shift);
byte |= val << shift;
- printk("ALI: new %04x=%02x\n", offset, byte);
+ DBG("ALI: new %04x=%02x\n", offset, byte);
pci_write_config_byte(router, offset, byte);
- set_level_irq(irq);
+ ali_set_level_irq(irq);
return irq;
}
}
return 0;
}
-
/*
* In case BIOS forgets to tell us about IRQ, we try to look it up in the routing
@@ -1380,13 +1379,17 @@ int pcibios_enable_device(struct pci_dev *dev)
if ((err = pcibios_enable_resources(dev)) < 0)
return err;
- if (!dev->irq && pirq_table) {
+ if (!dev->irq) {
u8 pin;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
- char *msg = pcibios_lookup_irq(dev, pirq_table, pin, 1);
- if (msg)
+ char *msg;
+ if (pirq_table && ((msg = pcibios_lookup_irq(dev, pirq_table, pin, 1))))
printk("PCI: Assigned IRQ %d to device %s [%s]\n", dev->irq, dev->slot_name, msg);
+ else
+ printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+ 'A' + pin - 1, dev->slot_name,
+ (pci_probe & PCI_BIOS_IRQ_SCAN) ? "" : " Please try using pci=biosirq.");
}
}
return 0;
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index a043b4cfe..3ba1d8257 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -75,11 +75,11 @@ void enable_hlt(void)
static void default_idle(void)
{
if (current_cpu_data.hlt_works_ok && !hlt_counter) {
- asm volatile("cli" : : : "memory");
+ __cli();
if (!current->need_resched)
- asm volatile("sti ; hlt" : : : "memory");
+ safe_halt();
else
- asm volatile("sti" : : : "memory");
+ __sti();
}
}
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index 24e274aa0..3ace288ef 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -5,7 +5,7 @@
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
-# Copyright (C) 1998, 1999 by David Mosberger-Tang <davidm@hpl.hp.com>
+# Copyright (C) 1998-2000 by David Mosberger-Tang <davidm@hpl.hp.com>
#
NM := $(CROSS_COMPILE)nm -B
@@ -14,12 +14,12 @@ LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds
# next line is for HP compiler backend:
#AFLAGS += -DGCC_RETVAL_POINTER_IN_R8
# The next line is needed when compiling with the July snapshot of the Cygnus compiler:
-#EXTRA = -ma0-bugs -D__GCC_DOESNT_KNOW_IN_REGS__
+#EXTRA = -D__GCC_DOESNT_KNOW_IN_REGS__
# next two lines are for the September snapshot of the Cygnus compiler:
AFLAGS += -D__GCC_MULTIREG_RETVALS__
-EXTRA = -ma0-bugs -D__GCC_MULTIREG_RETVALS__
+EXTRA = -D__GCC_MULTIREG_RETVALS__
-CFLAGS := -g $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127
+CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127
ifdef CONFIG_IA64_GENERIC
CORE_FILES := arch/$(ARCH)/hp/hp.a \
diff --git a/arch/ia64/config.in b/arch/ia64/config.in
index 2d2388590..3d1dd7e02 100644
--- a/arch/ia64/config.in
+++ b/arch/ia64/config.in
@@ -35,7 +35,7 @@ if [ "$CONFIG_IA64_SGI_SN1_SIM" = "y" ]; then
define_bool CONFIG_IA64_SOFTSDV_HACKS y
fi
-define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /dev/kcore.
+define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore.
bool 'SMP support' CONFIG_SMP n
bool 'Performance monitor support' CONFIG_PERFMON n
@@ -123,7 +123,7 @@ endmenu
source drivers/char/Config.in
source drivers/usb/Config.in
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
source fs/Config.in
diff --git a/arch/ia64/dig/iosapic.c b/arch/ia64/dig/iosapic.c
index 6a392226e..4861aa2d9 100644
--- a/arch/ia64/dig/iosapic.c
+++ b/arch/ia64/dig/iosapic.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -19,7 +20,6 @@
#include <asm/io.h>
#include <asm/iosapic.h>
-#include <asm/irq.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/delay.h>
@@ -258,6 +258,21 @@ disable_pin (unsigned int pin, unsigned long iosapic_addr)
#define iosapic_shutdown_irq iosapic_disable_irq
+static unsigned int
+iosapic_startup_irq (unsigned int irq)
+{
+ int pin;
+
+ pin = iosapic_pin(irq);
+ if (pin < 0)
+ /* happens during irq auto probing... */
+ return 0;
+ set_rte(iosapic_addr(irq), pin, iosapic_polarity(irq), iosapic_trigger(irq),
+ iosapic_dmode(irq), (ia64_get_lid() >> 16) & 0xffff, irq);
+ enable_pin(pin, iosapic_addr(irq));
+ return 0;
+}
+
static void
iosapic_enable_irq (unsigned int irq)
{
@@ -295,58 +310,26 @@ iosapic_version(unsigned long base_addr)
return readl(IO_SAPIC_WINDOW + base_addr);
}
-static int
-iosapic_handle_irq (unsigned int irq, struct pt_regs *regs)
+static void
+iosapic_ack_irq (unsigned int irq)
{
- struct irqaction *action = 0;
- struct irq_desc *id = irq_desc + irq;
- unsigned int status;
- int retval;
-
- spin_lock(&irq_controller_lock);
- {
- status = id->status;
-
- /* do we need to do something IOSAPIC-specific to ACK the irq here??? */
- /* Yes, but only level-triggered interrupts. We'll do that later */
- if ((status & IRQ_INPROGRESS) == 0 && (status & IRQ_ENABLED) != 0) {
- action = id->action;
- status |= IRQ_INPROGRESS;
- }
- id->status = status & ~(IRQ_REPLAY | IRQ_WAITING);
- }
- spin_unlock(&irq_controller_lock);
-
- if (!action) {
- if (!(id->status & IRQ_AUTODETECT))
- printk("iosapic_handle_irq: unexpected interrupt %u;"
- "disabling it (status=%x)\n", irq, id->status);
- /*
- * If we don't have a handler, disable the pin so we
- * won't get any further interrupts (until
- * re-enabled). --davidm 99/12/17
- */
- iosapic_disable_irq(irq);
- return 0;
- }
-
- retval = invoke_irq_handlers (irq, regs, action);
+}
+static void
+iosapic_end_irq (unsigned int irq)
+{
if (iosapic_trigger(irq) == IO_SAPIC_LEVEL) /* ACK Level trigger interrupts */
writel(irq, iosapic_addr(irq) + IO_SAPIC_EOI);
+}
- spin_lock(&irq_controller_lock);
- {
- status = (id->status & ~IRQ_INPROGRESS);
- id->status = status;
- }
- spin_unlock(&irq_controller_lock);
-
- return retval;
+static void
+iosapic_set_affinity (unsigned int irq, unsigned long mask)
+{
+ printk("iosapic_set_affinity: not implemented yet\n");
}
-void __init
-iosapic_init (unsigned long addr)
+void
+iosapic_init (unsigned long address)
{
int i;
#ifdef CONFIG_IA64_IRQ_ACPI
@@ -357,18 +340,9 @@ iosapic_init (unsigned long addr)
#endif
/*
- * Disable all local interrupts
- */
-
- ia64_set_itv(0, 1);
- ia64_set_lrr0(0, 1);
- ia64_set_lrr1(0, 1);
-
- /*
* Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
* enabled.
*/
-
outb(0xff, 0xA1);
outb(0xff, 0x21);
@@ -376,10 +350,13 @@ iosapic_init (unsigned long addr)
memset(iosapic_vector, 0x0, sizeof(iosapic_vector));
for (i = 0; i < NR_IRQS; i++) {
iosapic_pin(i) = 0xff;
- iosapic_addr(i) = (unsigned long) ioremap(IO_SAPIC_DEFAULT_ADDR, 0);
+ iosapic_addr(i) = (unsigned long) ioremap(address, 0);
}
/* XXX this should come from systab or some such: */
+# if 0
+ /* this doesn't look right --davidm 00/03/07 */
iosapic_pin(TIMER_IRQ) = 5; /* System Clock Interrupt */
+# endif
iosapic_pin(0x40) = 3; /* Keyboard */
iosapic_pin(0x92) = 9; /* COM1 Serial Port */
iosapic_pin(0x80) = 4; /* Periodic Interrupt */
@@ -396,7 +373,7 @@ iosapic_init (unsigned long addr)
i = -1;
while (intr_routing[++i].srcbus != 0xff) {
if (intr_routing[i].srcbus == BUS_ISA) {
- vector = map_legacy_irq(intr_routing[i].srcbusirq);
+ vector = isa_irq_to_vector(intr_routing[i].srcbusirq);
} else if (intr_routing[i].srcbus == BUS_PCI) {
vector = intr_routing[i].iosapic_pin;
} else {
@@ -414,7 +391,7 @@ iosapic_init (unsigned long addr)
iosapic_trigger(vector));
# endif
}
-#else /* !defined(CONFIG_IA64_SOFTSDV_HACKS) && !defined(CONFIG_IA64_IRQ_ACPI) */
+#else /* !defined(CONFIG_IA64_SOFTSDV_HACKS) && defined(CONFIG_IA64_IRQ_ACPI) */
/*
* Map the legacy ISA devices into the IOAPIC data; We'll override these
* later with data from the ACPI Interrupt Source Override table.
@@ -425,8 +402,8 @@ iosapic_init (unsigned long addr)
* here, so that this works on BigSur but will go ask Intel. --wfd 2000-Jan-19
*
*/
- for (i =0 ; i < IA64_MIN_VECTORED_IRQ; i++) {
- irq = map_legacy_irq(i);
+ for (i =0 ; i < 16; i++) {
+ irq = isa_irq_to_vector(i);
iosapic_pin(irq) = i;
iosapic_bus(irq) = BUS_ISA;
iosapic_busdata(irq) = 0;
@@ -445,7 +422,9 @@ iosapic_init (unsigned long addr)
ia64_boot_param.pci_vectors = (__u64) __va(ia64_boot_param.pci_vectors);
vectors = (struct pci_vector_struct *) ia64_boot_param.pci_vectors;
for (i = 0; i < ia64_boot_param.num_pci_vectors; i++) {
- irq = map_legacy_irq(vectors[i].irq);
+ irq = vectors[i].irq;
+ if (irq < 16)
+ irq = isa_irq_to_vector(irq);
iosapic_bustype(irq) = BUS_PCI;
iosapic_pin(irq) = irq - iosapic_baseirq(irq);
@@ -469,34 +448,19 @@ iosapic_init (unsigned long addr)
#endif /* !CONFIG_IA64_IRQ_ACPI */
}
-static void
-iosapic_startup_irq (unsigned int irq)
-{
- int pin;
-
- if (irq == TIMER_IRQ)
- return;
- pin = iosapic_pin(irq);
- if (pin < 0)
- /* happens during irq auto probing... */
- return;
- set_rte(iosapic_addr(irq), pin, iosapic_polarity(irq), iosapic_trigger(irq),
- iosapic_dmode(irq), (ia64_get_lid() >> 16) & 0xffff, irq);
- enable_pin(pin, iosapic_addr(irq));
-}
-
struct hw_interrupt_type irq_type_iosapic = {
- "IOSAPIC",
- iosapic_init,
- iosapic_startup_irq,
- iosapic_shutdown_irq,
- iosapic_handle_irq,
- iosapic_enable_irq,
- iosapic_disable_irq
+ typename: "IOSAPIC",
+ startup: iosapic_startup_irq,
+ shutdown: iosapic_shutdown_irq,
+ enable: iosapic_enable_irq,
+ disable: iosapic_disable_irq,
+ ack: iosapic_ack_irq,
+ end: iosapic_end_irq,
+ set_affinity: iosapic_set_affinity
};
void
-dig_irq_init (struct irq_desc desc[NR_IRQS])
+dig_irq_init (void)
{
int i;
@@ -505,10 +469,20 @@ dig_irq_init (struct irq_desc desc[NR_IRQS])
* claimed by someone else already (e.g., timer or IPI are
* handled internally).
*/
+#if 0
for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) {
- if (irq_desc[i].handler == &irq_type_default)
+ if (irq_desc[i].handler == &no_irq_type)
irq_desc[i].handler = &irq_type_iosapic;
}
+#else
+ for (i = 0; i <= IA64_MAX_VECTORED_IRQ; ++i) {
+ if (irq_desc[i].handler == &no_irq_type)
+ irq_desc[i].handler = &irq_type_iosapic;
+ }
+#endif
+#ifndef CONFIG_IA64_DIG
+ iosapic_init(IO_SAPIC_DEFAULT_ADDR);
+#endif
}
void
diff --git a/arch/ia64/hp/hpsim_irq.c b/arch/ia64/hp/hpsim_irq.c
index 72b36d6d6..00f4d1a51 100644
--- a/arch/ia64/hp/hpsim_irq.c
+++ b/arch/ia64/hp/hpsim_irq.c
@@ -1,83 +1,42 @@
/*
* Platform dependent support for HP simulator.
*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/kdev_t.h>
-#include <linux/console.h>
-
-#include <asm/delay.h>
-#include <asm/irq.h>
-#include <asm/pal.h>
-#include <asm/machvec.h>
-#include <asm/pgtable.h>
-#include <asm/sal.h>
+#include <linux/init.h>
+#include <linux/irq.h>
-static int
-irq_hp_sim_handle_irq (unsigned int irq, struct pt_regs *regs)
+static unsigned int
+hpsim_irq_startup (unsigned int irq)
{
- struct irqaction *action = 0;
- struct irq_desc *id = irq_desc + irq;
- unsigned int status;
- int retval;
-
- spin_lock(&irq_controller_lock);
- {
- status = id->status;
- if ((status & IRQ_INPROGRESS) == 0 && (status & IRQ_ENABLED) != 0) {
- action = id->action;
- status |= IRQ_INPROGRESS;
- }
- id->status = status & ~(IRQ_REPLAY | IRQ_WAITING);
- }
- spin_unlock(&irq_controller_lock);
-
- if (!action) {
- if (!(id->status & IRQ_AUTODETECT))
- printk("irq_hpsim_handle_irq: unexpected interrupt %u\n", irq);
- return 0;
- }
-
- retval = invoke_irq_handlers(irq, regs, action);
-
- spin_lock(&irq_controller_lock);
- {
- id->status &= ~IRQ_INPROGRESS;
- }
- spin_unlock(&irq_controller_lock);
-
- return retval;
+ return 0;
}
static void
-irq_hp_sim_noop (unsigned int irq)
+hpsim_irq_noop (unsigned int irq)
{
}
static struct hw_interrupt_type irq_type_hp_sim = {
- "hp_sim",
- (void (*)(unsigned long)) irq_hp_sim_noop, /* init */
- irq_hp_sim_noop, /* startup */
- irq_hp_sim_noop, /* shutdown */
- irq_hp_sim_handle_irq, /* handle */
- irq_hp_sim_noop, /* enable */
- irq_hp_sim_noop, /* disable */
+ typename: "hpsim",
+ startup: hpsim_irq_startup,
+ shutdown: hpsim_irq_noop,
+ enable: hpsim_irq_noop,
+ disable: hpsim_irq_noop,
+ ack: hpsim_irq_noop,
+ end: hpsim_irq_noop,
+ set_affinity: (void (*)(unsigned int, unsigned long)) hpsim_irq_noop,
};
-void
-hpsim_irq_init (struct irq_desc desc[NR_IRQS])
+void __init
+hpsim_irq_init (void)
{
int i;
for (i = IA64_MIN_VECTORED_IRQ; i <= IA64_MAX_VECTORED_IRQ; ++i) {
- irq_desc[i].handler = &irq_type_hp_sim;
+ if (irq_desc[i].handler == &no_irq_type)
+ irq_desc[i].handler = &irq_type_hp_sim;
}
}
diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
index af51038e5..a99983681 100644
--- a/arch/ia64/ia32/binfmt_elf32.c
+++ b/arch/ia64/ia32/binfmt_elf32.c
@@ -50,13 +50,13 @@ put_shared_page(struct task_struct * tsk, struct page *page, unsigned long addre
pmd = pmd_alloc(pgd, address);
if (!pmd) {
__free_page(page);
- oom(tsk);
+ force_sig(SIGKILL, tsk);
return 0;
}
pte = pte_alloc(pmd, address);
if (!pte) {
__free_page(page);
- oom(tsk);
+ force_sig(SIGKILL, tsk);
return 0;
}
if (!pte_none(*pte)) {
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 7cb47da72..7a2fcd214 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -15,7 +15,7 @@
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
-O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_default.o irq_internal.o ivt.o \
+O_OBJS := acpi.o entry.o gate.o efi.o efi_stub.o irq.o irq_ia64.o irq_internal.o ivt.o \
pal.o pci-dma.o process.o perfmon.o ptrace.o sal.o sal_stub.o semaphore.o setup.o signal.o \
sys_ia64.o traps.o time.o unaligned.o unwind.o
#O_OBJS := fpreg.o
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index e289efab6..078d908c8 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -11,6 +11,7 @@
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
@@ -22,7 +23,6 @@
#include <asm/efi.h>
#include <asm/io.h>
#include <asm/iosapic.h>
-#include <asm/irq.h>
#undef ACPI_DEBUG /* Guess what this does? */
@@ -83,8 +83,8 @@ acpi_iosapic(char *p)
*/
#ifdef CONFIG_IA64_DIG
acpi_entry_iosapic_t *iosapic = (acpi_entry_iosapic_t *) p;
- unsigned int ver;
- int l, v, pins;
+ unsigned int ver, v;
+ int l, pins;
ver = iosapic_version(iosapic->address);
pins = (ver >> 16) & 0xff;
@@ -94,9 +94,11 @@ acpi_iosapic(char *p)
iosapic->irq_base, iosapic->irq_base + pins);
for (l = 0; l < pins; l++) {
- v = map_legacy_irq(iosapic->irq_base + l);
+ v = iosapic->irq_base + l;
+ if (v < 16)
+ v = isa_irq_to_vector(v);
if (v > IA64_MAX_VECTORED_IRQ) {
- printk(" !!! IRQ %d > 255\n", v);
+ printk(" !!! bad IOSAPIC interrupt vector: %u\n", v);
continue;
}
/* XXX Check for IOSAPIC collisions */
@@ -115,7 +117,7 @@ static void __init
acpi_legacy_irq(char *p)
{
/*
- * This is not good. ACPI is not necessarily limited to CONFIG_IA64_SV, yet
+ * This is not good. ACPI is not necessarily limited to CONFIG_IA64_DIG, yet
* ACPI does not necessarily imply IOSAPIC either. Perhaps there should be
* a means for platform_setup() to register ACPI handlers?
*/
@@ -124,7 +126,7 @@ acpi_legacy_irq(char *p)
unsigned char vector;
int i;
- vector = map_legacy_irq(legacy->isa_irq);
+ vector = isa_irq_to_vector(legacy->isa_irq);
/*
* Clobber any old pin mapping. It may be that it gets replaced later on
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 6e0d09ea7..fc2d50558 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -227,8 +227,8 @@ efi_init (void)
panic("Woah! Can't find EFI system table.\n");
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
panic("Woah! EFI system table signature incorrect\n");
- if (efi.systab->hdr.revision != EFI_SYSTEM_TABLE_REVISION)
- printk("Warning: EFI system table version mismatch: "
+ if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
+ printk("Warning: EFI system table major version mismatch: "
"got %d.%02d, expected %d.%02d\n",
efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff,
EFI_SYSTEM_TABLE_REVISION >> 16, EFI_SYSTEM_TABLE_REVISION & 0xffff);
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 47b972cb4..eb575a39c 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -738,7 +738,7 @@ handle_syscall_error:
st8.spill [r2]=r9 // store errno in pt_regs.r8 and set unat bit
st8.spill [r3]=r10 // store error indication in pt_regs.r10 and set unat bit
br.cond.sptk.many ia64_leave_kernel
- .endp __ret_from_syscall
+ .endp handle_syscall_error
#ifdef CONFIG_SMP
/*
@@ -767,7 +767,9 @@ invoke_schedule_tail:
invoke_do_softirq:
alloc loc0=ar.pfs,8,2,0,0
mov loc1=rp
+(pEOI) mov cr.eoi=r0
;;
+(pEOI) cmp.ne pEOI,p0=r0,r0
br.call.sptk.few rp=do_softirq
.ret9:
mov ar.pfs=loc0
diff --git a/arch/ia64/kernel/fw-emu.c b/arch/ia64/kernel/fw-emu.c
index 212ff299c..23ded0730 100644
--- a/arch/ia64/kernel/fw-emu.c
+++ b/arch/ia64/kernel/fw-emu.c
@@ -139,6 +139,24 @@ pal_emulator_static:
movl r9 =0x100000064 /* proc_ratio (1/100) */
movl r10=0x100000100 /* bus_ratio<<32 (1/256) */
movl r11=0x100000064 /* itc_ratio<<32 (1/100) */
+ ;;
+1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */
+(p7) br.cond.sptk.few 1f
+ mov r9=ar.lc
+ movl r8=524288 /* flush 512k million cache lines (16MB) */
+ ;;
+ mov ar.lc=r8
+ movl r8=0xe000000000000000
+ ;;
+.loop: fc r8
+ add r8=32,r8
+ br.cloop.sptk.few .loop
+ sync.i
+ ;;
+ srlz.i
+ ;;
+ mov ar.lc=r9
+ mov r8=r0
1: br.cond.sptk.few rp
.endp pal_emulator_static\n");
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index 65de8e589..a710870c0 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -82,7 +82,7 @@ ia64_sigtramp:
br.call.sptk.many rp=invoke_sighandler
.ret0: mov r15=__NR_rt_sigreturn
break __BREAK_SYSCALL
- .endp ia64_sigramp
+ .endp ia64_sigtramp
.proc invoke_sighandler
invoke_sighandler:
@@ -167,7 +167,7 @@ back_from_restore_rbs:
br.ret.sptk.few b6
cont: mov ar.pfs=r8 // ar.pfs = CFM0
br.ret.sptk.few rp // re-establish CFM0
- .endp invoke_signal_handler
+ .endp invoke_sighandler
.proc setup_rbs
setup_rbs:
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 6059e41c6..0ddfe3f05 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -1,105 +1,146 @@
/*
- * linux/arch/ia64/kernel/irq.c
+ * linux/arch/ia64/kernel/irq.c
*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*
- * 6/10/99: Updated to bring in sync with x86 version to facilitate
- * support for SMP and different interrupt controllers.
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
*/
-#include <linux/config.h>
+/*
+ * (mostly architecture independent, will move to kernel/irq.c in 2.5.)
+ *
+ * IRQs are in fact implemented a bit like signal handlers for the kernel.
+ * Naturally it's not a 1:1 relation, but there are similarities.
+ */
-#include <linux/sched.h>
+#include <linux/config.h>
+#include <linux/ptrace.h>
#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
#include <linux/ioport.h>
-#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
#include <linux/malloc.h>
-#include <linux/ptrace.h>
-#include <linux/random.h> /* for rand_initialize_irq() */
-#include <linux/signal.h>
-#include <linux/smp.h>
+#include <linux/random.h>
#include <linux/smp_lock.h>
-#include <linux/threads.h>
-
-#ifdef CONFIG_KDB
-# include <linux/kdb.h>
-#endif
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/irq.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/system.h>
#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
#include <asm/delay.h>
-#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/machvec.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-/* This is used to detect bad usage of probe_irq_on()/probe_irq_off(). */
-#define PROBE_IRQ_COOKIE 0xfeedC0FFEE
-struct irq_desc irq_desc[NR_IRQS];
/*
- * Micro-access to controllers is serialized over the whole
- * system. We never hold this lock when we call the actual
- * IRQ handler.
+ * Linux has a controller-independent x86 interrupt architecture.
+ * every controller has a 'controller-template', that is used
+ * by the main code to do the right thing. Each driver-visible
+ * interrupt source is transparently wired to the apropriate
+ * controller. Thus drivers need not be aware of the
+ * interrupt-controller.
+ *
+ * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
+ * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
+ * (IO-APICs assumed to be messaging to Pentium local-APICs)
+ *
+ * the code is designed to be easily extended with new/different
+ * interrupt controllers, without having to do assembly magic.
*/
-spinlock_t irq_controller_lock;
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
-spinlock_t ivr_read_lock;
-#endif
+irq_cpustat_t irq_stat [NR_CPUS];
-unsigned int local_bh_count[NR_CPUS];
/*
- * used in irq_enter()/irq_exit()
+ * Controller mappings for all interrupt sources:
*/
-unsigned int local_irq_count[NR_CPUS];
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
+ { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}};
-static struct irqaction timer_action = { NULL, 0, 0, NULL, NULL, NULL};
+static void register_irq_proc (unsigned int irq);
-#ifdef CONFIG_SMP
-static struct irqaction ipi_action = { NULL, 0, 0, NULL, NULL, NULL};
-#endif
+/*
+ * Special irq handlers.
+ */
+
+void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
/*
- * Legacy IRQ to IA-64 vector translation table. Any vector not in
- * this table maps to itself (ie: irq 0x30 => IA64 vector 0x30)
+ * Generic no controller code
*/
-__u8 irq_to_vector_map[IA64_MIN_VECTORED_IRQ] = {
- /* 8259 IRQ translation, first 16 entries */
- TIMER_IRQ, 0x50, 0x0f, 0x51, 0x52, 0x53, 0x43, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x40, 0x41,
-};
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
/*
- * Reverse of the above table.
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesnt deserve
+ * a generic callback i think.
*/
-static __u8 vector_to_legacy_map[256];
+#if CONFIG_X86
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+#ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * Currently unexpected vectors happen only on SMP and APIC.
+ * We _must_ ack these because every local APIC has only N
+ * irq slots per priority level, and a 'hanging, unacked' IRQ
+ * holds up an irq slot - in excessive cases (when multiple
+ * unexpected vectors occur) that might lock up the APIC
+ * completely.
+ */
+ ack_APIC_irq();
+#endif
+#endif
+#if CONFIG_IA64
+ printk("Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id());
+#endif
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none disable_none
+#define end_none enable_none
+
+struct hw_interrupt_type no_irq_type = {
+ "none",
+ startup_none,
+ shutdown_none,
+ enable_none,
+ disable_none,
+ ack_none,
+ end_none
+};
+
+volatile unsigned long irq_err_count;
/*
- * used by proc fs (/proc/interrupts)
+ * Generic, controller-independent functions:
*/
-int
-get_irq_list (char *buf)
+
+int get_irq_list(char *buf)
{
- int i;
+ int i, j;
struct irqaction * action;
char *p = buf;
-#ifdef CONFIG_SMP
p += sprintf(p, " ");
- for (i = 0; i < smp_num_cpus; i++)
- p += sprintf(p, "CPU%d ", i);
+ for (j=0; j<smp_num_cpus; j++)
+ p += sprintf(p, "CPU%d ",j);
*p++ = '\n';
-#endif
- /*
- * Simply scans the external vectored interrupts
- */
- for (i = 0; i < NR_IRQS; i++) {
+
+ for (i = 0 ; i < NR_IRQS ; i++) {
action = irq_desc[i].action;
if (!action)
continue;
@@ -107,356 +148,496 @@ get_irq_list (char *buf)
#ifndef CONFIG_SMP
p += sprintf(p, "%10u ", kstat_irqs(i));
#else
- {
- int j;
- for (j = 0; j < smp_num_cpus; j++)
- p += sprintf(p, "%10u ",
- kstat.irqs[cpu_logical_map(j)][i]);
- }
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
#endif
p += sprintf(p, " %14s", irq_desc[i].handler->typename);
- p += sprintf(p, " %c%s", (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
+ p += sprintf(p, " %s", action->name);
- for (action = action->next; action; action = action->next) {
- p += sprintf(p, ", %c%s",
- (action->flags & SA_INTERRUPT)?'+':' ',
- action->name);
- }
+ for (action=action->next; action; action = action->next)
+ p += sprintf(p, ", %s", action->name);
*p++ = '\n';
}
+ p += sprintf(p, "NMI: ");
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ atomic_read(&nmi_counter(cpu_logical_map(j))));
+ p += sprintf(p, "\n");
+#if CONFIG_SMP
+ p += sprintf(p, "LOC: ");
+ for (j = 0; j < smp_num_cpus; j++)
+ p += sprintf(p, "%10u ",
+ apic_timer_irqs[cpu_logical_map(j)]);
+ p += sprintf(p, "\n");
+#endif
+ p += sprintf(p, "ERR: %10lu\n", irq_err_count);
return p - buf;
}
-int usbfix;
-static int __init
-usbfix_option (char *str)
+/*
+ * Global interrupt locks for SMP. Allow interrupts to come in on any
+ * CPU, yet make cli/sti act globally to protect critical regions..
+ */
+
+#ifdef CONFIG_SMP
+unsigned char global_irq_holder = NO_PROC_ID;
+unsigned volatile int global_irq_lock;
+
+extern void show_stack(unsigned long* esp);
+
+static void show(char * str)
{
- printk("irq: enabling USB workaround\n");
- usbfix = 1;
- return 1;
+ int i;
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [",irqs_running());
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_irq_count(i));
+ printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_bh_count(i));
+
+ printk(" ]\nStack dumps:");
+ for(i=0;i< smp_num_cpus;i++) {
+ unsigned long esp;
+ if(i==cpu)
+ continue;
+ printk("\nCPU %d:",i);
+ esp = init_tss[i].esp0;
+ if(esp==NULL) {
+ /* tss->esp0 is set to NULL in cpu_init(),
+ * it's initialized when the cpu returns to user
+ * space. -- manfreds
+ */
+ printk(" <unknown> ");
+ continue;
+ }
+ esp &= ~(THREAD_SIZE-1);
+ esp += sizeof(struct task_struct);
+ show_stack((void*)esp);
+ }
+ printk("\nCPU %d:",cpu);
+ show_stack(NULL);
+ printk("\n");
}
+
+#define MAXCOUNT 100000000
-__setup("usbfix", usbfix_option);
+/*
+ * I had a lockup scenario where a tight loop doing
+ * spin_unlock()/spin_lock() on CPU#1 was racing with
+ * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but
+ * apparently the spin_unlock() information did not make it
+ * through to CPU#0 ... nasty, is this by design, do we have to limit
+ * 'memory update oscillation frequency' artificially like here?
+ *
+ * Such 'high frequency update' races can be avoided by careful design, but
+ * some of our major constructs like spinlocks use similar techniques,
+ * it would be nice to clarify this issue. Set this define to 0 if you
+ * want to check whether your system freezes. I suspect the delay done
+ * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but
+ * i thought that such things are guaranteed by design, since we use
+ * the 'LOCK' prefix.
+ */
+#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0
+#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND
+# define SYNC_OTHER_CORES(x) udelay(x+1)
+#else
/*
- * That's where the IVT branches when we get an external
- * interrupt. This branches to the correct hardware IRQ handler via
- * function ptr.
+ * We have to allow irqs to arrive between __sti and __cli
*/
-void
-ia64_handle_irq (unsigned long irq, struct pt_regs *regs)
+# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
+#endif
+
+static inline void wait_on_irq(int cpu)
{
- unsigned long bsp, sp, saved_tpr;
-
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
-# ifndef CONFIG_SMP
- static unsigned int max_prio = 0;
-# endif
- unsigned int prev_prio;
- unsigned long eoi_ptr;
-
-# ifdef CONFIG_USB
- extern void reenable_usb (void);
- extern void disable_usb (void);
-
- if (usbfix)
- disable_usb();
-# endif
- /*
- * Stop IPIs by getting the ivr_read_lock
- */
- spin_lock(&ivr_read_lock);
+ int count = MAXCOUNT;
+
+ for (;;) {
+
+ /*
+ * Wait until all interrupts are gone. Wait
+ * for bottom half handlers unless we're
+ * already executing in one..
+ */
+ if (!irqs_running())
+ if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
+ break;
+
+ /* Duh, we have to loop. Release the lock to avoid deadlocks */
+ clear_bit(0,&global_irq_lock);
+
+ for (;;) {
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
+ __sti();
+ SYNC_OTHER_CORES(cpu);
+ __cli();
+ if (irqs_running())
+ continue;
+ if (global_irq_lock)
+ continue;
+ if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
+ continue;
+ if (!test_and_set_bit(0,&global_irq_lock))
+ break;
+ }
+ }
+}
- /*
- * Disable PCI writes
- */
- outl(0x80ff81c0, 0xcf8);
- outl(0x73002188, 0xcfc);
- eoi_ptr = inl(0xcfc);
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+ if (irqs_running()) {
+ /* Stupid approach */
+ cli();
+ sti();
+ }
+}
- irq = ia64_get_ivr();
+static inline void get_irqlock(int cpu)
+{
+ if (test_and_set_bit(0,&global_irq_lock)) {
+ /* do we already hold the lock? */
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ do {
+ do {
+ } while (test_bit(0,&global_irq_lock));
+ } while (test_and_set_bit(0,&global_irq_lock));
+ }
+ /*
+ * We also to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu);
/*
- * Enable PCI writes
+ * Ok, finally..
*/
- outl(0x73182188, 0xcfc);
-
- spin_unlock(&ivr_read_lock);
+ global_irq_holder = cpu;
+}
-# ifdef CONFIG_USB
- if (usbfix)
- reenable_usb();
-# endif
+#define EFLAGS_IF_SHIFT 9
-# ifndef CONFIG_SMP
- prev_prio = max_prio;
- if (irq < max_prio) {
- printk ("ia64_handle_irq: got irq %lu while %u was in progress!\n",
- irq, max_prio);
-
- } else
- max_prio = irq;
-# endif /* !CONFIG_SMP */
-#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
-
- /* Always set TPR to limit maximum interrupt nesting depth to
- * 16 (without this, it would be ~240, which could easily lead
- * to kernel stack overflows.
- */
- saved_tpr = ia64_get_tpr();
- ia64_srlz_d();
- ia64_set_tpr(irq);
- ia64_srlz_d();
-
- asm ("mov %0=ar.bsp" : "=r"(bsp));
- asm ("mov %0=sp" : "=r"(sp));
-
- if ((sp - bsp) < 1024) {
- static long last_time;
- static unsigned char count;
-
- if (count > 5 && jiffies - last_time > 5*HZ)
- count = 0;
- if (++count < 5) {
- last_time = jiffies;
- printk("ia64_handle_irq: DANGER: less than 1KB of free stack space!!\n"
- "(bsp=0x%lx, sp=%lx)\n", bsp, sp);
- }
-#ifdef CONFIG_KDB
- kdb(KDB_REASON_PANIC, 0, regs);
-#endif
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
+void __global_cli(void)
+{
+ unsigned int flags;
+
+ __save_flags(flags);
+ if (flags & (1 << EFLAGS_IF_SHIFT)) {
+ int cpu = smp_processor_id();
+ __cli();
+ if (!local_irq_count(cpu))
+ get_irqlock(cpu);
}
+}
- /*
- * The interrupt is now said to be in service
- */
- if (irq >= NR_IRQS) {
- printk("handle_irq: invalid irq=%lu\n", irq);
- goto out;
- }
+void __global_sti(void)
+{
+ int cpu = smp_processor_id();
- ++kstat.irqs[smp_processor_id()][irq];
+ if (!local_irq_count(cpu))
+ release_irqlock(cpu);
+ __sti();
+}
- if (irq == IA64_SPURIOUS_INT) {
- printk("handle_irq: spurious interrupt\n");
- goto out;
- }
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+ int retval;
+ int local_enabled;
+ unsigned long flags;
+ int cpu = smp_processor_id();
- /*
- * Handle the interrupt by calling the hardware specific handler (IOSAPIC, Internal, etc).
- */
- (*irq_desc[irq].handler->handle)(irq, regs);
- out:
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
- {
- long pEOI;
-
- asm ("mov %0=0;; (p1) mov %0=1" : "=r"(pEOI));
- if (!pEOI) {
- printk("Yikes: ia64_handle_irq() without pEOI!!\n");
- asm volatile ("cmp.eq p1,p0=r0,r0" : "=r"(pEOI));
-# ifdef CONFIG_KDB
- kdb(KDB_REASON_PANIC, 0, regs);
-# endif
- }
+ __save_flags(flags);
+ local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
+ /* default to local */
+ retval = 2 + local_enabled;
+
+ /* check for global flags if we're not in an interrupt */
+ if (!local_irq_count(cpu)) {
+ if (local_enabled)
+ retval = 1;
+ if (global_irq_holder == cpu)
+ retval = 0;
}
+ return retval;
+}
- local_irq_disable();
-# ifndef CONFIG_SMP
- if (max_prio == irq)
- max_prio = prev_prio;
-# endif /* !CONFIG_SMP */
-#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
-
- ia64_srlz_d();
- ia64_set_tpr(saved_tpr);
- ia64_srlz_d();
+void __global_restore_flags(unsigned long flags)
+{
+ switch (flags) {
+ case 0:
+ __global_cli();
+ break;
+ case 1:
+ __global_sti();
+ break;
+ case 2:
+ __cli();
+ break;
+ case 3:
+ __sti();
+ break;
+ default:
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
+ }
}
+#endif
/*
- * This should really return information about whether we should do
- * bottom half handling etc. Right now we end up _always_ checking the
- * bottom half, which is a waste of time and is not what some drivers
- * would prefer.
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
*/
-int
-invoke_irq_handlers (unsigned int irq, struct pt_regs *regs, struct irqaction *action)
+int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
{
- void (*handler)(int, void *, struct pt_regs *);
- unsigned long flags, flags_union = 0;
+ int status;
int cpu = smp_processor_id();
- unsigned int requested_irq;
- void *dev_id;
irq_enter(cpu, irq);
- if ((action->flags & SA_INTERRUPT) == 0)
+ status = 1; /* Force the "do bottom halves" bit */
+
+ if (!(action->flags & SA_INTERRUPT))
__sti();
do {
- flags = action->flags;
- requested_irq = irq;
- if ((flags & SA_LEGACY) != 0)
- requested_irq = vector_to_legacy_map[irq];
- flags_union |= flags;
- handler = action->handler;
- dev_id = action->dev_id;
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
action = action->next;
- (*handler)(requested_irq, dev_id, regs);
} while (action);
- if ((flags_union & SA_SAMPLE_RANDOM) != 0)
+ if (status & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
__cli();
irq_exit(cpu, irq);
- return flags_union | 1; /* force the "do bottom halves" bit */
+
+ return status;
}
-void
-disable_irq_nosync (unsigned int irq)
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock.
+ */
+void inline disable_irq_nosync(unsigned int irq)
{
+ irq_desc_t *desc = irq_desc + irq;
unsigned long flags;
- irq = map_legacy_irq(irq);
-
- spin_lock_irqsave(&irq_controller_lock, flags);
- if (irq_desc[irq].depth++ > 0) {
- irq_desc[irq].status &= ~IRQ_ENABLED;
- irq_desc[irq].handler->disable(irq);
+ spin_lock_irqsave(&desc->lock, flags);
+ if (!desc->depth++) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->disable(irq);
}
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ spin_unlock_irqrestore(&desc->lock, flags);
}
/*
* Synchronous version of the above, making sure the IRQ is
* no longer running on any other IRQ..
*/
-void
-disable_irq (unsigned int irq)
+void disable_irq(unsigned int irq)
{
disable_irq_nosync(irq);
- irq = map_legacy_irq(irq);
-
- if (!local_irq_count[smp_processor_id()]) {
+ if (!local_irq_count(smp_processor_id())) {
do {
barrier();
- } while ((irq_desc[irq].status & IRQ_INPROGRESS) != 0);
+ } while (irq_desc[irq].status & IRQ_INPROGRESS);
}
}
-void
-enable_irq (unsigned int irq)
+void enable_irq(unsigned int irq)
{
+ irq_desc_t *desc = irq_desc + irq;
unsigned long flags;
- irq = map_legacy_irq(irq);
-
- spin_lock_irqsave(&irq_controller_lock, flags);
- switch (irq_desc[irq].depth) {
- case 1:
- irq_desc[irq].status |= IRQ_ENABLED;
- (*irq_desc[irq].handler->enable)(irq);
- /* fall through */
- default:
- --irq_desc[irq].depth;
+ spin_lock_irqsave(&desc->lock, flags);
+ switch (desc->depth) {
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+ desc->status = status;
+ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+ desc->status = status | IRQ_REPLAY;
+ hw_resend_irq(desc->handler,irq);
+ }
+ desc->handler->enable(irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
break;
-
- case 0:
- printk("enable_irq: unbalanced from %p\n", __builtin_return_address(0));
+ case 0:
+ printk("enable_irq() unbalanced from %p\n",
+ __builtin_return_address(0));
}
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ spin_unlock_irqrestore(&desc->lock, flags);
}
/*
- * This function encapsulates the initialization that needs to be
- * performed under the protection of lock irq_controller_lock. The
- * lock must have been acquired by the time this is called.
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
*/
-static inline int
-setup_irq (unsigned int irq, struct irqaction *new)
-{
- int shared = 0;
- struct irqaction *old, **p;
+unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs)
+{
+ /*
+ * We ack quickly, we don't want the irq controller
+ * thinking we're snobs just because some other CPU has
+ * disabled global interrupts (we have already done the
+ * INT_ACK cycles, it's too late to try to pretend to the
+ * controller that we aren't taking the interrupt).
+ *
+ * 0 return value means that this irq is already being
+ * handled by some other CPU. (or is disabled)
+ */
+ int cpu = smp_processor_id();
+ irq_desc_t *desc = irq_desc + irq;
+ struct irqaction * action;
+ unsigned int status;
- p = &irq_desc[irq].action;
- old = *p;
- if (old) {
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- return -EBUSY;
- }
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
+ kstat.irqs[cpu][irq]++;
+ spin_lock(&desc->lock);
+ desc->handler->ack(irq);
+ /*
+ REPLAY is when Linux resends an IRQ that was dropped earlier
+ WAITING is used by probe to mark irqs that are being tested
+ */
+ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+ status |= IRQ_PENDING; /* we _want_ to handle it */
+
+ /*
+ * If the IRQ is disabled for whatever reason, we cannot
+ * use the action we have.
+ */
+ action = NULL;
+ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+ action = desc->action;
+ status &= ~IRQ_PENDING; /* we commit to handling */
+ status |= IRQ_INPROGRESS; /* we are handling it */
}
- *p = new;
+ desc->status = status;
- /* when sharing do not unmask */
- if (!shared) {
- irq_desc[irq].depth = 0;
- irq_desc[irq].status |= IRQ_ENABLED;
- (*irq_desc[irq].handler->startup)(irq);
+ /*
+ * If there is no IRQ handler or it was disabled, exit early.
+ Since we set PENDING, if another processor is handling
+ a different instance of this same irq, the other processor
+ will take care of it.
+ */
+ if (!action)
+{
+ desc->status = status & ~IRQ_INPROGRESS;
+ goto out;
+}
+
+ /*
+ * Edge triggered interrupts need to remember
+ * pending events.
+ * This applies to any hw interrupts that allow a second
+ * instance of the same irq to arrive while we are in do_IRQ
+ * or in the handler. But the code here only handles the _second_
+ * instance of the irq, not the third or fourth. So it is mostly
+ * useful for irq hardware that does not mask cleanly in an
+ * SMP environment.
+ */
+ for (;;) {
+ spin_unlock(&desc->lock);
+ handle_IRQ_event(irq, regs, action);
+ spin_lock(&desc->lock);
+
+ if (!(desc->status & IRQ_PENDING))
+ break;
+ desc->status &= ~IRQ_PENDING;
}
- return 0;
+ desc->status &= ~IRQ_INPROGRESS;
+out:
+ /*
+ * The ->end() handler has to deal with interrupts which got
+ * disabled while the handler was running.
+ */
+ desc->handler->end(irq);
+ spin_unlock(&desc->lock);
+
+#if 0
+ /*
+ * let kernel exit path take care of this; we want to do the
+ * CPU EOI before doing softirq() so a new interrupt can come
+ * through
+ */
+ if (softirq_state[cpu].active & softirq_state[cpu].mask)
+ do_softirq();
+#endif
+ return 1;
}
-int
-request_irq (unsigned int requested_irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
{
- int retval, need_kfree = 0;
- struct irqaction *action;
- unsigned long flags;
- unsigned int irq;
+ int retval;
+ struct irqaction * action;
-#ifdef IA64_DEBUG
- printk("request_irq(0x%x) called\n", requested_irq);
-#endif
+#if 1
/*
* Sanity-check: shared interrupts should REALLY pass in
* a real dev-ID, otherwise we'll have trouble later trying
* to figure out which interrupt is which (messes up the
* interrupt freeing logic etc).
*/
- if ((irqflags & SA_SHIRQ) && !dev_id)
- printk("Bad boy: %s (at %p) called us without a dev_id!\n",
- devname, current_text_addr());
-
- irq = map_legacy_irq(requested_irq);
- if (irq != requested_irq)
- irqflags |= SA_LEGACY;
+ if (irqflags & SA_SHIRQ) {
+ if (!dev_id)
+ printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
+ }
+#endif
if (irq >= NR_IRQS)
return -EINVAL;
-
if (!handler)
return -EINVAL;
- /*
- * The timer_action and ipi_action cannot be allocated
- * dynamically because its initialization happens really early
- * on in init/main.c at this point the memory allocator has
- * not yet been initialized. So we use a statically reserved
- * buffer for it. In some sense that's no big deal because we
- * need one no matter what.
- */
- if (irq == TIMER_IRQ)
- action = &timer_action;
-#ifdef CONFIG_SMP
- else if (irq == IPI_IRQ)
- action = &ipi_action;
-#endif
- else {
- action = kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- need_kfree = 1;
- }
-
+ action = (struct irqaction *)
+ kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
@@ -467,208 +648,412 @@ request_irq (unsigned int requested_irq, void (*handler)(int, void *, struct pt_
action->next = NULL;
action->dev_id = dev_id;
- if ((irqflags & SA_SAMPLE_RANDOM) != 0)
- rand_initialize_irq(irq);
-
- spin_lock_irqsave(&irq_controller_lock, flags);
retval = setup_irq(irq, action);
- spin_unlock_irqrestore(&irq_controller_lock, flags);
-
- if (need_kfree && retval)
+ if (retval)
kfree(action);
-
return retval;
}
-void
-free_irq (unsigned int irq, void *dev_id)
+void free_irq(unsigned int irq, void *dev_id)
{
- struct irqaction *action, **p;
+ irq_desc_t *desc;
+ struct irqaction **p;
unsigned long flags;
- /*
- * some sanity checks first
- */
- if (irq >= NR_IRQS) {
- printk("Trying to free IRQ%d\n",irq);
+ if (irq >= NR_IRQS)
return;
- }
- irq = map_legacy_irq(irq);
-
- /*
- * Find the corresponding irqaction
- */
- spin_lock_irqsave(&irq_controller_lock, flags);
- for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now remove it from the list of entries */
- *p = action->next;
- if (!irq_desc[irq].action) {
- irq_desc[irq].status &= ~IRQ_ENABLED;
- (*irq_desc[irq].handler->shutdown)(irq);
- }
-
- spin_unlock_irqrestore(&irq_controller_lock, flags);
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ for (;;) {
+ struct irqaction * action = *p;
+ if (action) {
+ struct irqaction **pp = p;
+ p = &action->next;
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now remove it from the list of entries */
+ *pp = action->next;
+ if (!desc->action) {
+ desc->status |= IRQ_DISABLED;
+ desc->handler->shutdown(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
#ifdef CONFIG_SMP
- /* Wait to make sure it's not being used on another CPU */
- while (irq_desc[irq].status & IRQ_INPROGRESS)
- barrier();
+ /* Wait to make sure it's not being used on another CPU */
+ while (desc->status & IRQ_INPROGRESS)
+ barrier();
#endif
-
- if (action != &timer_action
-#ifdef CONFIG_SMP
- && action != &ipi_action
-#endif
- )
kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
+ spin_unlock_irqrestore(&desc->lock,flags);
return;
}
- printk("Trying to free free IRQ%d\n", irq);
}
/*
- * IRQ autodetection code. Note that the return value of
- * probe_irq_on() is no longer being used (it's role has been replaced
- * by the IRQ_AUTODETECT flag).
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
*/
-unsigned long
-probe_irq_on (void)
+unsigned long probe_irq_on(void)
{
- struct irq_desc *id;
+ unsigned int i;
+ irq_desc_t *desc;
+ unsigned long val;
unsigned long delay;
-#ifdef IA64_DEBUG
- printk("probe_irq_on() called\n");
-#endif
+ /*
+ * something may have generated an irq long ago and we want to
+ * flush such a longstanding irq before considering it as spurious.
+ */
+ for (i = NR_IRQS-1; i > 0; i--) {
+ desc = irq_desc + i;
- spin_lock_irq(&irq_controller_lock);
- for (id = irq_desc; id < irq_desc + NR_IRQS; ++id) {
- if (!id->action) {
- id->status |= IRQ_AUTODETECT | IRQ_WAITING;
- (*id->handler->startup)(id - irq_desc);
- }
+ spin_lock_irq(&desc->lock);
+ if (!irq_desc[i].action)
+ irq_desc[i].handler->startup(i);
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
- /* wait for spurious interrupts to trigger: */
+ /* Wait for longstanding interrupts to trigger. */
+ for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+ /* about 20ms delay */ synchronize_irq();
- for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
- /* about 100ms delay */
- synchronize_irq();
-
- /* filter out obviously spurious interrupts: */
- spin_lock_irq(&irq_controller_lock);
- for (id = irq_desc; id < irq_desc + NR_IRQS; ++id) {
- unsigned int status = id->status;
+ /*
+ * enable any unassigned irqs
+ * (we must startup again here because if a longstanding irq
+ * happened in the previous stage, it may have masked itself)
+ */
+ for (i = NR_IRQS-1; i > 0; i--) {
+ desc = irq_desc + i;
+
+ spin_lock_irq(&desc->lock);
+ if (!desc->action) {
+ desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+ if (desc->handler->startup(i))
+ desc->status |= IRQ_PENDING;
+ }
+ spin_unlock_irq(&desc->lock);
+ }
- if (!(status & IRQ_AUTODETECT))
- continue;
+ /*
+ * Wait for spurious interrupts to trigger
+ */
+ for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+ /* about 100ms delay */ synchronize_irq();
- if (!(status & IRQ_WAITING)) {
- id->status = status & ~IRQ_AUTODETECT;
- (*id->handler->shutdown)(id - irq_desc);
+ /*
+ * Now filter out any obviously spurious interrupts
+ */
+ val = 0;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ /* It triggered already - consider it spurious. */
+ if (!(status & IRQ_WAITING)) {
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ } else
+ if (i < 32)
+ val |= 1 << i;
}
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
- return PROBE_IRQ_COOKIE; /* return meaningless return value */
+
+ return val;
}
-int
-probe_irq_off (unsigned long cookie)
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+unsigned int probe_irq_mask(unsigned long val)
{
- int irq_found, nr_irqs;
- struct irq_desc *id;
+ int i;
+ unsigned int mask;
-#ifdef IA64_DEBUG
- printk("probe_irq_off(cookie=0x%lx) -> ", cookie);
-#endif
+ mask = 0;
+ for (i = 0; i < 16; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
- if (cookie != PROBE_IRQ_COOKIE)
- printk("bad irq probe from %p\n", __builtin_return_address(0));
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
- nr_irqs = 0;
- irq_found = 0;
- spin_lock_irq(&irq_controller_lock);
- for (id = irq_desc + IA64_MIN_VECTORED_IRQ; id < irq_desc + NR_IRQS; ++id) {
- unsigned int status = id->status;
+ if (status & IRQ_AUTODETECT) {
+ if (!(status & IRQ_WAITING))
+ mask |= 1 << i;
- if (!(status & IRQ_AUTODETECT))
- continue;
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
+ }
+ spin_unlock_irq(&desc->lock);
+ }
+
+ return mask & val;
+}
- if (!(status & IRQ_WAITING)) {
- if (!nr_irqs)
- irq_found = (id - irq_desc);
- ++nr_irqs;
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source)
+ */
+int probe_irq_off(unsigned long val)
+{
+ int i, irq_found, nr_irqs;
+
+ nr_irqs = 0;
+ irq_found = 0;
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc_t *desc = irq_desc + i;
+ unsigned int status;
+
+ spin_lock_irq(&desc->lock);
+ status = desc->status;
+
+ if (status & IRQ_AUTODETECT) {
+ if (!(status & IRQ_WAITING)) {
+ if (!nr_irqs)
+ irq_found = i;
+ nr_irqs++;
+ }
+ desc->status = status & ~IRQ_AUTODETECT;
+ desc->handler->shutdown(i);
}
- id->status = status & ~IRQ_AUTODETECT;
- (*id->handler->shutdown)(id - irq_desc);
+ spin_unlock_irq(&desc->lock);
}
- spin_unlock_irq(&irq_controller_lock);
if (nr_irqs > 1)
irq_found = -irq_found;
-
-#ifdef IA64_DEBUG
- printk("%d\n", irq_found);
-#endif
return irq_found;
}
-#ifdef CONFIG_SMP
-
-void __init
-init_IRQ_SMP (void)
+/* this was setup_x86_irq but it seems pretty generic */
+int setup_irq(unsigned int irq, struct irqaction * new)
{
- if (request_irq(IPI_IRQ, handle_IPI, 0, "IPI", NULL))
- panic("Could not allocate IPI Interrupt Handler!");
+ int shared = 0;
+ unsigned long flags;
+ struct irqaction *old, **p;
+ irq_desc_t *desc = irq_desc + irq;
+
+ /*
+ * Some drivers like serial.c use request_irq() heavily,
+ * so we have to be careful not to interfere with a
+ * running system.
+ */
+ if (new->flags & SA_SAMPLE_RANDOM) {
+ /*
+ * This function might sleep, we want to call it first,
+ * outside of the atomic block.
+ * Yes, this might clear the entropy pool if the wrong
+ * driver is attempted to be loaded, without actually
+ * installing a new handler, but is this really a problem,
+ * only the sysadmin is able to do this.
+ */
+ rand_initialize_irq(irq);
+ }
+
+ /*
+ * The following block of code has to be executed atomically
+ */
+ spin_lock_irqsave(&desc->lock,flags);
+ p = &desc->action;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ)) {
+ spin_unlock_irqrestore(&desc->lock,flags);
+ return -EBUSY;
+ }
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ *p = new;
+
+ if (!shared) {
+ desc->depth = 0;
+ desc->status &= ~IRQ_DISABLED;
+ desc->handler->startup(irq);
+ }
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ register_irq_proc(irq);
+ return 0;
}
-#endif
+static struct proc_dir_entry * root_irq_dir;
+static struct proc_dir_entry * irq_dir [NR_IRQS];
+static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
+
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
-void __init
-init_IRQ (void)
+#define HEX_DIGITS 8
+
+static int irq_affinity_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
{
+ if (count < HEX_DIGITS+1)
+ return -EINVAL;
+ return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
+}
+
+static unsigned int parse_hex_value (const char *buffer,
+ unsigned long count, unsigned long *ret)
+{
+ unsigned char hexnum [HEX_DIGITS];
+ unsigned long value;
int i;
- for (i = 0; i < IA64_MIN_VECTORED_IRQ; ++i)
- vector_to_legacy_map[irq_to_vector_map[i]] = i;
+ if (!count)
+ return -EINVAL;
+ if (count > HEX_DIGITS)
+ count = HEX_DIGITS;
+ if (copy_from_user(hexnum, buffer, count))
+ return -EFAULT;
+
+ /*
+ * Parse the first 8 characters as a hex string, any non-hex char
+ * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+ */
+ value = 0;
+
+ for (i = 0; i < count; i++) {
+ unsigned int c = hexnum[i];
- for (i = 0; i < NR_IRQS; ++i) {
- irq_desc[i].handler = &irq_type_default;
+ switch (c) {
+ case '0' ... '9': c -= '0'; break;
+ case 'a' ... 'f': c -= 'a'-10; break;
+ case 'A' ... 'F': c -= 'A'-10; break;
+ default:
+ goto out;
+ }
+ value = (value << 4) | c;
}
+out:
+ *ret = value;
+ return 0;
+}
- irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal;
-#ifdef CONFIG_SMP
- /*
- * Configure the IPI vector and handler
+static int irq_affinity_write_proc (struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int irq = (long) data, full_count = count, err;
+ unsigned long new_value;
+
+ if (!irq_desc[irq].handler->set_affinity)
+ return -EIO;
+
+ err = parse_hex_value(buffer, count, &new_value);
+
+#if CONFIG_SMP
+ /*
+ * Do not allow disabling IRQs completely - it's a too easy
+ * way to make the system unusable accidentally :-) At least
+ * one online CPU still has to be targeted.
*/
- irq_desc[IPI_IRQ].handler = &irq_type_ia64_internal;
- init_IRQ_SMP();
+ if (!(new_value & cpu_online_map))
+ return -EINVAL;
#endif
- ia64_set_pmv(1 << 16);
- ia64_set_cmcv(CMC_IRQ); /* XXX fix me */
+ irq_affinity[irq] = new_value;
+ irq_desc[irq].handler->set_affinity(irq, new_value);
- platform_irq_init(irq_desc);
+ return full_count;
+}
- /* clear TPR to enable all interrupt classes: */
- ia64_set_tpr(0);
+static int prof_cpu_mask_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ unsigned long *mask = (unsigned long *) data;
+ if (count < HEX_DIGITS+1)
+ return -EINVAL;
+ return sprintf (page, "%08lx\n", *mask);
}
-/* TBD:
- * Certain IA64 platforms can have inter-processor interrupt support.
- * This interface is supposed to default to the IA64 IPI block-based
- * mechanism if the platform doesn't provide a separate mechanism
- * for IPIs.
- * Choices : (1) Extend hw_interrupt_type interfaces
- * (2) Use machine vector mechanism
- * For now defining the following interface as a place holder.
- */
-void
-ipi_send (int cpu, int vector, int delivery_mode)
+static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+ unsigned long count, void *data)
{
+ unsigned long *mask = (unsigned long *) data, full_count = count, err;
+ unsigned long new_value;
+
+ err = parse_hex_value(buffer, count, &new_value);
+ if (err)
+ return err;
+
+ *mask = new_value;
+ return full_count;
}
+
+#define MAX_NAMELEN 10
+
+static void register_irq_proc (unsigned int irq)
+{
+ struct proc_dir_entry *entry;
+ char name [MAX_NAMELEN];
+
+ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type))
+ return;
+
+ memset(name, 0, MAX_NAMELEN);
+ sprintf(name, "%d", irq);
+
+ /* create /proc/irq/1234 */
+ irq_dir[irq] = proc_mkdir(name, root_irq_dir);
+
+ /* create /proc/irq/1234/smp_affinity */
+ entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
+
+ entry->nlink = 1;
+ entry->data = (void *)(long)irq;
+ entry->read_proc = irq_affinity_read_proc;
+ entry->write_proc = irq_affinity_write_proc;
+
+ smp_affinity_entry[irq] = entry;
+}
+
+unsigned long prof_cpu_mask = -1;
+
+void init_irq_proc (void)
+{
+ struct proc_dir_entry *entry;
+ int i;
+
+ /* create /proc/irq */
+ root_irq_dir = proc_mkdir("irq", 0);
+
+ /* create /proc/irq/prof_cpu_mask */
+ entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir);
+
+ entry->nlink = 1;
+ entry->data = (void *)&prof_cpu_mask;
+ entry->read_proc = prof_cpu_mask_read_proc;
+ entry->write_proc = prof_cpu_mask_write_proc;
+
+ /*
+ * Create entries for all existing IRQs.
+ */
+ for (i = 0; i < NR_IRQS; i++) {
+ if (irq_desc[i].handler == &no_irq_type)
+ continue;
+ register_irq_proc(i);
+ }
+}
+
diff --git a/arch/ia64/kernel/irq_default.c b/arch/ia64/kernel/irq_default.c
deleted file mode 100644
index bf8c62642..000000000
--- a/arch/ia64/kernel/irq_default.c
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include <asm/irq.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-
-
-static int
-irq_default_handle_irq (unsigned int irq, struct pt_regs *regs)
-{
- printk("Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id());
- return 0; /* don't call do_bottom_half() for spurious interrupts */
-}
-
-static void
-irq_default_noop (unsigned int irq)
-{
- /* nuthing to do... */
-}
-
-struct hw_interrupt_type irq_type_default = {
- "default",
- (void (*)(unsigned long)) irq_default_noop, /* init */
- irq_default_noop, /* startup */
- irq_default_noop, /* shutdown */
- irq_default_handle_irq, /* handle */
- irq_default_noop, /* enable */
- irq_default_noop /* disable */
-};
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
new file mode 100644
index 000000000..a2c493ba5
--- /dev/null
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -0,0 +1,247 @@
+/*
+ * linux/arch/ia64/kernel/irq.c
+ *
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 6/10/99: Updated to bring in sync with x86 version to facilitate
+ * support for SMP and different interrupt controllers.
+ */
+
+#include <linux/config.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel_stat.h>
+#include <linux/malloc.h>
+#include <linux/ptrace.h>
+#include <linux/random.h> /* for rand_initialize_irq() */
+#include <linux/signal.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/threads.h>
+
+#ifdef CONFIG_KDB
+# include <linux/kdb.h>
+#endif
+
+#include <asm/bitops.h>
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <asm/machvec.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+spinlock_t ivr_read_lock;
+#endif
+
+/*
+ * Legacy IRQ to IA-64 vector translation table. Any vector not in
+ * this table maps to itself (ie: irq 0x30 => IA64 vector 0x30)
+ */
+__u8 isa_irq_to_vector_map[IA64_MIN_VECTORED_IRQ] = {
+ /* 8259 IRQ translation, first 16 entries */
+ 0x60, 0x50, 0x0f, 0x51, 0x52, 0x53, 0x43, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x40, 0x41
+};
+
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+
+int usbfix;
+
+static int __init
+usbfix_option (char *str)
+{
+ printk("irq: enabling USB workaround\n");
+ usbfix = 1;
+ return 1;
+}
+
+__setup("usbfix", usbfix_option);
+
+#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
+
+/*
+ * That's where the IVT branches when we get an external
+ * interrupt. This branches to the correct hardware IRQ handler via
+ * function ptr.
+ */
+void
+ia64_handle_irq (unsigned long vector, struct pt_regs *regs)
+{
+ unsigned long bsp, sp, saved_tpr;
+
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+# ifndef CONFIG_SMP
+ static unsigned int max_prio = 0;
+# endif
+ unsigned int prev_prio;
+ unsigned long eoi_ptr;
+
+# ifdef CONFIG_USB
+ extern void reenable_usb (void);
+ extern void disable_usb (void);
+
+ if (usbfix)
+ disable_usb();
+# endif
+ /*
+ * Stop IPIs by getting the ivr_read_lock
+ */
+ spin_lock(&ivr_read_lock);
+
+ /*
+ * Disable PCI writes
+ */
+ outl(0x80ff81c0, 0xcf8);
+ outl(0x73002188, 0xcfc);
+ eoi_ptr = inl(0xcfc);
+
+ vector = ia64_get_ivr();
+
+ /*
+ * Enable PCI writes
+ */
+ outl(0x73182188, 0xcfc);
+
+ spin_unlock(&ivr_read_lock);
+
+# ifdef CONFIG_USB
+ if (usbfix)
+ reenable_usb();
+# endif
+
+# ifndef CONFIG_SMP
+ prev_prio = max_prio;
+ if (vector < max_prio) {
+ printk ("ia64_handle_irq: got vector %lu while %u was in progress!\n",
+ vector, max_prio);
+
+ } else
+ max_prio = vector;
+# endif /* !CONFIG_SMP */
+#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
+
+ /*
+ * Always set TPR to limit maximum interrupt nesting depth to
+ * 16 (without this, it would be ~240, which could easily lead
+ * to kernel stack overflows.
+ */
+ saved_tpr = ia64_get_tpr();
+ ia64_srlz_d();
+ ia64_set_tpr(vector);
+ ia64_srlz_d();
+
+ asm ("mov %0=ar.bsp" : "=r"(bsp));
+ asm ("mov %0=sp" : "=r"(sp));
+
+ if ((sp - bsp) < 1024) {
+ static long last_time;
+ static unsigned char count;
+
+ if (count > 5 && jiffies - last_time > 5*HZ)
+ count = 0;
+ if (++count < 5) {
+ last_time = jiffies;
+ printk("ia64_handle_irq: DANGER: less than 1KB of free stack space!!\n"
+ "(bsp=0x%lx, sp=%lx)\n", bsp, sp);
+ }
+#ifdef CONFIG_KDB
+ kdb(KDB_REASON_PANIC, 0, regs);
+#endif
+ }
+
+ /*
+ * The interrupt is now said to be in service
+ */
+ if (vector >= NR_IRQS) {
+ printk("handle_irq: invalid vector %lu\n", vector);
+ goto out;
+ }
+
+ do_IRQ(vector, regs);
+ out:
+#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
+ {
+ long pEOI;
+
+ asm ("mov %0=0;; (p1) mov %0=1" : "=r"(pEOI));
+ if (!pEOI) {
+ printk("Yikes: ia64_handle_irq() without pEOI!!\n");
+ asm volatile ("cmp.eq p1,p0=r0,r0" : "=r"(pEOI));
+# ifdef CONFIG_KDB
+ kdb(KDB_REASON_PANIC, 0, regs);
+# endif
+ }
+ }
+
+ local_irq_disable();
+# ifndef CONFIG_SMP
+ if (max_prio == vector)
+ max_prio = prev_prio;
+# endif /* !CONFIG_SMP */
+#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
+
+ ia64_srlz_d();
+ ia64_set_tpr(saved_tpr);
+ ia64_srlz_d();
+}
+
+#ifdef CONFIG_SMP
+
+void __init
+init_IRQ_SMP (void)
+{
+ if (request_irq(IPI_IRQ, handle_IPI, 0, "IPI", NULL))
+ panic("Could not allocate IPI Interrupt Handler!");
+}
+
+#endif
+
+void __init
+init_IRQ (void)
+{
+ /*
+ * Disable all local interrupts
+ */
+ ia64_set_itv(0, 1);
+ ia64_set_lrr0(0, 1);
+ ia64_set_lrr1(0, 1);
+
+ irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal;
+#ifdef CONFIG_SMP
+ /*
+ * Configure the IPI vector and handler
+ */
+ irq_desc[IPI_IRQ].handler = &irq_type_ia64_internal;
+ init_IRQ_SMP();
+#endif
+
+ ia64_set_pmv(1 << 16);
+ ia64_set_cmcv(CMC_IRQ); /* XXX fix me */
+
+ platform_irq_init();
+
+ /* clear TPR to enable all interrupt classes: */
+ ia64_set_tpr(0);
+}
+
+/* TBD:
+ * Certain IA64 platforms can have inter-processor interrupt support.
+ * This interface is supposed to default to the IA64 IPI block-based
+ * mechanism if the platform doesn't provide a separate mechanism
+ * for IPIs.
+ * Choices : (1) Extend hw_interrupt_type interfaces
+ * (2) Use machine vector mechanism
+ * For now defining the following interface as a place holder.
+ */
+void
+ipi_send (int cpu, int vector, int delivery_mode)
+{
+}
diff --git a/arch/ia64/kernel/irq_internal.c b/arch/ia64/kernel/irq_internal.c
index cc59e0c72..2b768cec1 100644
--- a/arch/ia64/kernel/irq_internal.c
+++ b/arch/ia64/kernel/irq_internal.c
@@ -6,51 +6,16 @@
*
* Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
-#include <linux/kernel.h>
-#include <linux/sched.h>
+#include <linux/irq.h>
-#include <asm/irq.h>
-#include <asm/processor.h>
-#include <asm/ptrace.h>
-
-/*
- * This is identical to IOSAPIC handle_irq. It may go away . . .
- */
-static int
-internal_handle_irq (unsigned int irq, struct pt_regs *regs)
+static unsigned int
+internal_noop_startup (unsigned int irq)
{
- struct irqaction *action = 0;
- struct irq_desc *id = irq_desc + irq;
- unsigned int status;
- int retval;
-
- spin_lock(&irq_controller_lock);
- {
- status = id->status;
- if ((status & IRQ_ENABLED) != 0)
- action = id->action;
- id->status = status & ~(IRQ_REPLAY | IRQ_WAITING);
- }
- spin_unlock(&irq_controller_lock);
-
- if (!action) {
- if (!(id->status & IRQ_AUTODETECT))
- printk("irq_hpsim_handle_irq: unexpected interrupt %u\n", irq);
- return 0;
- }
-
- retval = invoke_irq_handlers(irq, regs, action);
-
- spin_lock(&irq_controller_lock);
- {
- status = (id->status & ~IRQ_INPROGRESS);
- id->status = status;
- }
- spin_unlock(&irq_controller_lock);
-
- return retval;
+ return 0;
}
static void
@@ -60,12 +25,12 @@ internal_noop (unsigned int irq)
}
struct hw_interrupt_type irq_type_ia64_internal = {
- "IA64-internal",
- (void (*)(unsigned long)) internal_noop, /* init */
- internal_noop, /* startup */
- internal_noop, /* shutdown */
- internal_handle_irq, /* handle */
- internal_noop, /* enable */
- internal_noop /* disable */
+ typename: "IA64-internal",
+ startup: internal_noop_startup,
+ shutdown: internal_noop,
+ enable: internal_noop,
+ disable: internal_noop,
+ ack: internal_noop,
+ end: internal_noop,
+ set_affinity: (void (*)(unsigned int, unsigned long)) internal_noop
};
-
diff --git a/arch/ia64/kernel/irq_lock.c b/arch/ia64/kernel/irq_lock.c
index 4a2ead673..43afeac60 100644
--- a/arch/ia64/kernel/irq_lock.c
+++ b/arch/ia64/kernel/irq_lock.c
@@ -281,7 +281,7 @@ __global_restore_flags(unsigned long flags)
__sti();
break;
default:
- printk("global_restore_flags: %08lx (%08lx)\n",
- flags, (&flags)[-1]);
+ printk("global_restore_flags: %08lx (%08lx) from %p\n",
+ flags, (&flags)[-1], __builtin_return_address(0));
}
}
diff --git a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c
index 4acc7f041..767cfa5ce 100644
--- a/arch/ia64/kernel/pci.c
+++ b/arch/ia64/kernel/pci.c
@@ -164,13 +164,6 @@ pcibios_fixup_bus(struct pci_bus *b)
return;
}
-int
-pci_assign_resource (struct pci_dev *dev, int i)
-{
- printk("pci_assign_resource: not implemented!\n");
- return -ENODEV;
-}
-
void __init
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 274b68a73..29291e1f9 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -1,15 +1,53 @@
-#include <linux/config.h>
+/*
+ * This file contains the code to configure and read/write the ia64 performance
+ * monitoring stuff.
+ *
+ * Originaly Written by Ganesh Venkitachalam, IBM Corp.
+ * Modifications by David Mosberger-Tang, Hewlett-Packard Co.
+ * Copyright (C) 1999 Ganesh Venkitachalam <venkitac@us.ibm.com>
+ * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <asm/errno.h>
-#include <asm/irq.h>
+#include <asm/hw_irq.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
+/* Long blurb on how this works:
+ * We set dcr.pp, psr.pp, and the appropriate pmc control values with
+ * this. Notice that we go about modifying _each_ task's pt_regs to
+ * set cr_ipsr.pp. This will start counting when "current" does an
+ * _rfi_. Also, since each task's cr_ipsr.pp, and cr_ipsr is inherited
+ * across forks, we do _not_ need additional code on context
+ * switches. On stopping of the counters we dont need to go about
+ * changing every task's cr_ipsr back to where it wuz, because we can
+ * just set pmc[0]=1. But we do it anyways becuase we will probably
+ * add thread specific accounting later.
+ *
+ * The obvious problem with this is that on SMP systems, it is a bit
+ * of work (when someone wants to do it:-)) - it would be easier if we
+ * just added code to the context-switch path, but if we wanted to support
+ * per-thread accounting, the context-switch path might be long unless
+ * we introduce a flag in the task_struct. Right now, the following code
+ * will NOT work correctly on MP (for more than one reason:-)).
+ *
+ * The short answer is that to make this work on SMP, we would need
+ * to lock the run queue to ensure no context switches, send
+ * an IPI to each processor, and in that IPI handler, set processor regs,
+ * and just modify the psr bit of only the _current_ thread, since we have
+ * modified the psr bit correctly in the kernel stack for every process
+ * which is not running. Also, we need pmd arrays per-processor, and
+ * the READ_PMD command will need to get values off of other processors.
+ * IPIs are the answer, irrespective of what the question is. Might
+ * crash on SMP systems without the lock_kernel().
+ */
+
#ifdef CONFIG_PERFMON
#define MAX_PERF_COUNTER 4 /* true for Itanium, at least */
@@ -22,33 +60,12 @@
struct perfmon_counter {
unsigned long data;
- int counter_num;
+ unsigned long counter_num;
};
unsigned long pmds[MAX_PERF_COUNTER];
-struct task_struct *perf_owner;
+struct task_struct *perf_owner=NULL;
-/*
- * We set dcr.pp, psr.pp, and the appropriate pmc control values with
- * this. Notice that we go about modifying _each_ task's pt_regs to
- * set cr_ipsr.pp. This will start counting when "current" does an
- * _rfi_. Also, since each task's cr_ipsr.pp, and cr_ipsr is inherited
- * across forks, we do _not_ need additional code on context
- * switches. On stopping of the counters we dont _need_ to go about
- * changing every task's cr_ipsr back to where it wuz, because we can
- * just set pmc[0]=1. But we do it anyways becuase we will probably
- * add thread specific accounting later.
- *
- * The obvious problem with this is that on SMP systems, it is a bit
- * of work (when someone wants to do it) - it would be easier if we
- * just added code to the context-switch path. I think we would need
- * to lock the run queue to ensure no context switches, send an IPI to
- * each processor, and in that IPI handler, just modify the psr bit of
- * only the _current_ thread, since we have modified the psr bit
- * correctly in the kernel stack for every process which is not
- * running. Might crash on SMP systems without the
- * lock_kernel(). Hence the lock..
- */
asmlinkage unsigned long
sys_perfmonctl (int cmd1, int cmd2, void *ptr)
{
@@ -66,7 +83,7 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
if (!access_ok(VERIFY_READ, cptr, sizeof(struct perf_counter)*cmd2))
return -EFAULT;
- if (cmd2 >= MAX_PERF_COUNTER)
+ if (cmd2 > MAX_PERF_COUNTER)
return -EFAULT;
if (perf_owner && perf_owner != current)
@@ -91,15 +108,12 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
/*
* This is a no can do. It obviously wouldn't
* work on SMP where another process may not
- * be blocked at all.
- *
- * Perhaps we need a global predicate in the
- * leave_kernel path to control if pp should
- * be on or off?
+ * be blocked at all. We need to put in a perfmon
+ * IPI to take care of MP systems. See blurb above.
*/
lock_kernel();
for_each_task(p) {
- regs = (struct pt_regs *) (((char *)p) + IA64_STK_OFFSET) - 1;
+ regs = (struct pt_regs *) (((char *)p) + IA64_STK_OFFSET) -1 ;
ia64_psr(regs)->pp = 1;
}
unlock_kernel();
@@ -108,12 +122,18 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
break;
case READ_PMDS:
- if (cmd2 >= MAX_PERF_COUNTER)
+ if (cmd2 > MAX_PERF_COUNTER)
return -EFAULT;
if (!access_ok(VERIFY_WRITE, cptr, sizeof(struct perf_counter)*cmd2))
return -EFAULT;
+
+ /* This looks shady, but IMHO this will work fine. This is
+ * the sequence that I could come up with to avoid races
+ * with the interrupt handler. See explanation in the
+ * following comment.
+ */
+
local_irq_save(flags);
- /* XXX this looks wrong */
__asm__ __volatile__("rsm psr.pp\n");
dcr = ia64_get_dcr();
dcr &= ~IA64_DCR_PP;
@@ -121,23 +141,23 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
local_irq_restore(flags);
/*
- * We cannot touch pmc[0] to stop counting here, as
+ * We cannot write to pmc[0] to stop counting here, as
* that particular instruction might cause an overflow
- * and the mask in pmc[0] might get lost. I'm not very
+ * and the mask in pmc[0] might get lost. I'm _not_
* sure of the hardware behavior here. So we stop
* counting by psr.pp = 0. And we reset dcr.pp to
* prevent an interrupt from mucking up psr.pp in the
* meanwhile. Perfmon interrupts are pended, hence the
- * above code should be ok if one of the above
- * instructions cause overflows. Is this ok? When I
- * muck with dcr, is the cli/sti needed??
+ * above code should be ok if one of the above instructions
+ * caused overflows, i.e the interrupt should get serviced
+ * when we re-enabled interrupts. When I muck with dcr,
+ * is the irq_save/restore needed?
*/
- for (i = 0, cnum = 4; i < MAX_PERF_COUNTER; i++, cnum++, cptr++) {
+ for (i = 0, cnum = 4;i < MAX_PERF_COUNTER; i++, cnum++, cptr++){
pmd = pmds[i] + (ia64_get_pmd(cnum) & PERF_OVFL_VAL);
put_user(pmd, &cptr->data);
}
local_irq_save(flags);
- /* XXX this looks wrong */
__asm__ __volatile__("ssm psr.pp");
dcr = ia64_get_dcr();
dcr |= IA64_DCR_PP;
@@ -158,11 +178,8 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
/*
* This is a no can do. It obviously wouldn't
* work on SMP where another process may not
- * be blocked at all.
- *
- * Perhaps we need a global predicate in the
- * leave_kernel path to control if pp should
- * be on or off?
+ * be blocked at all. We need to put in a perfmon
+ * IPI to take care of MP systems. See blurb above.
*/
lock_kernel();
for_each_task(p) {
@@ -170,7 +187,7 @@ sys_perfmonctl (int cmd1, int cmd2, void *ptr)
ia64_psr(regs)->pp = 0;
}
unlock_kernel();
- perf_owner = 0;
+ perf_owner = NULL;
break;
default:
@@ -184,12 +201,12 @@ update_counters (void)
{
unsigned long mask, i, cnum, val;
- mask = ia64_get_pmd(0) >> 4;
+ mask = ia64_get_pmc(0) >> 4;
for (i = 0, cnum = 4; i < MAX_PERF_COUNTER; cnum++, i++, mask >>= 1) {
if (mask & 0x1)
val = PERF_OVFL_VAL;
else
- /* since we got an interrupt, might as well clear every pmd. */
+ /* since we got an interrupt, might as well clear every pmd. */
val = ia64_get_pmd(cnum) & PERF_OVFL_VAL;
pmds[i] += val;
ia64_set_pmd(cnum, 0);
@@ -214,10 +231,10 @@ perfmon_init (void)
}
ia64_set_pmv(PERFMON_IRQ);
ia64_srlz_d();
+ printk("Initialized perfmon vector to %u\n",PERFMON_IRQ);
}
#else /* !CONFIG_PERFMON */
-
asmlinkage unsigned long
sys_perfmonctl (int cmd1, int cmd2, void *ptr)
{
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index cc26b8760..a8c217b9a 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -99,7 +99,7 @@ cpu_idle (void *unused)
(*pm_idle)();
#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
if (ia64_get_itm() < ia64_get_itc()) {
- extern void ia64_reset_itm();
+ extern void ia64_reset_itm (void);
printk("cpu_idle: ITM in past, resetting it...\n");
ia64_reset_itm();
@@ -238,7 +238,7 @@ void
ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst)
{
struct switch_stack *sw = ((struct switch_stack *) pt) - 1;
- unsigned long ar_ec, cfm, ar_bsp, ndirty, *krbs;
+ unsigned long ar_ec, cfm, ar_bsp, ndirty, *krbs, addr;
ar_ec = (sw->ar_pfs >> 52) & 0x3f;
@@ -249,8 +249,18 @@ ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst)
}
krbs = (unsigned long *) current + IA64_RBS_OFFSET/8;
- ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 16));
- ar_bsp = (long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty);
+ ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
+ ar_bsp = (unsigned long) ia64_rse_skip_regs((long *) pt->ar_bspstore, ndirty);
+
+ /*
+ * Write portion of RSE backing store living on the kernel
+ * stack to the VM of the process.
+ */
+ for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) {
+ long val;
+ if (ia64_peek(pt, current, addr, &val) == 0)
+ access_process_vm(current, addr, &val, sizeof(val), 1);
+ }
/* r0-r31
* NaT bits (for r0-r31; bit N == 1 iff rN is a NaT)
@@ -310,7 +320,6 @@ sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs)
{
int error;
- lock_kernel();
filename = getname(filename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
@@ -318,7 +327,6 @@ sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs)
error = do_execve(filename, argv, envp, regs);
putname(filename);
out:
- unlock_kernel();
return error;
}
diff --git a/arch/ia64/kernel/semaphore.c b/arch/ia64/kernel/semaphore.c
index 84581af2e..980fa4329 100644
--- a/arch/ia64/kernel/semaphore.c
+++ b/arch/ia64/kernel/semaphore.c
@@ -138,9 +138,10 @@ __down_interruptible (struct semaphore * sem)
int
__down_trylock (struct semaphore *sem)
{
+ unsigned long flags;
int sleepers;
- spin_lock_irq(&semaphore_lock);
+ spin_lock_irqsave(&semaphore_lock, flags);
sleepers = sem->sleepers + 1;
sem->sleepers = 0;
@@ -151,7 +152,7 @@ __down_trylock (struct semaphore *sem)
if (!atomic_add_negative(sleepers, &sem->count))
wake_up(&sem->wait);
- spin_unlock_irq(&semaphore_lock);
+ spin_unlock_irqrestore(&semaphore_lock, flags);
return 1;
}
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index f3283d535..58ddb1fb1 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -101,6 +101,7 @@ void __init
setup_arch (char **cmdline_p)
{
unsigned long max_pfn, bootmap_start, bootmap_size;
+ u64 progress;
/*
* The secondary bootstrap loader passes us the boot
@@ -167,6 +168,7 @@ setup_arch (char **cmdline_p)
conswitchp = &dummy_con;
# endif
#endif
+ paging_init();
platform_setup(cmdline_p);
}
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index cfcff3063..133520b84 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -10,21 +10,17 @@
*/
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <asm/delay.h>
#include <asm/efi.h>
-#include <asm/irq.h>
-#include <asm/machvec.h>
+#include <asm/hw_irq.h>
#include <asm/ptrace.h>
#include <asm/sal.h>
#include <asm/system.h>
-#ifdef CONFIG_KDB
-# include <linux/kdb.h>
-#endif
-
extern rwlock_t xtime_lock;
extern volatile unsigned long lost_ticks;
@@ -43,8 +39,12 @@ static struct {
static void
do_profile (unsigned long ip)
{
+ extern unsigned long prof_cpu_mask;
extern char _stext;
+ if (!((1UL << smp_processor_id()) & prof_cpu_mask))
+ return;
+
if (prof_buffer && current->pid) {
ip -= (unsigned long) &_stext;
ip >>= prof_shift;
@@ -65,7 +65,7 @@ do_profile (unsigned long ip)
* update to jiffy. The xtime_lock must be at least read-locked when
* calling this routine.
*/
-static /*inline*/ unsigned long
+static inline unsigned long
gettimeoffset (void)
{
unsigned long now = ia64_get_itc();
@@ -198,7 +198,7 @@ ia64_reset_itm (void)
unsigned long flags;
local_irq_save(flags);
- timer_interrupt(0, 0, current);
+ timer_interrupt(0, 0, ia64_task_regs(current));
local_irq_restore(flags);
}
@@ -293,15 +293,19 @@ ia64_init_itm (void)
ia64_cpu_local_tick();
}
+static struct irqaction timer_irqaction = {
+ handler: timer_interrupt,
+ flags: SA_INTERRUPT,
+ name: "timer"
+};
+
void __init
time_init (void)
{
- /*
- * Request the IRQ _before_ doing anything to cause that
- * interrupt to be posted.
- */
- if (request_irq(TIMER_IRQ, timer_interrupt, 0, "timer", NULL))
- panic("Could not allocate timer IRQ!");
+ /* we can't do request_irq() here because the kmalloc() would fail... */
+ irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
+ irq_desc[TIMER_IRQ].handler = &irq_type_ia64_internal;
+ setup_irq(TIMER_IRQ, &timer_irqaction);
efi_gettimeofday(&xtime);
ia64_init_itm();
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index 1f5106036..ddb079f13 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -456,7 +456,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
case 32: /* fp fault */
case 33: /* fp trap */
- result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, &isr);
+ result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr);
if (result < 0) {
siginfo.si_signo = SIGFPE;
siginfo.si_errno = 0;
diff --git a/arch/ia64/lib/copy_page.S b/arch/ia64/lib/copy_page.S
index 0a956e5a2..7595ac83a 100644
--- a/arch/ia64/lib/copy_page.S
+++ b/arch/ia64/lib/copy_page.S
@@ -15,6 +15,9 @@
*/
#include <asm/page.h>
+#define PIPE_DEPTH 6
+#define EPI p[PIPE_DEPTH-1]
+
#define lcount r16
#define saved_pr r17
#define saved_lc r18
@@ -34,10 +37,10 @@
.proc copy_page
copy_page:
- alloc saved_pfs=ar.pfs,10,0,0,8 // we need 6 roatating (8 minimum)
- // + 2 input
+ alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7)
- .rotr t1[4], t2[4] // our 2 pipelines with depth of 4 each
+ .rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH]
+ .rotp p[PIPE_DEPTH]
mov saved_lc=ar.lc // save ar.lc ahead of time
mov saved_pr=pr // rotating predicates are preserved
@@ -53,29 +56,30 @@ copy_page:
mov pr.rot=1<<16 // pr16=1 & pr[17-63]=0 , 63 not modified
mov ar.lc=lcount // set loop counter
- mov ar.ec=4 // ar.ec must match pipeline depth
+ mov ar.ec=PIPE_DEPTH // ar.ec must match pipeline depth
;;
// We need to preload the n-1 stages of the pipeline (n=depth).
// We do this during the "prolog" of the loop: we execute
// n-1 times the "load" bundle. Then both loads & stores are
// enabled until we reach the end of the last word of the page
- // on the load side. Then, we enter the epilogue (controlled by ec)
- // where we just do the stores and no loads n-1 times : drain the pipe.
+ // on the load side. Then, we enter the epilog (controlled by ec)
+ // where we just do the stores and no loads n times : drain the pipe
+ // (we exit the loop when ec=1).
//
// The initialization of the prolog is done via the predicate registers:
- // the choice of pr19 DEPENDS on the depth of the pipeline (n).
+ // the choice of EPI DEPENDS on the depth of the pipeline (n).
// When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62
// are then shifted right at every iteration,
- // Thus by initializing pr16=1 and pr17-19=0 (19=16+4-1) before the loop
- // we get pr19=1 after 4 iterations (n in our case).
+ // Thus by initializing pr16=1 and the rest to 0 before the loop
+ // we get EPI=1 after n iterations.
//
1: // engage loop now, let the magic happen...
(p16) ld8 t1[0]=[src1],16 // new data on top of pipeline in 1st stream
(p16) ld8 t2[0]=[src2],16 // new data on top of pipeline in 2nd stream
nop.i 0x0
-(p19) st8 [tgt1]=t1[3],16 // store top of 1st pipeline
-(p19) st8 [tgt2]=t2[3],16 // store top of 2nd pipeline
+(EPI) st8 [tgt1]=t1[PIPE_DEPTH-1],16 // store top of 1st pipeline
+(EPI) st8 [tgt2]=t2[PIPE_DEPTH-1],16 // store top of 2nd pipeline
br.ctop.dptk.few 1b // once lc==0, ec-- & p16=0
// stores but no loads anymore
;;
diff --git a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S
index 58c92876f..3743174ba 100644
--- a/arch/ia64/lib/copy_user.S
+++ b/arch/ia64/lib/copy_user.S
@@ -1,3 +1,34 @@
+/*
+ *
+ * Optimized version of the copy_user() routine.
+ * It is used to copy date across the kernel/user boundary.
+ *
+ * The source and destination are always on opposite side of
+ * the boundary. When reading from user space we must catch
+ * faults on loads. When writing to user space we must catch
+ * errors on stores. Note that because of the nature of the copy
+ * we don't need to worry about overlapping regions.
+ *
+ *
+ * Inputs:
+ * in0 address of source buffer
+ * in1 address of destination buffer
+ * in2 number of bytes to copy
+ *
+ * Outputs:
+ * ret0 0 in case of sucess. The number of bytes NOT copied in
+ * case of error.
+ *
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * Fixme:
+ * - handle the case where we have more than 16 bytes and the alignment
+ * are different.
+ * - more benchmarking
+ * - fix extraneous stop bit introduced by the EX() macro.
+ */
+
// The label comes first because our store instruction contains a comma
// and confuse the preprocessor otherwise
//
diff --git a/arch/ia64/lib/strncpy_from_user.S b/arch/ia64/lib/strncpy_from_user.S
index 17f71f1a0..f2d40984a 100644
--- a/arch/ia64/lib/strncpy_from_user.S
+++ b/arch/ia64/lib/strncpy_from_user.S
@@ -1,6 +1,5 @@
/*
- * Just like strncpy() except for the return value. If no fault occurs during
- * the copying, the number of bytes copied is returned. If a fault occurs,
+ * Just like strncpy() except that if a fault occurs during copying,
* -EFAULT is returned.
*
* Inputs:
@@ -10,8 +9,11 @@
* Outputs:
* r8: -EFAULT in case of fault or number of bytes copied if no fault
*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 00/03/06 D. Mosberger Fixed to return proper return value (bug found by
+ * by Andreas Schwab <schwab@suse.de>).
*/
#define EX(x...) \
@@ -30,24 +32,26 @@
.global __strncpy_from_user
.proc __strncpy_from_user
__strncpy_from_user:
- alloc r11=ar.pfs,3,0,0,0
+ alloc r2=ar.pfs,3,0,0,0
+ mov r8=0
mov r9=in1
+ ;;
add r10=in1,in2
+ cmp.eq p6,p0=r0,in2
+(p6) br.ret.spnt.many rp
// XXX braindead copy loop---this needs to be optimized
.Loop1:
- EX(ld1 r8=[in1],1)
+ EX(ld1 r8=[in1],1;; st1 [in0]=r8,1; cmp.ne p6,p7=r8,r0)
;;
- st1 [in0]=r8,1
- cmp.ltu p6,p0=in1,r10
+(p6) cmp.ne.unc p8,p0=in1,r10
+(p8) br.cond.dpnt.few .Loop1
;;
-(p6) cmp.ne.and p6,p0=r8,r0
- ;;
-(p6) br.cond.dpnt.few .Loop1
+(p6) mov r8=in2 // buffer filled up---return buffer length
+(p7) sub r8=in1,r9,1 // return string length (excluding NUL character)
+ br.ret.sptk.few rp
-1: sub r8=in1,r9 // length of string (including NUL character)
.Lexit:
- mov ar.pfs=r11
br.ret.sptk.few rp
.endp __strncpy_from_user
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 388f1fe0c..3a630ca8c 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -241,13 +241,13 @@ put_gate_page (struct page *page, unsigned long address)
pmd = pmd_alloc(pgd, address);
if (!pmd) {
__free_page(page);
- oom(current);
+ panic("Out of memory.");
return 0;
}
pte = pte_alloc(pmd, address);
if (!pte) {
__free_page(page);
- oom(current);
+ panic("Out of memory.");
return 0;
}
if (!pte_none(*pte)) {
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index 72ece4147..568f7a347 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -97,7 +97,7 @@ __flush_tlb_all (void)
stride0 = ia64_ptce_info.stride[0];
stride1 = ia64_ptce_info.stride[1];
- save_and_cli(flags);
+ __save_and_cli(flags);
for (i = 0; i < count0; ++i) {
for (j = 0; j < count1; ++j) {
asm volatile ("ptc.e %0" :: "r"(addr));
@@ -105,7 +105,7 @@ __flush_tlb_all (void)
}
addr += stride0;
}
- restore_flags(flags);
+ __restore_flags(flags);
ia64_insn_group_barrier();
ia64_srlz_i(); /* srlz.i implies srlz.d */
ia64_insn_group_barrier();
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 189a2126b..c26394e33 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.42 2000/02/24 00:12:40 ralf Exp $
+# $Id: config.in,v 1.43 2000/03/12 10:07:55 harald Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
@@ -272,7 +272,7 @@ fi
source drivers/usb/Config.in
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
source fs/Config.in
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index bec96e794..1fda5e771 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -177,7 +177,6 @@ CONFIG_SCSI_CONSTANTS=y
#
CONFIG_SCSI_SGIWD93=y
CONFIG_SCSI_SGIWD93=y
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -270,7 +269,6 @@ CONFIG_PSMOUSE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
#
# Video For Linux
@@ -294,10 +292,6 @@ CONFIG_PSMOUSE=y
# CONFIG_USB is not set
#
-# Misc devices
-#
-
-#
# File systems
#
# CONFIG_QUOTA is not set
diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation
index 4cc592e43..0eda6e9fc 100644
--- a/arch/mips/defconfig-decstation
+++ b/arch/mips/defconfig-decstation
@@ -177,6 +177,8 @@ CONFIG_SCSI_CONSTANTS=y
#
CONFIG_SCSI_DECNCR=y
# CONFIG_SCSI_DECSII is not set
+CONFIG_SCSI_DECNCR=y
+# CONFIG_SCSI_DECSII is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -211,7 +213,6 @@ CONFIG_SCSI_DECNCR=y
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_DEBUG is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
#
# I2O device support
@@ -243,6 +244,7 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_UNIX98_PTYS is not set
# CONFIG_KEYBOARD is not set
# CONFIG_MOUSE is not set
+# CONFIG_RTC is not set
#
# USB support
@@ -250,10 +252,6 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_USB is not set
#
-# Misc devices
-#
-
-#
# File systems
#
# CONFIG_QUOTA is not set
diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22
index 5516700c1..1fda5e771 100644
--- a/arch/mips/defconfig-ip22
+++ b/arch/mips/defconfig-ip22
@@ -176,6 +176,7 @@ CONFIG_SCSI_CONSTANTS=y
# SCSI low-level drivers
#
CONFIG_SCSI_SGIWD93=y
+CONFIG_SCSI_SGIWD93=y
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -210,7 +211,6 @@ CONFIG_SCSI_SGIWD93=y
# CONFIG_SCSI_U14_34F is not set
# CONFIG_SCSI_ULTRASTOR is not set
# CONFIG_SCSI_DEBUG is not set
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
#
# I2O device support
@@ -292,10 +292,6 @@ CONFIG_PSMOUSE=y
# CONFIG_USB is not set
#
-# Misc devices
-#
-
-#
# File systems
#
# CONFIG_QUOTA is not set
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 0d0fac150..eca74b629 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.25 2000/03/07 15:45:28 ralf Exp $
+/* $Id: sysirix.c,v 1.26 2000/03/12 23:15:33 ralf Exp $
*
* sysirix.c: IRIX system call emulation.
*
@@ -725,8 +725,6 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
int len, int fs_type)
{
struct dentry *dentry;
- struct inode *inode;
- mm_segment_t old_fs;
struct statfs kbuf;
int error, i;
@@ -745,11 +743,7 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
if (IS_ERR(dentry))
goto out;
- inode = dentry->d_inode;
- old_fs = get_fs(); set_fs(get_ds());
- error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
- sizeof(struct statfs));
- set_fs(old_fs);
+ error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
if (error)
goto dput_and_out;
@@ -775,9 +769,7 @@ out:
asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
{
- struct inode *inode;
struct statfs kbuf;
- mm_segment_t old_fs;
struct file *file;
int error, i;
@@ -790,23 +782,7 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
goto out;
}
- if (!(inode = file->f_dentry->d_inode)) {
- error = -ENOENT;
- goto out_f;
- }
- if (!inode->i_sb) {
- error = -ENODEV;
- goto out_f;
- }
- if (!inode->i_sb->s_op->statfs) {
- error = -ENOSYS;
- goto out_f;
- }
-
- old_fs = get_fs(); set_fs(get_ds());
- error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
- sizeof(struct statfs));
- set_fs(old_fs);
+ error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
if (error)
goto out_f;
@@ -1507,8 +1483,6 @@ struct irix_statvfs {
asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
{
struct dentry *dentry;
- struct inode *inode;
- mm_segment_t old_fs;
struct statfs kbuf;
int error, i;
@@ -1522,16 +1496,7 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
error = PTR_ERR(dentry);
if(!IS_ERR(dentry))
goto out;
- inode = dentry->d_inode;
-
- error = -ENOSYS;
- if(!inode->i_sb->s_op->statfs)
- goto dput_and_out;
-
- old_fs = get_fs(); set_fs(get_ds());
- error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
- sizeof(struct statfs));
- set_fs(old_fs);
+ error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
if (error)
goto dput_and_out;
@@ -1566,8 +1531,6 @@ out:
asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
{
- struct inode *inode;
- mm_segment_t old_fs;
struct statfs kbuf;
struct file *file;
int error, i;
@@ -1583,23 +1546,7 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
error = -EBADF;
goto out;
}
- if (!(inode = file->f_dentry->d_inode)) {
- error = -ENOENT;
- goto out_f;
- }
- if (!inode->i_sb) {
- error = -ENODEV;
- goto out_f;
- }
- if (!inode->i_sb->s_op->statfs) {
- error = -ENOSYS;
- goto out_f;
- }
-
- old_fs = get_fs(); set_fs(get_ds());
- error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
- sizeof(struct statfs));
- set_fs(old_fs);
+ error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
if (error)
goto out_f;
@@ -1811,8 +1758,6 @@ struct irix_statvfs64 {
asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
{
struct dentry *dentry;
- struct inode *inode;
- mm_segment_t old_fs;
struct statfs kbuf;
int error, i;
@@ -1826,15 +1771,7 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
error = PTR_ERR(dentry);
if(IS_ERR(dentry))
goto out;
- error = -ENOSYS;
- inode = dentry->d_inode;
- if(!inode->i_sb->s_op->statfs)
- goto dput_and_out;
-
- old_fs = get_fs(); set_fs(get_ds());
- error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
- sizeof(struct statfs));
- set_fs(old_fs);
+ error = vfs_statfs(dentry->d_inode->i_sb, &kbuf);
if (error)
goto dput_and_out;
@@ -1869,8 +1806,6 @@ out:
asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
{
- struct inode *inode;
- mm_segment_t old_fs;
struct statfs kbuf;
struct file *file;
int error, i;
@@ -1886,23 +1821,7 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
error = -EBADF;
goto out;
}
- if (!(inode = file->f_dentry->d_inode)) {
- error = -ENOENT;
- goto out_f;
- }
- if (!inode->i_sb) {
- error = -ENODEV;
- goto out_f;
- }
- if (!inode->i_sb->s_op->statfs) {
- error = -ENOSYS;
- goto out_f;
- }
-
- old_fs = get_fs(); set_fs(get_ds());
- error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
- sizeof(struct statfs));
- set_fs(old_fs);
+ error = vfs_statfs(file->f_dentry->d_inode->i_sb, &kbuf);
if (error)
goto out_f;
diff --git a/arch/mips64/config.in b/arch/mips64/config.in
index 179f4f74d..be0501f60 100644
--- a/arch/mips64/config.in
+++ b/arch/mips64/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.14 2000/02/18 11:06:20 ulfc Exp $
+# $Id: config.in,v 1.15 2000/03/09 15:38:28 ralf Exp $
#
# For a description of the syntax of this configuration file,
# see the Configure script.
@@ -174,7 +174,6 @@ source drivers/char/Config.in
source drivers/usb/Config.in
-# drivers/misc has currently only i386 specific devices.
#source drivers/misc/Config.in
source fs/Config.in
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index 21623e01f..f34f2e63a 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -54,7 +54,9 @@ CONFIG_BINFMT_ELF32=y
#
# Loadable module support
#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
CONFIG_PCI_NAMES=y
#
@@ -112,6 +114,7 @@ CONFIG_SKB_LARGE=y
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
#
# Telephony Support
@@ -144,6 +147,7 @@ CONFIG_SD_EXTRA_DEVS=40
#
# SCSI low-level drivers
#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -306,7 +310,6 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
#
# Video For Linux
@@ -389,5 +392,6 @@ CONFIG_KCORE_ELF=y
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
+# CONFIG_MIPS_FPE_MODULE is not set
# CONFIG_REMOTE_DEBUG is not set
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index 21623e01f..f34f2e63a 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -54,7 +54,9 @@ CONFIG_BINFMT_ELF32=y
#
# Loadable module support
#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
CONFIG_PCI_NAMES=y
#
@@ -112,6 +114,7 @@ CONFIG_SKB_LARGE=y
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
#
# Telephony Support
@@ -144,6 +147,7 @@ CONFIG_SD_EXTRA_DEVS=40
#
# SCSI low-level drivers
#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
@@ -306,7 +310,6 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
#
# Video For Linux
@@ -389,5 +392,6 @@ CONFIG_KCORE_ELF=y
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
+# CONFIG_MIPS_FPE_MODULE is not set
# CONFIG_REMOTE_DEBUG is not set
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/mips64/kernel/mips64_ksyms.c b/arch/mips64/kernel/mips64_ksyms.c
index eb1317ca3..e74eb781a 100644
--- a/arch/mips64/kernel/mips64_ksyms.c
+++ b/arch/mips64/kernel/mips64_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: mips64_ksyms.c,v 1.7 2000/02/04 07:40:24 ralf Exp $
+/* $Id: mips64_ksyms.c,v 1.8 2000/02/24 00:12:41 ralf Exp $
*
* Export MIPS64-specific functions needed for loadable modules.
*
@@ -56,8 +56,6 @@ EXPORT_SYMBOL_NOVERS(strtok);
EXPORT_SYMBOL_NOVERS(strpbrk);
EXPORT_SYMBOL(_clear_page);
-EXPORT_SYMBOL(local_bh_count);
-EXPORT_SYMBOL(local_irq_count);
EXPORT_SYMBOL(enable_irq);
EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(kernel_thread);
@@ -83,8 +81,10 @@ EXPORT_SYMBOL(csum_partial_copy);
*/
EXPORT_SYMBOL(_flush_page_to_ram);
EXPORT_SYMBOL(_flush_cache_all);
+#ifndef CONFIG_COHERENT_IO
EXPORT_SYMBOL(_dma_cache_wback_inv);
EXPORT_SYMBOL(_dma_cache_inv);
+#endif
EXPORT_SYMBOL(invalid_pte_table);
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 6b8378839..604205565 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -53,7 +53,6 @@ GZIP_FLAGS = -v9f
OBJECTS := head.o misc.o ../coffboot/zlib.o
CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin
-OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O elf32-powerpc
OBJECTS += vreset.o kbd.o of1275.o
diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile
index 5a7f063fc..216b289ed 100644
--- a/arch/ppc/chrpboot/Makefile
+++ b/arch/ppc/chrpboot/Makefile
@@ -18,7 +18,6 @@
CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
LD_ARGS = -Ttext 0x00400000
-OBJCOPY = $(CROSS_COMPILE)objcopy
OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o sysmap.o
LIBS = $(TOPDIR)/lib/lib.a
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
index 29a4fdc35..5c46f9540 100644
--- a/arch/ppc/coffboot/Makefile
+++ b/arch/ppc/coffboot/Makefile
@@ -5,14 +5,10 @@
HOSTCFLAGS = -O -I$(TOPDIR)/include
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
CFLAGS = $(CPPFLAGS) -O -fno-builtin
-OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
CHRP_LD_ARGS = -Ttext 0x00400000
-GZ = gzip -9
COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o
diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig
index c849bac82..bcab91ec6 100644
--- a/arch/ppc/configs/common_defconfig
+++ b/arch/ppc/configs/common_defconfig
@@ -1,5 +1,5 @@
#
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
#
# CONFIG_UID16 is not set
@@ -33,7 +33,6 @@ CONFIG_KMOD=y
#
# General setup
#
-# CONFIG_PCI is not set
CONFIG_PCI=y
CONFIG_PCI=y
CONFIG_NET=y
@@ -46,6 +45,10 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_PCI_NAMES is not set
# CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
CONFIG_VGA_CONSOLE=y
CONFIG_FB=y
@@ -53,6 +56,7 @@ CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
CONFIG_MAC_FLOPPY=y
CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
CONFIG_ADB=y
CONFIG_ADB_CUDA=y
CONFIG_ADB_MACIO=y
@@ -69,27 +73,21 @@ CONFIG_BOOTX_TEXT=y
# Plug and Play configuration
#
# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
CONFIG_BLK_DEV_IDEFLOPPY=y
CONFIG_BLK_DEV_IDESCSI=y
-
-#
-# IDE chipset support/bugfixes
-#
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEPCI=y
@@ -108,10 +106,6 @@ CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_AUTO=y
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
@@ -144,18 +138,10 @@ CONFIG_IP_MULTICAST=y
# CONFIG_IP_MROUTE is not set
CONFIG_IP_ALIAS=y
CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
-
-#
-#
-#
# CONFIG_IPX is not set
CONFIG_ATALK=m
# CONFIG_DECNET is not set
@@ -177,10 +163,6 @@ CONFIG_ATALK=m
# SCSI support
#
CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
@@ -189,10 +171,6 @@ CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_SR_EXTRA_DEVS=2
CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
@@ -272,6 +250,13 @@ CONFIG_NETDEVICES=y
# ARCnet devices
#
# CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_IPDDP is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -299,6 +284,7 @@ CONFIG_PCNET32=y
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
# CONFIG_TULIP is not set
# CONFIG_DGRS is not set
@@ -324,13 +310,6 @@ CONFIG_DE4X5=y
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
CONFIG_PPP=y
# CONFIG_PPP_ASYNC is not set
# CONFIG_PPP_SYNC_TTY is not set
@@ -344,7 +323,7 @@ CONFIG_PPP=y
# CONFIG_NET_RADIO is not set
#
-# Token Ring driver support
+# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
@@ -397,7 +376,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y
CONFIG_FB_MATROX_G100=y
# CONFIG_FB_MATROX_MULTIHEAD is not set
CONFIG_FB_ATY=y
-# CONFIG_FB_ATY128 is not set
+CONFIG_FB_ATY128=y
CONFIG_FB_3DFX=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
@@ -456,7 +435,6 @@ CONFIG_PSMOUSE=y
# CONFIG_WATCHDOG is not set
CONFIG_NVRAM=y
# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
#
# Video For Linux
@@ -471,28 +449,17 @@ CONFIG_NVRAM=y
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
# CONFIG_AGP is not set
#
# USB support
#
CONFIG_USB=y
-
-#
-# USB Controllers
-#
# CONFIG_USB_UHCI is not set
# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=y
-
-#
-# Miscellaneous USB options
-#
# CONFIG_USB_DEVICEFS is not set
-
-#
-# USB Devices
-#
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_SCANNER is not set
# CONFIG_USB_AUDIO is not set
@@ -503,14 +470,11 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_OV511 is not set
# CONFIG_USB_DC2XX is not set
# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_USS720 is not set
# CONFIG_USB_DABUSB is not set
# CONFIG_USB_PLUSB is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RIO500 is not set
-
-#
-# USB HID
-#
# CONFIG_USB_HID is not set
CONFIG_USB_KBD=y
CONFIG_USB_MOUSE=y
@@ -546,6 +510,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -559,6 +524,7 @@ CONFIG_EXT2_FS=y
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
@@ -630,7 +596,6 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
# CONFIG_SOUND_AD1816 is not set
# CONFIG_SOUND_SGALAXY is not set
CONFIG_SOUND_CS4232=m
@@ -643,7 +608,9 @@ CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_NM256 is not set
# CONFIG_SOUND_MAD16 is not set
# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
# CONFIG_SOUND_PSS is not set
+# CONFIG_PSS_HAVE_BOOT is not set
# CONFIG_SOUND_SOFTOSS is not set
# CONFIG_SOUND_SB is not set
# CONFIG_SOUND_WAVEFRONT is not set
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
index c849bac82..bcab91ec6 100644
--- a/arch/ppc/defconfig
+++ b/arch/ppc/defconfig
@@ -1,5 +1,5 @@
#
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
#
# CONFIG_UID16 is not set
@@ -33,7 +33,6 @@ CONFIG_KMOD=y
#
# General setup
#
-# CONFIG_PCI is not set
CONFIG_PCI=y
CONFIG_PCI=y
CONFIG_NET=y
@@ -46,6 +45,10 @@ CONFIG_KERNEL_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_PCI_NAMES is not set
# CONFIG_HOTPLUG is not set
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
CONFIG_VGA_CONSOLE=y
CONFIG_FB=y
@@ -53,6 +56,7 @@ CONFIG_FB_COMPAT_XPMAC=y
CONFIG_PMAC_PBOOK=y
CONFIG_MAC_FLOPPY=y
CONFIG_MAC_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
CONFIG_ADB=y
CONFIG_ADB_CUDA=y
CONFIG_ADB_MACIO=y
@@ -69,27 +73,21 @@ CONFIG_BOOTX_TEXT=y
# Plug and Play configuration
#
# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
# CONFIG_BLK_DEV_HD_IDE is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
CONFIG_BLK_DEV_IDECD=y
# CONFIG_BLK_DEV_IDETAPE is not set
CONFIG_BLK_DEV_IDEFLOPPY=y
CONFIG_BLK_DEV_IDESCSI=y
-
-#
-# IDE chipset support/bugfixes
-#
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEPCI=y
@@ -108,10 +106,6 @@ CONFIG_BLK_DEV_IDEDMA=y
CONFIG_IDEDMA_AUTO=y
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_BLK_CPQ_DA is not set
-
-#
-# Additional Block Devices
-#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_MD is not set
@@ -144,18 +138,10 @@ CONFIG_IP_MULTICAST=y
# CONFIG_IP_MROUTE is not set
CONFIG_IP_ALIAS=y
CONFIG_SYN_COOKIES=y
-
-#
-# (it is safe to leave these untouched)
-#
CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
-
-#
-#
-#
# CONFIG_IPX is not set
CONFIG_ATALK=m
# CONFIG_DECNET is not set
@@ -177,10 +163,6 @@ CONFIG_ATALK=m
# SCSI support
#
CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
CONFIG_CHR_DEV_ST=y
@@ -189,10 +171,6 @@ CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_SR_EXTRA_DEVS=2
CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
@@ -272,6 +250,13 @@ CONFIG_NETDEVICES=y
# ARCnet devices
#
# CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_LTPC is not set
+# CONFIG_COPS is not set
+# CONFIG_IPDDP is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -299,6 +284,7 @@ CONFIG_PCNET32=y
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_AC3200 is not set
# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
CONFIG_DE4X5=y
# CONFIG_TULIP is not set
# CONFIG_DGRS is not set
@@ -324,13 +310,6 @@ CONFIG_DE4X5=y
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_LTPC is not set
-# CONFIG_COPS is not set
-# CONFIG_IPDDP is not set
CONFIG_PPP=y
# CONFIG_PPP_ASYNC is not set
# CONFIG_PPP_SYNC_TTY is not set
@@ -344,7 +323,7 @@ CONFIG_PPP=y
# CONFIG_NET_RADIO is not set
#
-# Token Ring driver support
+# Token Ring devices
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
@@ -397,7 +376,7 @@ CONFIG_FB_MATROX_MYSTIQUE=y
CONFIG_FB_MATROX_G100=y
# CONFIG_FB_MATROX_MULTIHEAD is not set
CONFIG_FB_ATY=y
-# CONFIG_FB_ATY128 is not set
+CONFIG_FB_ATY128=y
CONFIG_FB_3DFX=y
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FBCON_ADVANCED is not set
@@ -456,7 +435,6 @@ CONFIG_PSMOUSE=y
# CONFIG_WATCHDOG is not set
CONFIG_NVRAM=y
# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
#
# Video For Linux
@@ -471,28 +449,17 @@ CONFIG_NVRAM=y
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
+# CONFIG_DRM_TDFX is not set
# CONFIG_AGP is not set
#
# USB support
#
CONFIG_USB=y
-
-#
-# USB Controllers
-#
# CONFIG_USB_UHCI is not set
# CONFIG_USB_UHCI_ALT is not set
CONFIG_USB_OHCI=y
-
-#
-# Miscellaneous USB options
-#
# CONFIG_USB_DEVICEFS is not set
-
-#
-# USB Devices
-#
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_SCANNER is not set
# CONFIG_USB_AUDIO is not set
@@ -503,14 +470,11 @@ CONFIG_USB_OHCI=y
# CONFIG_USB_OV511 is not set
# CONFIG_USB_DC2XX is not set
# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_USS720 is not set
# CONFIG_USB_DABUSB is not set
# CONFIG_USB_PLUSB is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RIO500 is not set
-
-#
-# USB HID
-#
# CONFIG_USB_HID is not set
CONFIG_USB_KBD=y
CONFIG_USB_MOUSE=y
@@ -546,6 +510,7 @@ CONFIG_ISO9660_FS=y
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -559,6 +524,7 @@ CONFIG_EXT2_FS=y
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
@@ -630,7 +596,6 @@ CONFIG_DMASOUND=y
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_OSS=y
-# CONFIG_SOUND_DMAP is not set
# CONFIG_SOUND_AD1816 is not set
# CONFIG_SOUND_SGALAXY is not set
CONFIG_SOUND_CS4232=m
@@ -643,7 +608,9 @@ CONFIG_SOUND_CS4232=m
# CONFIG_SOUND_NM256 is not set
# CONFIG_SOUND_MAD16 is not set
# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
# CONFIG_SOUND_PSS is not set
+# CONFIG_PSS_HAVE_BOOT is not set
# CONFIG_SOUND_SOFTOSS is not set
# CONFIG_SOUND_SB is not set
# CONFIG_SOUND_WAVEFRONT is not set
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
index d55fa24c0..c692b54d0 100644
--- a/arch/ppc/kernel/chrp_time.c
+++ b/arch/ppc/kernel/chrp_time.c
@@ -173,7 +173,7 @@ void __init chrp_calibrate_decr(void)
}
freq *= 30;
divisor = 30;
- printk("time_init: decrementer frequency = %lu/%d (%d MHz)\n", freq,
+ printk("time_init: decrementer frequency = %lu/%d (%ld MHz)\n", freq,
divisor, (freq/divisor)>>20);
decrementer_count = freq / HZ / divisor;
count_period_num = divisor;
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index f8e11ecc0..e4b279032 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -677,7 +677,7 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
err = parse_hex_value(buffer, count, &new_value);
-#if CONFIG_SMP
+#if 0/*CONFIG_SMP*/
/*
* Do not allow disabling IRQs completely - it's a too easy
* way to make the system unusable accidentally :-) At least
diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
index 301a82ba8..9438c57ee 100644
--- a/arch/ppc/kernel/open_pic.c
+++ b/arch/ppc/kernel/open_pic.c
@@ -97,7 +97,7 @@ struct hw_interrupt_type open_pic = {
#define check_arg_cpu(cpu) do {} while (0)
#endif
-static void no_action(int ir1, void *dev, struct pt_regs *regs)
+void no_action(int ir1, void *dev, struct pt_regs *regs)
{
}
@@ -301,7 +301,7 @@ void find_ISUs(void)
NumSources = 0x10;
#else
/* for non-distributed OpenPIC implementations it's in the IDU -- Cort */
- ISU = OpenPIC->Source;
+ ISU = (OpenPIC_Source *)OpenPIC->Source;
#endif
}
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
index 310e301e6..a987b8fd6 100644
--- a/arch/ppc/kernel/prom.c
+++ b/arch/ppc/kernel/prom.c
@@ -114,9 +114,6 @@ static struct device_node *allnodes = 0;
static void clearscreen(void);
static void flushscreen(void);
-void prom_drawchar(char c);
-void prom_drawstring(const char *c);
-void prom_drawhex(unsigned long v);
static void scrollscreen(void);
static void draw_byte(unsigned char c, long locX, long locY);
diff --git a/arch/ppc/mbxboot/Makefile b/arch/ppc/mbxboot/Makefile
index 0a70462a7..59b95c5df 100644
--- a/arch/ppc/mbxboot/Makefile
+++ b/arch/ppc/mbxboot/Makefile
@@ -27,11 +27,9 @@ ISZ = 0
TFTPIMAGE=/tftpboot/zImage.mbx
ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000
-GZIP_FLAGS = -v9
OBJECTS := head.o misc.o ../coffboot/zlib.o m8xx_tty.o
CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -DCONFIG_8xx
-OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O elf32-powerpc
ifeq ($(CONFIG_MBX),y)
diff --git a/arch/ppc/treeboot/Makefile b/arch/ppc/treeboot/Makefile
index f84810e1e..7d42a6741 100644
--- a/arch/ppc/treeboot/Makefile
+++ b/arch/ppc/treeboot/Makefile
@@ -10,11 +10,6 @@
HOSTCFLAGS = -O -I$(TOPDIR)/include
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
-OBJCOPY = $(CROSS_COMPILE)objcopy
-OBJDUMP = $(CROSS_COMPILE)objdump
-
GZIP = gzip -vf9
RM = rm -f
MKEVIMG = mkevimg -l
diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
index 620df9aea..b81e21890 100644
--- a/arch/ppc/xmon/xmon.c
+++ b/arch/ppc/xmon/xmon.c
@@ -7,6 +7,7 @@
#include <linux/sched.h>
#include <asm/ptrace.h>
#include <asm/string.h>
+#include <asm/prom.h>
#include "nonstdio.h"
#include "privinst.h"
@@ -81,7 +82,7 @@ static void insert_bpts(void);
static struct bpt *at_breakpoint(unsigned pc);
static void bpt_cmds(void);
static void cacheflush(void);
-static char *pretty_lookup_name(unsigned long addr);
+static char *pretty_print_addr(unsigned long addr);
static char *lookup_name(unsigned long addr);
extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned);
@@ -141,7 +142,7 @@ xmon(struct pt_regs *excp)
prom_drawstring(" msr="); prom_drawhex(excp->msr);
prom_drawstring(" trap="); prom_drawhex(excp->trap);
prom_drawstring(" sp="); prom_drawhex(excp->gpr[1]);
- sp = &excp->gpr[0];
+ sp = (unsigned *)&excp->gpr[0];
for (i = 0; i < 32; ++i) {
if ((i & 7) == 0)
prom_drawstring("\n");
@@ -544,10 +545,10 @@ getsp()
void
excprint(struct pt_regs *fp)
{
- printf("vector: %x at pc = %x %s",
- fp->trap, fp->nip, pretty_lookup_name(fp->nip));
- printf(", msr = %x, sp = %x [%x]\n",
- fp->msr, fp->gpr[1], fp);
+ printf("vector: %x at pc = %x",
+ fp->trap, fp->nip);
+ printf(", lr = %x, msr = %x, sp = %x [%x]\n",
+ fp->link, fp->msr, fp->gpr[1], fp);
if (fp->trap == 0x300 || fp->trap == 0x600)
printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
if (current)
@@ -1385,25 +1386,14 @@ char *str;
lineptr = str;
}
-/*
- * We use this array a lot here. We assume we don't have multiple
- * instances of xmon running and that we don't use the return value of
- * any functions other than printing them.
- * -- Cort
- */
-char last[64];
-static char *pretty_lookup_name(unsigned long addr)
+static char *pretty_print_addr(unsigned long addr)
{
+ printf("%08x", addr);
if ( lookup_name(addr) )
- {
- sprintf(last, " (%s)", lookup_name(addr));
- return last;
- }
- else
- return NULL;
+ printf(" %s", lookup_name(addr) );
+ return NULL;
}
-
static char *lookup_name(unsigned long addr)
{
extern char *sysmap;
@@ -1413,11 +1403,8 @@ static char *lookup_name(unsigned long addr)
if ( !sysmap || !sysmap_size )
return NULL;
-
- /* adjust if addr is relative to kernelbase */
- if ( addr < PAGE_OFFSET )
- addr += PAGE_OFFSET;
-
+return NULL;
+#if 0
cmp = simple_strtoul(c, &c, 8);
strcpy( last, strsep( &c, "\n"));
while ( c < (sysmap+sysmap_size) )
@@ -1427,6 +1414,7 @@ static char *lookup_name(unsigned long addr)
break;
strcpy( last, strsep( &c, "\n"));
}
- return last;
+ return NULLlast;
+#endif
}
diff --git a/arch/sh/config.in b/arch/sh/config.in
index 8b74eeafa..fd858e00e 100644
--- a/arch/sh/config.in
+++ b/arch/sh/config.in
@@ -155,7 +155,7 @@ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
source drivers/char/pcmcia/Config.in
fi
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
source fs/Config.in
diff --git a/arch/sh/defconfig b/arch/sh/defconfig
index 5fabcdedc..ea5851d39 100644
--- a/arch/sh/defconfig
+++ b/arch/sh/defconfig
@@ -96,10 +96,6 @@ CONFIG_SERIAL_CONSOLE=y
# CONFIG_UNIX98_PTYS is not set
#
-# Misc devices
-#
-
-#
# Filesystems
#
# CONFIG_QUOTA is not set
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 580d004d7..e719d9214 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -83,6 +83,10 @@ CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
CONFIG_SUNOS_EMUL=y
+
+#
+# Parallel port support
+#
# CONFIG_PARPORT is not set
# CONFIG_PRINTER is not set
@@ -146,7 +150,6 @@ CONFIG_ATALK=m
CONFIG_DECNET=m
CONFIG_DECNET_SIOCGIFCONF=y
# CONFIG_DECNET_ROUTER is not set
-CONFIG_DECNET_RAW=y
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index d4585d9d5..e0bb41045 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.93 2000/02/26 11:02:45 anton Exp $
+/* $Id: sparc_ksyms.c,v 1.94 2000/02/28 04:00:53 anton Exp $
* arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -107,16 +107,10 @@ EXPORT_SYMBOL_PRIVATE(_rw_read_exit);
EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
#endif
#ifdef __SMP__
-#ifdef DEBUG_IRQLOCK
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_cli);
-#else
-EXPORT_SYMBOL_PRIVATE(_global_restore_flags);
-EXPORT_SYMBOL_PRIVATE(_global_sti);
-EXPORT_SYMBOL_PRIVATE(_global_cli);
-#endif
#endif
/* rw semaphores */
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 54c701768..1d6f208f6 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.113 2000/02/16 07:31:29 davem Exp $
+/* $Id: sys_sunos.c,v 1.114 2000/03/07 22:27:27 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 1a8c404e2..d269e148b 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.31 1999/12/28 11:50:39 jj Exp $
+# $Id: Makefile,v 1.32 2000/02/28 04:00:48 anton Exp $
# Makefile for Sparc library files..
#
@@ -8,10 +8,6 @@ OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \
ashldi3.o rwsem.o
-ifdef CONFIG_SMP
-OBJS += irqlock.o
-endif
-
lib.a: $(OBJS)
$(AR) rcs lib.a $(OBJS)
sync
diff --git a/arch/sparc/lib/irqlock.S b/arch/sparc/lib/irqlock.S
deleted file mode 100644
index 4c41e9825..000000000
--- a/arch/sparc/lib/irqlock.S
+++ /dev/null
@@ -1,122 +0,0 @@
-/* $Id: irqlock.S,v 1.5 1999/04/20 13:22:37 anton Exp $
- * irqlock.S: High performance IRQ global locking and interrupt entry.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/psr.h>
-#include <asm/smp.h>
-
- .text
- .align 4
-
- /* Weird calling conventions... %g7=flags, %g4=%prev_o7
- * Very clever for the __global_sti case, the inline which
- * gets us here clears %g7 and it just works.
- */
- .globl ___global_restore_flags, ___global_sti, ___global_cli
-___global_restore_flags:
- bne,a ___global_cli
- rd %tbr, %g7
- rd %tbr, %g2
-
-___global_sti:
- sethi %hi(global_irq_holder), %g1
- sethi %hi(global_irq_lock), %g3
- srl %g2, 12, %g2
- ldub [%g1 + %lo(global_irq_holder)], %g5
- and %g2, 3, %g2
- cmp %g5, %g2
- bne 1f
- mov NO_PROC_ID, %g5
- stb %g5, [%g1 + %lo(global_irq_holder)]
- stb %g0, [%g3 + %lo(global_irq_lock)]
-1:
- rd %psr, %g3
- andcc %g7, 2, %g0
- bne,a 1f
- or %g3, PSR_PIL, %g3
- andn %g3, PSR_PIL, %g3
-1:
- wr %g3, 0x0, %psr
- nop
-__global_cli_out: ! All togther now... "fuuunnnnn"
- retl
- mov %g4, %o7
-
-__spin_on_global_irq_lock:
- orcc %g2, 0x0, %g0
- bne,a __spin_on_global_irq_lock
- ldub [%g1], %g2
- b,a 1f
-
- /* This is a royal pain in the ass to make fast... 8-( */
-___global_cli:
- sethi %hi(global_irq_lock), %g5
- srl %g7, 12, %g7
- sethi %hi(global_irq_holder), %g3
- and %g7, 3, %g7
- ldub [%g3 + %lo(global_irq_holder)], %g1
- rd %psr, %g2
- cmp %g1, %g7
- or %g2, PSR_PIL, %g2
- be __global_cli_out
- wr %g2, 0x0, %psr ! XXX some sparcs may choke on this...
- sethi %hi(local_irq_count), %g3
- or %g3, %lo(local_irq_count), %g3
- or %g5, %lo(global_irq_lock), %g1
-1:
- ldstub [%g1], %g2
- orcc %g2, 0x0, %g0
- bne,a __spin_on_global_irq_lock
- ldub [%g1], %g2
-__wait_on_irq:
- sll %g7, 2, %g7
- ld [%g3 + %g7], %g2
- sethi %hi(global_irq_count), %g1
- or %g1, %lo(global_irq_count), %g1
- srl %g7, 2, %g7
- ld [%g1], %g5
- sra %g5, 8, %g5
-__wait_on_irq_loop:
- cmp %g5, %g2
- sethi %hi(global_irq_holder), %g3
- be,a __global_cli_out ! Mamamia, Mamamia, this is the fast path
- stb %g7, [%g3 + %lo(global_irq_holder)]
-1:
- ldstub [%g1 + 3], %g3
- orcc %g3, 0x0, %g0
- bne 1b
- ld [%g1], %g3
- sra %g3, 8, %g3
- sub %g3, %g2, %g3
- sll %g3, 8, %g3
- st %g3, [%g1]
- sethi %hi(global_irq_lock), %g3
- stb %g0, [%g3 + %lo(global_irq_lock)]
-0:
- ld [%g1], %g5
-9:
- ldub [%g3 + %lo(global_irq_lock)], %g3
- sra %g5, 8, %g5
- orcc %g3, %g5, %g0
- bne 0b
- sethi %hi(global_irq_lock), %g3
- ldstub [%g3 + %lo(global_irq_lock)], %g5
- orcc %g5, 0x0, %g0
- bne,a 9b
- ld [%g1], %g5
-1:
- ldstub [%g1 + 3], %g3
- orcc %g3, 0x0, %g0
- bne 1b
- ld [%g1], %g3
- sra %g3, 8, %g3
- add %g3, %g2, %g5
- sll %g5, 8, %g3
- b __wait_on_irq_loop
- st %g3, [%g1]
-
-#if 0 /* XXX I'm not delirious enough to debug this yet. */
- add %o7, (8 + (__wait_on_irq_loop - . - 4)), %o7 ! AIEEEEE
-#endif
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index 3ac49a10b..d92fbbb0b 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.81 2000/02/26 11:59:31 anton Exp $
+/* $Id: init.c,v 1.83 2000/03/07 23:12:35 anton Exp $
* linux/arch/sparc/mm/init.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -121,8 +121,8 @@ unsigned long __init bootmem_init(void)
int i;
/* Limit maximum memory until we implement highmem for sparc */
- if (cmdline_memory_size > 0x9000000)
- cmdline_memory_size = 0x9000000;
+ if (!cmdline_memory_size || cmdline_memory_size > 0x0d000000)
+ cmdline_memory_size = 0x0d000000;
/* XXX It is a bit ambiguous here, whether we should
* XXX treat the user specified mem=xxx as total wanted
@@ -138,7 +138,7 @@ unsigned long __init bootmem_init(void)
sp_banks[i].num_bytes;
if (cmdline_memory_size) {
if (end_of_phys_memory > cmdline_memory_size) {
- if (cmdline_memory_size > sp_banks[i].base_addr) {
+ if (cmdline_memory_size < sp_banks[i].base_addr) {
end_of_phys_memory =
sp_banks[i-1].base_addr +
sp_banks[i-1].num_bytes;
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index 4f51537e2..868dd6851 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.41 1999/12/21 04:02:23 davem Exp $
+# $Id: Makefile,v 1.42 2000/03/09 05:56:43 jj Exp $
# sparc64/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
@@ -14,8 +14,9 @@ SHELL =/bin/bash
CC := sparc64-linux-gcc
-IS_EGCS := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
+NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
+UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
ifneq ($(NEW_GAS),y)
AS = sparc64-linux-as
@@ -28,19 +29,26 @@ AS := $(AS) -64
LD := $(LD) -m elf64_sparc
endif
ELFTOAOUT = elftoaout
+ifneq ($(UNDECLARED_REGS),y)
+CC_UNDECL =
+else
+CC_UNDECL = -Wa,--undeclared-regs
+AS := $(AS) --undeclared-regs
+endif
#
# Uncomment the first CFLAGS if you are doing kgdb source level
# debugging of the kernel to get the proper debugging information.
#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
-ifneq ($(IS_EGCS),y)
+ifneq ($(NEW_GCC),y)
CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
-ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
else
CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
- -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
- AFLAGS += -m64 -mcpu=ultrasparc
+ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare \
+ $(CC_UNDECL)
+ AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
endif
# Uncomment this to get spinlock/rwlock debugging on SMP.
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 7e7a45a70..a61d4d049 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -97,6 +97,10 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
# CONFIG_SUNOS_EMUL is not set
CONFIG_SOLARIS_EMUL=m
+
+#
+# Parallel port support
+#
CONFIG_PARPORT=m
CONFIG_PARPORT_PC=m
CONFIG_PARPORT_PC_FIFO=y
@@ -176,7 +180,6 @@ CONFIG_ATALK=m
CONFIG_DECNET=m
CONFIG_DECNET_SIOCGIFCONF=y
# CONFIG_DECNET_ROUTER is not set
-CONFIG_DECNET_RAW=y
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_BRIDGE is not set
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 00f635ab3..d7267880a 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.10 2000/02/18 13:48:54 davem Exp $
+/* $Id: pci_iommu.c,v 1.11 2000/03/10 02:42:15 davem Exp $
* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -34,46 +34,96 @@
: "r" (__val), "r" (__reg), \
"i" (ASI_PHYS_BYPASS_EC_E))
+/* Must be invoked under the IOMMU lock. */
+static void __iommu_flushall(struct pci_iommu *iommu)
+{
+ unsigned long tag;
+ int entry;
+
+ tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
+ for (entry = 0; entry < 16; entry++) {
+ pci_iommu_write(tag, 0);
+ tag += 8;
+ }
+
+ /* Ensure completion of previous PIO writes. */
+ (void) pci_iommu_read(iommu->write_complete_reg);
+
+ /* Now update everyone's flush point. */
+ for (entry = 0; entry < PBM_NCLUSTERS; entry++) {
+ iommu->alloc_info[entry].flush =
+ iommu->alloc_info[entry].next;
+ }
+}
+
static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages)
{
- iopte_t *iopte;
- unsigned long cnum, ent;
+ iopte_t *iopte, *limit;
+ unsigned long cnum, ent, flush_point;
cnum = 0;
while ((1UL << cnum) < npages)
cnum++;
- iopte = iommu->page_table + (cnum << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS));
- iopte += ((ent = iommu->lowest_free[cnum]) << cnum);
+ iopte = (iommu->page_table +
+ (cnum << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)));
- if (iopte_val(iopte[(1UL << cnum)]) == 0UL) {
- /* Fast path. */
- iommu->lowest_free[cnum] = ent + 1;
- } else {
- unsigned long pte_off = 1;
+ if (cnum == 0)
+ limit = (iommu->page_table +
+ iommu->lowest_consistent_map);
+ else
+ limit = (iopte +
+ (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)));
- ent += 1;
- do {
- pte_off++;
- ent++;
- } while (iopte_val(iopte[(pte_off << cnum)]) != 0UL);
- iommu->lowest_free[cnum] = ent;
+ iopte += ((ent = iommu->alloc_info[cnum].next) << cnum);
+ flush_point = iommu->alloc_info[cnum].flush;
+
+ for (;;) {
+ if (iopte_val(*iopte) == 0UL) {
+ if ((iopte + (1 << cnum)) >= limit)
+ ent = 0;
+ else
+ ent = ent + 1;
+ iommu->alloc_info[cnum].next = ent;
+ if (ent == flush_point)
+ __iommu_flushall(iommu);
+ break;
+ }
+ iopte += (1 << cnum);
+ ent++;
+ if (iopte >= limit) {
+ iopte = (iommu->page_table +
+ (cnum <<
+ (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)));
+ ent = 0;
+ }
+ if (ent == flush_point)
+ __iommu_flushall(iommu);
}
/* I've got your streaming cluster right here buddy boy... */
return iopte;
}
-static inline void free_streaming_cluster(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages)
+static void free_streaming_cluster(struct pci_iommu *iommu, dma_addr_t base,
+ unsigned long npages, unsigned long ctx)
{
unsigned long cnum, ent;
cnum = 0;
while ((1UL << cnum) < npages)
cnum++;
+
ent = (base << (32 - PAGE_SHIFT + PBM_LOGCLUSTERS - iommu->page_table_sz_bits))
>> (32 + PBM_LOGCLUSTERS + cnum - iommu->page_table_sz_bits);
- if (ent < iommu->lowest_free[cnum])
- iommu->lowest_free[cnum] = ent;
+
+ /* If the global flush might not have caught this entry,
+ * adjust the flush point such that we will flush before
+ * ever trying to reuse it.
+ */
+#define between(X,Y,Z) (((Z) - (Y)) >= ((X) - (Y)))
+ if (between(ent, iommu->alloc_info[cnum].next, iommu->alloc_info[cnum].flush))
+ iommu->alloc_info[cnum].flush = ent;
+#undef between
}
/* We allocate consistent mappings from the end of cluster zero. */
@@ -92,8 +142,13 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long
if (iopte_val(*iopte) & IOPTE_VALID)
break;
}
- if (tmp == 0)
+ if (tmp == 0) {
+ u32 entry = (iopte - iommu->page_table);
+
+ if (entry < iommu->lowest_consistent_map)
+ iommu->lowest_consistent_map = entry;
return iopte;
+ }
}
}
return NULL;
@@ -182,7 +237,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_
struct pcidev_cookie *pcp;
struct pci_iommu *iommu;
iopte_t *iopte;
- unsigned long flags, order, npages, i;
+ unsigned long flags, order, npages, i, ctx;
npages = PAGE_ALIGN(size) >> PAGE_SHIFT;
pcp = pdev->sysdata;
@@ -192,15 +247,45 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_
spin_lock_irqsave(&iommu->lock, flags);
+ if ((iopte - iommu->page_table) ==
+ iommu->lowest_consistent_map) {
+ iopte_t *walk = iopte + npages;
+ iopte_t *limit;
+
+ limit = (iommu->page_table +
+ (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)));
+ while (walk < limit) {
+ if (iopte_val(*walk) != IOPTE_INVALID)
+ break;
+ walk++;
+ }
+ iommu->lowest_consistent_map =
+ (walk - iommu->page_table);
+ }
+
/* Data for consistent mappings cannot enter the streaming
- * buffers, so we only need to update the TSB. Flush of the
- * IOTLB is done later when these ioptes are used for a new
- * allocation.
+ * buffers, so we only need to update the TSB. We flush
+ * the IOMMU here as well to prevent conflicts with the
+ * streaming mapping deferred tlb flush scheme.
*/
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
+
for (i = 0; i < npages; i++, iopte++)
iopte_val(*iopte) = IOPTE_INVALID;
+ if (iommu->iommu_ctxflush) {
+ pci_iommu_write(iommu->iommu_ctxflush, ctx);
+ } else {
+ for (i = 0; i < npages; i++) {
+ u32 daddr = dvma + (i << PAGE_SHIFT);
+
+ pci_iommu_write(iommu->iommu_flush, daddr);
+ }
+ }
+
spin_unlock_irqrestore(&iommu->lock, flags);
order = get_order(size);
@@ -253,14 +338,6 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct
for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
iopte_val(*base) = iopte_protection | base_paddr;
- /* Flush the IOMMU TLB. */
- if (iommu->iommu_ctxflush) {
- pci_iommu_write(iommu->iommu_ctxflush, ctx);
- } else {
- for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
- pci_iommu_write(iommu->iommu_flush, bus_addr);
- }
-
spin_unlock_irqrestore(&iommu->lock, flags);
return ret;
@@ -294,15 +371,15 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int
spin_lock_irqsave(&iommu->lock, flags);
+ /* Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+
/* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled) {
u32 vaddr = bus_addr;
- /* Record the context, if any. */
- ctx = 0;
- if (iommu->iommu_ctxflush)
- ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
-
PCI_STC_FLUSHFLAG_INIT(strbuf);
if (strbuf->strbuf_ctxflush &&
iommu->iommu_ctxflush) {
@@ -327,10 +404,8 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int
/* Step 2: Clear out first TSB entry. */
iopte_val(*base) = IOPTE_INVALID;
- free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages);
-
- /* Step 3: Ensure completion of previous PIO writes. */
- (void) pci_iommu_read(iommu->write_complete_reg);
+ free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
+ npages, ctx);
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -415,7 +490,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int
struct pcidev_cookie *pcp;
struct pci_iommu *iommu;
struct pci_strbuf *strbuf;
- unsigned long flags, ctx, i, npages, iopte_protection;
+ unsigned long flags, ctx, npages, iopte_protection;
iopte_t *base;
u32 dma_base;
struct scatterlist *sgtmp;
@@ -474,14 +549,6 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int
verify_sglist(sglist, nelems, base, npages);
#endif
- /* Step 6: Flush the IOMMU TLB. */
- if (iommu->iommu_ctxflush) {
- pci_iommu_write(iommu->iommu_ctxflush, ctx);
- } else {
- for (i = 0; i < npages; i++, dma_base += PAGE_SIZE)
- pci_iommu_write(iommu->iommu_flush, dma_base);
- }
-
spin_unlock_irqrestore(&iommu->lock, flags);
return used;
@@ -522,15 +589,15 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
spin_lock_irqsave(&iommu->lock, flags);
+ /* Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+
/* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled) {
u32 vaddr = bus_addr;
- /* Record the context, if any. */
- ctx = 0;
- if (iommu->iommu_ctxflush)
- ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
-
PCI_STC_FLUSHFLAG_INIT(strbuf);
if (strbuf->strbuf_ctxflush &&
iommu->iommu_ctxflush) {
@@ -555,10 +622,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
/* Step 2: Clear out first TSB entry. */
iopte_val(*base) = IOPTE_INVALID;
- free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages);
-
- /* Step 3: Ensure completion of previous PIO writes. */
- (void) pci_iommu_read(iommu->write_complete_reg);
+ free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
+ npages, ctx);
spin_unlock_irqrestore(&iommu->lock, flags);
}
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index b3248de39..1c8f59f3f 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.13 2000/02/18 13:48:54 davem Exp $
+/* $Id: pci_psycho.c,v 1.14 2000/03/10 02:42:15 davem Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1246,11 +1246,14 @@ static void __init psycho_iommu_init(struct pci_controller_info *p)
control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL);
control |= PSYCHO_IOMMU_CTRL_DENAB;
psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
- for(i = 0; i < 16; i++)
+ for(i = 0; i < 16; i++) {
+ psycho_write(p->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
psycho_write(p->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
+ }
- control &= ~(PSYCHO_IOMMU_CTRL_DENAB);
- psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control);
+ /* Leave diag mode enabled for full-flushing done
+ * in pci_iommu.c
+ */
/* Using assumed page size 8K with 128K entries we need 1MB iommu page
* table (128K ioptes * 8 bytes per iopte). This is
@@ -1267,9 +1270,14 @@ static void __init psycho_iommu_init(struct pci_controller_info *p)
p->iommu.dma_addr_mask = 0xffffffff;
memset((char *)tsbbase, 0, PAGE_SIZE << 7);
- /* Make sure DMA address 0 is never returned just to allow catching
- of buggy drivers. */
- p->iommu.lowest_free[0] = 1;
+ /* We start with no consistent mappings. */
+ p->iommu.lowest_consistent_map =
+ 1 << (p->iommu.page_table_sz_bits - PBM_LOGCLUSTERS);
+
+ for (i = 0; i < PBM_NCLUSTERS; i++) {
+ p->iommu.alloc_info[i].flush = 0;
+ p->iommu.alloc_info[i].next = 0;
+ }
psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase));
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index e96af490d..a10f5f072 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.14 2000/02/18 13:48:55 davem Exp $
+/* $Id: pci_sabre.c,v 1.15 2000/03/10 02:42:16 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1128,11 +1128,14 @@ static void __init sabre_iommu_init(struct pci_controller_info *p,
control |= SABRE_IOMMUCTRL_DENAB;
sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
- for(i = 0; i < 16; i++)
+ for(i = 0; i < 16; i++) {
+ sabre_write(p->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
+ }
- control &= ~(SABRE_IOMMUCTRL_DENAB);
- sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
+ /* Leave diag mode enabled for full-flushing done
+ * in pci_iommu.c
+ */
tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8));
if (!tsbbase) {
@@ -1144,10 +1147,6 @@ static void __init sabre_iommu_init(struct pci_controller_info *p,
p->iommu.dma_addr_mask = dma_mask;
memset((char *)tsbbase, 0, PAGE_SIZE << order);
- /* Make sure DMA address 0 is never returned just to allow catching
- of buggy drivers. */
- p->iommu.lowest_free[0] = 1;
-
sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase));
control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL);
@@ -1168,6 +1167,15 @@ static void __init sabre_iommu_init(struct pci_controller_info *p,
break;
}
sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control);
+
+ /* We start with no consistent mappings. */
+ p->iommu.lowest_consistent_map =
+ 1 << (p->iommu.page_table_sz_bits - PBM_LOGCLUSTERS);
+
+ for (i = 0; i < PBM_NCLUSTERS; i++) {
+ p->iommu.alloc_info[i].flush = 0;
+ p->iommu.alloc_info[i].next = 0;
+ }
}
static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 1b454fa2c..c9a0d4a59 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.9 2000/02/18 13:48:57 davem Exp $
+/* $Id: sbus.c,v 1.10 2000/03/10 07:52:08 davem Exp $
* sbus.c: UltraSparc SBUS controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -53,13 +53,18 @@ struct sbus_iommu {
* you must increase the size of the type of
* these counters. You have been duly warned. -DaveM
*/
-/*0x30*/u16 lowest_free[NCLUSTERS];
+/*0x30*/struct {
+ u16 next;
+ u16 flush;
+ } alloc_info[NCLUSTERS];
+
+ /* The lowest used consistent mapping entry. Since
+ * we allocate consistent maps out of cluster 0 this
+ * is relative to the beginning of closter 0.
+ */
+/*0x50*/u32 lowest_consistent_map;
};
-/* Flushing heuristics */
-#define IOMMU_DIAG_LIM 16
-#define STRBUF_DIAG_LIM 32
-
/* Offsets from iommu_regs */
#define SYSIO_IOMMUREG_BASE 0x2400UL
#define IOMMU_CONTROL (0x2400UL - 0x2400UL) /* IOMMU control register */
@@ -73,49 +78,29 @@ struct sbus_iommu {
#define IOMMU_DRAM_VALID (1UL << 30UL)
-static void __iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
+static void __iommu_flushall(struct sbus_iommu *iommu)
{
- int hit = 0;
-
- if (npages <= IOMMU_DIAG_LIM) {
- while (npages--)
- upa_writeq(base + (npages << PAGE_SHIFT),
- iommu->iommu_regs + IOMMU_FLUSH);
- hit = 1;
- } else {
- u32 limit = base + ((npages << PAGE_SHIFT) - 1UL);
- unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG;
- unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
- int entry;
+ unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
+ int entry;
- for (entry = 0; entry < 16; entry++, dram += 8, tag += 8) {
- u32 addr = ((u32)upa_readq(tag) << PAGE_SHIFT);
- if (addr >= base && addr <= limit) {
- u64 val = upa_readq(dram);
+ for (entry = 0; entry < 16; entry++) {
+ upa_writeq(0, tag);
+ tag += 8UL;
+ }
+ upa_readq(iommu->sbus_control_reg);
- if (val & IOMMU_DRAM_VALID) {
- upa_writeq(addr,
- iommu->iommu_regs + IOMMU_FLUSH);
- hit = 1;
- }
- }
- }
+ for (entry = 0; entry < NCLUSTERS; entry++) {
+ iommu->alloc_info[entry].flush =
+ iommu->alloc_info[entry].next;
}
- if (hit != 0)
- upa_readq(iommu->sbus_control_reg);
}
-/* In an effort to keep latency under control, we special
- * case single page IOMMU flushes.
- */
-static __inline__ void iommu_flush(struct sbus_iommu *iommu,
- u32 base, unsigned long npages)
+static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
{
- if (npages == 1) {
- upa_writeq(base, iommu->iommu_regs + IOMMU_FLUSH);
- upa_readq(iommu->sbus_control_reg);
- } else
- __iommu_flush(iommu, base, npages);
+ while (npages--)
+ upa_writeq(base + (npages << PAGE_SHIFT),
+ iommu->iommu_regs + IOMMU_FLUSH);
+ upa_readq(iommu->sbus_control_reg);
}
/* Offsets from strbuf_regs */
@@ -132,65 +117,57 @@ static __inline__ void iommu_flush(struct sbus_iommu *iommu,
static void strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
{
- int hit = 0;
-
iommu->strbuf_flushflag = 0UL;
- if (npages <= STRBUF_DIAG_LIM) {
- while (npages--)
- upa_writeq(base + (npages << PAGE_SHIFT),
- iommu->strbuf_regs + STRBUF_PFLUSH);
- hit = 1;
- } else {
- u32 limit = base + ((npages << PAGE_SHIFT) - 1UL);
- unsigned long tag = iommu->strbuf_regs + STRBUF_PTAGDIAG;
- int entry;
-
- for (entry = 0; entry < 16; entry++, tag += 8) {
- u64 val = upa_readq(tag);
-
- if (val & STRBUF_TAG_VALID) {
- u32 addr = ((u32)(val & ~3UL)) << (PAGE_SHIFT - 2UL);
- if (addr >= base && addr <= limit) {
- upa_writeq(addr,
- iommu->strbuf_regs + STRBUF_PFLUSH);
- hit = 1;
- }
- }
- }
- }
- if (hit != 0) {
- /* Whoopee cushion! */
- upa_writeq(__pa(&iommu->strbuf_flushflag),
- iommu->strbuf_regs + STRBUF_FSYNC);
- upa_readq(iommu->sbus_control_reg);
- while (iommu->strbuf_flushflag == 0UL)
- membar("#LoadLoad");
- }
+ while (npages--)
+ upa_writeq(base + (npages << PAGE_SHIFT),
+ iommu->strbuf_regs + STRBUF_PFLUSH);
+
+ /* Whoopee cushion! */
+ upa_writeq(__pa(&iommu->strbuf_flushflag),
+ iommu->strbuf_regs + STRBUF_FSYNC);
+ upa_readq(iommu->sbus_control_reg);
+ while (iommu->strbuf_flushflag == 0UL)
+ membar("#LoadLoad");
}
static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages)
{
- iopte_t *iopte;
- unsigned long cnum, ent;
+ iopte_t *iopte, *limit;
+ unsigned long cnum, ent, flush_point;
cnum = 0;
while ((1UL << cnum) < npages)
cnum++;
iopte = iommu->page_table + (cnum * CLUSTER_NPAGES);
- iopte += ((ent = iommu->lowest_free[cnum]) << cnum);
-
- if (iopte_val(iopte[(1UL << cnum)]) == 0UL) {
- /* Fast path. */
- iommu->lowest_free[cnum] = ent + 1;
- } else {
- unsigned long pte_off = 1;
- ent += 1;
- do {
- pte_off++;
- ent++;
- } while (iopte_val(iopte[(pte_off << cnum)]) != 0UL);
- iommu->lowest_free[cnum] = ent;
+ if (cnum == 0)
+ limit = (iommu->page_table +
+ iommu->lowest_consistent_map);
+ else
+ limit = (iopte + CLUSTER_NPAGES);
+
+ iopte += ((ent = iommu->alloc_info[cnum].next) << cnum);
+ flush_point = iommu->alloc_info[cnum].flush;
+
+ for (;;) {
+ if (iopte_val(*iopte) == 0UL) {
+ if ((iopte + (1 << cnum)) >= limit)
+ ent = 0;
+ else
+ ent = ent + 1;
+ iommu->alloc_info[cnum].next = ent;
+ if (ent == flush_point)
+ __iommu_flushall(iommu);
+ break;
+ }
+ iopte += (1 << cnum);
+ ent++;
+ if (iopte >= limit) {
+ iopte = (iommu->page_table + (cnum * CLUSTER_NPAGES));
+ ent = 0;
+ }
+ if (ent == flush_point)
+ __iommu_flushall(iommu);
}
/* I've got your streaming cluster right here buddy boy... */
@@ -208,8 +185,15 @@ static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned
ent = (base & CLUSTER_MASK) >> (PAGE_SHIFT + cnum);
iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT);
iopte_val(*iopte) = 0UL;
- if (ent < iommu->lowest_free[cnum])
- iommu->lowest_free[cnum] = ent;
+
+ /* If the global flush might not have caught this entry,
+ * adjust the flush point such that we will flush before
+ * ever trying to reuse it.
+ */
+#define between(X,Y,Z) (((Z) - (Y)) >= ((X) - (Y)))
+ if (between(ent, iommu->alloc_info[cnum].next, iommu->alloc_info[cnum].flush))
+ iommu->alloc_info[cnum].flush = ent;
+#undef between
}
/* We allocate consistent mappings from the end of cluster zero. */
@@ -228,8 +212,13 @@ static iopte_t *alloc_consistent_cluster(struct sbus_iommu *iommu, unsigned long
if (iopte_val(*iopte) & IOPTE_VALID)
break;
}
- if (tmp == 0)
+ if (tmp == 0) {
+ u32 entry = (iopte - iommu->page_table);
+
+ if (entry < iommu->lowest_consistent_map)
+ iommu->lowest_consistent_map = entry;
return iopte;
+ }
}
}
return NULL;
@@ -239,6 +228,20 @@ static void free_consistent_cluster(struct sbus_iommu *iommu, u32 base, unsigned
{
iopte_t *iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT);
+ if ((iopte - iommu->page_table) == iommu->lowest_consistent_map) {
+ iopte_t *walk = iopte + npages;
+ iopte_t *limit;
+
+ limit = iommu->page_table + CLUSTER_NPAGES;
+ while (walk < limit) {
+ if (iopte_val(*walk) != 0UL)
+ break;
+ walk++;
+ }
+ iommu->lowest_consistent_map =
+ (walk - iommu->page_table);
+ }
+
while (npages--)
*iopte++ = __iopte(0UL);
}
@@ -301,6 +304,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_add
spin_lock_irq(&iommu->lock);
free_consistent_cluster(iommu, dvma, npages);
+ iommu_flush(iommu, dvma, npages);
spin_unlock_irq(&iommu->lock);
order = get_order(size);
@@ -337,7 +341,6 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int di
phys_base += PAGE_SIZE;
}
npages = size >> PAGE_SHIFT;
- iommu_flush(iommu, dma_base, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
return (dma_base | offset);
@@ -472,7 +475,6 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int di
#ifdef VERIFY_SG
verify_sglist(sg, nents, iopte, npages);
#endif
- iommu_flush(iommu, dma_base, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
return used;
@@ -1061,9 +1063,13 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
memset(iommu, 0, sizeof(*iommu));
- /* Make sure DMA address 0 is never returned just to allow catching
- of buggy drivers. */
- iommu->lowest_free[0] = 1;
+ /* We start with no consistent mappings. */
+ iommu->lowest_consistent_map = CLUSTER_NPAGES;
+
+ for (i = 0; i < NCLUSTERS; i++) {
+ iommu->alloc_info[i].flush = 0;
+ iommu->alloc_info[i].next = 0;
+ }
/* Setup spinlock. */
spin_lock_init(&iommu->lock);
@@ -1110,9 +1116,12 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
*/
for (i = 0; i < 16; i++) {
unsigned long dram = iommu->iommu_regs + IOMMU_DRAMDIAG;
+ unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG;
dram += (unsigned long)i * 8UL;
+ tag += (unsigned long)i * 8UL;
upa_writeq(0, dram);
+ upa_writeq(0, tag);
}
upa_readq(iommu->sbus_control_reg);
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 96360b010..b4ee5625e 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -328,6 +328,7 @@ again:
stxa %6, [%0+%8] %3
membar #Sync
stxa %%g0, [%7] %3
+ membar #Sync
mov 0x20, %%g1
ldxa [%%g1] 0x7f, %%g0
membar #Sync"
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index d3f02ae54..1fc0b1ba5 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.133 2000/03/01 02:53:33 davem Exp $
+/* $Id: sys_sparc32.c,v 1.134 2000/03/07 22:27:30 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index d977c7952..9673cdd36 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.39 2000/02/16 07:31:37 davem Exp $
+/* $Id: sys_sunos32.c,v 1.40 2000/03/07 22:27:31 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 68147d4d4..d09ac451b 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.147 2000/03/03 23:48:44 davem Exp $
+/* $Id: init.c,v 1.148 2000/03/07 07:08:31 anton Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -824,7 +824,7 @@ unsigned long __init bootmem_init(void)
sp_banks[i].num_bytes;
if (cmdline_memory_size) {
if (end_of_phys_memory > cmdline_memory_size) {
- if (cmdline_memory_size > sp_banks[i].base_addr) {
+ if (cmdline_memory_size < sp_banks[i].base_addr) {
end_of_phys_memory =
sp_banks[i-1].base_addr +
sp_banks[i-1].num_bytes;
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index e15ef157c..4adaf4077 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.16 2000/01/12 02:59:27 davem Exp $
+/* $Id: fs.c,v 1.17 2000/03/10 04:43:30 davem Exp $
* fs.c: fs related syscall emulation for Solaris
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -410,17 +410,10 @@ struct sol_statvfs64 {
static int report_statvfs(struct inode *inode, u32 buf)
{
struct statfs s;
- mm_segment_t old_fs = get_fs();
int error;
struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
- if (!inode->i_sb)
- return -ENODEV;
- if (!inode->i_sb->s_op->statfs)
- return -ENOSYS;
- set_fs (KERNEL_DS);
- error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
- set_fs (old_fs);
+ error = vfs_statfs(inode->i_sb, &s);
if (!error) {
const char *p = inode->i_sb->s_type->name;
int i = 0;
@@ -451,17 +444,10 @@ static int report_statvfs(struct inode *inode, u32 buf)
static int report_statvfs64(struct inode *inode, u32 buf)
{
struct statfs s;
- mm_segment_t old_fs = get_fs();
int error;
struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf);
- if (!inode->i_sb)
- return -ENODEV;
- if (!inode->i_sb->s_op->statfs)
- return -ENOSYS;
- set_fs (KERNEL_DS);
- error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs));
- set_fs (old_fs);
+ error = vfs_statfs(inode->i_sb, &s);
if (!error) {
const char *p = inode->i_sb->s_type->name;
int i = 0;
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 1495809d6..e969e2dd7 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1051,20 +1051,23 @@ static int DAC_merge_requests_fn(request_queue_t *q,
int max_segments;
DAC960_Controller_T * Controller = q->queuedata;
int total_segments = req->nr_segments + next->nr_segments;
+ int same_segment;
max_segments = Controller->MaxSegmentsPerRequest[MINOR(req->rq_dev)];
if (__max_segments < max_segments)
max_segments = __max_segments;
+ same_segment = 0;
if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data)
{
total_segments--;
- q->nr_segments--;
+ same_segment = 1;
}
if (total_segments > max_segments)
return 0;
+ q->nr_segments -= same_segment;
req->nr_segments = total_segments;
return 1;
}
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 9e00cfa89..6882d03f3 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -182,6 +182,10 @@ ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
IDE_OBJS += ide-pci.o
endif
+ifeq ($(CONFIG_BLK_DEV_ISAPNP),y)
+IDE_OBJS += ide-pnp.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_IDE_PMAC),y)
IDE_OBJS += ide-pmac.o
endif
diff --git a/drivers/block/aec6210.c b/drivers/block/aec6210.c
index 30be6a7cc..cc0aca5fd 100644
--- a/drivers/block/aec6210.c
+++ b/drivers/block/aec6210.c
@@ -54,9 +54,9 @@
#include "ide_modes.h"
-#define ACARD_DEBUG_DRIVE_INFO 1
+#define ACARD_DEBUG_DRIVE_INFO 0
-#define DISPLAY_AEC6210_TIMINGS
+#undef DISPLAY_AEC6210_TIMINGS
#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
diff --git a/drivers/block/cmd64x.c b/drivers/block/cmd64x.c
index 40b5c7797..542ad44a1 100644
--- a/drivers/block/cmd64x.c
+++ b/drivers/block/cmd64x.c
@@ -21,8 +21,11 @@
#include <asm/io.h>
#include "ide_modes.h"
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
#define CMD_DEBUG 0
-#undef NO_WRITE
#if CMD_DEBUG
#define cmdprintk(x...) printk(##x)
@@ -47,14 +50,25 @@
#define ARTTIM23 0x57
#define ARTTIM23_DIS_RA2 0x04
#define ARTTIM23_DIS_RA3 0x08
+#define ARTTIM2 0x57
+#define ARTTIM3 0x57
#define DRWTIM23 0x58
#define DRWTIM2 0x58
#define BRST 0x59
#define DRWTIM3 0x5b
+#define BMIDECR0 0x70
#define MRDMODE 0x71
+#define BMIDESR0 0x72
+#define UDIDETCR0 0x73
+#define DTPR0 0x74
+#define BMIDECR1 0x78
+#define BMIDECSR 0x79
+#define BMIDESR1 0x7A
+#define UDIDETCR1 0x7B
+#define DTPR1 0x7C
-#define DISPLAY_CMD64X_TIMINGS
+#undef DISPLAY_CMD64X_TIMINGS
#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
@@ -68,8 +82,11 @@ static struct pci_dev *bmide_dev;
static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
{
char *p = buffer;
- u32 bibma = bmide_dev->resource[4].start;
- u8 c0 = 0, c1 = 0;
+ u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0; /* primary */
+ u8 reg57 = 0, reg58 = 0, reg5b; /* secondary */
+ u8 reg72 = 0, reg73 = 0; /* primary */
+ u8 reg7a = 0, reg7b = 0; /* secondary */
+ u8 hi_byte = 0, lo_byte = 0;
switch(bmide_dev->device) {
case PCI_DEVICE_ID_CMD_648:
@@ -85,26 +102,57 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
p += sprintf(p, "\n CMD64? Chipse.\n");
break;
}
+ (void) pci_read_config_byte(bmide_dev, ARTTIM0, &reg53);
+ (void) pci_read_config_byte(bmide_dev, DRWTIM0, &reg54);
+ (void) pci_read_config_byte(bmide_dev, ARTTIM1, &reg55);
+ (void) pci_read_config_byte(bmide_dev, DRWTIM1, &reg56);
+ (void) pci_read_config_byte(bmide_dev, ARTTIM2, &reg57);
+ (void) pci_read_config_byte(bmide_dev, DRWTIM2, &reg58);
+ (void) pci_read_config_byte(bmide_dev, DRWTIM3, &reg5b);
+ (void) pci_read_config_byte(bmide_dev, BMIDESR0, &reg72);
+ (void) pci_read_config_byte(bmide_dev, UDIDETCR0, &reg73);
+ (void) pci_read_config_byte(bmide_dev, BMIDESR1, &reg7a);
+ (void) pci_read_config_byte(bmide_dev, UDIDETCR1, &reg7b);
- /*
- * at that point bibma+0x2 et bibma+0xa are byte registers
- * to investigate:
- */
- c0 = inb_p((unsigned short)bibma + 0x02);
- c1 = inb_p((unsigned short)bibma + 0x0a);
p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
p += sprintf(p, " %sabled %sabled\n",
- (c0&0x80) ? "dis" : " en",
- (c1&0x80) ? "dis" : " en");
+ (reg72&0x80) ? "dis" : " en", (reg7a&0x80) ? "dis" : " en");
p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
p += sprintf(p, "DMA enabled: %s %s %s %s\n",
- (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
- (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
- p += sprintf(p, "UDMA\n");
- p += sprintf(p, "DMA\n");
+ (reg72&0x20) ? "yes" : "no ", (reg72&0x40) ? "yes" : "no ", (reg7a&0x20) ? "yes" : "no ", (reg7a&0x40) ? "yes" : "no " );
+ p += sprintf(p, "UDMA enabled: %s %s %s %s\n",
+ (reg73&0x01) ? "yes" : "no ", (reg73&0x02) ? "yes" : "no ", (reg7b&0x01) ? "yes" : "no ", (reg7b&0x02) ? "yes" : "no " );
+ p += sprintf(p, "UDMA enabled: %s %s %s %s\n",
+ (reg73&0x15) ? "4" : (reg73&0x25) ? "3" : (reg73&0x11) ? "2" : (reg73&0x21) ? "1" : (reg73&0x31) ? "0" : "X",
+ (reg73&0x4A) ? "4" : (reg73&0x8A) ? "3" : (reg73&0x42) ? "2" : (reg73&0x82) ? "1" : (reg73&0xC2) ? "0" : "X",
+ (reg7b&0x15) ? "4" : (reg7b&0x25) ? "3" : (reg7b&0x11) ? "2" : (reg7b&0x21) ? "1" : (reg7b&0x31) ? "0" : "X",
+ (reg7b&0x4A) ? "4" : (reg7b&0x8A) ? "3" : (reg7b&0x42) ? "2" : (reg7b&0x82) ? "1" : (reg7b&0xC2) ? "0" : "X" );
+ p += sprintf(p, "DMA enabled: %s %s %s %s\n",
+ (reg73&0x10) ? "2" : (reg73&0x20) ? "1" : (reg73&0x30) ? "0" : "X",
+ (reg73&0x40) ? "2" : (reg73&0x80) ? "1" : (reg73&0xC0) ? "0" : "X",
+ (reg7b&0x10) ? "2" : (reg7b&0x20) ? "1" : (reg7b&0x30) ? "0" : "X",
+ (reg7b&0x40) ? "2" : (reg7b&0x80) ? "1" : (reg7b&0xC0) ? "0" : "X" );
p += sprintf(p, "PIO\n");
+ SPLIT_BYTE(reg53, hi_byte, lo_byte);
+ p += sprintf(p, "ARTTIM0 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg53, hi_byte, lo_byte);
+ SPLIT_BYTE(reg54, hi_byte, lo_byte);
+ p += sprintf(p, "DRWTIM0 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg54, hi_byte, lo_byte);
+ SPLIT_BYTE(reg55, hi_byte, lo_byte);
+ p += sprintf(p, "ARTTIM1 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg55, hi_byte, lo_byte);
+ SPLIT_BYTE(reg56, hi_byte, lo_byte);
+ p += sprintf(p, "DRWTIM1 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg56, hi_byte, lo_byte);
+ SPLIT_BYTE(reg57, hi_byte, lo_byte);
+ p += sprintf(p, "ARTTIM23 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
+ SPLIT_BYTE(reg58, hi_byte, lo_byte);
+ p += sprintf(p, "DRWTIM2 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg58, hi_byte, lo_byte);
+ SPLIT_BYTE(reg5b, hi_byte, lo_byte);
+ p += sprintf(p, "DRWTIM3 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg5b, hi_byte, lo_byte);
+ SPLIT_BYTE(reg73, hi_byte, lo_byte);
+ p += sprintf(p, "UDIDETCR0 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg73, hi_byte, lo_byte);
+ SPLIT_BYTE(reg7b, hi_byte, lo_byte);
+ p += sprintf(p, "UDIDETCR1 = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg7b, hi_byte, lo_byte);
+
return p-buffer; /* => must be less than 4k! */
}
#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
@@ -176,12 +224,10 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ
* and then the active/recovery counts into the DRWTIM reg
*/
(void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
-#ifndef NO_WRITE
(void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
((byte) setup_count) | (temp_b & 0x3f));
(void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
(byte) ((active_count << 4) | recovery_count));
-#endif
cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
__restore_flags(flags);
@@ -212,7 +258,7 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
return;
}
- (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+ mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
pio_mode = d.pio_mode;
cycle_time = d.cycle_time;
@@ -253,12 +299,84 @@ static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
*/
program_drive_counts (drive, setup_count, active_count, recovery_count);
- printk ("%s: selected cmd646 PIO mode%d (%dns)%s, clocks=%d/%d/%d\n",
- drive->name, pio_mode, cycle_time,
+ cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, clocks=%d/%d/%d\n",
+ drive->name, pio_mode, mode_wanted, cycle_time,
d.overridden ? " (overriding vendor mode)" : "",
setup_count, active_count, recovery_count);
}
+static int tune_chipset_for_dma (ide_drive_t *drive, byte speed)
+{
+#if 0
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned long dma_base = hwif->dma_base;
+ byte unit = (drive->select.b.unit & 0x01);
+
+ u8 reg72 = 0, reg73 = 0; /* primary */
+ u8 reg7a = 0, reg7b = 0; /* secondary */
+ u8 pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+ u8 pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+ u8 regU = (hwif->channel) ? 2 : 0;
+ u8 regD = (hwif->channel) ? 2 : 0;
+
+ (void) pci_read_config_byte(dev, BMIDESR0, &reg72);
+ (void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+ (void) pci_read_config_byte(dev, BMIDESR1, &reg7a);
+ (void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ pciU = unit ? 0x4A : 0x15;
+ case XFER_UDMA_3:
+ pciU = unit ? 0x8A : 0x25;
+ case XFER_UDMA_2:
+ pciU = unit ? 0x42 : 0x11;
+ case XFER_UDMA_1:
+ pciU = unit ? 0x82 : 0x21;
+ case XFER_UDMA_0:
+ pciU = unit ? 0xC2 : 0x31
+(reg73&0x15)?"4":(reg73&0x25)?"3":(reg73&0x11)?"2":(reg73&0x21)?"1":(reg73&0x31)?"0":"X",
+(reg73&0x4A)?"4":(reg73&0x8A)?"3":(reg73&0x42)?"2":(reg73&0x82)?"1":(reg73&0xC2)?"0":"X",
+(reg7b&0x15)?"4":(reg7b&0x25)?"3":(reg7b&0x11)?"2":(reg7b&0x21)?"1":(reg7b&0x31)?"0":"X",
+(reg7b&0x4A)?"4":(reg7b&0x8A)?"3":(reg7b&0x42)?"2":(reg7b&0x82)?"1":(reg7b&0xC2)?"0":"X",
+
+ case XFER_MW_DMA_2:
+ pciD = unit ? 0x40 : 0x10;
+ case XFER_MW_DMA_1:
+ pciD = unit ? 0x80 : 0x20;
+ case XFER_MW_DMA_0:
+ pciD = unit ? 0xC0 : 0x30;
+ case XFER_SW_DMA_2:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+(reg73&0x10)?"2":(reg73&0x20)?"1":(reg73&0x30)?"0":"X",
+(reg73&0x40)?"2":(reg73&0x80)?"1":(reg73&0xC0)?"0":"X",
+(reg7b&0x10)?"2":(reg7b&0x20)?"1":(reg7b&0x30)?"0":"X",
+(reg7b&0x40)?"2":(reg7b&0x80)?"1":(reg7b&0xC0)?"0":"X" );
+
+ default:
+ return 1;
+ }
+
+ (void) ide_config_drive_speed(drive, speed);
+ outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+#endif
+ return 0;
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ byte speed = 0x00;
+ byte set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+ cmd64x_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
{
struct hd_driveid *id = drive->id;
@@ -268,6 +386,7 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
byte unit = (drive->select.b.unit & 0x01);
byte speed = 0x00;
+ byte set_pio = 0x00;
byte udma_timing_bits = 0x00;
byte udma_33 = ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0;
@@ -326,9 +445,19 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
} else if (id->dma_1word & 0x0001) {
speed = XFER_SW_DMA_0;
} else {
- return ((int) ide_dma_off_quietly);
+ set_pio = 1;
}
+ config_chipset_for_pio(drive, set_pio);
+
+ if (set_pio)
+ return ((int) ide_dma_off_quietly);
+
+#if 1
+ /*
+ * This the alternate access method. :-(
+ * The correct method is to directly setup the pci-config space.
+ */
(void) ide_config_drive_speed(drive, speed);
outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
@@ -343,6 +472,10 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
udma_ctrl |= (udma_timing_bits << (unit * 2));
outb(udma_ctrl, dma_base+3);
}
+#endif
+
+ if (tune_chipset_for_dma(drive, speed))
+ return ((int) ide_dma_off);
rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
((id->dma_ultra >> 8) & 7) ? ide_dma_on :
@@ -353,11 +486,6 @@ static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ul
return rval;
}
-static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev)
-{
- cmd64x_tuneproc(drive, 5);
-}
-
static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -428,7 +556,7 @@ try_dma_modes:
fast_ata_pio:
dma_func = ide_dma_off_quietly;
no_dma_set:
- config_chipset_for_pio(drive, class_rev);
+ config_chipset_for_pio(drive, 1);
}
return HWIF(drive)->dmaproc(dma_func, drive);
}
@@ -476,6 +604,11 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
+#if 0
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+#endif
+
switch(dev->device) {
case PCI_DEVICE_ID_CMD_643:
break;
@@ -520,18 +653,19 @@ unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
* this point.
*/
(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
-#if 0
+
/* Set reasonable active/recovery/address-setup values. */
(void) pci_write_config_byte(dev, ARTTIM0, 0x40);
(void) pci_write_config_byte(dev, DRWTIM0, 0x3f);
(void) pci_write_config_byte(dev, ARTTIM1, 0x40);
(void) pci_write_config_byte(dev, DRWTIM1, 0x3f);
+#ifdef __i386__
+ (void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#else
(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+#endif
(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
(void) pci_write_config_byte(dev, DRWTIM3, 0x3f);
-#else
- (void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#endif
#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
cmd64x_proc = 1;
@@ -547,7 +681,7 @@ unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
byte ata66 = 0;
byte mask = (hwif->channel) ? 0x02 : 0x01;
- pci_read_config_byte(hwif->pci_dev, 0x79, &ata66);
+ pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
return (ata66 & mask) ? 1 : 0;
}
@@ -560,12 +694,11 @@ void __init ide_init_cmd64x (ide_hwif_t *hwif)
class_rev &= 0xff;
hwif->tuneproc = &cmd64x_tuneproc;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[0].autotune = 1;
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ if (!hwif->dma_base)
return;
- }
switch(dev->device) {
case PCI_DEVICE_ID_CMD_643:
diff --git a/drivers/block/hpt34x.c b/drivers/block/hpt34x.c
index 7a077368e..425ce35a4 100644
--- a/drivers/block/hpt34x.c
+++ b/drivers/block/hpt34x.c
@@ -46,9 +46,10 @@
#define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4)))
#endif
-#define HPT343_DEBUG_DRIVE_INFO 1
+#define HPT343_DEBUG_DRIVE_INFO 0
+
+#undef DISPLAY_HPT34X_TIMINGS
-#define DISPLAY_HPT34X_TIMINGS
#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
diff --git a/drivers/block/hpt366.c b/drivers/block/hpt366.c
index 02c9c16dd..d2f2fb433 100644
--- a/drivers/block/hpt366.c
+++ b/drivers/block/hpt366.c
@@ -30,7 +30,7 @@
#include "ide_modes.h"
-#define DISPLAY_HPT366_TIMINGS
+#undef DISPLAY_HPT366_TIMINGS
#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
@@ -241,6 +241,11 @@ static int hpt366_tune_chipset (ide_drive_t *drive, byte speed)
/*
* Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
*/
+ if (speed >= XFER_MW_DMA_0) {
+ reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+ } else {
+ reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
+ }
reg2 &= ~0x80000000;
pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
@@ -270,7 +275,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
struct hd_driveid *id = drive->id;
byte speed = 0x00;
byte reg51h = 0;
- unsigned int reg40 = 0;
int rval;
if ((id->dma_ultra & 0x0010) &&
@@ -326,13 +330,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
if (reg51h & 0x80)
pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80);
#endif /* CONFIG_HPT366_FIP */
-
- /*
- * Preserve existing PIO settings:
- */
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, &reg40);
- speed = (speed & ~0xc0000000) | (reg40 & 0xc0000000);
-
#if HPT366_DEBUG_DRIVE_INFO
printk("%s: config_chipset_for_dma: speed=0x%04x\n", drive->name, speed);
#endif /* HPT366_DEBUG_DRIVE_INFO */
@@ -355,7 +352,6 @@ static void config_chipset_for_pio (ide_drive_t *drive)
unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
unsigned short xfer_pio = drive->id->eide_pio_modes;
byte timing, speed, pio;
- unsigned int reg40 = 0;
#if HPT366_DEBUG_DRIVE_INFO
printk("%s: config_chipset_for_pio\n", drive->name);
@@ -389,11 +385,6 @@ static void config_chipset_for_pio (ide_drive_t *drive)
speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
break;
}
- /*
- * Preserve existing DMA settings:
- */
- pci_read_config_dword(HWIF(drive)->pci_dev, 0x40, &reg40);
- speed = (speed & ~0x30070000) | (reg40 & 0x30070000);
#if HPT366_DEBUG_DRIVE_INFO
printk("%s: config_chipset_for_pio: speed=0x%04x\n", drive->name, speed);
#endif /* HPT366_DEBUG_DRIVE_INFO */
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index f766605bc..2ef50f285 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -105,8 +105,11 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
* The ATA spec tells large drives to return
* C/H/S = 16383/16/63 independent of their size.
* Some drives can be jumpered to use 15 heads instead of 16.
+ * Some drives can be jumpered to use 4092 cyls instead of 16383.
*/
- if (id->cyls == 16383 && id->sectors == 63 &&
+ if ((id->cyls == 16383
+ || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
+ id->sectors == 63 &&
(id->heads == 15 || id->heads == 16) &&
id->lba_capacity >= 16383*63*id->heads)
return 1;
diff --git a/drivers/block/ide-geometry.c b/drivers/block/ide-geometry.c
index 0f24b0ac3..6ebf20fe1 100644
--- a/drivers/block/ide-geometry.c
+++ b/drivers/block/ide-geometry.c
@@ -2,6 +2,8 @@
* linux/drivers/block/ide-geometry.c
*/
#include <linux/config.h>
+
+#ifdef CONFIG_BLK_DEV_IDE
#include <linux/ide.h>
#include <asm/io.h>
@@ -60,15 +62,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
/* Extract drive geometry from CMOS+BIOS if not already setup */
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
-#if 0
- if ((cmos_disks & (0xf0 >> (unit*4))) &&
- !drive->present && !drive->nobios) {
- drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS;
- drive->head = drive->bios_head = *(BIOS+2);
- drive->sect = drive->bios_sect = *(BIOS+14);
- drive->ctl = *(BIOS+8);
- }
-#else
+
if ((cmos_disks & (0xf0 >> (unit*4)))
&& !drive->present && !drive->nobios) {
unsigned short cyl = *(unsigned short *)BIOS;
@@ -83,7 +77,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", unit, cyl, head, sect);
}
}
-#endif
+
BIOS += 16;
}
#endif
@@ -98,13 +92,15 @@ static void
ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
const byte *headp = dm_head_vals;
- unsigned long total, tracks;
+ unsigned long total;
/*
* The specs say: take geometry as obtained from Identify,
* compute total capacity C*H*S from that, and truncate to
* 1024*255*63. Now take S=63, H the first in the sequence
* 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
+ * [Please tell aeb@cwi.nl in case this computes a
+ * geometry different from what OnTrack uses.]
*/
total = DRIVER(drive)->capacity(drive);
@@ -116,32 +112,10 @@ ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
return;
}
-#if 0
while (63 * headp[0] * 1024 < total && headp[1] != 0)
headp++;
*h = headp[0];
*c = total / (63 * headp[0]);
-#else
- /* The code below differs in two aspects:
- (i) It will not produce geometries like C/H/S = 1024/64/63
- because of the `>='. This follows OnTracks text (which
- claims that 512 <= C <= 1023), but not OnTracks code.
- (ii) It starts dividing by 63, so that a rounding down occurs.
- For example, with C=11159, H=10, S=37 we find total=4128830
- and DM would make C=512, H=128, S=63, but we make 1024/64/63
- if `>=' is replaced by `>'.
- The reason we use this code is mainly that we have done so for
- a long time without getting complaints.
- */
-
- tracks = total / 63;
- while (*c >= 1024) {
- *h = *headp;
- *c = tracks / *h;
- if (*++headp == 0)
- break;
- }
-#endif
}
/*
@@ -237,3 +211,4 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
drive->bios_cyl, drive->bios_head, drive->bios_sect);
return ret;
}
+#endif /* CONFIG_BLK_DEV_IDE */
diff --git a/drivers/block/ide-pnp.c b/drivers/block/ide-pnp.c
new file mode 100644
index 000000000..ffa3ade56
--- /dev/null
+++ b/drivers/block/ide-pnp.c
@@ -0,0 +1,158 @@
+/*
+ * linux/drivers/block/ide-pnp.c
+ *
+ * This file provides autodetection for ISA PnP IDE interfaces.
+ * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
+ *
+ * Copyright (C) 2000 Andrey Panin <pazke@orbita.don.sitek.net>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/ide.h>
+#include <linux/isapnp.h>
+
+#ifndef PREPARE_FUNC
+#define PREPARE_FUNC(dev) (dev->prepare)
+#define ACTIVATE_FUNC(dev) (dev->activate)
+#define DEACTIVATE_FUNC(dev) (dev->deactivate)
+#endif
+
+#define DEV_IO(dev, index) (dev->resource[index].start)
+#define DEV_IRQ(dev, index) (dev->irq_resource[index].start)
+
+#define DEV_NAME(dev) (dev->bus->name ? dev->bus->name : "ISA PnP")
+
+#define GENERIC_HD_DATA 0
+#define GENERIC_HD_ERROR 1
+#define GENERIC_HD_NSECTOR 2
+#define GENERIC_HD_SECTOR 3
+#define GENERIC_HD_LCYL 4
+#define GENERIC_HD_HCYL 5
+#define GENERIC_HD_SELECT 6
+#define GENERIC_HD_STATUS 7
+
+static int generic_ide_offsets[IDE_NR_PORTS] __initdata = {
+ GENERIC_HD_DATA, GENERIC_HD_ERROR, GENERIC_HD_NSECTOR,
+ GENERIC_HD_SECTOR, GENERIC_HD_LCYL, GENERIC_HD_HCYL,
+ GENERIC_HD_SELECT, GENERIC_HD_STATUS, -1, -1
+};
+
+/* ISA PnP device table entry */
+struct pnp_dev_t {
+ unsigned int vendor, device;
+ int (*init_fn)(struct pci_dev *dev, int enable);
+};
+
+/* Generic initialisation function for ISA PnP IDE interface */
+static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
+{
+ hw_regs_t hw;
+ int index;
+
+ if (!enable)
+ return 0;
+
+ if (!(DEV_IO(dev, 0) && DEV_IO(dev, 1) && DEV_IRQ(dev, 0)))
+ return 1;
+
+ ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
+ generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
+ 0, NULL, DEV_IRQ(dev, 0));
+
+ index = ide_register_hw(&hw, NULL);
+
+ if (index != -1) {
+ printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Add your devices here :)) */
+struct pnp_dev_t idepnp_devices[] __initdata = {
+ /* Generic ESDI/IDE/ATA compatible hard disk controller */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
+ pnpide_generic_init },
+ { 0 }
+};
+
+#ifdef MODULE
+#define NR_PNP_DEVICES 8
+struct pnp_dev_inst {
+ struct pci_dev *dev;
+ struct pnp_dev_t *dev_type;
+};
+static struct pnp_dev_inst devices[NR_PNP_DEVICES];
+static int pnp_ide_dev_idx = 0;
+#endif
+
+/*
+ * Probe for ISA PnP IDE interfaces.
+ */
+void pnpide_init(int enable)
+{
+ struct pci_dev *dev = NULL;
+ struct pnp_dev_t *dev_type;
+
+ if (!isapnp_present())
+ return;
+
+#ifdef MODULE
+ /* Module unload, deactivate all registered devices. */
+ if (!enable) {
+ int i;
+ for (i = 0; i < pnp_ide_dev_idx; i++) {
+ devices[i].dev_type->init_fn(dev, 0);
+
+ if (DEACTIVATE_FUNC(devices[i].dev))
+ DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev);
+ }
+ return;
+ }
+#endif
+ for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
+ while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
+ dev_type->device, dev))) {
+
+ if (dev->active)
+ continue;
+
+ if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+ printk("ide: %s prepare failed\n", DEV_NAME(dev));
+ continue;
+ }
+
+ if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
+ printk("ide: %s activate failed\n", DEV_NAME(dev));
+ continue;
+ }
+
+ /* Call device initialization function */
+ if (dev_type->init_fn(dev, 1)) {
+ if (DEACTIVATE_FUNC(dev))
+ DEACTIVATE_FUNC(dev)(dev);
+ } else {
+#ifdef MODULE
+ /*
+ * Register device in the array to
+ * deactivate it on a module unload.
+ */
+ if (pnp_ide_dev_idx >= NR_PNP_DEVICES)
+ return;
+ devices[pnp_ide_dev_idx].dev = dev;
+ devices[pnp_ide_dev_idx].dev_type = dev_type;
+ pnp_ide_dev_idx++;
+#endif
+ }
+ }
+ }
+}
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index a51d6ee15..311bcfa25 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -404,6 +404,7 @@ static int hwif_check_regions (ide_hwif_t *hwif)
{
int region_errors = 0;
+ hwif->straight8 = 0;
region_errors = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
@@ -412,16 +413,28 @@ static int hwif_check_regions (ide_hwif_t *hwif)
region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+
if (hwif->io_ports[IDE_CONTROL_OFFSET])
region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+
if (hwif->io_ports[IDE_IRQ_OFFSET])
region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+ /*
+ * If any errors are return, we drop the hwif interface.
+ */
return(region_errors);
}
static void hwif_register (ide_hwif_t *hwif)
{
+ if ((hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
+ (hwif->io_ports[IDE_STATUS_OFFSET])) {
+ ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+ hwif->straight8 = 1;
+ goto jump_straight8;
+ }
+
if (hwif->io_ports[IDE_DATA_OFFSET])
ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
if (hwif->io_ports[IDE_ERROR_OFFSET])
@@ -438,6 +451,8 @@ static void hwif_register (ide_hwif_t *hwif)
ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
if (hwif->io_ports[IDE_STATUS_OFFSET])
ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
+
+jump_straight8:
if (hwif->io_ports[IDE_CONTROL_OFFSET])
ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
if (hwif->io_ports[IDE_IRQ_OFFSET])
diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c
index debba3207..753597e9c 100644
--- a/drivers/block/ide-proc.c
+++ b/drivers/block/ide-proc.c
@@ -51,7 +51,7 @@
* be updated someday soon to use this mechanism.
*
* Feel free to develop and distribute fancy GUI configuration
- * utilities for you favorite PCI chipsets. I'll be working on
+ * utilities for your favorite PCI chipsets. I'll be working on
* one for the Promise 20246 someday soon. -ml
*
*/
@@ -798,7 +798,7 @@ void proc_ide_create(void)
create_proc_ide_interfaces();
- create_proc_read_entry("drivers",0,proc_ide_root,
+ create_proc_read_entry("drivers", 0, proc_ide_root,
proc_ide_read_drivers, NULL);
#ifdef CONFIG_BLK_DEV_AEC6210
@@ -823,11 +823,11 @@ void proc_ide_create(void)
#endif /* CONFIG_BLK_DEV_CS5530 */
#ifdef CONFIG_BLK_DEV_HPT34X
if ((hpt34x_display_info) && (hpt34x_proc))
- create_proc_info_entry("", 0, proc_ide_root, hpt34x_display_info);
+ create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
#endif /* CONFIG_BLK_DEV_HPT34X */
#ifdef CONFIG_BLK_DEV_HPT366
if ((hpt366_display_info) && (hpt366_proc))
- create_proc_info_entry("", 0, proc_ide_root, hpt366_display_info);
+ create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
#endif /* CONFIG_BLK_DEV_HPT366 */
#ifdef CONFIG_BLK_DEV_PDC202XX
if ((pdc202xx_display_info) && (pdc202xx_proc))
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 987093e56..326533e7f 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -161,18 +161,14 @@
extern byte fifoconfig; /* defined in via82cxxx.c used by ide_setup() */
#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
- IDE2_MAJOR, IDE3_MAJOR,
- IDE4_MAJOR, IDE5_MAJOR,
- IDE6_MAJOR, IDE7_MAJOR,
- IDE8_MAJOR, IDE9_MAJOR };
-
-static int idebus_parameter; /* holds the "idebus=" parameter */
-static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */
+static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
+
+static int idebus_parameter = 0; /* holds the "idebus=" parameter */
+static int system_bus_speed = 0; /* holds what we think is VESA/PCI bus speed */
static int initializing; /* set while initializing built-in drivers */
#ifdef CONFIG_BLK_DEV_IDEPCI
-static int ide_scan_direction = 0; /* HELLO, comment me!! */
+static int ide_scan_direction = 0; /* THIS was formerly 2.2.x pci=reverse */
#endif /* CONFIG_BLK_DEV_IDEPCI */
#if defined(__mc68000__) || defined(CONFIG_APUS)
@@ -186,8 +182,8 @@ static int ide_lock = 0;
/*
* ide_modules keeps track of the available IDE chipset/probe/driver modules.
*/
-ide_module_t *ide_modules = NULL;
-ide_module_t *ide_probe = NULL;
+ide_module_t *ide_modules = NULL;
+ide_module_t *ide_probe = NULL;
/*
* This is declared extern in ide.h, for access by other IDE modules:
@@ -1922,6 +1918,10 @@ ide_proc_entry_t generic_subdriver_entries[] = {
*/
void hwif_unregister (ide_hwif_t *hwif)
{
+ if (hwif->straight8) {
+ ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+ goto jump_eight;
+ }
if (hwif->io_ports[IDE_DATA_OFFSET])
ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
if (hwif->io_ports[IDE_ERROR_OFFSET])
@@ -1938,6 +1938,7 @@ void hwif_unregister (ide_hwif_t *hwif)
ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
if (hwif->io_ports[IDE_STATUS_OFFSET])
ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+jump_eight:
if (hwif->io_ports[IDE_CONTROL_OFFSET])
ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
if (hwif->io_ports[IDE_IRQ_OFFSET])
@@ -2102,6 +2103,7 @@ void ide_unregister (unsigned int index)
hwif->pci_dev = old_hwif.pci_dev;
hwif->pci_devid = old_hwif.pci_devid;
#endif /* CONFIG_BLK_DEV_IDEPCI */
+ hwif->straight8 = old_hwif.straight8;
abort:
restore_flags(flags); /* all CPUs */
@@ -2535,6 +2537,11 @@ static int ide_ioctl (struct inode *inode, struct file *file,
err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
if (!err && set_transfer(drive, args[0], args[1], args[2])) {
+#if 0
+ /* active-retuning-calls future */
+ if (HWIF(drive)->tune2proc)
+ HWIF(drive)->tune2proc(drive, args[1]);
+#endif
ide_driveid_update(drive);
}
abort:
@@ -2796,6 +2803,7 @@ int __init ide_setup (char *s)
const char max_hwif = '0' + (MAX_HWIFS - 1);
printk("ide_setup: %s", s);
+ init_ide_data ();
#ifdef CONFIG_BLK_DEV_IDEDOUBLER
if (!strcmp(s, "ide=doubler")) {
@@ -2815,10 +2823,6 @@ int __init ide_setup (char *s)
}
#endif /* CONFIG_BLK_DEV_IDEPCI */
-#ifndef CONFIG_BLK_DEV_IDEPCI
- init_ide_data ();
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-
/*
* Look for drive options: "hdx="
*/
@@ -2971,9 +2975,9 @@ int __init ide_setup (char *s)
if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
if (match_parm(&s[6], NULL, vals, 1) != 1)
goto bad_option;
- if (vals[0] >= 20 && vals[0] <= 66)
+ if (vals[0] >= 20 && vals[0] <= 66) {
idebus_parameter = vals[0];
- else
+ } else
printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
goto done;
}
@@ -3216,6 +3220,12 @@ static void __init probe_for_hwifs (void)
buddha_init();
}
#endif /* CONFIG_BLK_DEV_BUDDHA */
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP)
+ {
+ extern void pnpide_init(int enable);
+ pnpide_init(1);
+ }
+#endif /* CONFIG_BLK_DEV_ISAPNP */
}
void __init ide_init_builtin_drivers (void)
@@ -3407,6 +3417,9 @@ int ide_unregister_subdriver (ide_drive_t *drive)
restore_flags(flags); /* all CPUs */
return 1;
}
+#if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
+ pnpide_init(0);
+#endif /* CONFIG_BLK_DEV_ISAPNP */
#ifdef CONFIG_PROC_FS
ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
@@ -3550,6 +3563,7 @@ int __init ide_init (void)
if (!banner_printed) {
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
ide_devfs_handle = devfs_mk_dir (NULL, "ide", 3, NULL);
+ (void) ide_system_bus_speed();
banner_printed = 1;
}
@@ -3578,6 +3592,7 @@ static void __init parse_options (char *line)
if ((next = strchr(line,' ')) != NULL)
*next++ = 0;
if (!strncmp(line,"ide",3) ||
+ !strncmp(line,"idebus",6) ||
#ifdef CONFIG_BLK_DEV_VIA82CXXX
!strncmp(line,"splitfifo",9) ||
#endif /* CONFIG_BLK_DEV_VIA82CXXX */
diff --git a/drivers/block/ide_modes.h b/drivers/block/ide_modes.h
index b6c28e6ab..f94d91313 100644
--- a/drivers/block/ide_modes.h
+++ b/drivers/block/ide_modes.h
@@ -197,6 +197,10 @@ byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode,
}
}
+#if 0
+ if (drive->id->major_rev_num & 0x0004) printf("ATA-2 ");
+#endif
+
/*
* Conservative "downgrade" for all pre-ATA2 drives
*/
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index a0ac26a49..c14591b92 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -212,15 +212,18 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
struct request *next, int max_segments)
{
int total_segments = req->nr_segments + next->nr_segments;
+ int same_segment;
+ same_segment = 0;
if (req->bhtail->b_data + req->bhtail->b_size == next->bh->b_data) {
total_segments--;
- q->nr_segments--;
+ same_segment = 1;
}
if (total_segments > max_segments)
return 0;
+ q->nr_segments -= same_segment;
req->nr_segments = total_segments;
return 1;
}
@@ -472,14 +475,8 @@ static inline void __elevator_merge(request_queue_t * q, struct request * req, i
int sequence = elevator_sequence(&q->elevator, latency);
if (after)
sequence -= req->nr_segments;
- if (elevator_sequence_before(sequence, req->elevator_sequence)) {
- if (!after)
- printk(KERN_WARNING __FUNCTION__
- ": req latency %d req latency %d\n",
- req->elevator_sequence - q->elevator.sequence,
- sequence - q->elevator.sequence);
+ if (elevator_sequence_before(sequence, req->elevator_sequence))
req->elevator_sequence = sequence;
- }
}
static inline void elevator_queue(request_queue_t * q,
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 65e7bfdc4..a0b63a8c8 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -4,7 +4,7 @@
* Note that you can not swap over this thing, yet. Seems to work but
* deadlocks sometimes - you can not swap over TCP in general.
*
- * Copyright 1997 Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
*
* (part of code stolen from loop.c)
*
@@ -24,6 +24,7 @@
* structure with userland
*/
+#undef NBD_PLUGGABLE
#define PARANOIA
#include <linux/major.h>
@@ -62,10 +63,11 @@ static int requests_in;
static int requests_out;
#endif
+static void nbd_plug_device(request_queue_t *q, kdev_t dev) { }
+
static int nbd_open(struct inode *inode, struct file *file)
{
int dev;
- struct nbd_device *nbdev;
if (!inode)
return -EINVAL;
@@ -73,13 +75,7 @@ static int nbd_open(struct inode *inode, struct file *file)
if (dev >= MAX_NBD)
return -ENODEV;
- nbdev = &nbd_dev[dev];
nbd_dev[dev].refcnt++;
- if (!(nbdev->flags & NBD_INITIALISED)) {
- init_MUTEX(&nbdev->queue_lock);
- INIT_LIST_HEAD(&nbdev->queue_head);
- nbdev->flags |= NBD_INITIALISED;
- }
MOD_INC_USE_COUNT;
return 0;
}
@@ -216,12 +212,18 @@ struct request *nbd_read_stat(struct nbd_device *lo)
void nbd_do_it(struct nbd_device *lo)
{
struct request *req;
+ int dequeued;
down (&lo->queue_lock);
- while (!list_empty(&lo->queue_head)) {
+ while (1) {
+ up (&lo->queue_lock);
req = nbd_read_stat(lo);
- if (!req)
+ down (&lo->queue_lock);
+
+ if (!req) {
+ printk(KERN_ALERT "req should never be null\n" );
goto out;
+ }
#ifdef PARANOIA
if (req != blkdev_entry_prev_request(&lo->queue_head)) {
printk(KERN_ALERT "NBD: I have problem...\n");
@@ -238,9 +240,11 @@ void nbd_do_it(struct nbd_device *lo)
list_del(&req->queue);
up (&lo->queue_lock);
- nbd_end_request(req);
+ dequeued = nbd_end_request(req);
down (&lo->queue_lock);
+ if (!dequeued)
+ list_add(&req->queue, &lo->queue_head);
}
out:
up (&lo->queue_lock);
@@ -249,26 +253,36 @@ void nbd_do_it(struct nbd_device *lo)
void nbd_clear_que(struct nbd_device *lo)
{
struct request *req;
+ int dequeued;
+
+#ifdef PARANOIA
+ if (lo->magic != LO_MAGIC) {
+ printk(KERN_ERR "NBD: nbd_dev[] corrupted: Not enough magic when clearing!\n");
+ return;
+ }
+#endif
while (!list_empty(&lo->queue_head)) {
req = blkdev_entry_prev_request(&lo->queue_head);
#ifdef PARANOIA
+ if (!req) {
+ printk( KERN_ALERT "NBD: panic, panic, panic\n" );
+ break;
+ }
if (lo != &nbd_dev[MINOR(req->rq_dev)]) {
printk(KERN_ALERT "NBD: request corrupted when clearing!\n");
continue;
}
- if (lo->magic != LO_MAGIC) {
- printk(KERN_ERR "NBD: nbd_dev[] corrupted: Not enough magic when clearing!\n");
- return;
- }
#endif
req->errors++;
list_del(&req->queue);
up(&lo->queue_lock);
- nbd_end_request(req);
+ dequeued = nbd_end_request(req);
down(&lo->queue_lock);
+ if (!dequeued)
+ list_add(&req->queue, &lo->queue_head);
}
}
@@ -290,6 +304,10 @@ static void do_nbd_request(request_queue_t * q)
while (!QUEUE_EMPTY) {
req = CURRENT;
+#ifdef PARANOIA
+ if (!req)
+ FAIL("que not empty but no request?");
+#endif
dev = MINOR(req->rq_dev);
#ifdef PARANOIA
if (dev >= MAX_NBD)
@@ -470,12 +488,17 @@ int nbd_init(void)
blksize_size[MAJOR_NR] = nbd_blksizes;
blk_size[MAJOR_NR] = nbd_sizes;
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_nbd_request);
+#ifndef NBD_PLUGGABLE
+ blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), nbd_plug_device);
+#endif
blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
for (i = 0; i < MAX_NBD; i++) {
nbd_dev[i].refcnt = 0;
nbd_dev[i].file = NULL;
nbd_dev[i].magic = LO_MAGIC;
nbd_dev[i].flags = 0;
+ INIT_LIST_HEAD(&nbd_dev[i].queue_head);
+ init_MUTEX(&nbd_dev[i].queue_lock);
nbd_blksizes[i] = 1024;
nbd_blksize_bits[i] = 10;
nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
diff --git a/drivers/block/pdc202xx.c b/drivers/block/pdc202xx.c
index bce80650c..9ec7c8997 100644
--- a/drivers/block/pdc202xx.c
+++ b/drivers/block/pdc202xx.c
@@ -100,7 +100,8 @@
#define PDC202XX_DEBUG_DRIVE_INFO 0
#define PDC202XX_DECODE_REGISTER_INFO 0
-#define DISPLAY_PDC202XX_TIMINGS
+#undef DISPLAY_PDC202XX_TIMINGS
+
#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
#include <linux/stat.h>
#include <linux/proc_fs.h>
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 9686f05b6..a51dcd36f 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -99,6 +99,7 @@ static int rd_hardsec[NUM_RAMDISKS]; /* Size of real blocks in bytes */
static int rd_blocksizes[NUM_RAMDISKS]; /* Size of 1024 byte blocks :) */
static int rd_kbsize[NUM_RAMDISKS]; /* Size in blocks of 1024 bytes */
static devfs_handle_t devfs_handle = NULL;
+static struct inode *rd_inode[NUM_RAMDISKS]; /* Protected device inodes */
/*
* Parameters for the boot-loading of the RAM disk. These are set by
@@ -169,11 +170,18 @@ static int __init ramdisk_size2(char *str)
return ramdisk_size(str);
}
+static int __init ramdisk_blocksize(char *str)
+{
+ rd_blocksize = simple_strtol(str,NULL,0);
+ return 1;
+}
+
__setup("ramdisk_start=", ramdisk_start_setup);
__setup("load_ramdisk=", load_ramdisk);
__setup("prompt_ramdisk=", prompt_ramdisk);
__setup("ramdisk=", ramdisk_size);
__setup("ramdisk_size=", ramdisk_size2);
+__setup("ramdisk_blocksize=", ramdisk_blocksize);
#endif
@@ -216,67 +224,16 @@ repeat:
goto repeat;
}
- /*
- * This has become somewhat more complicated with the addition of
- * the page cache. The problem is that in some cases the furnished
- * buffer is "real", i.e., part of the existing ramdisk, while in
- * others it is "unreal", e.g., part of a page. In the first case
- * not much needs to be done, while in the second, some kind of
- * transfer is needed.
- *
- * The two cases are distinguished here by checking whether the
- * real buffer is already in the buffer cache, and whether it is
- * the same as the one supplied.
- *
- * There are three cases with read/write to consider:
- *
- * 1. Supplied buffer matched one in the buffer cache:
- * Read - Clear the buffer, as it wasn't already valid.
- * Write - Mark the buffer as "Protected".
- *
- * 2. Supplied buffer mismatched one in the buffer cache:
- * Read - Copy the data from the buffer cache entry.
- * Write - Copy the data to the buffer cache entry.
- *
- * 3 No buffer cache entry existed:
- * Read - Clear the supplied buffer, but do not create a real
- * one.
- * Write - Create a real buffer, copy the data to it, and mark
- * it as "Protected".
- *
- * NOTE: There seems to be some schizophrenia here - the logic
- * using "len" seems to assume arbitrary request lengths, while
- * the "protect" logic assumes a single buffer cache entry.
- * This seems to be left over from the ancient contiguous ramdisk
- * logic.
- */
-
sbh = CURRENT->bh;
- rbh = get_hash_table(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
- if (sbh == rbh) {
- if (CURRENT->cmd == READ)
- memset(CURRENT->buffer, 1, len);
- } else if (rbh) {
- if (CURRENT->cmd == READ)
+ rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
+ if (CURRENT->cmd == READ) {
+ if (sbh != rbh)
memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
- else
+ } else
+ if (sbh != rbh)
memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
- } else { /* !rbh */
- if (CURRENT->cmd == READ)
- memset(sbh->b_data, 2, len);
- else {
- rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
- if (rbh)
- memcpy(rbh->b_data, CURRENT->buffer,
- rbh->b_size);
- else
- BUG(); /* No buffer, what to do here? */
- }
- }
- if (rbh) {
- mark_buffer_protected(rbh);
- brelse(rbh);
- }
+ mark_buffer_protected(rbh);
+ brelse(rbh);
end_request(1);
goto repeat;
@@ -372,6 +329,14 @@ static int rd_open(struct inode * inode, struct file * filp)
if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
return -ENXIO;
+ /*
+ * Immunize device against invalidate_buffers() and prune_icache().
+ */
+ if (rd_inode[DEVICE_NR(inode->i_rdev)] == NULL) {
+ if((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
+ atomic_inc(&rd_inode[DEVICE_NR(inode->i_rdev)]->i_bdev->bd_openers);
+ }
+
MOD_INC_USE_COUNT;
return 0;
@@ -389,24 +354,31 @@ static struct block_device_operations fd_fops = {
ioctl: rd_ioctl,
};
+#ifdef MODULE
/* Before freeing the module, invalidate all of the protected buffers! */
static void __exit rd_cleanup (void)
{
int i;
for (i = 0 ; i < NUM_RAMDISKS; i++) {
- struct block_device *bdev;
- bdev = bdget(kdev_t_to_nr(MKDEV(MAJOR_NR,i)));
- atomic_dec(&bdev->bd_openers);
+ if (rd_inode[i]) {
+ /* withdraw invalidate_buffers() and prune_icache() immunity */
+ atomic_dec(&rd_inode[i]->i_bdev->bd_openers);
+ /* remove stale pointer to module address space */
+ rd_inode[i]->i_bdev->bd_op = NULL;
+ iput(rd_inode[i]);
+ }
destroy_buffers(MKDEV(MAJOR_NR, i));
}
devfs_unregister (devfs_handle);
unregister_blkdev( MAJOR_NR, "ramdisk" );
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+ hardsect_size[MAJOR_NR] = NULL;
blksize_size[MAJOR_NR] = NULL;
blk_size[MAJOR_NR] = NULL;
}
+#endif
/* This is the registration and initialization section of the RAM disk driver */
int __init rd_init (void)
@@ -441,21 +413,16 @@ int __init rd_init (void)
S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
&fd_fops, NULL);
- hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */
- blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */
-
- for (i = 0; i < NUM_RAMDISKS; i++) {
- struct block_device *bdev;
+ for (i = 0; i < NUM_RAMDISKS; i++)
register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &fd_fops, rd_size<<1);
- bdev = bdget(kdev_t_to_nr(MKDEV(MAJOR_NR,i)));
- atomic_inc(&bdev->bd_openers); /* avoid invalidate_buffers() */
- }
#ifdef CONFIG_BLK_DEV_INITRD
/* We ought to separate initrd operations here */
register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &fd_fops, rd_size<<1);
#endif
+ hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */
+ blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */
blk_size[MAJOR_NR] = rd_kbsize; /* Size of the RAM disk in kB */
/* rd_size is given in kB */
@@ -468,8 +435,8 @@ int __init rd_init (void)
#ifdef MODULE
module_init(rd_init);
-#endif
module_exit(rd_cleanup);
+#endif
/* loadable module support */
MODULE_PARM (rd_size, "1i");
diff --git a/drivers/block/via82cxxx.c b/drivers/block/via82cxxx.c
index 54681f38c..c2ec24d39 100644
--- a/drivers/block/via82cxxx.c
+++ b/drivers/block/via82cxxx.c
@@ -43,6 +43,38 @@
* Note that by default (if no command line is provided) and if a channel
* has been disabled in Bios, all the fifo is given to the active channel,
* and its threshold is set to 3/4.
+ *
+ * VT82c586B
+ *
+ * Offset 4B-48 - Drive Timing Control
+ * | pio0 | pio1 | pio2 | pio3 | pio4
+ * 25.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20
+ * 33.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20
+ * 37.5 MHz | 0xA9 | 0x76 | 0x76 | 0x32 | 0x21
+ *
+ * Offset 53-50 - UltraDMA Extended Timing Control
+ * UDMA | NO | 0 | 1 | 2
+ * | 0x03 | 0x62 | 0x61 | 0x60
+ *
+ * VT82c596B & VT82c686A
+ *
+ * Offset 4B-48 - Drive Timing Control
+ * | pio0 | pio1 | pio2 | pio3 | pio4
+ * 25.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20
+ * 33.0 MHz | 0xA8 | 0x65 | 0x65 | 0x31 | 0x20
+ * 37.5 MHz | 0xDB | 0x87 | 0x87 | 0x42 | 0x31
+ * 41.5 MHz | 0xFE | 0xA8 | 0xA8 | 0x53 | 0x32
+ *
+ * Offset 53-50 - UltraDMA Extended Timing Control
+ * UDMA | NO | 0 | 1 | 2
+ * 33.0 MHz | 0x03 | 0xE2 | 0xE1 | 0xE0
+ * 37.5 MHz | 0x03 | 0xE2 | 0xE2 | 0xE1 (1)
+ *
+ * Offset 53-50 - UltraDMA Extended Timing Control
+ * UDMA | NO | 0 | 1 | 2 | 3 | 4
+ * 33.0 MHz | (2) | 0xE6 | 0xE4 | 0xE2 | 0xE1 | 0xE0
+ * 37.5 MHz | (2) | 0xE6 | 0xE6 | 0xE4 | 0xE2 | 0xE1 (1)
+ *
*/
#include <linux/config.h>
@@ -76,6 +108,8 @@ static const struct {
{ "VT 82C691 Apollo Pro", PCI_DEVICE_ID_VIA_82C691, },
{ "VT 82C693 Apollo Pro Plus", PCI_DEVICE_ID_VIA_82C693, },
{ "Apollo MVP4", PCI_DEVICE_ID_VIA_8501_0, },
+ { "VT 8371", PCI_DEVICE_ID_VIA_8371_0, },
+ { "VT 8601", PCI_DEVICE_ID_VIA_8601_0, },
};
#define NUM_APOLLO_ISA_CHIP_DEVICES 2
@@ -96,6 +130,8 @@ static const struct {
{ PCI_DEVICE_ID_VIA_82C691, PCI_DEVICE_ID_VIA_82C596, 0 },
{ PCI_DEVICE_ID_VIA_82C693, PCI_DEVICE_ID_VIA_82C596, 0 },
{ PCI_DEVICE_ID_VIA_8501_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66 },
+ { PCI_DEVICE_ID_VIA_8371_0, PCI_DEVICE_ID_VIA_82C686, VIA_FLAG_ATA_66 },
+ { PCI_DEVICE_ID_VIA_8601_0, PCI_DEVICE_ID_VIA_8231, VIA_FLAG_ATA_66 },
};
#define arraysize(x) (sizeof(x)/sizeof(*(x)))
@@ -477,6 +513,220 @@ static int via_set_fifoconfig(ide_hwif_t *hwif)
return 0;
}
+#ifdef CONFIG_VIA82CXXX_TUNING
+
+static int via82cxxx_tune_chipset (ide_drive_t *drive, byte speed)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned long dma_base = hwif->dma_base;
+ byte unit = (drive->select.b.unit & 0x01);
+ int drive_number = ((hwif->channel ? 2 : 0) + unit);
+
+ byte ata2_pci = 0x00;
+ byte ata3_pci = 0x00;
+ byte timing = 0x00;
+ byte ultra = 0x00;
+ int err;
+
+ int bus_speed = ide_system_bus_speed();
+
+ switch(drive_number) {
+ case 0: ata2_pci = 0x48; ata3_pci = 0x50; break;
+ case 1: ata2_pci = 0x49; ata3_pci = 0x51; break;
+ case 2: ata2_pci = 0x4a; ata3_pci = 0x52; break;
+ case 3: ata2_pci = 0x4b; ata3_pci = 0x53; break;
+ default:
+ return err;
+ }
+
+ pci_read_config_byte(dev, ata2_pci, &timing);
+ pci_read_config_byte(dev, ata3_pci, &ultra);
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_2:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ case XFER_PIO_SLOW:
+ default:
+ break;
+ }
+
+ pci_write_config_byte(dev, ata2_pci, timing);
+ pci_write_config_byte(dev, ata3_pci, ultra);
+
+ err = ide_config_drive_speed(drive, speed);
+
+ return(err);
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ byte speed = 0x00;
+ int rval;
+
+ if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) {
+ speed = XFER_UDMA_4;
+ } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) {
+ speed = XFER_UDMA_3;
+ } else if (id->dma_ultra & 0x0004) {
+ speed = XFER_UDMA_2;
+ } else if (id->dma_ultra & 0x0002) {
+ speed = XFER_UDMA_1;
+ } else if (id->dma_ultra & 0x0001) {
+ speed = XFER_UDMA_0;
+ } else if (id->dma_mword & 0x0004) {
+ speed = XFER_MW_DMA_2;
+ } else if (id->dma_mword & 0x0002) {
+ speed = XFER_MW_DMA_1;
+ } else if (id->dma_mword & 0x0001) {
+ speed = XFER_MW_DMA_0;
+ } else if (id->dma_1word & 0x0004) {
+ speed = XFER_SW_DMA_2;
+ } else if (id->dma_1word & 0x0002) {
+ speed = XFER_SW_DMA_1;
+ } else if (id->dma_1word & 0x0001) {
+ speed = XFER_SW_DMA_0;
+ } else {
+ return ((int) ide_dma_off_quietly);
+ }
+
+ (void) via82cxxx_tune_chipset(drive, speed);
+
+ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on :
+ ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
+ ((id->dma_mword >> 8) & 7) ? ide_dma_on :
+ ((id->dma_1word >> 8) & 7) ? ide_dma_on :
+ ide_dma_off_quietly);
+ return rval;
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ unsigned short xfer_pio = drive->id->eide_pio_modes;
+ byte timing, speed, pio;
+
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 :
+ (drive->id->tPIO & 2) ? 0x02 :
+ (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ switch(timing) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default:
+ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; break;
+ }
+ (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+static void via82cxxx_tune_drive (ide_drive_t *drive, byte pio)
+{
+ byte speed;
+ switch(pio) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default: speed = XFER_PIO_0;break;
+ }
+ (void) via82cxxx_tune_chipset(drive, speed);
+}
+
+static int config_drive_xfer_rate (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_dma_action_t dma_func = ide_dma_on;
+
+ if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+ /* Consult the list of known "bad" drives */
+ if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+ dma_func = ide_dma_off;
+ goto fast_ata_pio;
+ }
+ dma_func = ide_dma_off_quietly;
+ if (id->field_valid & 4) {
+ if (id->dma_ultra & 0x001F) {
+ /* Force if Capable UltraDMA */
+ dma_func = config_chipset_for_dma(drive);
+ if ((id->field_valid & 2) &&
+ (dma_func != ide_dma_on))
+ goto try_dma_modes;
+ }
+ } else if (id->field_valid & 2) {
+try_dma_modes:
+ if ((id->dma_mword & 0x0007) ||
+ (id->dma_1word & 0x0007)) {
+ /* Force if Capable regular DMA modes */
+ dma_func = config_chipset_for_dma(drive);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ }
+ } else if (ide_dmaproc(ide_dma_good_drive, drive)) {
+ if (id->eide_dma_time > 150) {
+ goto no_dma_set;
+ }
+ /* Consult the list of known "good" drives */
+ dma_func = config_chipset_for_dma(drive);
+ if (dma_func != ide_dma_on)
+ goto no_dma_set;
+ } else {
+ goto fast_ata_pio;
+ }
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ dma_func = ide_dma_off_quietly;
+no_dma_set:
+ config_chipset_for_pio(drive);
+ }
+ return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+int via82cxxx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ switch (func) {
+ case ide_dma_check:
+ return config_drive_xfer_rate(drive);
+ default:
+ break;
+ }
+ return ide_dmaproc(func, drive); /* use standard DMA stuff */
+}
+#endif /* CONFIG_VIA82CXXX_TUNING */
+
unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
{
struct pci_dev *host;
@@ -501,7 +751,7 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
continue;
isa = pci_find_device (PCI_VENDOR_ID_VIA,
- ApolloISAChipInfo[i].isa_id,
+ ApolloISAChipInfo[j].isa_id,
NULL);
if (!isa)
continue;
@@ -511,10 +761,10 @@ unsigned int __init pci_init_via82cxxx (struct pci_dev *dev, const char *name)
ata33 = 1;
ata66 = 0;
- if (ApolloISAChipInfo[i].flags & VIA_FLAG_CHECK_REV) {
+ if (ApolloISAChipInfo[j].flags & VIA_FLAG_CHECK_REV) {
pci_read_config_byte(isa_dev, 0x0d, &revision);
ata33 = (revision >= 0x20) ? 1 : 0;
- } else if (ApolloISAChipInfo[i].flags & VIA_FLAG_ATA_66) {
+ } else if (ApolloISAChipInfo[j].flags & VIA_FLAG_ATA_66) {
ata33 = 0;
ata66 = 1;
}
@@ -543,7 +793,8 @@ unsigned int __init ata66_via82cxxx (ide_hwif_t *hwif)
void __init ide_init_via82cxxx (ide_hwif_t *hwif)
{
set_via_timings(hwif);
-#if 0
+
+#ifdef CONFIG_VIA82CXXX_TUNING
hwif->tuneproc = &via82cxxx_tune_drive;
if (hwif->dma_base) {
hwif->dmaproc = &via82cxxx_dmaproc;
@@ -552,7 +803,7 @@ void __init ide_init_via82cxxx (ide_hwif_t *hwif)
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
}
-#endif
+#endif /* CONFIG_VIA82CXXX_TUNING */
}
/*
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 920546763..18f867c04 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -140,7 +140,9 @@ fi
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
-bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
+if [ "$CONFIG_IA64" = "y" ]; then
+ bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
+fi
if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
bool 'Tadpole ANA H8 Support' CONFIG_H8
fi
@@ -207,8 +209,8 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
fi
fi
- dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
- dep_tristate ' SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV
+ dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV $CONFIG_I2C
+ dep_tristate ' SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
if [ "$CONFIG_SGI" = "y" ]; then
dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI
diff --git a/drivers/char/README.epca b/drivers/char/README.epca
index da2e11400..d95ff1fed 100644
--- a/drivers/char/README.epca
+++ b/drivers/char/README.epca
@@ -523,3 +523,10 @@ Description (Verbose) : Updated driver:
Files affected : epca.c
Release version : 1.3.0.1-LK
-----------------------------------------------------------------------
+Programmer : Arjan van de Ven <adve@oce.nl>
+Date : March 10, 2000
+Description (Verbose) : Fixed includes to make it actually compile
+ for kernel 2.3.51
+Files affected : epca.c
+Release version : 1.3.0.2-LK
+-----------------------------------------------------------------------
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index 82f545ecc..19e252968 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -20,7 +20,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 8ed17fd71..ac27c9e0e 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -1,9 +1,9 @@
/*
* The DSP56001 Device Driver, saviour of the Free World(tm)
*
- * Authors: Fredrik Noring <noring@lysator.liu.se>
- * lars brinkhoff <f93labr@dd.chalmers.se>
- * Tomas Berndtsson <tobe@lysator.liu.se>
+ * Authors: Fredrik Noring <noring@nocrew.org>
+ * lars brinkhoff <lars@nocrew.org>
+ * Tomas Berndtsson <tomas@nocrew.org>
*
* First version May 1996
*
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 31cd5546c..dd94223bc 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -38,7 +38,10 @@
#include <linux/ctype.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
#include <asm/uaccess.h>
+#include <asm/io.h>
#ifdef CONFIG_PCI
#define ENABLE_PCI
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 2ca3145d9..3bf3fbf28 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -52,6 +52,7 @@ extern int videodev_init(void);
#endif
#ifdef CONFIG_FB
extern void fbmem_init(void);
+extern void fbconsole_init(void);
#endif
#ifdef CONFIG_PROM_CONSOLE
extern void prom_con_init(void);
@@ -620,6 +621,7 @@ int __init chr_dev_init(void)
#endif
#if defined (CONFIG_FB)
fbmem_init();
+ fbconsole_init();
#endif
#if defined (CONFIG_PROM_CONSOLE)
prom_con_init();
diff --git a/drivers/char/radio-miropcm20.c b/drivers/char/radio-miropcm20.c
index 04beea2d5..15985380b 100644
--- a/drivers/char/radio-miropcm20.c
+++ b/drivers/char/radio-miropcm20.c
@@ -10,7 +10,7 @@
#include <linux/init.h> /* Initdata */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
-#include "../sound/lowlevel/miroaci.h" /* ACI Control by acimixer */
+#include "../sound/miroaci.h" /* ACI Control by acimixer */
static int users = 0;
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 61dfd6e42..a7c1b0703 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -197,14 +197,17 @@ int raw_ctl_ioctl(struct inode *inode,
raw_device_bindings[minor] =
bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor)));
} else {
+ struct block_device *bdev;
kdev_t dev;
- if (!raw_device_bindings[minor]) {
- err = -ENODEV;
- break;
+
+ bdev = raw_device_bindings[minor];
+ if (bdev) {
+ dev = to_kdev_t(bdev->bd_dev);
+ rq.block_major = MAJOR(dev);
+ rq.block_minor = MINOR(dev);
+ } else {
+ rq.block_major = rq.block_minor = 0;
}
- dev = to_kdev_t(raw_device_bindings[minor]->bd_dev);
- rq.block_major = MAJOR(dev);
- rq.block_minor = MINOR(dev);
err = copy_to_user((void *) arg, &rq, sizeof(rq));
}
break;
@@ -304,7 +307,12 @@ ssize_t rw_raw_dev(int rw, struct file *filp, char *buf,
err = map_user_kiobuf(rw, iobuf, (unsigned long) buf, iosize);
if (err)
break;
-
+#if 0
+ err = lock_kiovec(1, &iobuf, 1);
+ if (err)
+ break;
+#endif
+
for (i=0; i < blocks; i++)
b[i] = blocknr++;
@@ -316,7 +324,7 @@ ssize_t rw_raw_dev(int rw, struct file *filp, char *buf,
buf += err;
}
- unmap_kiobuf(iobuf);
+ unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */
if (err != iosize)
break;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 06a616592..08c92ace9 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -186,8 +186,10 @@ u16 el3_isapnp_phys_addr[8][3] = {
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
};
-#endif
+#endif /* CONFIG_ISAPNP */
+#if defined(CONFIG_ISAPNP) || defined(MODULE)
static int nopnp = 0;
+#endif
int el3_probe(struct net_device *dev)
{
@@ -195,8 +197,10 @@ int el3_probe(struct net_device *dev)
int ioaddr, irq, if_port;
u16 phys_addr[3];
static int current_tag = 0;
- static int pnp_cards = 0;
int mca_slot = -1;
+#ifdef CONFIG_ISAPNP
+ static int pnp_cards = 0;
+#endif
/* First check all slots of the EISA bus. The next slot address to
probe is kept in 'eisa_addr' to support multiple probe() calls. */
diff --git a/drivers/net/aironet4500.h b/drivers/net/aironet4500.h
index 914976a70..45e3bc044 100644
--- a/drivers/net/aironet4500.h
+++ b/drivers/net/aironet4500.h
@@ -66,8 +66,8 @@ struct awc_cis {
};
-/* timeout for transmit watchdog timer */
-#define TX_TIMEOUT (HZ * 3)
+/* timeout for transmit watchdog timer, AP default is 8 sec */
+#define AWC_TX_TIMEOUT (HZ * 8)
@@ -454,7 +454,7 @@ struct awc_fid_queue {
};
-extern inline void
+extern void
awc_fid_queue_init(struct awc_fid_queue * queue){
unsigned long flags;
@@ -1429,10 +1429,10 @@ extern struct awc_rid_dir awc_rids[];
struct awc_private {
- dev_node_t node;
-
-
- int dummy_test;
+ dev_node_t node; // somewhere back in times PCMCIA needed that
+
+ int dummy_test; // left for cleanup
+ // card rid inmemory copy
struct awc_config config; // card RID mirrors
struct awc_config general_config; //
struct awc_SSIDs SSIDs;
@@ -1452,6 +1452,7 @@ struct awc_private {
struct awc_wep_key wep_nonvolatile;
struct awc_modulation modulation;
+ // here are just references to rids
struct awc_rid_dir rid_dir[AWC_NOF_RIDS];
int rids_read;
@@ -1493,12 +1494,14 @@ struct awc_private {
// Command serialize stuff
//changed to spinlock struct semaphore command_semaphore;
- my_spinlock_t both_bap_spinlock;
+ my_spinlock_t both_bap_spinlock; // on SMP, card should theorethically live without that
unsigned long both_bap_spinlock_flags;
- my_spinlock_t bap_setup_spinlock;
+ my_spinlock_t bap_setup_spinlock; // on SMP, card should theoretically live without that
unsigned long bap_setup_spinlock_flags;
my_spinlock_t command_issuing_spinlock;
unsigned long command_issuing_spinlock_flags;
+ my_spinlock_t interrupt_spinlock;
+
volatile int unlock_command_postponed;
struct awc_command cmd;
long long async_command_start;
@@ -1511,6 +1514,13 @@ struct awc_private {
int p2p_uc;
int p2p_found;
int p802_11_send;
+ int simple_bridge;
+ int force_rts_on_shorter;
+ int force_tx_rate;
+ int ip_tos_reliability_rts;
+ int ip_tos_troughput_no_retries;
+ int full_stats;
+ int debug;
struct enet_statistics stats;
diff --git a/drivers/net/aironet4500_card.c b/drivers/net/aironet4500_card.c
index b271b18f4..04108ad73 100644
--- a/drivers/net/aironet4500_card.c
+++ b/drivers/net/aironet4500_card.c
@@ -188,9 +188,8 @@ static int awc_pci_init(struct net_device * dev, struct pci_dev *pdev,
dev->base_addr = ioaddr;
dev->irq = pci_irq_line;
dev->tx_timeout = &awc_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
+ dev->watchdog_timeo = AWC_TX_TIMEOUT;
- netif_start_queue (dev);
request_irq(dev->irq,awc_interrupt, SA_SHIRQ | SA_INTERRUPT ,"Aironet 4X00",dev);
@@ -377,7 +376,7 @@ int awc4500_pnp_probe(struct net_device *dev)
dev->base_addr = isa_ioaddr;
dev->irq = isa_irq_line;
dev->tx_timeout = &awc_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
+ dev->watchdog_timeo = AWC_TX_TIMEOUT;
netif_start_queue (dev);
@@ -498,7 +497,7 @@ int awc4500_isa_probe(struct net_device *dev)
if (! io[0] || ! irq[0]){
- printk(" Both irq and io params must be supplied for ISA mode !!!\n");
+// printk(" Both irq and io params must be supplied for ISA mode !!!\n");
return -ENODEV;
}
@@ -538,10 +537,8 @@ int awc4500_isa_probe(struct net_device *dev)
dev->base_addr = isa_ioaddr;
dev->irq = isa_irq_line;
dev->tx_timeout = &awc_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
+ dev->watchdog_timeo = AWC_TX_TIMEOUT;
- netif_start_queue (dev);
-
request_irq(dev->irq,awc_interrupt ,SA_INTERRUPT ,"Aironet 4X00",dev);
awc_private_init( dev);
@@ -815,9 +812,8 @@ static int awc_i365_init(struct i365_socket * s) {
dev->irq = s->irq;
dev->base_addr = s->io;
dev->tx_timeout = &awc_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
+ dev->watchdog_timeo = AWC_TX_TIMEOUT;
- netif_start_queue (dev);
awc_private_init( dev);
@@ -946,37 +942,40 @@ int init_module(void)
#ifdef CONFIG_AIRONET4500_PCI
if (awc4500_pci_probe(NULL) == -ENODEV){
- printk("PCI 4X00 aironet cards not found\n");
+// printk("PCI 4X00 aironet cards not found\n");
} else {
found++;
- printk("PCI 4X00 found some cards \n");
+// printk("PCI 4X00 found some cards \n");
}
#endif
#ifdef CONFIG_AIRONET4500_PNP
if (awc4500_pnp_probe(NULL) == -ENODEV){
- printk("PNP 4X00 aironet cards not found\n");
+// printk("PNP 4X00 aironet cards not found\n");
} else {
found++;
- printk("PNP 4X00 found some cards \n");
+// printk("PNP 4X00 found some cards \n");
}
#endif
#ifdef CONFIG_AIRONET4500_365
if ( awc_i365_probe() == -1) {
- printk("PCMCIA 4X00 aironet cards not found for i365(without card services) initialization\n");
+// printk("PCMCIA 4X00 aironet cards not found for i365(without card services) initialization\n");
} else {
found++ ;
- printk("PCMCIA 4X00 found some cards, take care, this code is not supposed to work yet \n");
+// printk("PCMCIA 4X00 found some cards, take care, this code is not supposed to work yet \n");
}
#endif
#ifdef CONFIG_AIRONET4500_ISA
if (awc4500_isa_probe(NULL) == -ENODEV){
- printk("ISA 4X00 aironet ISA-bus non-PNP-mode cards not found\n");
+// printk("ISA 4X00 aironet ISA-bus non-PNP-mode cards not found\n");
} else {
found++;
- printk("ISA 4X00 found some cards \n");
+// printk("ISA 4X00 found some cards \n");
}
#endif
- if (!found) return -1;
+ if (!found) {
+ printk(KERN_ERR "No Aironet 4X00 cards were found. Note that for ISA \n cards you should use either automatic PNP mode or \n ISA mode with both io and irq param \n Aironet is also afraid of: being second PNP controller(by slot), having anything(brandname bios weirdnesses) in range 0x100-0x180 and maybe around 0xd0000\n If you PNP type card does not get found, try non-PNP switch before complainig. \n");
+ return -1;
+ }
return 0;
diff --git a/drivers/net/aironet4500_core.c b/drivers/net/aironet4500_core.c
index 36554e46f..8c818d46a 100644
--- a/drivers/net/aironet4500_core.c
+++ b/drivers/net/aironet4500_core.c
@@ -15,6 +15,7 @@
november 99, integration with 2.3
17.12.99: finally, got SMP near-correct.
timing issues remain- on SMP box its 15% slower on tcp
+ 10.03.00 looks like softnet take us back to normal on SMP
*/
#include <linux/module.h>
@@ -36,6 +37,7 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include "aironet4500.h"
+#include <linux/ip.h>
int bap_sleep = 10 ;
@@ -371,7 +373,7 @@ final:
/******************************** BAP *************************/
-inline
+// inline // too long for inline
int awc_bap_setup(struct awc_command * cmd) {
int status;
@@ -1524,6 +1526,8 @@ awc_802_11_router_rx(struct net_device * dev,struct awc_fid * rx_buff){
rx_buff->skb = NULL;
rx_buff->u.rx.payload = NULL;
priv->stats.rx_packets++;
+ priv->stats.rx_bytes++;
+
netif_rx(skb);
AWC_ENTRY_EXIT_DEBUG("exit\n");
return ;
@@ -1577,11 +1581,12 @@ awc_802_11_tx_find_path_and_post(struct net_device * dev,
struct awc_fid * fid = NULL;
// u16 saved_fid ;
u16 p2p_direct =priv->p2p_found;
-// struct iphdr * ip_hdr;
+ struct iphdr * ip_hdr;
//buffer = skb->data;
AWC_ENTRY_EXIT_DEBUG("awc_802_11_tx_find_path_and_post");
+ // netif_stop_queue(dev);
DOWN(&priv->tx_buff_semaphore);
if (len > dev->mtu + 16 ) {
printk(KERN_ERR "%s packet size too large %d \n",dev->name, len);
@@ -1644,28 +1649,33 @@ awc_802_11_tx_find_path_and_post(struct net_device * dev,
}
};
- if (tx_rate == 2 || tx_rate == 4 || tx_rate== 20 || tx_rate == 22)
- fid->u.tx.radio_tx.tx_bit_rate = tx_rate;
+ if (priv->force_tx_rate == 2 || priv->force_tx_rate == 4 ||
+ priv->force_tx_rate== 11 || priv->force_tx_rate == 22){
+ fid->u.tx.radio_tx.tx_bit_rate = priv->force_tx_rate;
+ } else if (priv->force_tx_rate != 0 ) {
+ printk(KERN_ERR "wrong force_tx_rate=%d changed to default \n", priv->force_tx_rate);
+ priv->force_tx_rate = 0;
+ };
fid->u.tx.radio_tx.TX_Control =
aironet4500_tx_control_tx_ok_event_enable |
aironet4500_tx_control_tx_fail_event_enable |
aironet4500_tx_control_no_release;
-/* if (len < 100){
+ if (len < priv->force_rts_on_shorter){
fid->u.tx.radio_tx.TX_Control |=
aironet4500_tx_control_use_rts;
};
-*/
-/* ip_hdr = skb->data + 14;
+
+ ip_hdr = (struct iphdr * ) ((( char * ) skb->data) + 14);
if (ip_hdr && skb->data[12] == 0x80 ){
- if (ip_hdr->tos & IPTOS_RELIABILITY)
+ if (ip_hdr->tos & IPTOS_RELIABILITY && priv->ip_tos_reliability_rts)
fid->u.tx.radio_tx.TX_Control |=
aironet4500_tx_control_use_rts;
- if (ip_hdr->tos & IPTOS_THROUGHPUT)
+ if (ip_hdr->tos & IPTOS_THROUGHPUT && priv->ip_tos_troughput_no_retries)
fid->u.tx.radio_tx.TX_Control |=
aironet4500_tx_control_no_retries;
};
-*/
+
if (priv->p802_11_send || memcmp(dev->dev_addr, skb->data +6, 6) ){
fid->u.tx.radio_tx.TX_Control |=
aironet4500_tx_control_header_type_802_11;
@@ -1683,7 +1693,7 @@ awc_802_11_tx_find_path_and_post(struct net_device * dev,
fid->pkt_len = len -12;
fid->u.tx.payload = skb->data +12;
- if (!memcmp(dev->dev_addr, skb->data +6, 6)){
+ if (priv->simple_bridge){
memcpy(fid->u.tx.ieee_802_11.mac1,skb->data,6);
memcpy(fid->u.tx.ieee_802_11.mac2,skb->data +6,6);
memcpy(fid->u.tx.ieee_802_11.mac3,priv->status.CurrentBssid ,6);
@@ -1691,14 +1701,12 @@ awc_802_11_tx_find_path_and_post(struct net_device * dev,
fid->u.tx.ieee_802_11.frame_control = 0x8;
fid->u.tx.ieee_802_11.gapLen=6;
} else {
-
memcpy(fid->u.tx.ieee_802_11.mac1,skb->data,6);
memcpy(fid->u.tx.ieee_802_11.mac2,dev->dev_addr,6);
memcpy(fid->u.tx.ieee_802_11.mac3,skb->data +6 ,6);
memset(fid->u.tx.ieee_802_11.mac4,0 ,6);
fid->u.tx.ieee_802_11.frame_control = 0x108;
fid->u.tx.ieee_802_11.gapLen=6;
-
}
} else { // plain old 802.3, with hdr copied
fid->u.tx.radio_tx.PayloadLength = len -12;
@@ -1745,11 +1753,20 @@ awc_802_11_tx_find_path_and_post(struct net_device * dev,
};
+ priv->stats.tx_bytes += fid->u.tx.ieee_802_3.payload_length;
+ priv->stats.tx_packets++;
awc_fid_queue_push_tail(&priv->tx_in_transmit,fid);
udelay(1);
awc_transmit_packet(dev,fid);
+ if (priv->tx_large_ready.size <= 2 || priv->tx_small_ready.size <= 2 ){
+ if (netif_running(dev))
+ netif_stop_queue(dev);
+ } else {
+ if (netif_running(dev))
+ netif_wake_queue(dev);
+ }
UP(&priv->tx_buff_semaphore);
AWC_ENTRY_EXIT_DEBUG("exit\n");
return 0;
@@ -1768,6 +1785,8 @@ awc_802_11_tx_find_path_and_post(struct net_device * dev,
final:
priv->stats.tx_errors++;
UP(&priv->tx_buff_semaphore);
+ if (!netif_running(dev))
+ netif_start_queue(dev);
dev_kfree_skb(skb);
AWC_ENTRY_EXIT_DEBUG("BADExit\n");
return -1;
@@ -1797,7 +1816,6 @@ awc_802_11_after_tx_packet_to_card_write(struct net_device * dev,
dev_kfree_skb(tx_buff->skb);
tx_buff->skb = NULL;
}
- netif_wake_queue (dev);
AWC_ENTRY_EXIT_DEBUG("exit\n");
};
@@ -1839,7 +1857,7 @@ awc_802_11_after_failed_tx_packet_to_card_write(struct net_device * dev,
};
-void
+inline void
awc_802_11_after_tx_complete(struct net_device * dev, struct awc_fid * tx_buff){
struct awc_private * priv = (struct awc_private *)dev->priv;
@@ -1861,7 +1879,7 @@ awc_802_11_after_tx_complete(struct net_device * dev, struct awc_fid * tx_buff){
}
tx_buff->busy = 0;
- netif_wake_queue (dev);
+// netif_wake_queue (dev);
AWC_ENTRY_EXIT_DEBUG("exit\n");
};
@@ -2294,7 +2312,8 @@ awc_interrupt_process(struct net_device * dev){
// save_flags(flags);
// cli();
-// disable_irq(dev->irq);
+ // here we need it, because on 2.3 SMP there are truly parallel irqs
+ disable_irq(dev->irq);
DEBUG(2," entering interrupt handler %s ",dev->name);
@@ -2503,14 +2522,14 @@ start:
//end_here:
-// enable_irq(dev->irq);
+ enable_irq(dev->irq);
// restore_flags(flags);
return 0;
bad_end:
AWC_ENTRY_EXIT_DEBUG(" bad_end exit \n");
-// enable_irq(dev->irq);
+ enable_irq(dev->irq);
// restore_flags(flags);
return -1;
@@ -2528,16 +2547,17 @@ static int p802_11_send = 0; // 1
static int awc_process_tx_results = 0;
int tx_queue_len = 10;
int tx_rate = 0;
-static int channel = 5;
+int channel = 5;
//static int tx_full_rate = 0;
-static int max_mtu = 2312;
-static int adhoc = 0;
-static int large_buff_mem = 1700 * 10;
-static int small_buff_no = 20;
-static int awc_full_stats = 0;
-static char SSID[33] = {0};
-static int master= 0;
-static int slave = 0;
+int max_mtu = 2312;
+int adhoc = 0;
+int large_buff_mem = 1700 * 10;
+int small_buff_no = 20;
+int awc_full_stats = 0;
+char SSID[33] = {0};
+int master= 0;
+int slave = 0;
+int awc_simple_bridge = 0;
// int debug =0;
#if LINUX_VERSION_CODE >= 0x20100
@@ -2550,6 +2570,7 @@ MODULE_PARM(tx_full_rate,"i");
MODULE_PARM(adhoc,"i");
MODULE_PARM(master,"i");
MODULE_PARM(slave,"i");
+MODULE_PARM(awc_simple_bridge,"i");
MODULE_PARM(max_mtu,"i");
MODULE_PARM(large_buff_mem,"i");
MODULE_PARM(small_buff_no,"i");
@@ -2572,7 +2593,7 @@ EXPORT_SYMBOL(awc_debug);
EXPORT_SYMBOL(awc_private_init);
EXPORT_SYMBOL(awc_tx_timeout);
EXPORT_SYMBOL(awc_start_xmit);
-EXPORT_SYMBOL(awc_rx);
+//EXPORT_SYMBOL(awc_rx);
EXPORT_SYMBOL(awc_interrupt);
EXPORT_SYMBOL(awc_get_stats);
EXPORT_SYMBOL(awc_change_mtu);
@@ -2674,7 +2695,7 @@ char name[] = "ElmerLinux";
i++;
}
- // following MUST be consistent with awc_rids !!!
+ // following MUST be consistent with awc_rids in count and ordrering !!!
priv->rid_dir[0].buff = &priv->config; // card RID mirrors
priv->rid_dir[1].buff = &priv->SSIDs;
priv->rid_dir[2].buff = &priv->fixed_APs;
@@ -2726,6 +2747,7 @@ char name[] = "ElmerLinux";
if (!adhoc)
priv->config.OperatingMode = MODE_STA_ESS;
// priv->config.OperatingMode = MODE_AP;
+// Setting rates does not work with new hardware, use force_tx_rate via proc
// priv->config.Rates[0] =0x82;
// priv->config.Rates[1] =0x4;
// priv->config.Rates[2] =tx_full_rate;
@@ -2738,7 +2760,9 @@ char name[] = "ElmerLinux";
if (adhoc && master){
priv->config.JoinNetTimeout = 0x1;//0 is facotry default
} else if (adhoc && slave){
- priv->config.JoinNetTimeout = 0xffff;
+ // by spec 0xffff, but, this causes immediate bad behaviour
+ // firmware behvaiour changed somehere around ver 2??
+ priv->config.JoinNetTimeout = 0x7fff;
};
// priv->config.AuthenticationType = 1;
priv->config.Stationary =1;
@@ -2761,6 +2785,7 @@ char name[] = "ElmerLinux";
// here we go, bad aironet
memset(&priv->SSIDs,0,sizeof(priv->SSIDs));
+ my_spin_lock_init(&priv->queues_lock);
priv->SSIDs.ridLen =0;
if (!SSID) {
priv->SSIDs.SSID[0].SSID[0] ='a';
@@ -2839,6 +2864,7 @@ int awc_private_init(struct net_device * dev){
my_spin_lock_init(&priv->command_issuing_spinlock);
my_spin_lock_init(&priv->both_bap_spinlock);
my_spin_lock_init(&priv->bap_setup_spinlock);
+ my_spin_lock_init(&priv->interrupt_spinlock);
priv->command_semaphore_on = 0;
priv->unlock_command_postponed = 0;
@@ -2877,7 +2903,12 @@ int awc_private_init(struct net_device * dev){
priv->p2p_found =0;
priv->p802_11_send =p802_11_send;
-
+ priv->full_stats = awc_full_stats;
+ priv->simple_bridge = awc_simple_bridge;
+ priv->force_rts_on_shorter = 0;
+ priv->force_tx_rate = tx_rate;
+ priv->ip_tos_reliability_rts = 0;
+ priv->ip_tos_troughput_no_retries = 0 ;
priv->ejected =0;
priv->interrupt_count =0;
@@ -2960,6 +2991,7 @@ void awc_tx_timeout (struct net_device *dev)
struct awc_private *priv = (struct awc_private *) dev->priv;
struct awc_fid * fid;
int cnt;
+ unsigned long flags;
DEBUG (2, "%s: awc_tx_timeout \n", dev->name);
@@ -2969,11 +3001,11 @@ void awc_tx_timeout (struct net_device *dev)
priv->tx_large_ready.size, priv->tx_small_ready.size);
priv->stats.tx_errors++;
- // save_flags(flags);
- // cli();
+ save_flags(flags);
+ cli();
fid = priv->tx_in_transmit.head;
cnt = 0;
- while (fid) {
+ while (fid) { // removing all fids older that that
if (jiffies - fid->transmit_start_time > (HZ)) {
// printk(KERN_ERR "%s staled tx_buff found, age %uld jiffies\n",dev->name,
// jiffies - fid->transmit_start_time );
@@ -2986,14 +3018,12 @@ void awc_tx_timeout (struct net_device *dev)
fid = fid->next;
if (cnt++ > 200) {
printk ("bbb in awc_fid_queue\n");
- // restore_flags(flags);
+ restore_flags(flags);
return;
};
}
- //restore_flags(flags);
- //debug =0x8;
-
+ restore_flags(flags);
dev->trans_start = jiffies;
netif_start_queue (dev);
}
@@ -3002,7 +3032,7 @@ void awc_tx_timeout (struct net_device *dev)
long long last_tx_q_hack = 0;
int direction = 1;
- int awc_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+int awc_start_xmit(struct sk_buff *skb, struct net_device *dev) {
struct awc_private *priv = (struct awc_private *)dev->priv;
int retval = 0;
@@ -3021,10 +3051,10 @@ int direction = 1;
return -1;
};
- if (test_and_set_bit( 0, (void *) &priv->tx_chain_active) ) {
- netif_start_queue (dev);
- return 1;
- }
+// if (test_and_set_bit( 0, (void *) &priv->tx_chain_active) ) {
+// netif_start_queue (dev);
+// return 1;
+// }
dev->trans_start = jiffies;
retval = awc_802_11_tx_find_path_and_post(dev,skb);
@@ -3035,7 +3065,7 @@ int direction = 1;
return retval;
}
-int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) {
+inline int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) {
// struct awc_private *lp = (struct awc_private *)dev->priv;
@@ -3062,20 +3092,23 @@ int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) {
void awc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *)dev_id;
-// struct awc_private *lp;
-// unsigned long flags;
+ struct awc_private *priv;
+ unsigned long flags;
// if ((dev == NULL)) return;
-// lp = (struct awc_private *)dev->priv;
+ priv = (struct awc_private *)dev->priv;
DEBUG(2, "%s: awc_interrupt \n", dev->name);
-
+ my_spin_lock_irqsave(&priv->interrupt_spinlock, flags);
+
awc_interrupt_process(dev);
+ my_spin_unlock_irqrestore(&priv->interrupt_spinlock, flags);
+
return;
}
@@ -3105,6 +3138,8 @@ int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) {
// the very following is the very wrong very probably
if (awc_full_stats){
+ priv->stats.rx_bytes = priv->statistics.HostRxBytes;
+ priv->stats.tx_bytes = priv->statistics.HostTxBytes;
priv->stats.rx_fifo_errors = priv->statistics.RxOverrunErr ;
priv->stats.rx_crc_errors = priv->statistics.RxPlcpCrcErr + priv->statistics.RxMacCrcErr ;
priv->stats.rx_frame_errors = priv->statistics.RxPlcpFormat ;
@@ -3130,7 +3165,7 @@ int awc_rx(struct net_device *dev, struct awc_fid * rx_fid) {
int awc_change_mtu(struct net_device *dev, int new_mtu){
// struct awc_private *priv = (struct awc_private *)dev->priv;
-// unsigned long flags;
+ unsigned long flags;
if ((new_mtu < 256 ) || (new_mtu > 2312) || (max_mtu && new_mtu > max_mtu) )
return -EINVAL;
@@ -3140,14 +3175,17 @@ int awc_change_mtu(struct net_device *dev, int new_mtu){
};
if (dev->mtu != new_mtu) {
-// save_flags(flags);
-// cli();
- awc_disable_MAC(dev);
+ save_flags(flags);
+ cli();
+ netif_stop_queue(dev);
+ awc_disable_MAC(dev);
+ restore_flags(flags);
+
awc_tx_dealloc(dev);
dev->mtu = new_mtu;
awc_tx_alloc(dev);
awc_enable_MAC(dev);
-// restore_flags(flags);
+ netif_start_queue(dev);
printk("%s mtu has been changed to %d \n ",dev->name,dev->mtu);
diff --git a/drivers/net/aironet4500_proc.c b/drivers/net/aironet4500_proc.c
index cefa41b88..abfd262b0 100644
--- a/drivers/net/aironet4500_proc.c
+++ b/drivers/net/aironet4500_proc.c
@@ -43,7 +43,7 @@
#endif
-
+#include "aironet4500.h"
#include "aironet4500_rid.c"
@@ -247,8 +247,9 @@ int awc_proc_format_bits(int write,u32 * buff, size_t* lenp, struct awc_rid_dir
DEBUG(0x20000,"awc proc int data %x \n",val);
+// both of them are crazy
// *lenp = sizeof(int);
- *lenp += 1;
+// *lenp += 1;
AWC_ENTRY_EXIT_DEBUG("exit");
return 0;
@@ -385,6 +386,18 @@ ctl_table awc_driver_proc_table[] = {
{0}
};
+ctl_table awc_driver_level_ctable[] = {
+ {1, "force_rts_on_shorter" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {2, "force_tx_rate" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {3, "ip_tos_reliability_rts" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {4, "ip_tos_troughput_no_retries", NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {5, "debug" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {6, "simple_bridge" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {7, "p802_11_send" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {8, "full_stats" , NULL, sizeof(int), 0600,NULL, proc_dointvec},
+ {0}
+};
+
ctl_table awc_root_table[] = {
{254, "aironet4500", NULL, 0, 0555, awc_driver_proc_table},
{0}
@@ -398,12 +411,12 @@ const char awc_procname[]= "awc5";
int awc_proc_set_device(int device_number){
int group =0;
int rid = 0;
- struct awc_priv * priv;
-
+ struct awc_private * priv;
+ ctl_table * tmp_table_ptr;
AWC_ENTRY_EXIT_DEBUG("awc_proc_set_device");
if (!aironet4500_devices[device_number] || (awc_nof_rids <=0 )) return -1 ;
- priv = (struct awc_priv * )aironet4500_devices[device_number]->priv;
+ priv = (struct awc_private * )aironet4500_devices[device_number]->priv;
awc_rids_setup(aironet4500_devices[device_number]);
@@ -413,7 +426,7 @@ int awc_proc_set_device(int device_number){
awc_proc_priv[device_number].proc_table_device_root[0].ctl_name = device_number+1;
awc_proc_priv[device_number].proc_table_sys_root->child = awc_proc_priv[device_number].proc_table_device_root;
- memcpy(awc_proc_priv[device_number].proc_name,(struct awc_priv * )aironet4500_devices[device_number]->name,5);
+ memcpy(awc_proc_priv[device_number].proc_name,(struct NET_DEVICE * )aironet4500_devices[device_number]->name,5);
awc_proc_priv[device_number].proc_name[4]=0;
// awc_proc_priv[device_number].proc_name[3]=48+device_number;
awc_proc_priv[device_number].proc_table_device_root[0].procname = &(awc_proc_priv[device_number].proc_name[0]);
@@ -484,6 +497,40 @@ int awc_proc_set_device(int device_number){
group++;
};
+// here are driver-level params dir
+ awc_proc_priv[device_number].proc_table[group].ctl_name = group +1;
+ awc_proc_priv[device_number].proc_table[group+1].ctl_name = 0;
+ awc_proc_priv[device_number].proc_table[group].procname = "driver-level";
+ awc_proc_priv[device_number].proc_table[group].data = awc_proc_buff;
+ awc_proc_priv[device_number].proc_table[group].maxlen = sizeof(awc_proc_buff) -1;
+ awc_proc_priv[device_number].proc_table[group].mode = 0600;
+ awc_proc_priv[device_number].proc_table[group].child = kmalloc(sizeof(awc_driver_level_ctable) , GFP_KERNEL);
+ awc_proc_priv[device_number].proc_table[group].proc_handler = NULL;
+ awc_proc_priv[device_number].proc_table[group].strategy = NULL;
+ awc_proc_priv[device_number].proc_table[group].de = NULL;
+ awc_proc_priv[device_number].proc_table[group].extra1 = NULL;
+ awc_proc_priv[device_number].proc_table[group].extra2 = NULL;
+ if (!awc_proc_priv[device_number].proc_table[group].child) {
+ awc_proc_priv[device_number].proc_table[group].ctl_name = 0;
+ printk(KERN_CRIT "Out of memory on aironet4500_proc huge table alloc \n");
+ return 0;
+ }
+
+
+ tmp_table_ptr = awc_proc_priv[device_number].proc_table[group].child;
+ memcpy(tmp_table_ptr,awc_driver_level_ctable,sizeof(awc_driver_level_ctable));
+
+
+ tmp_table_ptr[0].data =
+ &(priv->force_rts_on_shorter);
+ tmp_table_ptr[1].data = &priv->force_tx_rate;
+ tmp_table_ptr[2].data = (void *) &priv->ip_tos_reliability_rts;
+ tmp_table_ptr[3].data = (void *) &priv->ip_tos_troughput_no_retries;
+ tmp_table_ptr[4].data = (void *) &priv->debug;
+ tmp_table_ptr[5].data = (void *) &priv->simple_bridge;
+ tmp_table_ptr[6].data = (void *) &priv->p802_11_send;
+ tmp_table_ptr[7].data = (void *) &priv->full_stats;
+
awc_proc_priv[device_number].sysctl_header =
register_sysctl_table(awc_proc_priv[device_number].proc_table_sys_root,0);
diff --git a/drivers/net/aironet4500_rid.c b/drivers/net/aironet4500_rid.c
index 7d52269f9..ff7550d33 100644
--- a/drivers/net/aironet4500_rid.c
+++ b/drivers/net/aironet4500_rid.c
@@ -58,14 +58,14 @@
#define awc_RID_gen_BasicRate_11Mbps {&aironet4500_RID_Select_General_Config,0x0010, 8,1,1,0,1,0xff,0x96,"BasicRate 11Mbps"}
-#define awc_RID_gen_Long_retry_limit {&aironet4500_RID_Select_General_Config,0x0018,16, 1,1,0,0,0,0,"Short Retry Limit"}
-#define awc_RID_gen_Short_retry_limit {&aironet4500_RID_Select_General_Config,0x001A,16, 1,1,0,0,0,0,"Long Retry Limit"}
-#define awc_RID_gen_Tx_MSDU_lifetime {&aironet4500_RID_Select_General_Config,0x001C,16, 1,1000,0,0,0,0,"TX MSDU Lifetime"}
-#define awc_RID_gen_Rx_MSDU_lifetime {&aironet4500_RID_Select_General_Config,0x001E,16, 1,1000,0,0,0,0,"RX MSDU Lifetime"}
-#define awc_RID_gen_Stationary {&aironet4500_RID_Select_General_Config,0x0020,16, 1,1,0,0,0,0,"Stationary"}
-#define awc_RID_gen_BC_MC_Ordering {&aironet4500_RID_Select_General_Config,0x0022,16, 1,1,0,0,0,0,"Strictly order Bcast and Mcast"}
-#define awc_RID_gen_Device_type {&aironet4500_RID_Select_General_Config,0x0024,16, 1,1,1,0,0xffff,0x0065,"Radio Type PC4500"}
-#define awc_RID_gen_Reserved_0x0026 {&aironet4500_RID_Select_General_Config,0x0026, 8,10,1,0,0,0,0,"Reserved 0x0028"}
+#define awc_RID_gen_Long_retry_limit {&aironet4500_RID_Select_General_Config,0x0018,16, 1,1,0,0,0xffff,0,"Short Retry Limit"}
+#define awc_RID_gen_Short_retry_limit {&aironet4500_RID_Select_General_Config,0x001A,16, 1,1,0,0,0xffff,0,"Long Retry Limit"}
+#define awc_RID_gen_Tx_MSDU_lifetime {&aironet4500_RID_Select_General_Config,0x001C,16, 1,1000,0,0,0xffff,0,"TX MSDU Lifetime"}
+#define awc_RID_gen_Rx_MSDU_lifetime {&aironet4500_RID_Select_General_Config,0x001E,16, 1,1000,0,0,0xffff,0,"RX MSDU Lifetime"}
+#define awc_RID_gen_Stationary {&aironet4500_RID_Select_General_Config,0x0020,16, 1,1,0,0,0xffff,0,"Stationary"}
+#define awc_RID_gen_BC_MC_Ordering {&aironet4500_RID_Select_General_Config,0x0022,16, 1,1,0,0,0xffff,0,"Strictly order Bcast and Mcast"}
+#define awc_RID_gen_Device_type {&aironet4500_RID_Select_General_Config,0x0024,16, 1,1,1,0,0xffff,0x00,"Radio Type"}
+#define awc_RID_gen_Reserved_0x0026 {&aironet4500_RID_Select_General_Config,0x0026, 8,10,1,0,0,0xff,0,"Reserved0x28"}
//SCANNING/ASSOCIATING
@@ -101,7 +101,7 @@
#define awc_RID_gen_FastListenInterval awc_def_gen_RID(0x0056,"FastListenInterval", 16,0xffff,0,"msek") // 0 default 100 kus The listen interval to be used immediately after
#define awc_RID_gen_ListenDecay awc_def_gen_RID(0x0058,"ListenDecay", 16,0xffff,0,"times") // 0 default 2Number of times to use the current listen interval
#define awc_RID_gen_FastListenDelay awc_def_gen_RID(0x005A,"FastListenDelay", 16,0xffff,0,"msek") // 0 default 200 kus Time interval to delay before going to fast listen
-#define awc_RID_gen_Reserved0x005C awc_def_gen_RID(0x005C,"Reserved0x005C", 32,0,0,"") //
+#define awc_RID_gen_Reserved0x005C awc_def_gen_RID(0x005C,"Reserved0x005C", 32,0xffffffff,0,"") //
//ADHOC (or AP) OPERATION
#define awc_RID_gen_BeaconPeriod awc_def_gen_RID(0x0060,"BeaconPeriod", 16,0xffff,0,"msek") // 0 default 100 0 selects the factory default of [~100 ms]. (kus)
#define awc_RID_gen_AtimDuration awc_def_gen_RID(0x0062,"AtimDuration", 16,0xffff,0,"msek") // 0 default 5 kus The time period reserved for ATIMs immediately after (kus) the beacon. 0xFFFF will disable the ATIM window; power save mode will not operate.This parameter only applies to adhoc/IBSS.
@@ -136,7 +136,7 @@
#define awc_RID_gen_ARLThreshold awc_def_gen_RID(0x0090,"ARLThreshold", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is
#define awc_RID_gen_ARLDecay awc_def_gen_RID(0x0092,"ARLDecay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is
#define awc_RID_gen_ARLDelay awc_def_gen_RID(0x0094,"ARLDelay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is
-#define awc_RID_gen_Unused0x0096 awc_def_gen_RID(0x0096,"Unused", 16,0,0,"") //
+#define awc_RID_gen_Unused0x0096 awc_def_gen_RID(0x0096,"Reserved0x96", 16,0xffff,0,"") //
#define awc_RID_gen_MagicPacketAction awc_def_gen_RID(0x0098,"MagicPacketAction", 8,0xff,0," hell knows what") // 0 0 0 selects no action to be taken on a magic packet and"
#define awc_RID_gen_MagicPacketControl awc_def_gen_RID(0x0099,"MagicPacketControl", 8,0xff,0," hell know what") // 0 0 0 will disable the magic packet mode command"
@@ -182,14 +182,14 @@
#define awc_RID_act_BasicRate_11Mbps {&aironet4500_RID_Select_Active_Config,0x0010, 8,1,1,0,1,0xff,0x96,"BasicRate 11Mbps"}
-#define awc_RID_act_Long_retry_limit {&aironet4500_RID_Select_Active_Config,0x0018,16, 1,1,0,0,0,0,"Short Retry Limit"}
-#define awc_RID_act_Short_retry_limit {&aironet4500_RID_Select_Active_Config,0x001A,16, 1,1,0,0,0,0,"Long Retry Limit"}
-#define awc_RID_act_Tx_MSDU_lifetime {&aironet4500_RID_Select_Active_Config,0x001C,16, 1,1000,0,0,0,0,"TX MSDU Lifetime"}
-#define awc_RID_act_Rx_MSDU_lifetime {&aironet4500_RID_Select_Active_Config,0x001E,16, 1,1000,0,0,0,0,"RX MSDU Lifetime"}
-#define awc_RID_act_Stationary {&aironet4500_RID_Select_Active_Config,0x0020,16, 1,1,0,0,0,0,"Stationary"}
-#define awc_RID_act_BC_MC_Ordering {&aironet4500_RID_Select_Active_Config,0x0022,16, 1,1,0,0,0,0,"Strictly order Bcast and Mcast"}
+#define awc_RID_act_Long_retry_limit {&aironet4500_RID_Select_Active_Config,0x0018,16, 1,1,0,0,0xffff,0,"Short Retry Limit"}
+#define awc_RID_act_Short_retry_limit {&aironet4500_RID_Select_Active_Config,0x001A,16, 1,1,0,0,0xffff,0,"Long Retry Limit"}
+#define awc_RID_act_Tx_MSDU_lifetime {&aironet4500_RID_Select_Active_Config,0x001C,16, 1,1000,0,0,0xffff,0,"TX MSDU Lifetime"}
+#define awc_RID_act_Rx_MSDU_lifetime {&aironet4500_RID_Select_Active_Config,0x001E,16, 1,1000,0,0,0xffff,0,"RX MSDU Lifetime"}
+#define awc_RID_act_Stationary {&aironet4500_RID_Select_Active_Config,0x0020,16, 1,1,0,0,0xffff,0,"Stationary"}
+#define awc_RID_act_BC_MC_Ordering {&aironet4500_RID_Select_Active_Config,0x0022,16, 1,1,0,0,0xffff,0,"Strictly order Bcast and Mcast"}
#define awc_RID_act_Device_type {&aironet4500_RID_Select_Active_Config,0x0024,16, 1,1,1,0,0xffff,0x0065,"Radio Type PC4500"}
-#define awc_RID_act_Reserved_0x0026 {&aironet4500_RID_Select_Active_Config,0x0026, 8,10,1,0,0,0,0,"Reserved 0x0028"}
+#define awc_RID_act_Reserved_0x0026 {&aironet4500_RID_Select_Active_Config,0x0026, 8,10,1,0,0,0xff,0,"Reserved0x28"}
//SCANNING/ASSOCIATING
@@ -260,7 +260,7 @@
#define awc_RID_act_ARLThreshold awc_def_act_RID(0x0090,"ARLThreshold", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is
#define awc_RID_act_ARLDecay awc_def_act_RID(0x0092,"ARLDecay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is
#define awc_RID_act_ARLDelay awc_def_act_RID(0x0094,"ARLDelay", 16,0xffff,0,"times") // 0 default 0xFFFF 0 selects the factory defaults. (which for now is
-#define awc_RID_act_Unused0x0096 awc_def_act_RID(0x0096,"Unused", 16,0,0,"") //
+#define awc_RID_act_Unused0x0096 awc_def_act_RID(0x0096,"Reserved0x96", 16,0xffff,0,"") //
#define awc_RID_act_MagicPacketAction awc_def_act_RID(0x0098,"MagicPacketAction", 8,0xff,0," hell knows what") // 0 0 0 selects no action to be taken on a magic packet and"
#define awc_RID_act_MagicPacketControl awc_def_act_RID(0x0099,"MagicPacketControl", 8,0xff,0," hell know what") // 0 0 0 will disable the magic packet mode command"
@@ -275,9 +275,12 @@
#define awc_RID_SSIDlen1 awc_def_SSID_RID(0x0002,"SSIDlen1", 16,0xffff,0,"") // 7 The length of the SSID1 byte string.
#define awc_RID_SSID1 awc_def_SSID_RID(0x0004,"SSID1", 255,0,0,"") // "tsunami" The identifier uniquely identifying the wireless system.
#define awc_RID_SSIDlen2 awc_def_SSID_RID(0x0024,"SSIDlen2", 16,0xffff,0,"") // 0 The length of the SSID2 byte string.
-#define awc_RID_SSID2 awc_def_SSID_RID(0x0026,"SSID2", 255,0,0,"") // 0's The identifier uniquely identifying the wireless system.
+#define awc_RID_SSID2 awc_def_SSID_RID(0x0026,"SSID2", 255,0,0,"") //
#define awc_RID_SSIDlen3 awc_def_SSID_RID(0x0046,"SSIDlen3", 16,0xffff,0,"") // 0 The length of the SSID3 byte string.
-#define awc_RID_SSID3 awc_def_SSID_RID(0x0048,"SSID3", 255,0,0,"") // 0's The identifier uniquely identifying the wireless system.
+#define awc_RID_SSID3 awc_def_SSID_RID(0x0048,"SSID3", 255,0,0,"") //
+#define awc_RID_SSID1hex awc_def_SSID_RID(0x0004,"SSID1hex", 255,0xff,0,"")
+#define awc_RID_SSID2hex awc_def_SSID_RID(0x0026,"SSID2hex", 255,0xff,0,"")
+#define awc_RID_SSID3hex awc_def_SSID_RID(0x0048,"SSID3hex", 255,0xff,0,"")
// AP list
@@ -1304,6 +1307,9 @@ struct aironet4500_RID awc_SSID_RID[]={
awc_RID_SSID2,
awc_RID_SSIDlen3,
awc_RID_SSID3,
+ awc_RID_SSID1hex,
+ awc_RID_SSID2hex,
+ awc_RID_SSID3hex,
{0}
};
diff --git a/drivers/net/arlan.c b/drivers/net/arlan.c
index 0e3b982fe..846db3d8e 100644
--- a/drivers/net/arlan.c
+++ b/drivers/net/arlan.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1997 Cullen Jennings
- * Copyright (C) 1998 Elmer.Joandi@ut.ee, +37-255-13500
+ * Copyright (C) 1998 Elmer Joandiu, elmer@ylenurme.ee
* Gnu Public License applies
* This module provides support for the Arlan 655 card made by Aironet
*/
@@ -638,15 +638,20 @@ static void arlan_registration_timer(unsigned long data)
priv->registrationLastSeen = jiffies;
priv->registrationLostCount = 0;
priv->reRegisterExp = 1;
- if (!netif_running(dev))
+ if (!netif_running(dev) )
netif_wake_queue(dev);
+ if (priv->tx_last_sent > priv->tx_last_cleared &&
+ jiffies - priv->tx_last_sent > 5*HZ ){
+ arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
+ priv->tx_last_cleared = jiffies;
+ };
}
if (!registrationBad(dev) && priv->ReTransmitRequested)
{
IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
- printk(KERN_ERR "Retranmit from timer \n");
+ printk(KERN_ERR "Retransmit from timer \n");
priv->ReTransmitRequested = 0;
arlan_retransmit_now(dev);
}
@@ -1335,8 +1340,8 @@ static void arlan_tx_timeout (struct net_device *dev)
printk(KERN_ERR "%s: arlan transmit timed out, kernel decided\n", dev->name);
/* Try to restart the adaptor. */
arlan_command(dev, ARLAN_COMMAND_CLEAN_AND_RESET);
- dev->trans_start = jiffies;
- netif_start_queue (dev);
+ // dev->trans_start = jiffies;
+ // netif_start_queue (dev);
}
@@ -1348,12 +1353,6 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev)
ARLAN_DEBUG_ENTRY("arlan_tx");
- /*
- * If some higher layer thinks we've missed an tx-done interrupt
- * we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- * itself.
- */
-
length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
buf = skb->data;
diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in
index 2a3011532..606d5a606 100644
--- a/drivers/net/pcmcia/Config.in
+++ b/drivers/net/pcmcia/Config.in
@@ -14,7 +14,6 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
dep_tristate ' New Media PCMCIA support' CONFIG_PCMCIA_NMCLAN $CONFIG_PCMCIA
dep_tristate ' SMC 91Cxx PCMCIA support' CONFIG_PCMCIA_SMC91C92 $CONFIG_PCMCIA
dep_tristate ' Xircom 16-bit PCMCIA support' CONFIG_PCMCIA_XIRC2PS $CONFIG_PCMCIA
- dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
dep_tristate ' COM20020 ARCnet PCMCIA support' CONFIG_ARCNET_COM20020_CS $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET $CONFIG_PCMCIA
if [ "$CONFIG_CARDBUS" = "y" ]; then
@@ -27,6 +26,7 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then
dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
+ dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
fi
fi
diff --git a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c
index 3ef45a297..641c67332 100644
--- a/drivers/net/pcmcia/aironet4500_cs.c
+++ b/drivers/net/pcmcia/aironet4500_cs.c
@@ -230,7 +230,6 @@ static dev_link_t *awc_attach(void)
dev->init = &awc_pcmcia_init;
dev->open = &awc_pcmcia_open;
dev->stop = &awc_pcmcia_close;
- netif_start_queue (dev);
link->priv = dev;
#if CS_RELEASE_CODE > 0x2911
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index ddfed868e..0b3aeff4b 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -558,7 +558,9 @@ int __init ppp_init(void)
{
int err;
#ifndef MODULE
+#ifdef CONFIG_PPP_DEFLATE
extern struct compressor ppp_deflate, ppp_deflate_draft;
+#endif
extern int ppp_async_init(void);
extern int ppp_sync_init(void);
#endif
diff --git a/drivers/net/setup.c b/drivers/net/setup.c
index d47b1062e..d9019b046 100644
--- a/drivers/net/setup.c
+++ b/drivers/net/setup.c
@@ -227,7 +227,7 @@ static void special_device_init(void)
extern int sb1000_probe(struct net_device *dev);
static struct net_device sb1000_dev =
{
- "cm0 __PAD3", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, sb1000_probe
+ "cm0" __PAD3, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, sb1000_probe
};
register_netdev(&sb1000_dev);
}
diff --git a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile
index bf48c15e4..f90055b45 100644
--- a/drivers/net/tokenring/Makefile
+++ b/drivers/net/tokenring/Makefile
@@ -14,7 +14,7 @@ obj-y :=
obj-n :=
obj-m :=
obj- :=
-export-objs :=
+export-objs := tms380tr.o
obj-$(CONFIG_IBMTR) += ibmtr.o
obj-$(CONFIG_IBMOL) += olympic.o
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 417cc7c29..937dfadf8 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -72,7 +72,6 @@ static const char *version = "tms380tr.c: v1.07 21/01/2000 by Christoph Goos, Ad
#endif
#ifdef MODULE
-#define EXPORT_SYMTAB
#include <linux/module.h>
#include <linux/version.h>
#endif
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index dbbaaa5d7..b82dbac51 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -420,8 +420,6 @@ media_picked:
tp->timer.data = (unsigned long)dev;
tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
add_timer(&tp->timer);
-
- netif_device_attach(dev);
}
@@ -439,6 +437,8 @@ tulip_open(struct net_device *dev)
tulip_up (dev);
+ netif_start_queue (dev);
+
return 0;
}
@@ -652,8 +652,6 @@ static void tulip_down (struct net_device *dev)
struct tulip_private *tp = (struct tulip_private *) dev->priv;
unsigned long flags;
- netif_device_detach (dev);
-
del_timer (&tp->timer);
spin_lock_irqsave (&tp->lock, flags);
@@ -686,6 +684,8 @@ static int tulip_close (struct net_device *dev)
long ioaddr = dev->base_addr;
struct tulip_private *tp = (struct tulip_private *) dev->priv;
int i;
+
+ netif_stop_queue (dev);
tulip_down (dev);
@@ -1338,8 +1338,10 @@ static void tulip_suspend (struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
- if (dev && netif_device_present (dev))
+ if (dev && netif_device_present (dev)) {
+ netif_device_detach (dev);
tulip_down (dev);
+ }
}
@@ -1347,8 +1349,10 @@ static void tulip_resume (struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
- if (dev && !netif_device_present (dev))
+ if (dev && !netif_device_present (dev)) {
tulip_up (dev);
+ netif_device_attach (dev);
+ }
}
diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in
index 962e171fa..bc4bd5331 100644
--- a/drivers/net/wan/Config.in
+++ b/drivers/net/wan/Config.in
@@ -51,12 +51,8 @@ if [ "$CONFIG_WAN" = "y" ]; then
# X.25 network drivers
- if [ "$CONFIG_X25" != "n" ]; then
- if [ "$CONFIG_LAPB" != "n" ]; then
- dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB
- dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
- fi
- fi
+ dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB $CONFIG_X25
+ dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB $CONFIG_X25
tristate 'SBNI12-xx support' CONFIG_SBNI
fi
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 72aeae112..633514166 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -1,4 +1,4 @@
-/* $Id: cosa.c,v 1.30 2000/02/21 15:19:49 kas Exp $ */
+/* $Id: cosa.c,v 1.31 2000/03/08 17:47:16 kas Exp $ */
/*
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
@@ -373,7 +373,7 @@ static int __init cosa_init(void)
{
int i;
- printk(KERN_INFO "cosa v1.07 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
+ printk(KERN_INFO "cosa v1.08 (c) 1997-2000 Jan Kasprzak <kas@fi.muni.cz>\n");
#ifdef __SMP__
printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
#endif
@@ -584,6 +584,7 @@ static void sppp_channel_init(struct channel_data *chan)
struct net_device *d;
chan->if_ptr = &chan->pppdev;
chan->pppdev.dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+ memset(chan->pppdev.dev, 0, sizeof(struct net_device));
sppp_attach(&chan->pppdev);
d=chan->pppdev.dev;
d->name = chan->name;
@@ -599,7 +600,6 @@ static void sppp_channel_init(struct channel_data *chan)
d->get_stats = cosa_net_stats;
d->tx_timeout = cosa_sppp_timeout;
d->watchdog_timeo = TX_TIMEOUT;
- dev_init_buffers(d);
if (register_netdev(d) == -1) {
printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
sppp_detach(chan->pppdev.dev);
@@ -757,7 +757,7 @@ static int sppp_tx_done(struct channel_data *chan, int size)
chan->stats.tx_aborted_errors++;
return 1;
}
- dev_kfree_skb(chan->tx_skb);
+ dev_kfree_skb_irq(chan->tx_skb);
chan->tx_skb = 0;
chan->stats.tx_packets++;
chan->stats.tx_bytes += size;
diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c
index 45592eacf..9fc75e5e6 100644
--- a/drivers/net/wavelan.c
+++ b/drivers/net/wavelan.c
@@ -1805,6 +1805,7 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
mm_t m;
unsigned long flags;
int ret = 0;
+ int err = 0;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
@@ -1813,8 +1814,6 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
- /* FIXME: can't copy*user when cli this is broken! */
- /* Note : is it still valid ? Jean II */
/* Look what is the request */
switch (cmd) {
@@ -1945,10 +1944,12 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* Copy the key in the driver */
- if (copy_from_user
- (psa.psa_encryption_key,
- wrq->u.encoding.pointer,
- wrq->u.encoding.length)) {
+ wv_splx(lp, &flags);
+ err = copy_from_user(psa.psa_encryption_key,
+ wrq->u.encoding.pointer,
+ wrq->u.encoding.length);
+ wv_splhi(lp, &flags);
+ if (err) {
ret = -EFAULT;
break;
}
@@ -2018,9 +2019,11 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* Copy the key to the user buffer */
wrq->u.encoding.length = 8;
- if (copy_to_user
- (wrq->u.encoding.pointer,
- psa.psa_encryption_key, 8)) ret = -EFAULT;
+ wv_splx(lp, &flags);
+ if (copy_to_user(wrq->u.encoding.pointer,
+ psa.psa_encryption_key, 8))
+ ret = -EFAULT;
+ wv_splhi(lp, &flags);
}
break;
@@ -2067,38 +2070,51 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* Copy structure to the user buffer. */
- if (copy_to_user
- (wrq->u.data.pointer, &range,
- sizeof(struct iw_range))) ret = -EFAULT;
+ wv_splx(lp, &flags);
+ if (copy_to_user(wrq->u.data.pointer,
+ &range,
+ sizeof(struct iw_range)))
+ ret = -EFAULT;
+ wv_splhi(lp, &flags);
}
break;
case SIOCGIWPRIV:
/* Basic checking */
if (wrq->u.data.pointer != (caddr_t) 0) {
- struct iw_priv_args priv[] = { /* cmd, set_args, get_args, name */
-
- {SIOCSIPQTHR,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
- 1, 0, "setqualthr"},
- {SIOCGIPQTHR, 0,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED |
- 1, "getqualthr"},
-
-
- {SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,
- 0, "sethisto"},
- {SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16,
- "gethisto"},
+ struct iw_priv_args priv[] = {
+ /* { cmd,
+ set_args,
+ get_args,
+ name } */
+ { SIOCSIPQTHR,
+ IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ 0,
+ "setqualthr" },
+ { SIOCGIPQTHR,
+ 0,
+ IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ "getqualthr" },
+ { SIOCSIPHISTO,
+ IW_PRIV_TYPE_BYTE | 16,
+ 0,
+ "sethisto" },
+ { SIOCGIPHISTO,
+ 0,
+ IW_PRIV_TYPE_INT | 16,
+ "gethisto" },
};
/* Set the number of available ioctls. */
wrq->u.data.length = 4;
/* Copy structure to the user buffer. */
- if (copy_to_user
- (wrq->u.data.pointer, (u8 *) priv,
- sizeof(priv))) ret = -EFAULT;
+ wv_splx(lp, &flags);
+ if (copy_to_user(wrq->u.data.pointer,
+ (u8 *) priv,
+ sizeof(priv)))
+ ret = -EFAULT;
+ wv_splhi(lp, &flags);
}
break;
@@ -2119,9 +2135,13 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
int i;
/* Copy addresses to the driver. */
- if (copy_from_user
- (address, wrq->u.data.pointer,
- sizeof(struct sockaddr) * lp->spy_number)) {
+ wv_splx(lp, &flags);
+ err = copy_from_user(address,
+ wrq->u.data.pointer,
+ sizeof(struct sockaddr)
+ * lp->spy_number);
+ wv_splhi(lp, &flags);
+ if (err) {
ret = -EFAULT;
break;
}
@@ -2175,18 +2195,20 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* Copy addresses to the user buffer. */
- if (copy_to_user
- (wrq->u.data.pointer, address,
- sizeof(struct sockaddr) * lp->spy_number)) {
- ret = -EFAULT;
- break;
- }
+ wv_splx(lp, &flags);
+ err = copy_to_user(wrq->u.data.pointer,
+ address,
+ sizeof(struct sockaddr)
+ * lp->spy_number);
/* Copy stats to the user buffer (just after). */
- if (copy_to_user(wrq->u.data.pointer +
- (sizeof(struct sockaddr) *
- lp->spy_number), lp->spy_stat,
- sizeof(iw_qual) * lp->spy_number)) {
+ err |= copy_to_user(wrq->u.data.pointer
+ + (sizeof(struct sockaddr)
+ * lp->spy_number),
+ lp->spy_stat,
+ sizeof(iw_qual) * lp->spy_number);
+ wv_splhi(lp, &flags);
+ if (err) {
ret = -EFAULT;
break;
}
@@ -2241,9 +2263,12 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* Are there addresses to copy? */
if (lp->his_number > 0) {
/* Copy interval ranges to the driver */
- if (copy_from_user
- (lp->his_range, wrq->u.data.pointer,
- sizeof(char) * lp->his_number)) {
+ wv_splx(lp, &flags);
+ err = copy_from_user(lp->his_range,
+ wrq->u.data.pointer,
+ sizeof(char) * lp->his_number);
+ wv_splhi(lp, &flags);
+ if (err) {
ret = -EFAULT;
break;
}
@@ -2261,10 +2286,12 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
if ((lp->his_number > 0)
&& (wrq->u.data.pointer != (caddr_t) 0)) {
/* Copy data to the user buffer. */
- if (copy_to_user
- (wrq->u.data.pointer, lp->his_sum,
- sizeof(long) * lp->his_number))
+ wv_splx(lp, &flags);
+ if (copy_to_user(wrq->u.data.pointer,
+ lp->his_sum,
+ sizeof(long) * lp->his_number);
ret = -EFAULT;
+ wv_splhi(lp, &flags);
} /* if(pointer != NULL) */
break;
@@ -2274,7 +2301,7 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
default:
ret = -EOPNOTSUPP;
- }
+ } /* switch (cmd) */
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
new file mode 100644
index 000000000..7429ec38b
--- /dev/null
+++ b/drivers/parport/ChangeLog
@@ -0,0 +1,10 @@
+2000-03-10 <twaugh@redhat.com>
+
+ * parport_pc.c (decode_winbond): Use correct 83877ATF chip ID.
+ (decode_winbond): Fix typo.
+
+2000-03-09 <twaugh@redhat.com>
+
+ * parport_pc.c: Integrate SuperIO PCI probe with normal PCI card
+ probe, so that the MODULE_DEVICE_TABLE is complete.
+
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 9cfa53b0d..86fc6f874 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1175,11 +1175,11 @@ static void decode_winbond(int efer, int key, int devid, int devrev, int oldid)
else if ((id & ~0x0f) == 0x5210) type="83627";
else if ((id & ~0x0f) == 0x6010) type="83697HF";
else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;}
- else if ((oldid &0x0f ) == 0x0c) { type="83877ATF"; progif=1;}
+ else if ((oldid &0x0f ) == 0x0d) { type="83877ATF"; progif=1;}
else progif=0;
if(type==NULL)
- printk("Winbond unkown chip type\n");
+ printk("Winbond unknown chip type\n");
else
printk("Winbond chip type %s\n",type);
@@ -2161,9 +2161,9 @@ static int __devinit sio_via_686a_probe (struct pci_dev *pdev)
enum parport_pc_sio_types {
sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */
+ last_sio
};
-
/* each element directly indexed from enum list, above */
static struct parport_pc_superio {
int (*probe) (struct pci_dev *pdev);
@@ -2172,195 +2172,180 @@ static struct parport_pc_superio {
};
+enum parport_pc_pci_cards {
+ siig_1s1p_10x_550 = last_sio,
+ siig_1s1p_10x_650,
+ siig_1s1p_10x_850,
+ siig_1p_10x,
+ siig_2p_10x,
+ siig_2s1p_10x_550,
+ siig_2s1p_10x_650,
+ siig_2s1p_10x_850,
+ siig_1p_20x,
+ siig_2p_20x,
+ siig_2p1s_20x_550,
+ siig_2p1s_20x_650,
+ siig_2p1s_20x_850,
+ siig_1s1p_20x_550,
+ siig_1s1p_20x_650,
+ siig_1s1p_20x_850,
+ siig_2s1p_20x_550,
+ siig_2s1p_20x_650,
+ siig_2s1p_20x_850,
+ lava_parallel,
+ lava_parallel_dual_a,
+ lava_parallel_dual_b,
+ boca_ioppar,
+ plx_9050,
+ afavlab_tk9902,
+};
+
+
+/* each element directly indexed from enum list, above
+ * (but offset by last_sio) */
+static struct parport_pc_pci {
+ int numports;
+ struct {
+ int lo;
+ int hi; /* -ve if not there */
+ } addr[4];
+} cards[] __devinitdata = {
+ /* siig_1s1p_10x_550 */ { 1, { { 3, 4 }, } },
+ /* siig_1s1p_10x_650 */ { 1, { { 3, 4 }, } },
+ /* siig_1s1p_10x_850 */ { 1, { { 3, 4 }, } },
+ /* siig_1p_10x */ { 1, { { 2, 3 }, } },
+ /* siig_2p_10x */ { 2, { { 2, 3 }, { 4, 5 }, } },
+ /* siig_2s1p_10x_550 */ { 1, { { 4, 5 }, } },
+ /* siig_2s1p_10x_650 */ { 1, { { 4, 5 }, } },
+ /* siig_2s1p_10x_850 */ { 1, { { 4, 5 }, } },
+ /* siig_1p_20x */ { 1, { { 0, 1 }, } },
+ /* siig_2p_20x */ { 2, { { 0, 1 }, { 2, 3 }, } },
+ /* siig_2p1s_20x_550 */ { 2, { { 1, 2 }, { 3, 4 }, } },
+ /* siig_2p1s_20x_650 */ { 2, { { 1, 2 }, { 3, 4 }, } },
+ /* siig_2p1s_20x_850 */ { 2, { { 1, 2 }, { 3, 4 }, } },
+ /* siig_1s1p_20x_550 */ { 1, { { 1, 2 }, } },
+ /* siig_1s1p_20x_650 */ { 1, { { 1, 2 }, } },
+ /* siig_1s1p_20x_850 */ { 1, { { 1, 2 }, } },
+ /* siig_2s1p_20x_550 */ { 1, { { 2, 3 }, } },
+ /* siig_2s1p_20x_650 */ { 1, { { 2, 3 }, } },
+ /* siig_2s1p_20x_850 */ { 1, { { 2, 3 }, } },
+ /* lava_parallel */ { 1, { { 0, -1 }, } },
+ /* lava_parallel_dual_a */ { 1, { { 0, -1 }, } },
+ /* lava_parallel_dual_b */ { 1, { { 0, -1 }, } },
+ /* boca_ioppar */ { 1, { { 0, -1 }, } },
+ /* plx_9050 */ { 2, { { 4, -1 }, { 5, -1 }, } },
+ /* afavlab_tk9902 */ { 1, { { 0, 1 }, } },
+};
+
static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
+ /* Super-IO onboard chips */
{ 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a },
+
+ /* PCI cards */
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_550 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_650 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x_850 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_10x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_550 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_650 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x_850 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_20x },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_550 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_650 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x_850 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_550 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x_650 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x_850 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_550 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_650 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x_850 },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_a },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_b },
+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar },
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 },
+ { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, afavlab_tk9902 },
{ 0, }, /* terminate list */
};
+MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
+
+static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ int count, n, i = id->driver_data;
+ if (i < last_sio)
+ /* This is an onboard Super-IO and has already been probed */
+ return 0;
+ /* This is a PCI card */
+ i -= last_sio;
+ count = 0;
+ for (n = 0; n < cards[i].numports; n++) {
+ int lo = cards[i].addr[n].lo;
+ int hi = cards[i].addr[n].hi;
+ unsigned long io_lo, io_hi;
+ io_lo = pci_resource_start (dev, lo);
+ io_hi = 0;
+ if (hi >= 0)
+ io_hi = pci_resource_start (dev, hi);
+ /* TODO: test if sharing interrupts works */
+ if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
+ PARPORT_DMA_NONE, dev))
+ count++;
+ }
-static int __devinit parport_pc_init_superio(void)
+ return count;
+}
+
+static struct pci_driver parport_pc_pci_driver = {
+ name: "parport_pc",
+ id_table: parport_pc_pci_tbl,
+ probe: parport_pc_pci_probe,
+};
+
+static int __devinit parport_pc_init_superio (void)
{
#ifdef CONFIG_PCI
const struct pci_device_id *id;
struct pci_dev *pdev;
-
+
pci_for_each_dev(pdev) {
id = pci_match_device (parport_pc_pci_tbl, pdev);
- if (id == NULL)
+ if (id == NULL || id->driver_data >= last_sio)
continue;
-
+
return parport_pc_superio_info[id->driver_data].probe (pdev);
}
#endif /* CONFIG_PCI */
-
- return 0; /* zero devices found */
-}
-
-/* Look for PCI parallel port cards. */
-static int __init parport_pc_init_pci (int irq, int dma)
-{
-#ifndef PCI_VENDOR_ID_AFAVLAB
-#define PCI_VENDOR_ID_AFAVLAB 0x14db
-#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120
-#endif
-
- struct {
- unsigned int vendor;
- unsigned int device;
- unsigned int subvendor;
- unsigned int subdevice;
- unsigned int numports;
- struct {
- unsigned long lo;
- unsigned long hi; /* -ve if not there */
- } addr[4];
- } cards[] = {
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x,
- PCI_ANY_ID, PCI_ANY_ID,
- 2, { { 2, 3 }, { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 4, 5 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 0, 1 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x,
- PCI_ANY_ID, PCI_ANY_ID,
- 2, { { 0, 1 }, { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- 2, { { 1, 2 }, { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- 2, { { 1, 2 }, { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- 2, { { 1, 2 }, { 3, 4 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 1, 2 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 1, 2 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 1, 2 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 2, 3 }, } },
- { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 2, 3 }, } },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 0, -1 }, } },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 0, -1 }, } },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 0, -1 }, } },
- { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 0, -1 }, } },
- { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
- PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014,
- 2, { { 4, -1 }, { 5, -1 }, } },
- { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902,
- PCI_ANY_ID, PCI_ANY_ID,
- 1, { { 0, 1 }, } },
- { 0, }
- };
-
- struct pci_dev *pcidev;
- int count = 0;
- int i;
-
- if (!pci_present ())
- return 0;
-
- for (i = 0; cards[i].vendor; i++) {
- pcidev = NULL;
- while ((pcidev = pci_find_device (cards[i].vendor,
- cards[i].device,
- pcidev)) != NULL) {
- int n;
-
- if (cards[i].subvendor != PCI_ANY_ID &&
- cards[i].subvendor != pcidev->subsystem_vendor)
- continue;
-
- if (cards[i].subdevice != PCI_ANY_ID &&
- cards[i].subdevice != pcidev->subsystem_device)
- continue;
-
- for (n = 0; n < cards[i].numports; n++) {
- unsigned long lo = cards[i].addr[n].lo;
- unsigned long hi = cards[i].addr[n].hi;
- unsigned long io_lo, io_hi;
- io_lo = pcidev->resource[lo].start;
- io_hi = ((hi < 0) ? 0 :
- pcidev->resource[hi].start);
- if (irq == PARPORT_IRQ_AUTO) {
- if (parport_pc_probe_port (io_lo,
- io_hi,
- pcidev->irq,
- dma,
- pcidev))
- count++;
- } else if (parport_pc_probe_port (io_lo, io_hi,
- irq, dma,
- pcidev))
- count++;
- }
- }
- }
-#ifdef CONFIG_PCI
- /* Look for parallel controllers that we don't know about. */
- pci_for_each_dev(pcidev) {
- const int class_noprogif = pcidev->class & ~0xff;
- if (class_noprogif != (PCI_CLASS_COMMUNICATION_PARALLEL << 8))
- continue;
-
- for (i = 0; cards[i].vendor; i++)
- if ((cards[i].vendor == pcidev->vendor) &&
- (cards[i].device == pcidev->device))
- break;
- if (cards[i].vendor)
- /* We know about this one. */
- continue;
-
- printk (KERN_INFO
- "Unknown PCI parallel I/O card (%04x/%04x)\n"
- "Please send 'lspci' output to "
- "tim@cyberelk.demon.co.uk\n",
- pcidev->vendor, pcidev->device);
- }
-#endif
-
- return count;
+ return 0; /* zero devices found */
}
/* Exported symbols. */
@@ -2401,7 +2386,7 @@ int init_module(void)
{
/* Work out how many ports we have, then get parport_share to parse
the irq values. */
- unsigned int i;
+ unsigned int i, n;
if (superio) {
detect_and_report_winbond ();
detect_and_report_smsc ();
@@ -2430,12 +2415,18 @@ int init_module(void)
}
}
- return (parport_pc_init(io, io_hi, irqval, dmaval)?0:1);
+ n = parport_pc_init_superio ();
+ n += parport_pc_init (io, io_hi, irqval, dmaval);
+ i = pci_register_driver (&parport_pc_pci_driver);
+
+ if (i > 0) n += i;
+ return !n;
}
void cleanup_module(void)
{
struct parport *p = parport_enumerate(), *tmp;
+ pci_unregister_driver (&parport_pc_pci_driver);
while (p) {
tmp = p->next;
if (p->modes & PARPORT_MODE_PCSPP) {
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 21a6a4ff1..dc7cfe9e1 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.50 2000/01/23 05:57:06 mj Exp $
+# $Id: pci.ids,v 1.53 2000/03/09 08:19:20 mj Exp $
#
# Vendors, devices and subsystems. Please keep sorted.
@@ -258,6 +258,8 @@
0026 DECchip 21154
0045 DECchip 21553
0046 DECchip 21554
+ 9005 1364 Dell PowerEdge RAID Controller 2
+ 9005 1365 Dell PowerEdge RAID Controller 2
1012 Micronics Computers Inc
1013 Cirrus Logic
0038 GD 7548
@@ -411,20 +413,35 @@
1489 M1489
1511 M1511
1513 M1513
- 1531 M1531
- 1533 M1533
+ 1531 M1531 Northbridge [Aladdin IV/IV+]
+ 1533 M1533 PCI-to-ISA Bridge
+ 1535 M1535 PCI Bridge + Super I/O + FIR
+ 1541 M1541 Northbridge [Aladdin V]
+ 1542 M1542 Northbridge [Aladdin V]
+ 1543 M1543 PCI-to-ISA Bridge + Super I/O + FIR
+ 1561 M1561 Northbridge [Aladdin 7]
+ 1621 M1621 Northbridge [Aladdin-Pro II]
+ 1631 M1631 Northbridge+3D Graphics [Aladdin TNT2]
+ 1641 M1641 Northbridge [Aladdin-Pro IV]
3141 M3141
3143 M3143
3145 M3145
3147 M3147
3149 M3149
3151 M3151
+ 3307 M3307 MPEG-I Video Controller
+ 3309 M3309 MPEG-II Video w/ Software Audio Decoder
+ 3321 M3321 MPEG-II Audio/Video Decoder
5217 M5217H
5219 M5219
5225 M5225
5229 M5229
5235 M5235
+ 5251 M5251 P1394 OHCI Controller
1028 Dell Computer Corporation
+ 0001 PowerEdge Expandable RAID Controller 2/Si
+ 0002 PowerEdge Expandable RAID Controller 3/Di
+ 0003 PowerEdge Expandable RAID Controller 3/Si
1029 Siemens Nixdorf IS
102a LSI Logic
0000 HYDRA
@@ -1000,9 +1017,30 @@
10a8 Sierra Semiconductor
0000 STB Horizon 64
10a9 Silicon Graphics, Inc.
- 0003 IOC3
+ 0001 Crosstalk to PCI Bridge
+ 0002 Linc I/O controller
+ 0003 IOC3 I/O controller
+ 0004 O2 MACE
0005 RAD Audio
+ 0006 HPCEX
+ 0007 RPCEX
+ 0008 DiVO VIP
0009 Alteon Gigabit Ethernet
+ 0010 AMP Video I/O
+ 0011 GRIP
+ 0012 SGH PSHAC GSN
+ 1001 Magic Carpet
+ 1002 Lithium
+ 1003 Dual JPEG 1
+ 1004 Dual JPEG 2
+ 1005 Dual JPEG 3
+ 1006 Dual JPEG 4
+ 1007 Dual JPEG 5
+ 1008 Cesium
+ 2001 Fibre Channel
+ 2002 ASDE
+ 8001 O2 1394
+ 8002 G-net NT
10aa ACC Microelectronics
0000 ACCM 2188
10ab Digicom
@@ -1031,6 +1069,23 @@
1077 VScom 400 4 port serial adaptor
9036 9036
9050 PCI <-> IOBus Bridge
+ d84d 4006 EX-4006 1P
+ d84d 4008 EX-4008 1P EPP/ECP
+ d84d 4014 EX-4014 2P
+ d84d 4018 EX-4018 3P EPP/ECP
+ d84d 4025 EX-4025 1S(16C550) RS-232
+ d84d 4027 EX-4027 1S(16C650) RS-232
+ d84d 4028 EX-4028 1S(16C850) RS-232
+ d84d 4036 EX-4036 2S(16C650) RS-232
+ d84d 4037 EX-4037 2S(16C650) RS-232
+ d84d 4038 EX-4038 2S(16C850) RS-232
+ d84d 4052 EX-4052 1S(16C550) RS-422/485
+ d84d 4053 EX-4053 2S(16C550) RS-422/485
+ d84d 4055 EX-4055 4S(16C550) RS-232
+ d84d 4058 EX-4055 4S(16C650) RS-232
+ d84d 4065 EX-4065 8S(16C550) RS-232
+ d84d 4068 EX-4068 8S(16C650) RS-232
+ d84d 4078 EX-4078 2S(16C552) RS-232+1P
9060 9060
906d 9060SD
125c 0640 Aries 16000P
@@ -1193,9 +1248,10 @@
10dc ATT2C15-3 FPGA
10dd Evans & Sutherland
10de nVidia Corporation
- 0008 NV1 EDGE 3D
- 0009 NV1 EDGE 3D
- 0020 Riva TNT 128
+ 0008 EDGE 3D [NV1]
+ 0009 EDGE 3D [NV1]
+ 0010 Mutara V08 [NV2]
+ 0020 Riva TnT 128 [NV04]
1043 0200 V3400 TNT
1092 0550 Viper V550
1092 0552 Viper V550
@@ -1210,7 +1266,7 @@
1092 4904 Viper V550
1092 4914 Viper V550
1092 8225 Viper V550
- 0028 Riva TNT2
+ 0028 Riva TnT2 [NV5]
1043 0200 AGP-V3800 SGRAM
1092 4804 Viper V770
1092 4a00 Viper V770
@@ -1219,16 +1275,20 @@
1092 7a02 Viper V770 Ultra
1102 1020 3D Blaster RIVA TNT2
14af 5810 Maxi Gamer Xentor
- 0029 Riva TNT2 Ultra
+ 0029 Riva TnT2 Ultra [NV5]
1043 0200 AGP-V3800 Deluxe
1102 1021 3D Blaster RIVA TNT2 Ultra
14af 5820 Maxi Gamer Xentor 32
- 002c Vanta
+ 002a Riva TnT2 [NV5]
+ 002b Riva TnT2 [NV5]
+ 002c Vanta [NV6]
1043 0200 AGP-V3800 Combat SDRAM
1092 6820 Viper V730
14af 5008 Maxi Gamer Phoenix 2
- 002d Riva TNT2 Model 64
+ 002d Vanta [NV6]
1043 0200 AGP-V3800M
+ 002e Vanta [NV6]
+ 002f Vanta [NV6]
00a0 Riva TNT2
14af 5810 Maxi Gamer Xentor
10df Emulex Corporation
@@ -1279,14 +1339,14 @@
0101 3GA
8111 Twist3 Frame Grabber
10ec Realtek Semiconductor Co., Ltd.
- 8029 RT8029(AS)
+ 8029 RTL-8029(AS)
10b8 2011 EZ-Card
10ec 8029 RT8029(AS)
1113 1208 EN1208
1186 0300 DE-528
1259 2400 AT-2400
- 8129 RT8129
- 8139 RT8139
+ 8129 RTL-8129
+ 8139 RTL-8139
1025 8920 ALN-325
1025 8921 ALN-325
10bd 0320 EP-320X-R
@@ -1304,9 +1364,14 @@
2646 0001 EtheRx
8e2e 7000 KF-230TX
8e2e 7100 KF-230TX/2
+ a0a0 0007 ALN-325C
10ed Ascii Corporation
7310 V7310
10ee Xilinx, Inc.
+ 3fc0 RME Digi96
+ 3fc1 RME Digi96/8
+ 3fc2 RME Digi96/8 Pro
+ 3fc3 RME Digi96/8 Pad
10ef Racore Computer Products, Inc.
8154 M815x Token Ring Adapter
10f0 Peritek Corporation
@@ -1329,6 +1394,7 @@
10ff NCube
1100 Jazz Multimedia
1101 Initio Corporation
+ 1060 INI-A100U2W
9100 INI-9100/9100W
9400 INI-940
9401 INI-950
@@ -1353,7 +1419,9 @@
1105 Sigma Designs, Inc.
8300 REALmagic Hollywood Plus DVD Decoder
1106 VIA Technologies, Inc.
+ 0391 VT8371 [KX133]
0501 VT8501
+ 0601 VT8601
0505 VT82C505
0561 VT82C561
0571 VT82C586 IDE [Apollo]
@@ -1385,11 +1453,14 @@
3068 VT82C686 [Apollo Super AC97/Modem]
5030 VT82C596 ACPI [Apollo PRO]
6100 VT85C100A [Rhine II]
+ 8231 VT8231 [PCI-to-ISA Bridge]
+ 8391 VT8371 [PCI-PCI Bridge]
8501 VT8501
8596 VT82C596 [Apollo PRO AGP]
8597 VT82C597 [Apollo VP3 AGP]
8598 VT82C598 [Apollo MVP3 AGP]
8691 VT82C691 [Apollo Pro]
+ 8601 VT8601
1107 Stratus Computers
0576 VIA VT82C570MV [Apollo] (Wrong vendor ID!)
1108 Proteon, Inc.
@@ -1491,7 +1562,7 @@
0000 155P-MF1 (FPGA)
0002 155P-MF1 (ASIC)
0003 ENI-25P ATM Adapter
- 0005 ENI-25P ATM Adapter
+ 0005 Speedstream 30xx ATM Adapter
111b Teledyne Electronic Systems
111c Tricord Systems Inc.
0001 Powerbis Bridge
@@ -2185,6 +2256,7 @@
1968 ES1968 Maestro 2
1969 ES1969 Solo-1 Audiodrive
1978 ES1978 Maestro 2E
+ 1988 ES1988 Allegro-1
2808 ES336H Fax Modem (Later Model)
2898 ES2898 Modem
125e Specialvideo Engineering SRL
@@ -2741,6 +2813,7 @@
0100 CM8338A
0101 CM8338B
0111 CM8738
+ 0211 CM8738
13f7 Wildfire Communications
13f8 Ad Lib Multimedia Inc
13f9 NTT Advanced Technology Corp.
@@ -2848,6 +2921,7 @@
145d Gallant Computer Inc
145e Aashima Technology B.V.
145f Baldor Electric Company
+ 0001 NextMove PCI
1460 DYNARC INC
1461 Avermedia Technologies Inc
1462 Micro-star International Co Ltd
@@ -2932,6 +3006,7 @@
14b1 Nextcom K.K.
14b2 ENNOVATE Networks Inc
14b3 XPEED Inc
+ 0000 DSL NIC
14b4 PHILIPS Business Electronics B.V.
14b5 Creamware GmBH
14b6 Quantum Data Corp.
@@ -2974,7 +3049,18 @@
14d9 Alpha Processor Inc
14da National Aerospace Laboratories
14db AFAVLAB Technology Inc
+ 2120 TK9902
14dc Amplicon Liveline Ltd
+ 0000 PCI230
+ 0001 PCI242
+ 0002 PCI244
+ 0003 PCI247
+ 0004 PCI248
+ 0005 PCI249
+ 0006 PCI260
+ 0007 PCI224
+ 0008 PCI234
+ 0009 PCI236
14dd Boulder Design Labs Inc
14de Applied Integration Corporation
14df ASIC Communications Corp
@@ -3115,6 +3201,7 @@
1d44 DPT
a400 PM2x24/PM3224
1de1 Tekram Technology Co.,Ltd.
+ 0391 TRM-S1040
2020 DC-390
690c 690c
dc29 DC290
@@ -3571,6 +3658,7 @@ c0fe Motion Engineering, Inc.
cafe Chrysalis-ITS
cccc Catapult Communications
d4d4 Dy4 Systems Inc
+d84d Exsys
e000 Winbond
e000 W89C940
e159 Tiger Jet Network Inc.
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 6ea612b84..af89ed1d3 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1336,7 +1336,6 @@ static int proc_read_exca(char *buf, char **start, off_t pos,
static void pcic_proc_setup(unsigned int sock, struct proc_dir_entry *base)
{
-#ifdef CONFIG_PROC_FS
socket_info_t *s = &socket[sock];
if (s->flags & IS_ALIVE)
@@ -1345,7 +1344,6 @@ static void pcic_proc_setup(unsigned int sock, struct proc_dir_entry *base)
create_proc_read_entry("info", 0, base, proc_read_info, s);
create_proc_read_entry("exca", 0, base, proc_read_exca, s);
s->proc = base;
-#endif
}
static void pcic_proc_remove(u_short sock)
@@ -1356,6 +1354,10 @@ static void pcic_proc_remove(u_short sock)
remove_proc_entry("exca", base);
}
+#else
+
+#define pcic_proc_setup NULL
+
#endif /* CONFIG_PROC_FS */
/*====================================================================*/
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index abb46572a..e517fbf27 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -555,6 +555,30 @@ static void yenta_clear_maps(pci_socket_t *socket)
}
}
+/*
+ * Many chipsets (all TI chips?) seem to have
+ * problems sensing the power state of the card
+ * that was inserted at chip init time, so force
+ * it if necessary..
+ */
+static void yenta_power_sense(pci_socket_t *socket)
+{
+ u32 status = config_readl(socket, CB_SOCKET_STATE);
+
+ /*
+ * Nothing inserted, nothing to sense..
+ * ..or sense status already available.
+ */
+ if (status & (CB_CDETECT1 | CB_CDETECT2 | CB_5VCARD | CB_3VCARD | CB_XVCARD | CB_YVCARD))
+ return;
+
+ /*
+ * Ho humm. It reports a card, but it doesn't report
+ * any voltages. Need to redo the VS test..
+ */
+ cb_writel(socket, CB_SOCKET_FORCE, CB_CVSTEST);
+}
+
/* Called at resume and initialization events */
static int yenta_init(pci_socket_t *socket)
{
@@ -595,6 +619,8 @@ static int yenta_init(pci_socket_t *socket)
exca_writeb(socket, I365_GBLCTL, 0x00);
exca_writeb(socket, I365_GENCTL, 0x00);
+ yenta_power_sense(socket);
+
yenta_clear_maps(socket);
return 0;
}
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index aeca7fc3c..12a82eba5 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -48,6 +48,25 @@ static void __init quirk_awe32_resources(struct pci_dev *dev)
printk(KERN_INFO "isapnp: AWE32 quirk - adding two ports\n");
}
+static void __init quirk_cmi8330_resources(struct pci_dev *dev)
+{
+ struct isapnp_resources *res = dev->sysdata;
+
+ for ( ; res ; res = res->alt ) {
+
+ struct isapnp_irq *irq;
+ struct isapnp_dma *dma;
+
+ for( irq = res->irq; irq; irq = irq->next ) // Valid irqs are 5, 7, 10
+ irq->map = 0x04A0; // 0000 0100 1010 0000
+
+ for( dma = res->dma; dma; dma = dma->next ) // Valid 8bit dma channels are 1,3
+ if( ( dma->flags & IORESOURCE_DMA_TYPE_MASK ) == IORESOURCE_DMA_8BIT )
+ dma->map = 0x000A;
+ }
+ printk(KERN_INFO "isapnp: CMI8330 quirk - fixing interrupts and dma\n");
+}
+
/*
* ISAPnP Quirks
@@ -61,6 +80,8 @@ static struct isapnp_fixup isapnp_fixups[] __initdata = {
quirk_awe32_resources },
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0023),
quirk_awe32_resources },
+ { ISAPNP_VENDOR('@','X','@'), ISAPNP_DEVICE(0x0001), // CMI8330
+ quirk_cmi8330_resources },
{ 0 }
};
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 42b86930d..31adb57fa 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -85,7 +85,7 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len);
static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
/* Globals */
-char *tw_driver_version="1.0.000";
+char *tw_driver_version="1.1.000";
TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
int tw_device_extension_count = 0;
@@ -2051,7 +2051,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
command_packet->status = 0;
command_packet->flags = 0;
- if ((srb->cmnd[0] == WRITE_6) || (srb->cmnd[0] == WRITE_10)) {
+ if (srb->cmnd[0] == WRITE_10) {
if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
command_packet->flags = 1;
}
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 4395cd682..4b68450e4 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -54,8 +54,8 @@ if [ "$CONFIG_DECSTATION" = "y" ]; then
dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_tristate '3ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI
+if [ "$CONFIG_PCI" = "y" ]; then
+ dep_tristate '3ware Hardware ATA-RAID support' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI
fi
dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 6ca7147d5..40ccb2fa8 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -956,7 +956,7 @@ typedef struct {
unsigned char numscbs; /* current number of scbs */
unsigned char maxhscbs; /* hardware scbs */
unsigned char maxscbs; /* max scbs including pageable scbs */
- unsigned int hscbs_dma; /* DMA handle to hscbs */
+ dma_addr_t hscbs_dma; /* DMA handle to hscbs */
unsigned int hscbs_dma_len; /* length of the above DMA area */
void *hscb_kmalloc_ptr;
} scb_data_type;
diff --git a/drivers/scsi/scsi_dma.c b/drivers/scsi/scsi_dma.c
index c0eb4baa0..ccb366593 100644
--- a/drivers/scsi/scsi_dma.c
+++ b/drivers/scsi/scsi_dma.c
@@ -147,7 +147,7 @@ int scsi_free(void *obj, unsigned int len)
nbits = len >> 9;
mask = (1 << nbits) - 1;
- if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
+ if (sector + nbits > SECTORS_PER_PAGE)
panic("scsi_free:Bad memory alignment");
if ((dma_malloc_freelist[page] &
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in
index 30ffe5cc0..1d74abb50 100644
--- a/drivers/sound/Config.in
+++ b/drivers/sound/Config.in
@@ -86,6 +86,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
fi
dep_tristate ' Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
+ dep_tristate ' ACI mixer (miroPCM12)' CONFIG_SOUND_ACI_MIXER $CONFIG_SOUND_OSS
dep_tristate ' Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS
dep_tristate ' Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND_OSS
dep_tristate ' Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND_OSS
@@ -115,10 +116,10 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
dep_tristate ' PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_SOUND_PSS $CONFIG_SOUND_OSS
if [ "$CONFIG_SOUND_PSS" = "y" -o "$CONFIG_SOUND_PSS" = "m" ]; then
bool ' Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER
- fi
- bool ' Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
- if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
- string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
+ bool ' Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
+ if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
+ string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
+ fi
fi
dep_tristate ' SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND_OSS
@@ -128,6 +129,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
fi
dep_tristate ' 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS
+ dep_tristate ' AWE32 synth' CONFIG_SOUND_AWE32_SYNTH $CONFIG_SOUND_OSS
dep_tristate ' Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m
dep_tristate ' Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS
if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
@@ -143,20 +145,33 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
dep_tristate ' Yamaha OPL3-SA2, SA3, and SAx based PnP cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS
dep_tristate ' 6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS
+ dep_tristate ' Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_SOUND_AEDSP16 $CONFIG_SOUND_OSS
+ if [ "$CONFIG_SOUND_AEDSP16" = "y" -o "$CONFIG_SOUND_AEDSP16" = "m" ]; then
+ bool ' SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600
+ if [ "$CONFIG_SC6600" = "y" ]; then
+ bool ' Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY
+ int ' SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' CONFIG_SC6600_CDROM 4
+ hex ' SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0
+ fi
+ if [ "$CONFIG_SOUND_SB" = "y" -o "$CONFIG_SOUND_SB" = "m" ]; then
+ if [ "$CONFIG_AEDSP16_MSS" != "y" ]; then
+ bool ' Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO
+ fi
+ fi
+ if [ "$CONFIG_SOUND_MSS" = "y" -o "$CONFIG_SOUND_MSS" = "m" ]; then
+ if [ "$CONFIG_AEDSP16_SBPRO" != "y" ]; then
+ bool ' Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
+ fi
+ fi
+ if [ "$CONFIG_SOUND_MPU401" = "y" -o "$CONFIG_SOUND_MPU401" = "m" ]; then
+ bool ' Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
+ fi
+ fi
+
if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS
fi
-
-
- # Additional low level drivers.
-
- mainmenu_option next_comment
- comment 'Additional low level sound drivers'
- bool 'Additional low level sound drivers' CONFIG_LOWLEVEL_SOUND $CONFIG_SOUND_OSS
- if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then
- source drivers/sound/lowlevel/Config.in
- fi
- endmenu
+
fi
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 2c5df3f14..6a3576df0 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -10,13 +10,7 @@
SUB_DIRS :=
MOD_SUB_DIRS :=
MOD_IN_SUB_DIRS :=
-ALL_SUB_DIRS := $(SUB_DIRS) lowlevel
-
-ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
- SUB_DIRS += lowlevel
- MOD_IN_SUB_DIRS += lowlevel
-endif
-
+ALL_SUB_DIRS := $(SUB_DIRS)
# All of the (potential) objects that export symbols.
@@ -47,6 +41,7 @@ obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
# Please leave it as is, cause the link order is significant !
+obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
@@ -69,6 +64,8 @@ obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o
obj-$(CONFIG_SOUND_AD1816) += ad1816.o
+obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o
+obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o sb_lib.o uart401.o ac97.o
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
@@ -85,7 +82,7 @@ obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
# Declare multi-part drivers.
-list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \
+list-multi := sound.o gus.o pas2.o sb.o sb_lib.o softoss2.o vidc_mod.o \
soundcore.o wavefront.o
sound-objs := \
@@ -137,8 +134,8 @@ O_OBJS := $(filter-out $(export-objs), $(obj-y))
OX_OBJS := $(filter $(export-objs), $(obj-y))
M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-#MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
-#MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
O_OBJS += lowlevel/lowlevel.o
diff --git a/drivers/sound/aci.c b/drivers/sound/aci.c
new file mode 100644
index 000000000..6970bec0d
--- /dev/null
+++ b/drivers/sound/aci.c
@@ -0,0 +1,718 @@
+/*
+ * Audio Command Interface (ACI) driver (sound/aci.c)
+ *
+ * ACI is a protocol used to communicate with the microcontroller on
+ * some sound cards produced by miro, e.g. the miroSOUND PCM12 and
+ * PCM20. The ACI has been developed for miro by Norberto Pellicci
+ * <pellicci@home.com>. Special thanks to both him and miro for
+ * providing the ACI specification.
+ *
+ * The main function of the ACI is to control the mixer and to get a
+ * product identification. On the PCM20, ACI also controls the radio
+ * tuner on this card, this is supported in the Video for Linux
+ * radio-miropcm20 driver.
+ *
+ * This Voxware ACI driver currently only supports the ACI functions
+ * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards
+ * with additional ACI functions can easily be added later.
+ *
+ * / NOTE / When compiling as a module, make sure to load the module
+ * after loading the mad16 module. The initialisation code expects the
+ * MAD16 default mixer to be already available.
+ *
+ * Revision history:
+ *
+ * 1995-11-10 Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
+ * First version written.
+ * 1995-12-31 Markus Kuhn
+ * Second revision, general code cleanup.
+ * 1996-05-16 Hannu Savolainen
+ * Integrated with other parts of the driver.
+ * 1996-05-28 Markus Kuhn
+ * Initialize CS4231A mixer, make ACI first mixer,
+ * use new private mixer API for solo mode.
+ * 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ * Small modification to export ACI functions and
+ * complete modularisation.
+ */
+
+/*
+ * Some driver specific information and features:
+ *
+ * This mixer driver identifies itself to applications as "ACI" in
+ * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
+ *
+ * Proprietary mixer features that go beyond the standard OSS mixer
+ * interface are:
+ *
+ * Full duplex solo configuration:
+ *
+ * int solo_mode;
+ * ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
+ *
+ * solo_mode = 0: deactivate solo mode (default)
+ * solo_mode > 0: activate solo mode
+ * With activated solo mode, the PCM input can not any
+ * longer hear the signals produced by the PCM output.
+ * Activating solo mode is important in duplex mode in order
+ * to avoid feedback distortions.
+ * solo_mode < 0: do not change solo mode (just retrieve the status)
+ *
+ * When the ioctl() returns 0, solo_mode contains the previous
+ * status (0 = deactivated, 1 = activated). If solo mode is not
+ * implemented on this card, ioctl() returns -1 and sets errno to
+ * EINVAL.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "sound_config.h"
+
+#undef DEBUG /* if defined, produce a verbose report via syslog */
+
+int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */
+unsigned char aci_idcode[2] = {0, 0}; /* manufacturer and product ID */
+unsigned char aci_version = 0; /* ACI firmware version */
+int aci_solo; /* status bit of the card that can't be *
+ * checked with ACI versions prior to 0xb0 */
+
+static int aci_present = 0;
+
+#ifdef MODULE /* Whether the aci mixer is to be reset. */
+int aci_reset = 0; /* Default: don't reset if the driver is a */
+MODULE_PARM(aci_reset,"i");
+#else /* module; use "insmod aci.o aci_reset=1" */
+int aci_reset = 1; /* to override. */
+#endif
+
+
+#define COMMAND_REGISTER (aci_port)
+#define STATUS_REGISTER (aci_port + 1)
+#define BUSY_REGISTER (aci_port + 2)
+
+/*
+ * Wait until the ACI microcontroller has set the READYFLAG in the
+ * Busy/IRQ Source Register to 0. This is required to avoid
+ * overrunning the sound card microcontroller. We do a busy wait here,
+ * because the microcontroller is not supposed to signal a busy
+ * condition for more than a few clock cycles. In case of a time-out,
+ * this function returns -1.
+ *
+ * This busy wait code normally requires less than 15 loops and
+ * practically always less than 100 loops on my i486/DX2 66 MHz.
+ *
+ * Warning: Waiting on the general status flag after reseting the MUTE
+ * function can take a VERY long time, because the PCM12 does some kind
+ * of fade-in effect. For this reason, access to the MUTE function has
+ * not been implemented at all.
+ */
+
+static int busy_wait(void)
+{
+ long timeout;
+
+ for (timeout = 0; timeout < 10000000L; timeout++)
+ if ((inb_p(BUSY_REGISTER) & 1) == 0)
+ return 0;
+
+#ifdef DEBUG
+ printk("ACI: READYFLAG timed out.\n");
+#endif
+
+ return -1;
+}
+
+
+/*
+ * Read the GENERAL STATUS register.
+ */
+
+static int read_general_status(void)
+{
+ unsigned long flags;
+ int status;
+
+ save_flags(flags);
+ cli();
+
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ status = (unsigned) inb_p(STATUS_REGISTER);
+ restore_flags(flags);
+ return status;
+}
+
+
+/*
+ * The four ACI command types (implied, write, read and indexed) can
+ * be sent to the microcontroller using the following four functions.
+ * If a problem occurred, they return -1.
+ */
+
+int aci_implied_cmd(unsigned char opcode)
+{
+ unsigned long flags;
+
+#ifdef DEBUG
+ printk("ACI: aci_implied_cmd(0x%02x)\n", opcode);
+#endif
+
+ save_flags(flags);
+ cli();
+
+ if (read_general_status() < 0 || busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(opcode, COMMAND_REGISTER);
+
+ restore_flags(flags);
+ return 0;
+}
+
+
+int aci_write_cmd(unsigned char opcode, unsigned char parameter)
+{
+ unsigned long flags;
+ int status;
+
+#ifdef DEBUG
+ printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
+#endif
+
+ save_flags(flags);
+ cli();
+
+ if (read_general_status() < 0 || busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(opcode, COMMAND_REGISTER);
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(parameter, COMMAND_REGISTER);
+
+ if ((status = read_general_status()) < 0) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ /* polarity of the INVALID flag depends on ACI version */
+ if ((aci_version < 0xb0 && (status & 0x40) != 0) ||
+ (aci_version >= 0xb0 && (status & 0x40) == 0)) {
+ restore_flags(flags);
+ printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
+ opcode, parameter);
+ return -1;
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * This write command send 2 parameters instead of one.
+ * Only used in PCM20 radio frequency tuning control
+ */
+
+int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2)
+{
+ unsigned long flags;
+ int status;
+
+#ifdef DEBUG
+ printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2);
+#endif
+
+ save_flags(flags);
+ cli();
+
+ if (read_general_status() < 0 || busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(opcode, COMMAND_REGISTER);
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(parameter, COMMAND_REGISTER);
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(parameter2, COMMAND_REGISTER);
+
+ if ((status = read_general_status()) < 0) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ /* polarity of the INVALID flag depends on ACI version */
+ if ((aci_version < 0xb0 && (status & 0x40) != 0) ||
+ (aci_version >= 0xb0 && (status & 0x40) == 0)) {
+ restore_flags(flags);
+#if 0 /* Frequency tuning works, but the INVALID flag is set ??? */
+ printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n",
+ opcode, parameter, parameter2);
+#endif
+ return -1;
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter)
+{
+ unsigned long flags;
+ int i = 0;
+
+ save_flags(flags);
+ cli();
+
+ if (read_general_status() < 0) {
+ restore_flags(flags);
+ return -1;
+ }
+ while (i < length) {
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(opcode, COMMAND_REGISTER);
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ parameter[i++] = inb_p(STATUS_REGISTER);
+#ifdef DEBUG
+ if (i == 1)
+ printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n",
+ opcode, length, parameter[i-1]);
+ else
+ printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]);
+#endif
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+
+int aci_indexed_cmd(unsigned char opcode, unsigned char index,
+ unsigned char *parameter)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (read_general_status() < 0 || busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(opcode, COMMAND_REGISTER);
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ outb_p(index, COMMAND_REGISTER);
+ if (busy_wait()) {
+ restore_flags(flags);
+ return -1;
+ }
+
+ *parameter = inb_p(STATUS_REGISTER);
+#ifdef DEBUG
+ printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
+ *parameter);
+#endif
+
+ restore_flags(flags);
+ return 0;
+}
+
+
+/*
+ * The following macro SCALE can be used to scale one integer volume
+ * value into another one using only integer arithmetic. If the input
+ * value x is in the range 0 <= x <= xmax, then the result will be in
+ * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
+ *
+ * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
+ * following nice properties:
+ *
+ * - SCALE(xmax,ymax,xmax) = ymax
+ * - SCALE(xmax,ymax,0) = 0
+ * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
+ *
+ * In addition, the rounding error is minimal and nicely distributed.
+ * The proofs are left as an exercise to the reader.
+ */
+
+#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
+
+
+static int getvolume(caddr_t arg,
+ unsigned char left_index, unsigned char right_index)
+{
+ int vol;
+ unsigned char buf;
+
+ /* left channel */
+ if (aci_indexed_cmd(0xf0, left_index, &buf))
+ return -EIO;
+ vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
+
+ /* right channel */
+ if (aci_indexed_cmd(0xf0, right_index, &buf))
+ return -EIO;
+ vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
+
+ return (*(int *) arg = vol);
+}
+
+
+static int setvolume(caddr_t arg,
+ unsigned char left_index, unsigned char right_index)
+{
+ int vol, ret;
+
+ /* left channel */
+ vol = *(int *)arg & 0xff;
+ if (vol > 100)
+ vol = 100;
+ vol = SCALE(100, 0x20, vol);
+ if (aci_write_cmd(left_index, 0x20 - vol))
+ return -EIO;
+ ret = SCALE(0x20, 100, vol);
+
+
+ /* right channel */
+ vol = (*(int *)arg >> 8) & 0xff;
+ if (vol > 100)
+ vol = 100;
+ vol = SCALE(100, 0x20, vol);
+ if (aci_write_cmd(right_index, 0x20 - vol))
+ return -EIO;
+ ret |= SCALE(0x20, 100, vol) << 8;
+
+ return (*(int *) arg = ret);
+}
+
+
+static int
+aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+{
+ int status, vol;
+ unsigned char buf;
+
+ /* handle solo mode control */
+ if (cmd == SOUND_MIXER_PRIVATE1) {
+ if (*(int *) arg >= 0) {
+ aci_solo = !!*(int *) arg;
+ if (aci_write_cmd(0xd2, aci_solo))
+ return -EIO;
+ } else if (aci_version >= 0xb0) {
+ if ((status = read_general_status()) < 0)
+ return -EIO;
+ return (*(int *) arg = (status & 0x20) == 0);
+ }
+
+ return (*(int *) arg = aci_solo);
+ }
+
+ if (((cmd >> 8) & 0xff) == 'M') {
+ if (cmd & IOC_IN)
+ /* read and write */
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_VOLUME:
+ return setvolume(arg, 0x01, 0x00);
+ case SOUND_MIXER_CD:
+ return setvolume(arg, 0x3c, 0x34);
+ case SOUND_MIXER_MIC:
+ return setvolume(arg, 0x38, 0x30);
+ case SOUND_MIXER_LINE:
+ return setvolume(arg, 0x39, 0x31);
+ case SOUND_MIXER_SYNTH:
+ return setvolume(arg, 0x3b, 0x33);
+ case SOUND_MIXER_PCM:
+ return setvolume(arg, 0x3a, 0x32);
+ case SOUND_MIXER_LINE1: /* AUX1 */
+ return setvolume(arg, 0x3d, 0x35);
+ case SOUND_MIXER_LINE2: /* AUX2 */
+ return setvolume(arg, 0x3e, 0x36);
+ case SOUND_MIXER_IGAIN: /* MIC pre-amp */
+ vol = *(int *) arg & 0xff;
+ if (vol > 100)
+ vol = 100;
+ vol = SCALE(100, 3, vol);
+ if (aci_write_cmd(0x03, vol))
+ return -EIO;
+ vol = SCALE(3, 100, vol);
+ return (*(int *) arg = vol | (vol << 8));
+ case SOUND_MIXER_RECSRC:
+ return (*(int *) arg = 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+ else
+ /* only read */
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_DEVMASK:
+ return (*(int *) arg =
+ SOUND_MASK_VOLUME | SOUND_MASK_CD |
+ SOUND_MASK_MIC | SOUND_MASK_LINE |
+ SOUND_MASK_SYNTH | SOUND_MASK_PCM |
+#if 0
+ SOUND_MASK_IGAIN |
+#endif
+ SOUND_MASK_LINE1 | SOUND_MASK_LINE2);
+ break;
+ case SOUND_MIXER_STEREODEVS:
+ return (*(int *) arg =
+ SOUND_MASK_VOLUME | SOUND_MASK_CD |
+ SOUND_MASK_MIC | SOUND_MASK_LINE |
+ SOUND_MASK_SYNTH | SOUND_MASK_PCM |
+ SOUND_MASK_LINE1 | SOUND_MASK_LINE2);
+ break;
+ case SOUND_MIXER_RECMASK:
+ return (*(int *) arg = 0);
+ break;
+ case SOUND_MIXER_RECSRC:
+ return (*(int *) arg = 0);
+ break;
+ case SOUND_MIXER_CAPS:
+ return (*(int *) arg = 0);
+ break;
+ case SOUND_MIXER_VOLUME:
+ return getvolume(arg, 0x04, 0x03);
+ case SOUND_MIXER_CD:
+ return getvolume(arg, 0x0a, 0x09);
+ case SOUND_MIXER_MIC:
+ return getvolume(arg, 0x06, 0x05);
+ case SOUND_MIXER_LINE:
+ return getvolume(arg, 0x08, 0x07);
+ case SOUND_MIXER_SYNTH:
+ return getvolume(arg, 0x0c, 0x0b);
+ case SOUND_MIXER_PCM:
+ return getvolume(arg, 0x0e, 0x0d);
+ case SOUND_MIXER_LINE1: /* AUX1 */
+ return getvolume(arg, 0x11, 0x10);
+ case SOUND_MIXER_LINE2: /* AUX2 */
+ return getvolume(arg, 0x13, 0x12);
+ case SOUND_MIXER_IGAIN: /* MIC pre-amp */
+ if (aci_indexed_cmd(0xf0, 0x21, &buf))
+ return -EIO;
+ vol = SCALE(3, 100, buf <= 3 ? buf : 3);
+ vol |= vol << 8;
+ return (*(int *) arg = vol);
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return -EINVAL;
+}
+
+
+static struct mixer_operations aci_mixer_operations =
+{
+ "ACI",
+ "ACI mixer",
+ aci_mixer_ioctl,
+ NULL
+};
+
+static unsigned char
+mad_read (int port)
+{
+ outb (0xE3, 0xf8f); /* Write MAD16 password */
+ return inb (port); /* Read from port */
+}
+
+
+/*
+ * Check, whether there actually is any ACI port operational and if
+ * one was found, then initialize the ACI interface, reserve the I/O
+ * addresses and attach the new mixer to the relevant VoxWare data
+ * structures.
+ *
+ * Returns: 1 ACI mixer detected
+ * 0 nothing there
+ *
+ * There is also an internal mixer in the codec (CS4231A or AD1845),
+ * that deserves no purpose in an ACI based system which uses an
+ * external ACI controlled stereo mixer. Make sure that this codec
+ * mixer has the AUX1 input selected as the recording source, that the
+ * input gain is set near maximum and that the other channels going
+ * from the inputs to the codec output are muted.
+ */
+
+static int __init attach_aci(void)
+{
+ char *boardname = "unknown";
+ int volume;
+
+#define MC4_PORT 0xf90
+
+ aci_port =
+ (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
+
+ if (check_region(aci_port, 3)) {
+#ifdef DEBUG
+ printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
+ aci_port, aci_port+2);
+#endif
+ return 0;
+ }
+
+ if (aci_read_cmd(0xf2, 2, aci_idcode)) {
+#ifdef DEBUG
+ printk("ACI: Failed to read idcode.\n");
+#endif
+ return 0;
+ }
+
+ if (aci_read_cmd(0xf1, 1, &aci_version)) {
+#ifdef DEBUG
+ printk("ACI: Failed to read version.\n");
+#endif
+ return 0;
+ }
+
+ if (aci_idcode[0] == 0x6d) {
+ /* It looks like a miro sound card. */
+ switch (aci_idcode[1]) {
+ case 0x41:
+ boardname = "PCM1 pro / early PCM12";
+ break;
+ case 0x42:
+ boardname = "PCM12";
+ break;
+ case 0x43:
+ boardname = "PCM20";
+ break;
+ default:
+ boardname = "unknown miro";
+ }
+ } else
+#ifndef DEBUG
+ return 0;
+#endif
+
+ printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
+ aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
+
+ if (aci_reset) {
+ /* initialize ACI mixer */
+ aci_implied_cmd(0xff);
+ aci_solo = 0;
+ }
+
+ /* attach the mixer */
+ request_region(aci_port, 3, "sound mixer (ACI)");
+ if (num_mixers < MAX_MIXER_DEV) {
+ if (num_mixers > 0 &&
+ !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) {
+ /*
+ * The previously registered mixer device is the CS4231A which
+ * has no function on an ACI card. Make the ACI mixer the first
+ * of the two mixer devices.
+ */
+ mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
+ mixer_devs[num_mixers-1] = &aci_mixer_operations;
+ /*
+ * Initialize the CS4231A mixer with reasonable values. It is
+ * unlikely that the user ever will want to change these as all
+ * channels can be mixed via ACI.
+ */
+ volume = 0x6464;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
+ volume = 0x6464;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_IGAIN, (caddr_t) &volume);
+ volume = 0;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
+ volume = 0;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
+ volume = 0;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume);
+ volume = 0;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
+ volume = 0;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
+ volume = 0;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume);
+ volume = SOUND_MASK_LINE1;
+ mixer_devs[num_mixers]->ioctl(num_mixers,
+ SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume);
+ num_mixers++;
+ } else
+ mixer_devs[num_mixers++] = &aci_mixer_operations;
+ }
+
+ /* Just do something; otherwise the first write command fails, at
+ * least with my PCM20.
+ */
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume);
+
+ if (aci_reset) {
+ /* Initialize ACI mixer with reasonable power-up values */
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &volume);
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE, (caddr_t) &volume);
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD, (caddr_t) &volume);
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
+ volume = 0x3232;
+ aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
+ }
+
+ aci_present = 1;
+
+ return 1;
+}
+
+static void __exit unload_aci(void)
+{
+ if (aci_present)
+ release_region(aci_port, 3);
+}
+
+module_init(attach_aci);
+module_exit(unload_aci);
diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c
index d44cf1389..8bd68c4dc 100644
--- a/drivers/sound/ad1816.c
+++ b/drivers/sound/ad1816.c
@@ -1386,7 +1386,7 @@ static int __init setup_ad1816(char *str)
io = ints[1];
irq = ints[2];
dma = ints[3];
- dma16 = ints[4];
+ dma2 = ints[4];
return 1;
}
diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c
index b7ad6f75c..bce04ef33 100644
--- a/drivers/sound/ad1848.c
+++ b/drivers/sound/ad1848.c
@@ -2502,11 +2502,6 @@ void attach_ms_sound(struct address_info *hw_config)
int dma = hw_config->dma;
int dma2 = hw_config->dma2;
- if(hw_config->io_base != -1 || hw_config->irq == -1 || hw_config->dma == -1) {
- printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n");
- return;
- }
-
if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */
{
hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,
@@ -2573,9 +2568,6 @@ void attach_ms_sound(struct address_info *hw_config)
dma2, 0,
hw_config->osp);
request_region(hw_config->io_base, 4, "WSS config");
-
- SOUND_LOCK;
- loaded = 1;
}
void unload_ms_sound(struct address_info *hw_config)
@@ -2710,15 +2702,6 @@ EXPORT_SYMBOL(probe_ms_sound);
EXPORT_SYMBOL(attach_ms_sound);
EXPORT_SYMBOL(unload_ms_sound);
-MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */
-MODULE_PARM(irq, "i"); /* IRQ to use */
-MODULE_PARM(dma, "i"); /* First DMA channel */
-MODULE_PARM(dma2, "i"); /* Second DMA channel */
-MODULE_PARM(type, "i"); /* Card type */
-MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen */
-MODULE_PARM(deskpro_m, "i"); /* Special magic for Deskpro M box */
-MODULE_PARM(soundpro, "i"); /* More special magic for SoundPro chips */
-
static int __initdata io = -1;
static int __initdata irq = -1;
static int __initdata dma = -1;
@@ -2727,21 +2710,41 @@ static int __initdata type = 0;
static struct address_info cfg;
+MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */
+MODULE_PARM(irq, "i"); /* IRQ to use */
+MODULE_PARM(dma, "i"); /* First DMA channel */
+MODULE_PARM(dma2, "i"); /* Second DMA channel */
+MODULE_PARM(type, "i"); /* Card type */
+MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen
+*/
+MODULE_PARM(deskpro_m, "i"); /* Special magic for Deskpro M box */
+MODULE_PARM(soundpro, "i"); /* More special magic for SoundPro
+chips */
+
static int __init init_ad1848(void)
{
printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n");
- cfg.irq = irq;
- cfg.io_base = io;
- cfg.dma = dma;
- cfg.dma2 = dma2;
- cfg.card_subtype = type;
+ if(io != -1) {
+ if(irq == -1 || dma == -1) {
+ printk(KERN_WARNING "ad1848: must give I/O , IRQ and DMA.\n");
+ return -EINVAL;
+ }
- if(probe_ms_sound(&cfg)) {
+ cfg.irq = irq;
+ cfg.io_base = io;
+ cfg.dma = dma;
+ cfg.dma2 = dma2;
+ cfg.card_subtype = type;
+
+ if(!probe_ms_sound(&cfg))
+ return -ENODEV;
attach_ms_sound(&cfg);
- return 0;
- } else
- return -ENODEV;
+ loaded = 1;
+ }
+
+ SOUND_LOCK;
+ return 0;
}
static void __exit cleanup_ad1848(void)
diff --git a/drivers/sound/lowlevel/aedsp16.c b/drivers/sound/aedsp16.c
index 48ef93f19..74b961521 100644
--- a/drivers/sound/lowlevel/aedsp16.c
+++ b/drivers/sound/aedsp16.c
@@ -27,25 +27,14 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
-#include "../sound_config.h"
-#include "../soundmodule.h"
+#include "sound_config.h"
+#include "soundmodule.h"
/*
* Sanity checks
*/
-#if !defined(CONFIG_AEDSP16_BASE)
-# undef CONFIG_AEDSP16
-#else
-# if defined(MODULE) && defined(CONFIG_AEDSP16_MODULE)
-# define CONFIG_AEDSP16 1
-# endif
-#endif
-
-
-#if defined(CONFIG_AEDSP16)
-
-#if defined(CONFIG_AEDSP16_SBPRO) && defined(CONFIG_AEDSP16_MSS)
+#if defined(CONFIG_SOUND_AEDSP16_SBPRO) && defined(CONFIG_SOUND_AEDSP16_MSS)
#error You have to enable only one of the MSS and SBPRO emulations.
#endif
@@ -1275,22 +1264,6 @@ int __init init_aedsp16(void)
{
int initialized = FALSE;
-#if !defined(MODULE)
- ae_config.base_io = CONFIG_AEDSP16_BASE;
-#if defined(CONFIG_AEDSP16_SBPRO)
- ae_config.irq = CONFIG_AEDSP16_SB_IRQ;
- ae_config.dma = CONFIG_AEDSP16_SB_DMA;
-#endif
-#if defined(CONFIG_AEDSP16_MSS)
- ae_config.mss_base = CONFIG_MSS_BASE;
- ae_config.irq = CONFIG_AEDSP16_MSS_IRQ;
- ae_config.dma = CONFIG_AEDSP16_MSS_DMA;
-#endif
-#if defined(CONFIG_AEDSP16_MPU401)
- ae_config.mpu_base = CONFIG_MPU_BASE;
- ae_config.mpu_irq = CONFIG_AEDSP16_MPU_IRQ;
-#endif
-#endif /* !MODULE */
DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n",
ae_config.base_io,ae_config.irq,ae_config.dma,ae_config.mpu_irq));
@@ -1339,15 +1312,12 @@ void __init uninit_aedsp16(void)
uninit_aedsp16_mpu();
}
-#if defined(MODULE)
-
-int io = -1;
-int irq = -1;
-int dma = -1;
-int mpu_irq = -1;
-int mss_base = -1;
-int mpu_base = -1;
-
+static int __initdata io = -1;
+static int __initdata irq = -1;
+static int __initdata dma = -1;
+static int __initdata mpu_irq = -1;
+static int __initdata mss_base = -1;
+static int __initdata mpu_base = -1;
MODULE_PARM(io, "i");
MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)");
@@ -1364,7 +1334,7 @@ MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)");
MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>");
MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION);
-int init_module(void) {
+static int __init do_init_aedsp16(void) {
printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n");
if (io == -1 || dma == -1 || irq == -1) {
printk(KERN_INFO "aedsp16: I/O, IRQ and DMA are mandatory\n");
@@ -1391,10 +1361,29 @@ int init_module(void) {
return 0;
}
-void cleanup_module(void) {
+static void __exit cleanup_aedsp16(void) {
uninit_aedsp16();
SOUND_LOCK_END;
}
-#endif /* MODULE */
-#endif /* CONFIG_AEDSP16 */
+module_init(do_init_aedsp16);
+module_exit(cleanup_aedsp16);
+
+#ifndef MODULE
+static int __init setup_aedsp16(char *str)
+{
+ /* io, irq, dma, mss_io, mpu_io, mpu_irq */
+ int ints[7];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+
+ io = ints[1];
+ irq = ints[2];
+ dma = ints[3];
+ mss_base = ints[4];
+ mpu_base = ints[5];
+ mpu_irq = ints[6];
+}
+
+__setup("aedsp16=", setup_aedsp16);
+#endif
diff --git a/drivers/sound/lowlevel/awe_hw.h b/drivers/sound/awe_hw.h
index c7dde2679..c7dde2679 100644
--- a/drivers/sound/lowlevel/awe_hw.h
+++ b/drivers/sound/awe_hw.h
diff --git a/drivers/sound/lowlevel/awe_wave.c b/drivers/sound/awe_wave.c
index 8608e179e..bedebb3b6 100644
--- a/drivers/sound/lowlevel/awe_wave.c
+++ b/drivers/sound/awe_wave.c
@@ -21,23 +21,29 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* include initial header files and compatibility macros */
-#ifdef __FreeBSD__
-# include <i386/isa/sound/awe_compat.h>
-#else
-# include "awe_compat.h"
-#endif /* FreeBSD */
-#ifdef __linux__
-# include <linux/config.h>
-#endif
+#include <linux/awe_voice.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
-/*----------------------------------------------------------------*/
+#include "sound_config.h"
+#include "soundmodule.h"
-#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE)
+#include "awe_wave.h"
+#include "awe_hw.h"
-/*----------------------------------------------------------------
+#ifdef AWE_HAS_GUS_COMPATIBILITY
+#include "tuning.h"
+#include <linux/ultrasound.h>
+#endif
+
+/*
* debug message
- *----------------------------------------------------------------*/
+ */
+
+/* do not allocate buffer at beginning */
+#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
#ifdef AWE_DEBUG_ON
#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
@@ -49,9 +55,9 @@
#define FATALERR(XXX) XXX
#endif
-/*----------------------------------------------------------------
+/*
* bank and voice record
- *----------------------------------------------------------------*/
+ */
/* soundfont record */
typedef struct _sf_list {
@@ -115,9 +121,9 @@ static awe_voice_list *infos = NULL;
/* preset table index */
static int preset_table[AWE_MAX_PRESETS];
-/*----------------------------------------------------------------
+/*
* voice table
- *----------------------------------------------------------------*/
+ */
/* effects table */
typedef struct FX_Rec { /* channel effects */
@@ -200,23 +206,18 @@ static awe_chan_info channels[AWE_MAX_CHANNELS];
#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */
#endif
-/* set variables */
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-/* replace awe_port variable with exported variable */
#define awe_port io
#define awe_mem_size memsize
int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
-#ifdef MODULE_PARM
+
+MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
+MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
MODULE_PARM(io, "i");
MODULE_PARM_DESC(io, "base i/o port of Emu8000");
MODULE_PARM(memsize, "i");
MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
-#endif
-#else
-static int awe_port = AWE_DEFAULT_BASE_ADDR;
-static int awe_mem_size = AWE_DEFAULT_MEM_SIZE;
-#endif /* module */
+EXPORT_NO_SYMBOLS;
/* DRAM start offset */
static int awe_mem_start = AWE_DRAM_OFFSET;
@@ -261,15 +262,13 @@ static struct synth_info awe_info = {
static struct voice_alloc_info *voice_alloc; /* set at initialization */
-/*----------------------------------------------------------------
+/*
* function prototypes
- *----------------------------------------------------------------*/
+ */
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
static int awe_check_port(void);
static void awe_request_region(void);
static void awe_release_region(void);
-#endif /* linux & obsolete */
static void awe_reset_samples(void);
/* emu8000 chip i/o access */
@@ -346,9 +345,6 @@ static void awe_aftertouch(int dev, int voice, int pressure);
static void awe_controller(int dev, int voice, int ctrl_num, int value);
static void awe_panning(int dev, int voice, int value);
static void awe_volume_method(int dev, int mode);
-#ifndef AWE_NO_PATCHMGR
-static int awe_patchmgr(int dev, struct patmgr_info *rec);
-#endif
static void awe_bender(int dev, int voice, int value);
static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
static void awe_setup_voice(int dev, int voice, int chn);
@@ -439,15 +435,9 @@ static void unload_midiemu(void);
#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)
-#ifdef __FreeBSD__
-/* FIXME */
-#define MALLOC_LOOP_DATA
-#define WAIT_BY_LOOP
-#endif
-
-/*----------------------------------------------------------------
+/*
* control parameters
- *----------------------------------------------------------------*/
+ */
#ifdef AWE_USE_NEW_VOLUME_CALC
@@ -499,9 +489,7 @@ static int ctrls[AWE_MD_END];
static struct synth_operations awe_operations =
{
-#ifdef AWE_OSS38
"EMU8K",
-#endif
&awe_info,
0,
SYNTH_TYPE_SAMPLE,
@@ -519,9 +507,6 @@ static struct synth_operations awe_operations =
awe_controller,
awe_panning,
awe_volume_method,
-#ifndef AWE_NO_PATCHMGR
- awe_patchmgr,
-#endif
awe_bender,
awe_alloc,
awe_setup_voice
@@ -543,12 +528,10 @@ static int _attach_awe(void)
}
/* check AWE32 ports are available */
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
if (awe_check_port()) {
printk(KERN_WARNING "AWE32: I/O area already used.\n");
return 0;
}
-#endif
/* set buffers to NULL */
sflists = NULL;
@@ -577,10 +560,8 @@ static int _attach_awe(void)
attach_midiemu();
#endif
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
/* reserve I/O ports for awedrv */
awe_request_region();
-#endif
/* clear all samples */
awe_reset_samples();
@@ -594,25 +575,22 @@ static int _attach_awe(void)
awe_present = TRUE;
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
SOUND_LOCK;
-#endif
return 1;
}
-#ifdef AWE_DYNAMIC_BUFFER
static void free_tables(void)
{
- if (sflists)
- my_free(sflists);
+ if(sflists)
+ vfree(sflists);
sflists = NULL; max_sfs = 0;
if (samples)
- my_free(samples);
+ vfree(samples);
samples = NULL; max_samples = 0;
if (infos)
- my_free(infos);
+ vfree(infos);
infos = NULL; max_infos = 0;
}
@@ -621,23 +599,16 @@ static void *realloc_block(void *buf, int oldsize, int size)
void *ptr;
if (oldsize == size)
return buf;
- if ((ptr = my_malloc(size)) == NULL)
+ if ((ptr = vmalloc(size)) == NULL)
return NULL;
if (oldsize && size)
- MEMCPY(ptr, buf, ((oldsize < size) ? oldsize : size) );
+ memcpy(ptr, buf, ((oldsize < size) ? oldsize : size) );
if (buf)
- my_free(buf);
+ vfree(buf);
return ptr;
}
-#else /* dynamic buffer */
-
-#define free_buffers() /**/
-
-#endif /* dynamic_buffer */
-
-
static void _unload_awe(void)
{
if (awe_present) {
@@ -652,22 +623,13 @@ static void _unload_awe(void)
#endif
sound_unload_synthdev(my_dev);
awe_present = FALSE;
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
SOUND_LOCK_END;
-#endif
}
}
-
-/*================================================================
- * Linux interface
- *================================================================*/
-
-#ifdef linux
-
-/*----------------------------------------------------------------
+/*
* Linux PnP driver support
- *----------------------------------------------------------------*/
+ */
#ifdef CONFIG_PNP_DRV
@@ -756,118 +718,9 @@ static void awe_unload_pnp (void)
}
#endif /* PnP support */
-/*----------------------------------------------------------------
- * device / lowlevel (module) interface
- *----------------------------------------------------------------*/
-
-#ifdef AWE_OBSOLETEL_VOXWARE
-
-/* old type interface */
-int attach_awe_obsolete(int mem_start, struct address_info *hw_config)
-{
- my_malloc_init(mem_start);
- if (! _attach_awe())
- return 0;
- return my_malloc_memptr();
-}
-
-int probe_awe_obsolete(struct address_info *hw_config)
-{
- return 1;
- /*return awe_detect();*/
-}
-
-#else /* !obsolete */
-
-/* new type interface */
-int attach_awe(void)
-{
-#ifdef CONFIG_PNP_DRV
- if (pnp) {
- awe_initpnp();
- if (awe_pnp_ok)
- return 0;
- }
-#endif /* pnp */
- _attach_awe();
- return 0;
-}
-
-void unload_awe(void)
-{
-#ifdef CONFIG_PNP_DRV
- if (pnp)
- awe_unload_pnp();
-#endif /* pnp */
- _unload_awe();
-}
-
-/* module interface */
-
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-int init_module(void)
-{
- return attach_awe();
-}
-
-void cleanup_module(void)
-{
- unload_awe();
-}
-
-#ifdef MODULE_PARM
-EXPORT_NO_SYMBOLS;
-MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
-MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
-MODULE_SUPPORTED_DEVICE("sound");
-#endif
-
-#endif /* module */
-
-#endif /* AWE_OBSOLETE_VOXWARE */
-
-#endif /* linux */
-
-
-/*================================================================
- * FreeBSD interface
- *================================================================*/
-
-#ifdef __FreeBSD__
-
-#ifdef AWE_OBSOLETE_VOXWARE
-long attach_awe_obsolete(long mem_start, struct address_info *hw_config)
-{
- _attach_awe();
- return 0;
-}
-
-int probe_awe_obsolete(struct address_info *hw_config)
-{
- return 1;
-}
-
-#else /* !obsolete */
-
-/* new type interface */
-void attach_awe(struct address_info *hw_config)
-{
- _attach_awe();
-}
-
-int probe_awe(struct address_info *hw_config)
-{
- return 1;
-}
-
-#endif /* obsolete */
-
-#endif /* FreeBSD */
-
-
-/*================================================================
+/*
* clear sample tables
- *================================================================*/
+ */
static void
awe_reset_samples(void)
@@ -886,16 +739,16 @@ awe_reset_samples(void)
}
-/*================================================================
+/*
* EMU register access
- *================================================================*/
+ */
/* select a given AWE32 pointer */
static int awe_ports[5];
static int port_setuped = FALSE;
static int awe_cur_cmd = -1;
#define awe_set_cmd(cmd) \
-if (awe_cur_cmd != cmd) { OUTW(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
+if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
/* store values to i/o port array */
static void setup_ports(int port1, int port2, int port3)
@@ -914,25 +767,25 @@ static void setup_ports(int port1, int port2, int port3)
}
/* write 16bit data */
-INLINE static void
+static inline void
awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
{
awe_set_cmd(cmd);
- OUTW(data, awe_ports[port]);
+ outw(data, awe_ports[port]);
}
/* write 32bit data */
-INLINE static void
+static inline void
awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
{
unsigned short addr = awe_ports[port];
awe_set_cmd(cmd);
- OUTW(data, addr); /* write lower 16 bits */
- OUTW(data >> 16, addr + 2); /* write higher 16 bits */
+ outw(data, addr); /* write lower 16 bits */
+ outw(data >> 16, addr + 2); /* write higher 16 bits */
}
/* read 16bit data */
-INLINE static unsigned short
+static inline unsigned short
awe_peek(unsigned short cmd, unsigned short port)
{
unsigned short k;
@@ -942,7 +795,7 @@ awe_peek(unsigned short cmd, unsigned short port)
}
/* read 32bit data */
-INLINE static unsigned int
+static inline unsigned int
awe_peek_dw(unsigned short cmd, unsigned short port)
{
unsigned int k1, k2;
@@ -987,19 +840,17 @@ static void awe_wait(unsigned short delay)
#endif /* wait by loop */
/* write a word data */
-INLINE static void
+static inline void
awe_write_dram(unsigned short c)
{
awe_poke(AWE_SMLD, c);
}
-#if defined(linux) && !defined(AWE_OBSOLETE_VOXWARE)
-
-/*================================================================
+/*
* port check / request
* 0x620-623, 0xA20-A23, 0xE20-E23
- *================================================================*/
+ */
static int
awe_check_port(void)
@@ -1028,12 +879,9 @@ awe_release_region(void)
release_region(awe_ports[3], 4);
}
-#endif /* linux && !AWE_OBSOLETE_VOXWARE */
-
-
-/*================================================================
+/*
* AWE32 initialization
- *================================================================*/
+ */
static void
awe_initialize(void)
{
@@ -1079,9 +927,9 @@ awe_initialize(void)
}
-/*================================================================
+/*
* AWE32 voice parameters
- *================================================================*/
+ */
/* initialize voice_info record */
static void
@@ -1244,9 +1092,9 @@ calc_rate_offset(int Hz)
}
-/*----------------------------------------------------------------
+/*
* convert envelope time parameter to AWE32 raw parameter
- *----------------------------------------------------------------*/
+ */
/* attack & decay/release time table (msec) */
static short attack_time_tbl[128] = {
@@ -1314,9 +1162,9 @@ calc_parm_search(int msec, short *table)
#endif /* AWE_HAS_GUS_COMPATIBILITY */
-/*================================================================
+/*
* effects table
- *================================================================*/
+ */
/* set an effect value */
#define FX_FLAG_OFF 0
@@ -1466,9 +1314,9 @@ FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode)
}
-/*================================================================
+/*
* turn on/off sample
- *================================================================*/
+ */
/* table for volume target calculation */
static unsigned short voltarget[16] = {
@@ -1687,9 +1535,9 @@ awe_exclusive_off(int voice)
}
-/*================================================================
+/*
* change the parameters of an audible voice
- *================================================================*/
+ */
/* change pitch */
static void
@@ -2137,9 +1985,9 @@ static void awe_terminate_and_init(int voice, int forced)
}
-/*================================================================
+/*
* synth operation routines
- *================================================================*/
+ */
#define AWE_VOICE_KEY(v) (0x8000 | (v))
#define AWE_CHAN_KEY(c,n) (((c) << 8) | ((n) + 1))
@@ -2185,8 +2033,8 @@ awe_voice_init(int voice, int init_all)
static void awe_fx_init(int ch)
{
if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) {
- BZERO(&channels[ch].fx, sizeof(channels[ch].fx));
- BZERO(&channels[ch].fx_layer, sizeof(&channels[ch].fx_layer));
+ memset(&channels[ch].fx, 0, sizeof(channels[ch].fx));
+ memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer));
}
}
@@ -2216,8 +2064,8 @@ static void awe_channel_init(int ch, int init_all)
cp->sustained = 0;
if (! ctrls[AWE_MD_KEEP_EFFECT]) {
- BZERO(&cp->fx, sizeof(cp->fx));
- BZERO(&cp->fx_layer, sizeof(cp->fx_layer));
+ memset(&cp->fx, 0, sizeof(cp->fx));
+ memset(&cp->fx_layer, 0, sizeof(cp->fx_layer));
}
}
@@ -2255,7 +2103,7 @@ static int
awe_open(int dev, int mode)
{
if (awe_busy)
- return RET_ERROR(EBUSY);
+ return -EBUSY;
awe_busy = TRUE;
@@ -2310,7 +2158,7 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
awe_info.nr_voices = awe_max_voices;
else
awe_info.nr_voices = AWE_MAX_CHANNELS;
- IOCTL_TO_USER((char*)arg, 0, &awe_info, sizeof(awe_info));
+ memcpy((char*)arg, &awe_info + 0, sizeof(awe_info));
return 0;
break;
@@ -2330,7 +2178,7 @@ awe_ioctl(int dev, unsigned int cmd, caddr_t arg)
default:
printk("AWE32: unsupported ioctl %d\n", cmd);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
}
@@ -2379,7 +2227,7 @@ awe_kill_note(int dev, int voice, int note, int velocity)
DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity));
if (! voice_in_range(voice))
- return RET_ERROR(EINVAL);
+ return -EINVAL;
switch (playing_mode) {
case AWE_PLAY_DIRECT:
@@ -2392,7 +2240,7 @@ awe_kill_note(int dev, int voice, int note, int velocity)
voice_alloc->map[voice] = 0;
voice = v2;
if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return RET_ERROR(EINVAL);
+ return -EINVAL;
/* continue to below */
default:
key = AWE_CHAN_KEY(voice, note);
@@ -2438,7 +2286,7 @@ awe_start_note(int dev, int voice, int note, int velocity)
DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity));
if (! voice_in_range(voice))
- return RET_ERROR(EINVAL);
+ return -EINVAL;
if (velocity == 0)
state = AWE_ST_STANDBY; /* stand by for playing */
@@ -2457,7 +2305,7 @@ awe_start_note(int dev, int voice, int note, int velocity)
case AWE_PLAY_MULTI2:
voice = voice_alloc->map[voice] >> 8;
if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return RET_ERROR(EINVAL);
+ return -EINVAL;
/* continue to below */
default:
if (note >= 128) { /* key volume mode */
@@ -2532,7 +2380,7 @@ awe_set_instr_2(int dev, int voice, int instr_no)
if (playing_mode == AWE_PLAY_MULTI2) {
voice = voice_alloc->map[voice] >> 8;
if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
return awe_set_instr(dev, voice, instr_no);
}
@@ -2545,10 +2393,10 @@ awe_set_instr(int dev, int voice, int instr_no)
int def_bank;
if (! voice_in_range(voice))
- return RET_ERROR(EINVAL);
+ return -EINVAL;
if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
- return RET_ERROR(EINVAL);
+ return -EINVAL;
cinfo = &channels[voice];
@@ -3049,17 +2897,6 @@ awe_volume_method(int dev, int mode)
}
-#ifndef AWE_NO_PATCHMGR
-/* patch manager */
-static int
-awe_patchmgr(int dev, struct patmgr_info *rec)
-{
- printk("AWE32 Warning: patch manager control not supported\n");
- return 0;
-}
-#endif
-
-
/* pitch wheel change: 0-16384 */
static void
awe_bender(int dev, int voice, int value)
@@ -3105,21 +2942,21 @@ awe_load_patch(int dev, int format, const char *addr,
return 0;
} else if (format != AWE_PATCH) {
printk("AWE32 Error: Invalid patch format (key) 0x%x\n", format);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (count < AWE_PATCH_INFO_SIZE) {
printk("AWE32 Error: Patch header too short\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
- COPY_FROM_USER(((char*)&patch) + offs, addr, offs,
+ copy_from_user(((char*)&patch) + offs, addr + offs,
AWE_PATCH_INFO_SIZE - offs);
count -= AWE_PATCH_INFO_SIZE;
if (count < patch.len) {
printk("AWE32: sample: Patch record too short (%d<%d)\n",
count, patch.len);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
switch (patch.type) {
@@ -3160,7 +2997,7 @@ awe_load_patch(int dev, int format, const char *addr,
default:
printk("AWE32 Error: unknown patch format type %d\n",
patch.type);
- rc = RET_ERROR(EINVAL);
+ rc = -EINVAL;
}
return rc;
@@ -3176,9 +3013,6 @@ awe_create_sf(int type, char *name)
/* terminate sounds */
awe_reset(0);
if (current_sf_id >= max_sfs) {
-#ifndef AWE_DYNAMIC_BUFFER
- return 1;
-#else
int newsize = max_sfs + AWE_MAX_SF_LISTS;
sf_list *newlist = realloc_block(sflists, sizeof(sf_list)*max_sfs,
sizeof(sf_list)*newsize);
@@ -3186,7 +3020,6 @@ awe_create_sf(int type, char *name)
return 1;
sflists = newlist;
max_sfs = newsize;
-#endif /* dynamic buffer */
}
rec = &sflists[current_sf_id];
rec->sf_id = current_sf_id + 1;
@@ -3238,7 +3071,7 @@ static int is_shared_sf(unsigned char *name)
AWE_MINOR_VERSION,
AWE_TINY_VERSION,
};
- if (MEMCMP(name, id_head, 6) == 0)
+ if (memcmp(name, id_head, 6) == 0)
return TRUE;
return FALSE;
}
@@ -3247,7 +3080,7 @@ static int is_shared_sf(unsigned char *name)
static int is_identical_name(unsigned char *name, int sf)
{
char *id = sflists[sf-1].name;
- if (is_shared_sf(id) && MEMCMP(id, name, AWE_PATCH_NAME_LEN) == 0)
+ if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
return TRUE;
return FALSE;
}
@@ -3285,7 +3118,7 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
awe_open_parm parm;
int shared;
- COPY_FROM_USER(&parm, addr, AWE_PATCH_INFO_SIZE, sizeof(parm));
+ copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm));
shared = FALSE;
#ifdef AWE_ALLOW_SAMPLE_SHARING
@@ -3303,7 +3136,7 @@ awe_open_patch(awe_patch_info *patch, const char *addr, int count)
if (! shared) {
if (awe_create_sf(parm.type, parm.name)) {
printk("AWE32: can't open: failed to alloc new list\n");
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
}
}
patch_opened = TRUE;
@@ -3317,7 +3150,7 @@ check_patch_opened(int type, char *name)
if (! patch_opened) {
if (awe_create_sf(type, name)) {
printk("AWE32: failed to alloc new list\n");
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
}
patch_opened = TRUE;
return current_sf_id;
@@ -3355,10 +3188,6 @@ static int alloc_new_info(int nvoices)
awe_voice_list *newlist;
free_info = awe_free_info();
if (free_info + nvoices >= max_infos) {
-#ifndef AWE_DYNAMIC_BUFFER
- printk("AWE32: can't alloc info table\n");
- return RET_ERROR(ENOSPC);
-#else
do {
newsize = max_infos + AWE_MAX_INFOS;
} while (free_info + nvoices >= newsize);
@@ -3366,11 +3195,10 @@ static int alloc_new_info(int nvoices)
sizeof(awe_voice_list)*newsize);
if (newlist == NULL) {
printk("AWE32: can't alloc info table\n");
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
}
infos = newlist;
max_infos = newsize;
-#endif
}
return 0;
}
@@ -3382,21 +3210,16 @@ static int alloc_new_sample(void)
awe_sample_list *newlist;
free_sample = awe_free_sample();
if (free_sample >= max_samples) {
-#ifndef AWE_DYNAMIC_BUFFER
- printk("AWE32: can't alloc sample table\n");
- return RET_ERROR(ENOSPC);
-#else
newsize = max_samples + AWE_MAX_SAMPLES;
newlist = realloc_block(samples,
sizeof(awe_sample_list)*max_samples,
sizeof(awe_sample_list)*newsize);
if (newlist == NULL) {
printk("AWE32: can't alloc sample table\n");
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
}
samples = newlist;
max_samples = newsize;
-#endif
}
return 0;
}
@@ -3412,9 +3235,9 @@ awe_load_map(awe_patch_info *patch, const char *addr, int count)
/* get the link info */
if (count < sizeof(map)) {
printk("AWE32 Error: invalid patch info length\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
- COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map));
+ copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
/* check if the identical mapping already exists */
p = awe_search_instr(map.map_bank, map.map_instr);
@@ -3428,10 +3251,10 @@ awe_load_map(awe_patch_info *patch, const char *addr, int count)
}
if (check_patch_opened(AWE_PAT_TYPE_MAP, NULL) < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
if (alloc_new_info(1) < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
free_info = awe_free_info();
rec = &infos[free_info];
@@ -3464,14 +3287,14 @@ awe_probe_info(awe_patch_info *patch, const char *addr, int count)
int p;
if (! patch_opened)
- return RET_ERROR(EINVAL);
+ return -EINVAL;
/* get the link info */
if (count < sizeof(map)) {
printk("AWE32 Error: invalid patch info length\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
- COPY_FROM_USER(&map, addr, AWE_PATCH_INFO_SIZE, sizeof(map));
+ copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map));
/* check if the identical mapping already exists */
p = awe_search_instr(map.src_bank, map.src_instr);
@@ -3483,7 +3306,7 @@ awe_probe_info(awe_patch_info *patch, const char *addr, int count)
return 0; /* already present! */
}
#endif /* allow sharing */
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
#endif
@@ -3493,13 +3316,13 @@ awe_probe_data(awe_patch_info *patch, const char *addr, int count)
{
#ifdef AWE_ALLOW_SAMPLE_SHARING
if (! patch_opened)
- return RET_ERROR(EINVAL);
+ return -EINVAL;
/* search the specified sample by optarg */
if (search_sample_index(current_sf_id, patch->optarg, 0) >= 0)
return 0;
#endif /* allow sharing */
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
/* load voice information data */
@@ -3513,26 +3336,26 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count)
if (count < AWE_VOICE_REC_SIZE) {
printk("AWE32 Error: invalid patch info length\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
offset = AWE_PATCH_INFO_SIZE;
- COPY_FROM_USER((char*)&hdr, addr, offset, AWE_VOICE_REC_SIZE);
+ copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE);
offset += AWE_VOICE_REC_SIZE;
if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
printk("AWE32 Error: Illegal voice number %d\n", hdr.nvoices);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
if (count < total_size) {
printk("AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
count, hdr.nvoices);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
#if 0 /* it looks like not so useful.. */
/* check if the same preset already exists in the info list */
@@ -3552,7 +3375,7 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count)
#endif
if (alloc_new_info(hdr.nvoices) < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
for (i = 0; i < hdr.nvoices; i++) {
int rec = awe_free_info();
@@ -3563,7 +3386,7 @@ awe_load_info(awe_patch_info *patch, const char *addr, int count)
infos[rec].disabled = FALSE;
/* copy awe_voice_info parameters */
- COPY_FROM_USER(&infos[rec].v, addr, offset, AWE_VOICE_INFO_SIZE);
+ copy_from_user(&infos[rec].v, addr + offset, AWE_VOICE_INFO_SIZE);
offset += AWE_VOICE_INFO_SIZE;
infos[rec].v.sf_id = current_sf_id;
#ifdef AWE_ALLOW_SAMPLE_SHARING
@@ -3592,16 +3415,16 @@ awe_load_data(awe_patch_info *patch, const char *addr, int count)
awe_sample_info tmprec, *rec;
if (check_patch_opened(AWE_PAT_TYPE_MISC, NULL) < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
offset = AWE_PATCH_INFO_SIZE;
- COPY_FROM_USER(&tmprec, addr, offset, AWE_SAMPLE_INFO_SIZE);
+ copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE);
offset += AWE_SAMPLE_INFO_SIZE;
if (size != tmprec.size) {
printk("AWE32: load: sample size differed (%d != %d)\n",
tmprec.size, size);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (search_sample_index(current_sf_id, tmprec.sample, 0) >= 0) {
@@ -3611,11 +3434,11 @@ awe_load_data(awe_patch_info *patch, const char *addr, int count)
return 0;
#endif /* allow sharing */
DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (alloc_new_sample() < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
free_sample = awe_free_sample();
rec = &samples[free_sample].v;
@@ -3646,22 +3469,22 @@ awe_replace_data(awe_patch_info *patch, const char *addr, int count)
if (! patch_opened) {
printk("AWE32: replace: patch not opened\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
offset = AWE_PATCH_INFO_SIZE;
- COPY_FROM_USER(&cursmp, addr, offset, AWE_SAMPLE_INFO_SIZE);
+ copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE);
offset += AWE_SAMPLE_INFO_SIZE;
if (cursmp.size == 0 || size != cursmp.size) {
printk("AWE32: replace: illegal sample size (%d!=%d)\n",
cursmp.size, size);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
channels = patch->optarg;
if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
printk("AWE32: replace: illegal channels %d\n", channels);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
for (i = sflists[current_sf_id-1].samples;
@@ -3672,18 +3495,18 @@ awe_replace_data(awe_patch_info *patch, const char *addr, int count)
if (i < 0) {
printk("AWE32: replace: cannot find existing sample data %d\n",
cursmp.sample);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (samples[i].v.size != cursmp.size) {
printk("AWE32: replace: exiting size differed (%d!=%d)\n",
samples[i].v.size, cursmp.size);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
save_mem_ptr = awe_free_mem_ptr();
sflists[current_sf_id-1].mem_ptr = samples[i].v.start - awe_mem_start;
- MEMCPY(&samples[i].v, &cursmp, sizeof(cursmp));
+ memcpy(&samples[i].v, &cursmp, sizeof(cursmp));
if ((rc = awe_write_wave_data(addr, offset, &samples[i].v, channels)) != 0)
return rc;
sflists[current_sf_id-1].mem_ptr = save_mem_ptr;
@@ -3713,10 +3536,10 @@ readbuf_init(const char *addr, int offset, awe_sample_info *sp)
readbuf_loopend = sp->loopend;
if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP)) {
int looplen = sp->loopend - sp->loopstart;
- readbuf_loop = my_malloc(looplen * 2);
+ readbuf_loop = vmalloc(looplen * 2);
if (readbuf_loop == NULL) {
printk("AWE32: can't malloc temp buffer\n");
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
}
}
#endif
@@ -3734,10 +3557,10 @@ readbuf_word(int pos)
/* read from user buffer */
if (readbuf_flags & AWE_SAMPLE_8BITS) {
unsigned char cc;
- GET_BYTE_FROM_USER(cc, readbuf_addr, readbuf_offs + pos);
+ get_user(cc, (unsigned char*)&(readbuf_addr)[readbuf_offs + pos]);
c = cc << 8; /* convert 8bit -> 16bit */
} else {
- GET_SHORT_FROM_USER(c, readbuf_addr, readbuf_offs + pos * 2);
+ get_user(c, (unsigned short*)&(readbuf_addr)[readbuf_offs + pos * 2]);
}
if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
c ^= 0x8000; /* unsigned -> signed */
@@ -3764,9 +3587,8 @@ readbuf_word_cache(int pos)
static void
readbuf_end(void)
{
- if (readbuf_loop) {
- my_free(readbuf_loop);
- }
+ if (readbuf_loop)
+ vfree(readbuf_loop);
readbuf_loop = NULL;
}
@@ -3805,7 +3627,7 @@ awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int chann
truesize += BLANK_LOOP_SIZE;
if (awe_free_mem_ptr() + truesize >= awe_mem_size/2) {
DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
}
/* recalculate address offset */
@@ -3829,7 +3651,7 @@ awe_write_wave_data(const char *addr, int offset, awe_sample_info *sp, int chann
return rc;
if (readbuf_init(addr, offset, sp) < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
for (i = 0; i < sp->size; i++) {
unsigned short c;
@@ -3913,21 +3735,21 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
if (size < sizeof_patch) {
printk("AWE32 Error: Patch header too short\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
- COPY_FROM_USER(((char*)&patch) + offs, addr, offs, sizeof_patch - offs);
+ copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs);
size -= sizeof_patch;
if (size < patch.len) {
printk("AWE32 Warning: Patch record too short (%d<%d)\n",
size, patch.len);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (check_patch_opened(AWE_PAT_TYPE_GUS, NULL) < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
if (alloc_new_sample() < 0)
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
if (alloc_new_info(1))
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
free_sample = awe_free_sample();
smp = &samples[free_sample].v;
@@ -4055,9 +3877,9 @@ awe_load_guspatch(const char *addr, int offs, int size, int pmgr_flag)
#endif /* AWE_HAS_GUS_COMPATIBILITY */
-/*----------------------------------------------------------------
+/*
* sample and voice list handlers
- *----------------------------------------------------------------*/
+ */
/* append this to the sf list */
static void add_sf_info(int rec)
@@ -4496,18 +4318,15 @@ awe_setup_voice(int dev, int voice, int chn)
#ifdef CONFIG_AWE32_MIXER
-/*================================================================
+/*
* AWE32 mixer device control
- *================================================================*/
+ */
static int awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg);
static int my_mixerdev = -1;
static struct mixer_operations awe_mixer_operations = {
-#ifndef __FreeBSD__
- "AWE32",
-#endif
"AWE32 Equalizer",
awe_mixer_ioctl,
};
@@ -4531,13 +4350,13 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
int i, level, value;
if (((cmd >> 8) & 0xff) != 'M')
- return RET_ERROR(EINVAL);
+ return -EINVAL;
- level = (int)IOCTL_IN(arg);
+ level = (int) *(int *)arg;
level = ((level & 0xff) + (level >> 8)) / 2;
DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
- if (IO_WRITE_CHECK(cmd)) {
+ if (_SIOC_DIR(cmd) & _IOC_WRITE) {
switch (cmd & 0xff) {
case SOUND_MIXER_BASS:
value = level * 12 / 100;
@@ -4589,14 +4408,14 @@ awe_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
level = 0;
break;
}
- return IOCTL_OUT(arg, level);
+ return *(int *)arg = level;
}
#endif /* CONFIG_AWE32_MIXER */
-/*================================================================
+/*
* initialization of AWE32
- *================================================================*/
+ */
/* intiailize audio channels */
static void
@@ -4912,7 +4731,7 @@ awe_open_dram_for_write(int offset, int channels)
awe_poke_dw(AWE_CCCA(vidx[i]), 0);
voices[vidx[i]].state = AWE_ST_OFF;
}
- return RET_ERROR(ENOSPC);
+ return -ENOSPC;
}
/* set address to write */
@@ -5091,13 +4910,13 @@ awe_load_chorus_fx(awe_patch_info *patch, const char *addr, int count)
{
if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
printk("AWE32 Error: illegal chorus mode %d for uploading\n", patch->optarg);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (count < sizeof(awe_chorus_fx_rec)) {
printk("AWE32 Error: too short chorus fx parameters\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
- COPY_FROM_USER(&chorus_parm[patch->optarg], addr, AWE_PATCH_INFO_SIZE,
+ copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
sizeof(awe_chorus_fx_rec));
chorus_defined[patch->optarg] = TRUE;
return 0;
@@ -5198,13 +5017,13 @@ awe_load_reverb_fx(awe_patch_info *patch, const char *addr, int count)
{
if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
printk("AWE32 Error: illegal reverb mode %d for uploading\n", patch->optarg);
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
if (count < sizeof(awe_reverb_fx_rec)) {
printk("AWE32 Error: too short reverb fx parameters\n");
- return RET_ERROR(EINVAL);
+ return -EINVAL;
}
- COPY_FROM_USER(&reverb_parm[patch->optarg], addr, AWE_PATCH_INFO_SIZE,
+ copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
sizeof(awe_reverb_fx_rec));
reverb_defined[patch->optarg] = TRUE;
return 0;
@@ -5400,9 +5219,9 @@ static void unload_midiemu(void)
}
-/*================================================================
+/*
* open/close midi device
- *================================================================*/
+ */
static int midi_opened = FALSE;
@@ -5465,7 +5284,7 @@ awe_midi_open (int dev, int mode,
curst.read = 0;
curst.status = 0;
curst.chan = 0;
- BZERO(curst.buf, sizeof(curst.buf));
+ memset(curst.buf, 0, sizeof(curst.buf));
init_midi_status(&curst);
@@ -5499,9 +5318,9 @@ awe_midi_outputc (int dev, unsigned char midi_byte)
}
-/*================================================================
+/*
* initialize
- *================================================================*/
+ */
static void init_midi_status(MidiStatus *st)
{
@@ -5511,9 +5330,9 @@ static void init_midi_status(MidiStatus *st)
}
-/*================================================================
+/*
* RPN & NRPN
- *================================================================*/
+ */
#define MAX_MIDI_CHANNELS 16
@@ -5538,9 +5357,9 @@ static void clear_rpn(void)
}
-/*================================================================
+/*
* process midi queue
- *================================================================*/
+ */
/* status event types */
typedef void (*StatusEvent)(MidiStatus *st);
@@ -5649,9 +5468,9 @@ static void queue_read(MidiStatus *st, int c)
}
-/*================================================================
+/*
* status events
- *================================================================*/
+ */
/* note on */
static void midi_note_on(MidiStatus *st)
@@ -5907,14 +5726,14 @@ static void midi_system_exclusive(MidiStatus *st)
#endif
/* GM on */
- if (MEMCMP(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
+ if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
if (midi_mode != MODE_GS && midi_mode != MODE_XG)
midi_mode = MODE_GM;
init_midi_status(st);
}
/* GS macros */
- else if (MEMCMP(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
+ else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
if (midi_mode != MODE_GS && midi_mode != MODE_XG)
midi_mode = MODE_GS;
@@ -5957,7 +5776,7 @@ static void midi_system_exclusive(MidiStatus *st)
}
/* XG on */
- else if (MEMCMP(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
+ else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
midi_mode = MODE_XG;
xg_mapping = TRUE;
xg_bankmode = 0;
@@ -5965,9 +5784,9 @@ static void midi_system_exclusive(MidiStatus *st)
}
-/*================================================================
+/*
* convert NRPN/control values
- *================================================================*/
+ */
static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
{
@@ -5996,9 +5815,9 @@ static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st
}
-/*----------------------------------------------------------------
+/*
* AWE32 NRPN effects
- *----------------------------------------------------------------*/
+ */
static unsigned short fx_delay(int val);
static unsigned short fx_attack(int val);
@@ -6120,9 +5939,9 @@ static ConvTable awe_effects[] =
static int num_awe_effects = numberof(awe_effects);
-/*----------------------------------------------------------------
+/*
* GS(SC88) NRPN effects; still experimental
- *----------------------------------------------------------------*/
+ */
/* cutoff: quarter semitone step, max=255 */
static unsigned short gs_cutoff(int val)
@@ -6252,4 +6071,48 @@ static int xg_control_change(MidiStatus *st, int cmd, int val)
#endif /* CONFIG_AWE32_MIDIEMU */
-#endif /* CONFIG_AWE32_SYNTH */
+/* new type interface */
+static int __init attach_awe(void)
+{
+#ifdef CONFIG_PNP_DRV
+ if (pnp) {
+ awe_initpnp();
+ if (awe_pnp_ok)
+ return 0;
+ }
+#endif /* pnp */
+
+ _attach_awe();
+
+ return 0;
+}
+
+static void __exit unload_awe(void)
+{
+#ifdef CONFIG_PNP_DRV
+ if (pnp)
+ awe_unload_pnp();
+#endif
+
+ _unload_awe();
+}
+
+module_init(attach_awe);
+module_exit(unload_awe);
+
+#ifndef MODULE
+static int __init setup_awe(char *str)
+{
+ /* io, memsize */
+ int ints[3];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+
+ io = ints[1];
+ memsize = ints[2];
+
+ return 1;
+}
+
+__setup("awe=", setup_awe);
+#endif
diff --git a/drivers/sound/lowlevel/awe_config.h b/drivers/sound/awe_wave.h
index ffb958d49..0984da765 100644
--- a/drivers/sound/lowlevel/awe_config.h
+++ b/drivers/sound/awe_wave.h
@@ -21,33 +21,18 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef AWE_CONFIG_H_DEF
-#define AWE_CONFIG_H_DEF
-
-/*----------------------------------------------------------------
- * system configuration
- *----------------------------------------------------------------*/
-
-/* if your kernel support module for each soundcard, define this.
- * NOTE: it will be automatically set on linux-2.1.x kernels.
- * only define here if you have moduler sound system on
- * 2.0.x kernel (like RedHat).
- */
-#undef AWE_MODULE_SUPPORT
-
-
-/*----------------------------------------------------------------
+/*
* chorus & reverb effects send for FM chip: from 0 to 0xff
* larger numbers often cause weird sounds.
- *----------------------------------------------------------------*/
+ */
#define DEF_FM_CHORUS_DEPTH 0x10
#define DEF_FM_REVERB_DEPTH 0x10
-/*----------------------------------------------------------------*
+/*
* other compile conditions
- *----------------------------------------------------------------*/
+ */
/* initialize FM passthrough even without extended RAM */
#undef AWE_ALWAYS_INIT_FM
@@ -73,30 +58,30 @@
/* allow sample sharing */
#define AWE_ALLOW_SAMPLE_SHARING
-/*================================================================
- * Usually, you don't have to touch the following options.
- *================================================================*/
-
-/*----------------------------------------------------------------
+/*
* AWE32 card configuration:
* uncomment the following lines *ONLY* when auto detection doesn't
* work properly on your machine.
- *----------------------------------------------------------------*/
+ */
/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */
/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */
-/*----------------------------------------------------------------
+/*
* maximum size of soundfont list table
- *----------------------------------------------------------------*/
+ */
#define AWE_MAX_SF_LISTS 16
-/*----------------------------------------------------------------
+/*
* chunk size of sample and voice tables
- *----------------------------------------------------------------*/
+ */
#define AWE_MAX_SAMPLES 400
#define AWE_MAX_INFOS 800
-#endif /* AWE_CONFIG_H_DEF */
+#define AWE_MAJOR_VERSION 0
+#define AWE_MINOR_VERSION 4
+#define AWE_TINY_VERSION 3
+#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
+#define AWEDRV_VERSION "0.4.3"
diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c
index 5be9a1eef..52d4d79f8 100644
--- a/drivers/sound/dev_table.c
+++ b/drivers/sound/dev_table.c
@@ -11,7 +11,6 @@
* for more info.
*/
-#include <linux/config.h>
#include <linux/init.h>
#define _DEV_TABLE_C_
diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h
index b15fd505c..db2b141d6 100644
--- a/drivers/sound/dev_table.h
+++ b/drivers/sound/dev_table.h
@@ -15,8 +15,6 @@
#ifndef _DEV_TABLE_H_
#define _DEV_TABLE_H_
-#include <linux/config.h>
-
/*
* Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h)
* Numbers 1000 to N are reserved for driver's internal use.
diff --git a/drivers/sound/lowlevel/Config.in b/drivers/sound/lowlevel/Config.in
deleted file mode 100644
index 091a8df33..000000000
--- a/drivers/sound/lowlevel/Config.in
+++ /dev/null
@@ -1,66 +0,0 @@
-dep_tristate ' ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND_OSS
-
-dep_tristate ' AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND_OSS
-
-if [ "$CONFIG_AWE32_SYNTH" = "y" -o "$CONFIG_AWE32_SYNTH" = "m" ]; then
- comment 'AWE32 PnP-ISA Cards are not always setup correctly'
- bool 'Configure AWE32 synth Base Address and Default Memory Size' CONFIG_AWE32_SYNTH_DEFAULTS
- if [ "$CONFIG_AWE32_SYNTH_DEFAULTS" = "y" ]; then
- hex 'AWE32 synth Base Address 620' AWE_DEFAULT_BASE_ADDR 620
- int 'AWE32 synth Default Memory Size 512 1024 or 4096' AWE_DEFAULT_MEM_SIZE 512
- fi
-fi
-
-if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND" = "m" ]; then
- dep_tristate ' Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND_OSS
- if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
- hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330
- fi
-
- if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
- comment 'SC-6600 Audio Cards have no jumper switches at all'
- bool ' SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600
- if [ "$CONFIG_SC6600" = "y" ]; then
- comment 'SC-6600 specific configuration'
- bool ' Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY
- int 'SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' CONFIG_SC6600_CDROM 4
- hex 'SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0
- fi
-
- if [ "$CONFIG_SOUND_SB" = "y" -o "$CONFIG_SOUND_SB" = "m" ]; then
- if [ "$CONFIG_AEDSP16_MSS" != "y" ]; then
- bool 'Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO
- if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then
- comment 'Audio Excel DSP 16 [Sound Blaster Pro]'
- hex 'I/O base for Audio Excel DSP 16 220, 240' CONFIG_AEDSP16_BASE $CONFIG_SB_BASE 220
- int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ 5
- int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA 0
- fi
- fi
- fi
-
- if [ "$CONFIG_SOUND_MSS" = "y" -o "$CONFIG_SOUND_MSS" = "m" ]; then
- if [ "$CONFIG_AEDSP16_SBPRO" != "y" ]; then
- bool ' Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS
- if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then
- comment 'Audio Excel DSP 16 [Microsoft Sound System]'
- hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ 5
- int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA 1
- fi
- fi
- fi
-
- if [ "$CONFIG_SOUND_MPU401" = "y" -o "$CONFIG_SOUND_MPU401" = "m" ]; then
- bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
- if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then
- comment 'Audio Excel DSP 16 [MPU-401]'
- if [ "$CONFIG_AEDSP16_SBPRO" != "y" -a "$CONFIG_AEDSP16_MSS" != "y" ]; then
- hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
- fi
- int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ
- fi
- fi
- fi
-fi
diff --git a/drivers/sound/lowlevel/Makefile b/drivers/sound/lowlevel/Makefile
deleted file mode 100644
index 921f10362..000000000
--- a/drivers/sound/lowlevel/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-# Makefile for the Linux low-level sound card drivers.
-#
-# 11 Feb 1998, Michael Elizabeth Chastain, <mailto:mec@shout.net>
-# Rewritten to use lists instead of if statements.
-
-export-objs := soundlow.o
-
-list-y :=
-list-m :=
-list-n :=
-list- :=
-
-obj-$(CONFIG_SOUND_OSS) += soundlow.o
-obj-$(CONFIG_ACI_MIXER) += aci.o
-obj-$(CONFIG_AEDSP16) += aedsp16.o
-obj-$(CONFIG_AWE32_SYNTH) += awe_wave.o
-
-O_TARGET := lowlevel.o
-O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
-OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
-M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-
-include $(TOPDIR)/Rules.make
diff --git a/drivers/sound/lowlevel/README b/drivers/sound/lowlevel/README
deleted file mode 100644
index da66e3396..000000000
--- a/drivers/sound/lowlevel/README
+++ /dev/null
@@ -1,22 +0,0 @@
-Additional low level sound drivers for Linux
-============================================
-
-This directory contains some low level sound drivers.
-These drivers are used to be (when Linux sound drivers was OSS/Lite) external
-drivers, not maintained by Hannu Savolainen and not touched by him.
-Now things are changed: the new Linux sound driver code maintained by Alan Cox
-include these lowlevel drivers and they are no more neglected (thanks Alan).
-
-The following low level drivers are included:
-
-- ACI MIXER for miroPCM12 by Markus Kuhn
- (mskuhn@cip.informatik.uni-erlangen.de).
-- Audio Excel DSP 16 initialization driver by Riccardo Facchetti
- (fizban@tin.it)
-- SB32/AWE synthesizer driver (Emu8000) by Takashi Iwai
- (iwai@dragon.mm.t.u-tokyo.ac.jp).
-
-You can find documentation for these drivers in the Documentation/sound
-directory.
-
-[ File edited 17.01.1999 - Riccardo Facchetti ]
diff --git a/drivers/sound/lowlevel/aci.c b/drivers/sound/lowlevel/aci.c
deleted file mode 100644
index fc71be47d..000000000
--- a/drivers/sound/lowlevel/aci.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Audio Command Interface (ACI) driver (sound/aci.c)
- *
- * ACI is a protocol used to communicate with the microcontroller on
- * some sound cards produced by miro, e.g. the miroSOUND PCM12 and
- * PCM20. The ACI has been developed for miro by Norberto Pellicci
- * <pellicci@home.com>. Special thanks to both him and miro for
- * providing the ACI specification.
- *
- * The main function of the ACI is to control the mixer and to get a
- * product identification. On the PCM20, ACI also controls the radio
- * tuner on this card, this is supported in the Video for Linux
- * radio-miropcm20 driver.
- *
- * This Voxware ACI driver currently only supports the ACI functions
- * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards
- * with additional ACI functions can easily be added later.
- *
- * / NOTE / When compiling as a module, make sure to load the module
- * after loading the mad16 module. The initialisation code expects the
- * MAD16 default mixer to be already available.
- *
- * / NOTE / When compiling as a module, make sure to load the module
- * after loading the mad16 module. The initialisation code expects the
- * MAD16 default mixer to be already available.
- *
- * Revision history:
- *
- * 1995-11-10 Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
- * First version written.
- * 1995-12-31 Markus Kuhn
- * Second revision, general code cleanup.
- * 1996-05-16 Hannu Savolainen
- * Integrated with other parts of the driver.
- * 1996-05-28 Markus Kuhn
- * Initialize CS4231A mixer, make ACI first mixer,
- * use new private mixer API for solo mode.
- * 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * Small modification to export ACI functions and
- * complete modularisation.
- */
-
-/*
- * Some driver specific information and features:
- *
- * This mixer driver identifies itself to applications as "ACI" in
- * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info).
- *
- * Proprietary mixer features that go beyond the standard OSS mixer
- * interface are:
- *
- * Full duplex solo configuration:
- *
- * int solo_mode;
- * ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode);
- *
- * solo_mode = 0: deactivate solo mode (default)
- * solo_mode > 0: activate solo mode
- * With activated solo mode, the PCM input can not any
- * longer hear the signals produced by the PCM output.
- * Activating solo mode is important in duplex mode in order
- * to avoid feedback distortions.
- * solo_mode < 0: do not change solo mode (just retrieve the status)
- *
- * When the ioctl() returns 0, solo_mode contains the previous
- * status (0 = deactivated, 1 = activated). If solo mode is not
- * implemented on this card, ioctl() returns -1 and sets errno to
- * EINVAL.
- *
- */
-
-#include <linux/config.h> /* for CONFIG_ACI_MIXER */
-#include <linux/module.h>
-#include "lowlevel.h"
-#include "../sound_config.h"
-
-#if defined(CONFIG_ACI_MIXER) || defined(CONFIG_ACI_MIXER_MODULE)
-
-#undef DEBUG /* if defined, produce a verbose report via syslog */
-
-int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */
-unsigned char aci_idcode[2] = {0, 0}; /* manufacturer and product ID */
-unsigned char aci_version = 0; /* ACI firmware version */
-int aci_solo; /* status bit of the card that can't be *
- * checked with ACI versions prior to 0xb0 */
-
-static int aci_present = 0;
-
-#ifdef MODULE /* Whether the aci mixer is to be reset. */
-int aci_reset = 0; /* Default: don't reset if the driver is a */
-MODULE_PARM(aci_reset,"i");
-#else /* module; use "insmod aci.o aci_reset=1" */
-int aci_reset = 1; /* to override. */
-#endif
-
-
-#define COMMAND_REGISTER (aci_port)
-#define STATUS_REGISTER (aci_port + 1)
-#define BUSY_REGISTER (aci_port + 2)
-
-/*
- * Wait until the ACI microcontroller has set the READYFLAG in the
- * Busy/IRQ Source Register to 0. This is required to avoid
- * overrunning the sound card microcontroller. We do a busy wait here,
- * because the microcontroller is not supposed to signal a busy
- * condition for more than a few clock cycles. In case of a time-out,
- * this function returns -1.
- *
- * This busy wait code normally requires less than 15 loops and
- * practically always less than 100 loops on my i486/DX2 66 MHz.
- *
- * Warning: Waiting on the general status flag after reseting the MUTE
- * function can take a VERY long time, because the PCM12 does some kind
- * of fade-in effect. For this reason, access to the MUTE function has
- * not been implemented at all.
- */
-
-static int busy_wait(void)
-{
- long timeout;
-
- for (timeout = 0; timeout < 10000000L; timeout++)
- if ((inb_p(BUSY_REGISTER) & 1) == 0)
- return 0;
-
-#ifdef DEBUG
- printk("ACI: READYFLAG timed out.\n");
-#endif
-
- return -1;
-}
-
-
-/*
- * Read the GENERAL STATUS register.
- */
-
-static int read_general_status(void)
-{
- unsigned long flags;
- int status;
-
- save_flags(flags);
- cli();
- if (busy_wait()) { restore_flags(flags); return -1; }
- status = (unsigned) inb_p(STATUS_REGISTER);
- restore_flags(flags);
- return status;
-}
-
-
-/*
- * The four ACI command types (implied, write, read and indexed) can
- * be sent to the microcontroller using the following four functions.
- * If a problem occurred, they return -1.
- */
-
-int aci_implied_cmd(unsigned char opcode)
-{
- unsigned long flags;
-
-#ifdef DEBUG
- printk("ACI: aci_implied_cmd(0x%02x)\n", opcode);
-#endif
-
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
- outb_p(opcode, COMMAND_REGISTER);
-
- restore_flags(flags);
- return 0;
-}
-
-
-int aci_write_cmd(unsigned char opcode, unsigned char parameter)
-{
- unsigned long flags;
- int status;
-
-#ifdef DEBUG
- printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter);
-#endif
-
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) { restore_flags(flags); return -1; }
- outb_p(parameter, COMMAND_REGISTER);
-
- if ((status = read_general_status()) < 0) {
- restore_flags(flags);
- return -1;
- }
- /* polarity of the INVALID flag depends on ACI version */
- if ((aci_version < 0xb0 && (status & 0x40) != 0) ||
- (aci_version >= 0xb0 && (status & 0x40) == 0)) {
- restore_flags(flags);
- printk("ACI: invalid write command 0x%02x, 0x%02x.\n",
- opcode, parameter);
- return -1;
- }
-
- restore_flags(flags);
- return 0;
-}
-
-/*
- * This write command send 2 parameters instead of one.
- * Only used in PCM20 radio frequency tuning control
- */
-
-int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2)
-{
- unsigned long flags;
- int status;
-
-#ifdef DEBUG
- printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2);
-#endif
-
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) { restore_flags(flags); return -1; }
- outb_p(parameter, COMMAND_REGISTER);
- if (busy_wait()) { restore_flags(flags); return -1; }
- outb_p(parameter2, COMMAND_REGISTER);
-
- if ((status = read_general_status()) < 0) {
- restore_flags(flags);
- return -1;
- }
- /* polarity of the INVALID flag depends on ACI version */
- if ((aci_version < 0xb0 && (status & 0x40) != 0) ||
- (aci_version >= 0xb0 && (status & 0x40) == 0)) {
- restore_flags(flags);
-#if 0 /* Frequency tuning works, but the INVALID flag is set ??? */
- printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n",
- opcode, parameter, parameter2);
-#endif
- return -1;
- }
-
- restore_flags(flags);
- return 0;
-}
-
-int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter)
-{
- unsigned long flags;
- int i = 0;
-
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0) { restore_flags(flags); return -1; }
- while (i < length) {
- if (busy_wait()) { restore_flags(flags); return -1; }
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) { restore_flags(flags); return -1; }
- parameter[i++] = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
- if (i == 1)
- printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length,
- parameter[i-1]);
- else
- printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]);
-#endif
- }
-
- restore_flags(flags);
- return 0;
-}
-
-
-int aci_indexed_cmd(unsigned char opcode, unsigned char index,
- unsigned char *parameter)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- if (read_general_status() < 0 || busy_wait()) {
- restore_flags(flags);
- return -1;
- }
- outb_p(opcode, COMMAND_REGISTER);
- if (busy_wait()) { restore_flags(flags); return -1; }
- outb_p(index, COMMAND_REGISTER);
- if (busy_wait()) { restore_flags(flags); return -1; }
- *parameter = inb_p(STATUS_REGISTER);
-#ifdef DEBUG
- printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index,
- *parameter);
-#endif
-
- restore_flags(flags);
- return 0;
-}
-
-
-/*
- * The following macro SCALE can be used to scale one integer volume
- * value into another one using only integer arithmetic. If the input
- * value x is in the range 0 <= x <= xmax, then the result will be in
- * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
- *
- * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
- * following nice properties:
- *
- * - SCALE(xmax,ymax,xmax) = ymax
- * - SCALE(xmax,ymax,0) = 0
- * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
- *
- * In addition, the rounding error is minimal and nicely distributed.
- * The proofs are left as an exercise to the reader.
- */
-
-#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
-
-
-static int getvolume(caddr_t arg,
- unsigned char left_index, unsigned char right_index)
-{
- int vol;
- unsigned char buf;
-
- /* left channel */
- if (aci_indexed_cmd(0xf0, left_index, &buf)) return -EIO;
- vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
- /* right channel */
- if (aci_indexed_cmd(0xf0, right_index, &buf)) return -EIO;
- vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
-
- return (*(int *) arg = vol);
-}
-
-
-static int setvolume(caddr_t arg,
- unsigned char left_index, unsigned char right_index)
-{
- int vol, ret;
-
- /* left channel */
- vol = *(int *)arg & 0xff;
- if (vol > 100) vol = 100;
- vol = SCALE(100, 0x20, vol);
- if (aci_write_cmd(left_index, 0x20 - vol)) return -EIO;
- ret = SCALE(0x20, 100, vol);
- /* right channel */
- vol = (*(int *)arg >> 8) & 0xff;
- if (vol > 100) vol = 100;
- vol = SCALE(100, 0x20, vol);
- if (aci_write_cmd(right_index, 0x20 - vol)) return -EIO;
- ret |= SCALE(0x20, 100, vol) << 8;
-
- return (*(int *) arg = ret);
-}
-
-
-static int
-aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
-{
- int status, vol;
- unsigned char buf;
-
- /* handle solo mode control */
- if (cmd == SOUND_MIXER_PRIVATE1) {
- if (*(int *) arg >= 0) {
- aci_solo = !!*(int *) arg;
- if (aci_write_cmd(0xd2, aci_solo)) return -EIO;
- } else if (aci_version >= 0xb0) {
- if ((status = read_general_status()) < 0) return -EIO;
- return (*(int *) arg = (status & 0x20) == 0);
- }
- return (*(int *) arg = aci_solo);
- }
-
- if (((cmd >> 8) & 0xff) == 'M') {
- if (cmd & IOC_IN)
- /* read and write */
- switch (cmd & 0xff) {
- case SOUND_MIXER_VOLUME:
- return setvolume(arg, 0x01, 0x00);
- case SOUND_MIXER_CD:
- return setvolume(arg, 0x3c, 0x34);
- case SOUND_MIXER_MIC:
- return setvolume(arg, 0x38, 0x30);
- case SOUND_MIXER_LINE:
- return setvolume(arg, 0x39, 0x31);
- case SOUND_MIXER_SYNTH:
- return setvolume(arg, 0x3b, 0x33);
- case SOUND_MIXER_PCM:
- return setvolume(arg, 0x3a, 0x32);
- case SOUND_MIXER_LINE1: /* AUX1 */
- return setvolume(arg, 0x3d, 0x35);
- case SOUND_MIXER_LINE2: /* AUX2 */
- return setvolume(arg, 0x3e, 0x36);
- case SOUND_MIXER_IGAIN: /* MIC pre-amp */
- vol = *(int *) arg & 0xff;
- if (vol > 100) vol = 100;
- vol = SCALE(100, 3, vol);
- if (aci_write_cmd(0x03, vol)) return -EIO;
- vol = SCALE(3, 100, vol);
- return (*(int *) arg = vol | (vol << 8));
- case SOUND_MIXER_RECSRC:
- return (*(int *) arg = 0);
- break;
- default:
- return -EINVAL;
- }
- else
- /* only read */
- switch (cmd & 0xff) {
- case SOUND_MIXER_DEVMASK:
- return (*(int *) arg =
- SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_MIC | SOUND_MASK_LINE |
- SOUND_MASK_SYNTH | SOUND_MASK_PCM |
-#if 0
- SOUND_MASK_IGAIN |
-#endif
- SOUND_MASK_LINE1 | SOUND_MASK_LINE2);
- break;
- case SOUND_MIXER_STEREODEVS:
- return (*(int *) arg =
- SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_MIC | SOUND_MASK_LINE |
- SOUND_MASK_SYNTH | SOUND_MASK_PCM |
- SOUND_MASK_LINE1 | SOUND_MASK_LINE2);
- break;
- case SOUND_MIXER_RECMASK:
- return (*(int *) arg = 0);
- break;
- case SOUND_MIXER_RECSRC:
- return (*(int *) arg = 0);
- break;
- case SOUND_MIXER_CAPS:
- return (*(int *) arg = 0);
- break;
- case SOUND_MIXER_VOLUME:
- return getvolume(arg, 0x04, 0x03);
- case SOUND_MIXER_CD:
- return getvolume(arg, 0x0a, 0x09);
- case SOUND_MIXER_MIC:
- return getvolume(arg, 0x06, 0x05);
- case SOUND_MIXER_LINE:
- return getvolume(arg, 0x08, 0x07);
- case SOUND_MIXER_SYNTH:
- return getvolume(arg, 0x0c, 0x0b);
- case SOUND_MIXER_PCM:
- return getvolume(arg, 0x0e, 0x0d);
- case SOUND_MIXER_LINE1: /* AUX1 */
- return getvolume(arg, 0x11, 0x10);
- case SOUND_MIXER_LINE2: /* AUX2 */
- return getvolume(arg, 0x13, 0x12);
- case SOUND_MIXER_IGAIN: /* MIC pre-amp */
- if (aci_indexed_cmd(0xf0, 0x21, &buf)) return -EIO;
- vol = SCALE(3, 100, buf <= 3 ? buf : 3);
- vol |= vol << 8;
- return (*(int *) arg = vol);
- default:
- return -EINVAL;
- }
- }
-
- return -EINVAL;
-}
-
-
-static struct mixer_operations aci_mixer_operations =
-{
- "ACI",
- "ACI mixer",
- aci_mixer_ioctl,
- NULL
-};
-
-static unsigned char
-mad_read (int port)
-{
- outb (0xE3, 0xf8f); /* Write MAD16 password */
- return inb (port); /* Read from port */
-}
-
-
-/*
- * Check, whether there actually is any ACI port operational and if
- * one was found, then initialize the ACI interface, reserve the I/O
- * addresses and attach the new mixer to the relevant VoxWare data
- * structures.
- *
- * Returns: 1 ACI mixer detected
- * 0 nothing there
- *
- * There is also an internal mixer in the codec (CS4231A or AD1845),
- * that deserves no purpose in an ACI based system which uses an
- * external ACI controlled stereo mixer. Make sure that this codec
- * mixer has the AUX1 input selected as the recording source, that the
- * input gain is set near maximum and that the other channels going
- * from the inputs to the codec output are muted.
- */
-
-int attach_aci(void)
-{
- char *boardname = "unknown";
- int volume;
-
-#define MC4_PORT 0xf90
-
- aci_port =
- (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354;
-
- if (check_region(aci_port, 3)) {
-#ifdef DEBUG
- printk("ACI: I/O area 0x%03x-0x%03x already used.\n",
- aci_port, aci_port+2);
-#endif
- return 0;
- }
-
- if (aci_read_cmd(0xf2, 2, aci_idcode)) {
-#ifdef DEBUG
- printk("ACI: Failed to read idcode.\n");
-#endif
- return 0;
- }
- if (aci_read_cmd(0xf1, 1, &aci_version)) {
-#ifdef DEBUG
- printk("ACI: Failed to read version.\n");
-#endif
- return 0;
- }
-
- if (aci_idcode[0] == 0x6d) {
- /* It looks like a miro sound card. */
- switch (aci_idcode[1]) {
- case 0x41:
- boardname = "PCM1 pro / early PCM12";
- break;
- case 0x42:
- boardname = "PCM12";
- break;
- case 0x43:
- boardname = "PCM20";
- break;
- default:
- boardname = "unknown miro";
- }
- } else
-#ifndef DEBUG
- return 0;
-#endif
-
- printk("<ACI %02x, id %02x %02x (%s)> at 0x%03x\n",
- aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port);
-
- if (aci_reset) {
- /* initialize ACI mixer */
- aci_implied_cmd(0xff);
- aci_solo = 0;
- }
-
- /* attach the mixer */
- request_region(aci_port, 3, "sound mixer (ACI)");
- if (num_mixers < MAX_MIXER_DEV) {
- if (num_mixers > 0 &&
- !strncmp("MAD16 WSS", mixer_devs[num_mixers-1]->name, 9)) {
- /*
- * The previously registered mixer device is the CS4231A which
- * has no function on an ACI card. Make the ACI mixer the first
- * of the two mixer devices.
- */
- mixer_devs[num_mixers] = mixer_devs[num_mixers-1];
- mixer_devs[num_mixers-1] = &aci_mixer_operations;
- /*
- * Initialize the CS4231A mixer with reasonable values. It is
- * unlikely that the user ever will want to change these as all
- * channels can be mixed via ACI.
- */
- volume = 0x6464;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
- volume = 0x6464;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_IGAIN, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
- volume = 0;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume);
- volume = SOUND_MASK_LINE1;
- mixer_devs[num_mixers]->
- ioctl(num_mixers, SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume);
- num_mixers++;
- } else
- mixer_devs[num_mixers++] = &aci_mixer_operations;
- }
-
- /* Just do something; otherwise the first write command fails, at
- * least with my PCM20.
- */
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_READ_VOLUME, (caddr_t) &volume);
-
- if (aci_reset) {
- /* Initialize ACI mixer with reasonable power-up values */
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume);
- volume = 0x3232;
- aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume);
- }
-
- aci_present = 1;
-
- return 1;
-}
-
-void unload_aci(void)
-{
- if (aci_present)
- release_region(aci_port, 3);
-}
-
-#endif
-
-#if defined(MODULE)
-
-int init_module(void) {
- attach_aci();
- return(0);
-}
-
-void cleanup_module(void) {
- unload_aci();
-}
-
-#endif /* MODULE */
- \ No newline at end of file
diff --git a/drivers/sound/lowlevel/awe_compat.h b/drivers/sound/lowlevel/awe_compat.h
deleted file mode 100644
index 6ced8d65d..000000000
--- a/drivers/sound/lowlevel/awe_compat.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * sound/awe_compat.h
- *
- * Compat defines for the AWE32/SB32/AWE64 wave table synth driver.
- * version 0.4.3; Oct. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_COMPAT_H_DEF
-#define AWE_COMPAT_H_DEF
-
-/*================================================================
- * version check
- *================================================================*/
-
-#include "awe_config.h"
-
-#define ASC_LINUX_VERSION(V,P,S) (((V) * 65536) + ((P) * 256) + (S))
-
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-/* linux version check */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-#define AWE_OBSOLETE_VOXWARE
-#endif
-
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
-#define AWE_NEW_KERNEL_INTERFACE
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,80)
-#define AWE_MODULE_SUPPORT
-#endif
-#endif
-
-#ifdef AWE_OBSOLETE_VOXWARE
-#include "soundvers.h"
-#else
-#include "../soundvers.h"
-#endif
-
-#if defined(SOUND_INTERNAL_VERSION) && SOUND_INTERNAL_VERSION >= 0x30803
-/* OSS/Free-3.8 */
-#define AWE_NO_PATCHMGR
-#define AWE_OSS38
-#define HAS_LOWLEVEL_H
-#endif
-
-/*================================================================
- * INCLUDE OTHER HEADER FILES
- *================================================================*/
-
-/* set up module */
-
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include "../soundmodule.h"
-#endif
-
-
-/* reading configuration of sound driver */
-
-#ifdef AWE_OBSOLETE_VOXWARE
-
-#include "sound_config.h"
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32)
-#define CONFIG_AWE32_SYNTH
-#endif
-
-#else /* AWE_OBSOLETE_VOXWARE */
-
-#ifdef HAS_LOWLEVEL_H
-#include "lowlevel.h"
-#endif
-
-#include "../sound_config.h"
-
-#endif /* AWE_OBSOLETE_VOXWARE */
-
-
-/*================================================================
- * include AWE header files
- *================================================================*/
-
-#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE)
-
-#include "awe_hw.h"
-#include "awe_version.h"
-#include <linux/awe_voice.h>
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* include finetune table */
-#ifdef AWE_OBSOLETE_VOXWARE
-# include "tuning.h"
-#else
-# include "../tuning.h"
-#endif
-#include <linux/ultrasound.h>
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*----------------------------------------------------------------
- * compatibility macros for AWE32 driver
- *----------------------------------------------------------------*/
-
-/* redefine following macros */
-#undef IOCTL_IN
-#undef IOCTL_OUT
-#undef OUTW
-#undef COPY_FROM_USER
-#undef COPY_TO_USER
-#undef GET_BYTE_FROM_USER
-#undef GET_SHORT_FROM_USER
-#undef IOCTL_TO_USER
-
-/* use inline prefix */
-#define INLINE /*inline*/
-
-/*----------------------------------------------------------------
- * memory management for linux
- *----------------------------------------------------------------*/
-
-#ifdef AWE_OBSOLETE_VOXWARE
-/* old type linux system */
-
-/* i/o requests; nothing */
-#define awe_check_port() 0 /* always false */
-#define awe_request_region() /* nothing */
-#define awe_release_region() /* nothing */
-
-static int _mem_start; /* memory pointer for permanent buffers */
-
-#define my_malloc_init(memptr) _mem_start = (memptr)
-#define my_malloc_memptr() _mem_start
-#define my_free(ptr) /* do nothing */
-
-/* allocate buffer only once */
-#define INIT_TABLE(buffer,index,nums,type) {\
-PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\
-}
-
-#else
-
-#define AWE_DYNAMIC_BUFFER
-
-#define my_malloc_init(ptr) /* nothing */
-#define my_malloc_memptr() 0
-#define my_malloc(size) vmalloc(size)
-#define my_free(ptr) if (ptr) {vfree(ptr);}
-
-/* do not allocate buffer at beginning */
-#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
-
-/* old type macro */
-#define RET_ERROR(err) -err
-
-#endif
-
-/*----------------------------------------------------------------
- * i/o interfaces for linux
- *----------------------------------------------------------------*/
-
-#define OUTW(data,addr) outw(data, addr)
-
-#ifdef AWE_NEW_KERNEL_INTERFACE
-#define COPY_FROM_USER(target,source,offs,count) \
- copy_from_user(target, (source)+(offs), count)
-#define GET_BYTE_FROM_USER(target,addr,offs) \
- get_user(target, (unsigned char*)&((addr)[offs]))
-#define GET_SHORT_FROM_USER(target,addr,offs) \
- get_user(target, (unsigned short*)&((addr)[offs]))
-#ifdef AWE_OSS38
-#define IOCTL_TO_USER(target,offs,source,count) \
- memcpy(target, (source)+(offs), count)
-#define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE)
-#else
-#define IOCTL_TO_USER(target,offs,source,count) \
- copy_to_user(target, (source)+(offs), count)
-#define IO_WRITE_CHECK(cmd) (_IOC_DIR(cmd) & _IOC_WRITE)
-#endif /* AWE_OSS38 */
-#define COPY_TO_USER IOCTL_TO_USER
-#define IOCTL_IN(arg) (*(int*)(arg))
-#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val))
-
-#else /* old type i/o */
-#define COPY_FROM_USER(target,source,offs,count) \
- memcpy_fromfs(target, (source)+(offs), (count))
-#define GET_BYTE_FROM_USER(target,addr,offs) \
- *((char *)&(target)) = get_fs_byte((addr)+(offs))
-#define GET_SHORT_FROM_USER(target,addr,offs) \
- *((short *)&(target)) = get_fs_word((addr)+(offs))
-#ifdef AWE_OSS38
-#define IOCTL_TO_USER(target,offs,source,count) \
- memcpy(target, (source)+(offs), count)
-#define COPY_TO_USER(target,offs,source,count) \
- memcpy_tofs(target, (source)+(offs), (count))
-#define IOCTL_IN(arg) (*(int*)(arg))
-#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val))
-#define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE)
-#else /* AWE_OSS38 */
-#define IOCTL_TO_USER(target,offs,source,count) \
- memcpy_tofs(target, (source)+(offs), (count))
-#define COPY_TO_USER IOCTL_TO_USER
-#define IOCTL_IN(arg) get_fs_long((long *)(arg))
-#define IOCTL_OUT(arg,ret) snd_ioctl_return((int *)arg, ret)
-#define IO_WRITE_CHECK(cmd) (cmd & IOC_IN)
-#endif /* AWE_OSS38 */
-
-#endif /* AWE_NEW_KERNEL_INTERFACE */
-
-#define BZERO(target,len) memset(target, 0, len)
-#define MEMCPY(dst,src,len) memcpy(dst, src, len)
-#define MEMCMP(p1,p2,len) memcmp(p1, p2, len)
-
-/* old style device tables (not modulized) */
-#ifndef AWE_MODULE_SUPPORT
-
-#define sound_alloc_synthdev() \
- (num_synths >= MAX_SYNTH_DEV ? -1 : num_synths++)
-#define sound_alloc_mixerdev() \
- (num_mixers >= MAX_MIXER_DEV ? -1 : num_mixers++)
-#define sound_alloc_mididev() \
- (num_midis >= MAX_MIXER_DEV ? -1 : num_midis++)
-#define sound_unload_synthdev(dev) /**/
-#define sound_unload_mixerdev(dev) /**/
-#define sound_unload_mididev(dev) /**/
-
-#endif /* AWE_MODULE_SUPPORT */
-
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
-inline static void interruptible_sleep_on_timeout(wait_queue_head_t *q, unsigned long timeout)
-{
- current->timeout = jiffies + timeout;
- interruptible_sleep_on(q);
-}
-#endif
-
-#endif /* CONFIG_AWE32_SYNTH */
-
-#endif /* AWE_COMPAT_H_DEF */
diff --git a/drivers/sound/lowlevel/awe_version.h b/drivers/sound/lowlevel/awe_version.h
deleted file mode 100644
index a012d734a..000000000
--- a/drivers/sound/lowlevel/awe_version.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * sound/awe_version.h
- *
- * Version defines for the AWE32/SB32/AWE64 wave table synth driver.
- * version 0.4.3; Mar. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* AWE32 driver version number */
-
-#ifndef AWE_VERSION_H_DEF
-#define AWE_VERSION_H_DEF
-
-#define AWE_MAJOR_VERSION 0
-#define AWE_MINOR_VERSION 4
-#define AWE_TINY_VERSION 3
-#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
-#define AWEDRV_VERSION "0.4.3"
-
-#endif
diff --git a/drivers/sound/lowlevel/lowlevel.h b/drivers/sound/lowlevel/lowlevel.h
deleted file mode 100644
index bb0f6c7d1..000000000
--- a/drivers/sound/lowlevel/lowlevel.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef LOWLEVEL_MODULE
-#define MODVERSIONS
-#include <linux/modversions.h>
-#include "manual_config.h"
-#endif
diff --git a/drivers/sound/lowlevel/soundlow.c b/drivers/sound/lowlevel/soundlow.c
deleted file mode 100644
index 96fdb94be..000000000
--- a/drivers/sound/lowlevel/soundlow.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * lowlevel/init.c - Calls initialization code for configured drivers.
- */
-
-#include "lowlevel.h"
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include "../soundvers.h"
-
-#ifdef LOWLEVEL_MODULE
-char *lowlevel_version = SOUND_VERSION_STRING;
-#endif
-
-extern int attach_aci(void);
-extern void unload_aci(void);
-extern int attach_awe(void);
-extern void unload_awe(void);
-extern int init_aedsp16(void) __init;
-extern void uninit_aedsp16(void) __init;
-
-/*
- * There are two places where you can insert initialization calls of
- * low level drivers. sound_init_lowlevel_drivers() is called after
- * the sound driver has been initialized (the normal case)
- * while sound_preinit_lowlevel_drivers() is called before that.
- */
-void
-sound_preinit_lowlevel_drivers(void)
-{
-#if defined(CONFIG_AEDSP16) && !defined(MODULE)
- init_aedsp16();
-#endif
-}
-
-void
-sound_init_lowlevel_drivers(void)
-{
-#ifdef CONFIG_ACI_MIXER
- attach_aci();
-#endif
-
-#ifdef CONFIG_AWE32_SYNTH
- attach_awe();
-#endif
-}
-
-void
-sound_unload_lowlevel_drivers(void)
-{
-#ifdef CONFIG_ACI_MIXER
- unload_aci();
-#endif
-
-#ifdef CONFIG_AWE32_SYNTH
- unload_awe();
-#endif
-
-#ifdef CONFIG_AEDSP16
- uninit_aedsp16();
-#endif
-
-}
-
-EXPORT_SYMBOL(sound_init_lowlevel_drivers);
-EXPORT_SYMBOL(sound_unload_lowlevel_drivers);
-EXPORT_SYMBOL(sound_preinit_lowlevel_drivers);
diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c
index 06b98aec2..bf605dbca 100644
--- a/drivers/sound/mad16.c
+++ b/drivers/sound/mad16.c
@@ -1107,7 +1107,7 @@ static void __exit cleanup_mad16(void)
}
module_init(init_mad16);
-module_exit(exit_mad16);
+module_exit(cleanup_mad16);
#ifndef MODULE
static int __init setup_mad16(char *str)
diff --git a/drivers/sound/lowlevel/miroaci.h b/drivers/sound/miroaci.h
index a8b7ff49a..9fea58a53 100644
--- a/drivers/sound/lowlevel/miroaci.h
+++ b/drivers/sound/miroaci.h
@@ -1,13 +1,6 @@
#include <linux/config.h>
-#if defined(CONFIG_ACI_MIXER) || defined(CONFIG_ACI_MIXER_MODULE)
extern int aci_implied_cmd(unsigned char opcode);
extern int aci_write_cmd(unsigned char opcode, unsigned char parameter);
extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2);
extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter);
extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter);
-#else
-
-
-#error Compiling a driver that needs the ACI-mixer but ACI-mixer support is not configured
-
-#endif
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index 7e3ecb1a1..40804417c 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -285,29 +285,8 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
if((sb_dev = isapnp_find_dev(bus,
ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL)))
{
-#ifdef CMI8330_DMA0BAD
- int dmahack = 0;
-#endif
sb_dev->prepare(sb_dev);
- /* This device doesn't work with DMA 0, so we must allocate
- * it to prevent PnP routines to assign it to the card.
- *
- * I know i could have inlined the following lines, but it's cleaner
- * this way.
- */
-
-#ifdef CMI8330_DMA0BAD
- if(sb_dev->dma_resource[0].start == 0)
- {
- if(!request_dma(0, "cmi8330 dma hack"))
- {
- /* DMA was free, we now have it */
- dmahack = 1;
- }
- }
-#endif
-
if((sb_dev = activate_dev("CMI8330", "sb", sb_dev)))
{
hw_config->io_base = sb_dev->resource[0].start;
@@ -318,9 +297,6 @@ static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, st
show_base("CMI8330", "sb", &sb_dev->resource[0]);
}
-#ifdef CMI8330_DMA0BAD
- if(dmahack) free_dma(0);
-#endif
if(!sb_dev) return(NULL);
}
else
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index ffb1204ad..25318c1ac 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -21,9 +21,6 @@
*
*/
-/* FIXME: *grr* why can't the f**in Makefile do this for me ? */
-#define EXPORT_SYMTAB
-
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c
index 5efd99dd2..89470da82 100644
--- a/drivers/sound/sscape.c
+++ b/drivers/sound/sscape.c
@@ -16,7 +16,6 @@
* Christoph Hellwig : adapted to module_init/module_exit
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c
index af1f8970d..4bf595f86 100644
--- a/drivers/sound/wavfront.c
+++ b/drivers/sound/wavfront.c
@@ -73,7 +73,6 @@
#include <linux/interrupt.h>
#include <linux/config.h>
-#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/sound/wf_midi.c b/drivers/sound/wf_midi.c
index 4b0708ec7..2d7d50fe9 100644
--- a/drivers/sound/wf_midi.c
+++ b/drivers/sound/wf_midi.c
@@ -49,7 +49,6 @@
* for more info.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "sound_config.h"
#include "soundmodule.h"
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 9f0943d3d..5f1b61d07 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -12,9 +12,11 @@ comment 'USB Controllers'
if [ "$CONFIG_USB_UHCI" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' USB-UHCI High Bandwidth (EXPERIMENTAL)' CONFIG_USB_UHCI_HIGH_BANDWIDTH
fi
- dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
- if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
+ if [ "$CONFIG_USB_UHCI" != "y" ]; then
+ dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
+ if [ "$CONFIG_USB_UHCI_ALT" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' UHCI unlink optimizations (EXPERIMENTAL)' CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
+ fi
fi
dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 6f8ebb3f6..7c5b02f21 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -4,7 +4,7 @@
# Subdirs.
-SUB_DIRS :=
+SUB_DIRS := serial
MOD_SUB_DIRS := $(SUB_DIRS)
ALL_SUB_DIRS := $(SUB_DIRS)
@@ -57,7 +57,6 @@ obj-$(CONFIG_INPUT_EVDEV) += evdev.o input.o
obj-$(CONFIG_USB_SCANNER) += scanner.o
obj-$(CONFIG_USB_ACM) += acm.o
obj-$(CONFIG_USB_PRINTER) += printer.o
-obj-$(CONFIG_USB_SERIAL) += usb-serial.o
obj-$(CONFIG_USB_AUDIO) += audio.o
obj-$(CONFIG_USB_CPIA) += cpia.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o
diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c
index afcd5d105..723ceb481 100644
--- a/drivers/usb/acm.c
+++ b/drivers/usb/acm.c
@@ -49,10 +49,8 @@
#include <linux/tty_flip.h>
#include <linux/tty.h>
#include <linux/module.h>
-
#define DEBUG
-
-#include "usb.h"
+#include <linux/usb.h>
/*
* CMSPAR, some architectures can't have space and mark parity.
diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c
index 6bf366890..ad2f666d5 100644
--- a/drivers/usb/audio.c
+++ b/drivers/usb/audio.c
@@ -152,8 +152,8 @@
#include <linux/bitops.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <linux/usb.h>
-#include "usb.h"
#include "audio.h"
#define AUDIO_DEBUG 1
diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c
index 6cf469a4b..510e8297f 100644
--- a/drivers/usb/cpia.c
+++ b/drivers/usb/cpia.c
@@ -18,10 +18,10 @@
#include <linux/wrapper.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/usb.h>
#include <asm/io.h>
-#include "usb.h"
#include "cpia.h"
static int debug = 0;
diff --git a/drivers/usb/dabusb.c b/drivers/usb/dabusb.c
index b67d70ac8..c13c4a02e 100644
--- a/drivers/usb/dabusb.c
+++ b/drivers/usb/dabusb.c
@@ -37,8 +37,7 @@
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/delay.h>
-
-#include "usb.h"
+#include <linux/usb.h>
#include "dabusb.h"
#include "dabfirmware.h"
@@ -801,6 +800,10 @@ int __init dabusb_init (void)
{
unsigned u;
+ /* register misc device */
+ if (usb_register(&dabusb_driver))
+ return -1;
+
/* initialize struct */
for (u = 0; u < NRDABUSB; u++) {
pdabusb_t s = &dabusb[u];
@@ -815,11 +818,7 @@ int __init dabusb_init (void)
INIT_LIST_HEAD (&s->rec_buff_list);
}
- /* register misc device */
- usb_register (&dabusb_driver);
-
dbg("dabusb_init: driver registered");
-
return 0;
}
diff --git a/drivers/usb/dabusb.h b/drivers/usb/dabusb.h
index 36db7aaff..ddb3685a4 100644
--- a/drivers/usb/dabusb.h
+++ b/drivers/usb/dabusb.h
@@ -6,7 +6,7 @@ typedef struct
unsigned int pipe;
}bulk_transfer_t,*pbulk_transfer_t;
-#define DABUSB_MINOR 64
+#define DABUSB_MINOR 240 /* some unassigned USB minor */
#define DABUSB_VERSION 0x1000
#define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t)
#define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int)
diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c
index 7cc2caf9f..3a2df9155 100644
--- a/drivers/usb/dc2xx.c
+++ b/drivers/usb/dc2xx.c
@@ -57,10 +57,8 @@
#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/module.h>
-
#undef DEBUG
-
-#include "usb.h"
+#include <linux/usb.h>
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
index 1ddbbcf60..099d90372 100644
--- a/drivers/usb/devices.c
+++ b/drivers/usb/devices.c
@@ -53,9 +53,9 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/poll.h>
+#include <linux/usb.h>
#include <asm/uaccess.h>
-#include "usb.h"
#include "usbdevice_fs.h"
#define MAX_TOPO_LEVEL 6
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index c4ae62d4c..c28614d07 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -40,9 +40,9 @@
#include <linux/smp_lock.h>
#include <linux/signal.h>
#include <linux/poll.h>
+#include <linux/usb.h>
#include <asm/uaccess.h>
-#include "usb.h"
#include "usbdevice_fs.h"
struct async {
diff --git a/drivers/usb/drivers.c b/drivers/usb/drivers.c
index 932fca8e0..7682c7442 100644
--- a/drivers/usb/drivers.c
+++ b/drivers/usb/drivers.c
@@ -36,9 +36,9 @@
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/usb.h>
#include <asm/uaccess.h>
-#include "usb.h"
#include "usbdevice_fs.h"
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index 3f98d9b14..c7bb34e4d 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -39,13 +39,12 @@
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
-
-#include <asm/unaligned.h>
-
#undef DEBUG
#undef DEBUG_DATA
+#include <linux/usb.h>
+
+#include <asm/unaligned.h>
-#include "usb.h"
#include "hid.h"
#ifdef DEBUG
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
index 4134574c2..9138ee4da 100644
--- a/drivers/usb/hub.c
+++ b/drivers/usb/hub.c
@@ -13,13 +13,12 @@
#include <linux/list.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
+#define DEBUG
+#include <linux/usb.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
-#define DEBUG
-
-#include "usb.h"
#include "hub.h"
/* Wakes up khubd */
diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
index 89e02b4ca..fe93e5bcc 100644
--- a/drivers/usb/ibmcam.c
+++ b/drivers/usb/ibmcam.c
@@ -20,10 +20,10 @@
#include <linux/wrapper.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/usb.h>
#include <asm/io.h>
-#include "usb.h"
#include "ibmcam.h"
/*
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index 7053d56d7..92a008d2f 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -36,9 +36,9 @@
#include <linux/locks.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/usb.h>
#include <asm/uaccess.h>
-#include "usb.h"
#include "usbdevice_fs.h"
/* --------------------------------------------------------------------- */
@@ -446,22 +446,17 @@ static void usbdevfs_put_super(struct super_block *sb)
INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist);
while (!list_empty(&sb->u.usbdevfs_sb.ilist))
free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist));
- MOD_DEC_USE_COUNT;
}
-static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = USBDEVICE_SUPER_MAGIC;
- tmp.f_bsize = PAGE_SIZE/sizeof(long); /* ??? */
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = USBDEVICE_SUPER_MAGIC;
+ buf->f_bsize = PAGE_SIZE/sizeof(long); /* ??? */
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
static struct super_operations usbdevfs_sops = {
@@ -552,8 +547,6 @@ struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int s
}
}
/* fill superblock */
- MOD_INC_USE_COUNT;
- lock_super(s);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = USBDEVICE_SUPER_MAGIC;
@@ -573,7 +566,6 @@ struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int s
if (!s->s_root)
goto out_no_root;
list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
- unlock_super(s);
for (i = 0; i < NRSPECIAL; i++) {
if (!(inode = iget(s, IROOT+1+i)))
continue;
@@ -595,23 +587,14 @@ struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int s
out_no_root:
printk("usbdevfs_read_super: get root inode failed\n");
iput(root_inode);
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
return NULL;
opterr:
printk(KERN_WARNING "usbdevfs: mount parameter error\n");
- s->s_dev = 0;
return NULL;
}
-static struct file_system_type usbdevice_fs_type = {
- "usbdevfs",
- 0,
- usbdevfs_read_super,
- NULL
-};
+static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, 0);
/* --------------------------------------------------------------------- */
@@ -675,7 +658,9 @@ void usbdevfs_remove_device(struct usb_device *dev)
/* --------------------------------------------------------------------- */
+#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *usbdir = NULL;
+#endif
int __init usbdevfs_init(void)
{
@@ -688,8 +673,10 @@ int __init usbdevfs_init(void)
return ret;
if ((ret = register_filesystem(&usbdevice_fs_type)))
usb_deregister(&usbdevfs_driver);
+#ifdef CONFIG_PROC_FS
/* create mount point for usbdevfs */
usbdir = proc_mkdir("usb", proc_bus);
+#endif
return ret;
}
@@ -697,8 +684,10 @@ void __exit usbdevfs_cleanup(void)
{
usb_deregister(&usbdevfs_driver);
unregister_filesystem(&usbdevice_fs_type);
+#ifdef CONFIG_PROC_FS
if (usbdir)
remove_proc_entry("usb", proc_bus);
+#endif
}
#if 0
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index 0984e48fd..607782829 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -87,8 +87,6 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
while (list) {
switch (type) {
case EV_ABS:
- if (test_bit(EV_REL, handle->dev->evbit) && test_bit(REL_X, handle->dev->relbit))
- return;
switch (code) {
case ABS_X:
size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index b63ddb7e8..4e9b4f65e 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -60,9 +60,9 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/time.h>
+#include <linux/usb.h>
#include <asm/io.h>
-#include "usb.h"
#include "ov511.h"
#define OV511_I2C_RETRIES 3
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 1e752dc75..d3761bf52 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -13,12 +13,11 @@
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/usb.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include "usb.h"
-
#if LINUX_VERSION_CODE<0x2032d || !defined(__KERNEL__) || !defined(__OPTIMIZE__)
#error You can not compile this driver on this kernel with this C options!
#endif
diff --git a/drivers/usb/plusb.c b/drivers/usb/plusb.c
index d780d8d9c..871cf8945 100644
--- a/drivers/usb/plusb.c
+++ b/drivers/usb/plusb.c
@@ -40,10 +40,9 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-
//#define DEBUG
+#include <linux/usb.h>
-#include "usb.h"
#include "plusb.h"
/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 182915a19..4c100f16c 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -39,10 +39,8 @@
#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/lp.h>
-
#define DEBUG
-
-#include "usb.h"
+#include <linux/usb.h>
#define USBLP_BUF_SIZE 8192
diff --git a/drivers/usb/rio500.c b/drivers/usb/rio500.c
index e25ba03d3..7529c7fc0 100644
--- a/drivers/usb/rio500.c
+++ b/drivers/usb/rio500.c
@@ -35,8 +35,7 @@
#include <linux/init.h>
#include <linux/malloc.h>
#include <linux/spinlock.h>
-
-#include "usb.h"
+#include <linux/usb.h>
#include "rio500_usb.h"
diff --git a/drivers/usb/scanner.h b/drivers/usb/scanner.h
index 9ba1bf0d5..ed8320424 100644
--- a/drivers/usb/scanner.h
+++ b/drivers/usb/scanner.h
@@ -6,10 +6,8 @@
#include <linux/malloc.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
-
// #define DEBUG
-
-#include "usb.h"
+#include <linux/usb.h>
/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
diff --git a/drivers/usb/serial/.cvsignore b/drivers/usb/serial/.cvsignore
new file mode 100644
index 000000000..b566130de
--- /dev/null
+++ b/drivers/usb/serial/.cvsignore
@@ -0,0 +1,5 @@
+.depend
+.*.flags
+conmakehash
+consolemap_deftbl.c
+uni_hash.tbl
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
new file mode 100644
index 000000000..d5c245bf1
--- /dev/null
+++ b/drivers/usb/serial/Makefile
@@ -0,0 +1,66 @@
+#
+# Makefile for the kernel USB device drivers.
+#
+
+# Subdirs.
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+# The target object and module list name.
+
+O_TARGET := usbdrv.o
+M_OBJS :=
+O_OBJS :=
+MOD_LIST_NAME := USB_MODULES
+
+# Objects that export symbols.
+
+# Multipart objects.
+
+# Optional parts of multipart objects.
+
+# Object file lists.
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_USB_SERIAL) += usb-serial.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y := $(filter $(list-multi), $(obj-y))
+multi-m := $(filter $(list-multi), $(obj-m))
+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+int-m := $(filter-out $(int-y), $(int-m))
+
+# Take multi-part drivers out of obj-y and put components in.
+
+obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
+OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
+
+# Link rules for multi-part drivers.
+
diff --git a/drivers/usb/serial/Makefile-keyspan_pda_fw b/drivers/usb/serial/Makefile-keyspan_pda_fw
new file mode 100644
index 000000000..219708e46
--- /dev/null
+++ b/drivers/usb/serial/Makefile-keyspan_pda_fw
@@ -0,0 +1,16 @@
+
+# some rules to handle the quirks of the 'as31' assembler, like
+# insisting upon fixed suffixes for the input and output files,
+# and its lack of preprocessor support
+
+all: keyspan_pda_fw.h
+
+%.asm: %.s
+ gcc -x assembler-with-cpp -P -E -o $@ $<
+
+%.hex: %.asm
+ as31 -l $<
+ mv $*.obj $@
+
+%_fw.h: %.hex ezusb_convert.pl
+ perl ezusb_convert.pl $* < $< > $@
diff --git a/drivers/usb/serial/ezusb_convert.pl b/drivers/usb/serial/ezusb_convert.pl
new file mode 100644
index 000000000..b4f08b2d7
--- /dev/null
+++ b/drivers/usb/serial/ezusb_convert.pl
@@ -0,0 +1,48 @@
+#! /usr/bin/perl -w
+
+
+# convert an Intel HEX file into a set of C records usable by the firmware
+# loading code in usb-serial.c (or others)
+
+# accepts the .hex file(s) on stdin, a basename (to name the initialized
+# array) as an argument, and prints the .h file to stdout. Typical usage:
+# perl ezusb_convert.pl foo <foo.hex >fw_foo.h
+
+
+my $basename = $ARGV[0];
+die "no base name specified" unless $basename;
+
+while (<STDIN>) {
+ # ':' <len> <addr> <type> <len-data> <crc> '\r'
+ # len, type, crc are 2-char hex, addr is 4-char hex. type is 00 for
+ # normal records, 01 for EOF
+ my($lenstring, $addrstring, $typestring, $reststring) =
+ /^:(\w\w)(\w\w\w\w)(\w\w)(\w+)$/;
+ die "malformed line: $_" unless $reststring;
+ last if $typestring eq '01';
+ my($len) = hex($lenstring);
+ my($addr) = hex($addrstring);
+ my(@bytes) = unpack("C*", pack("H".(2*$len), $reststring));
+ #pop(@bytes); # last byte is a CRC
+ push(@records, [$addr, \@bytes]);
+}
+
+print <<"EOF";
+/*
+ * ${basename}_fw.h
+ *
+ * Generated from ${basename}.s by ezusb_convert.pl
+ * This file is presumed to be under the same copyright as the source file
+ * from which it was derived.
+ */
+
+EOF
+
+print "static const struct ezusb_hex_record ${basename}_firmware[] = {\n";
+foreach $r (@records) {
+ printf("{ 0x%04x,\t%d,\t{", $r->[0], scalar(@{$r->[1]}));
+ print join(", ", map {sprintf('0x%02x', $_);} @{$r->[1]});
+ print "} },\n";
+}
+print "{ 0xffff,\t0,\t{0x00} }\n";
+print "};\n";
diff --git a/drivers/usb/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 36fa7bb3e..36fa7bb3e 100644
--- a/drivers/usb/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
diff --git a/drivers/usb/keyspan_pda_fw.h b/drivers/usb/serial/keyspan_pda_fw.h
index 5366c0a28..5366c0a28 100644
--- a/drivers/usb/keyspan_pda_fw.h
+++ b/drivers/usb/serial/keyspan_pda_fw.h
diff --git a/drivers/usb/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 4af993264..ad86c6a80 100644
--- a/drivers/usb/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -175,10 +175,8 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/spinlock.h>
-
#define DEBUG
-
-#include "usb.h"
+#include <linux/usb.h>
#ifdef CONFIG_USB_SERIAL_WHITEHEAT
#include "whiteheat.h" /* firmware for the ConnectTech WhiteHEAT device */
diff --git a/drivers/usb/usb-serial.h b/drivers/usb/serial/usb-serial.h
index f02eeedf5..f02eeedf5 100644
--- a/drivers/usb/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
diff --git a/drivers/usb/whiteheat.h b/drivers/usb/serial/whiteheat.h
index d7053e337..d7053e337 100644
--- a/drivers/usb/whiteheat.h
+++ b/drivers/usb/serial/whiteheat.h
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index ec4cad491..c3b4ebc2e 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -21,7 +21,6 @@
* - working around the horridness of the rest
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -34,15 +33,14 @@
#include <linux/unistd.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#define DEBUG
+#include <linux/usb.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#define DEBUG
-#include "usb.h"
-
#include "uhci.h"
#include "uhci-debug.h"
@@ -54,18 +52,21 @@ MODULE_PARM(debug, "i");
static kmem_cache_t *uhci_td_cachep;
static kmem_cache_t *uhci_qh_cachep;
+static kmem_cache_t *uhci_up_cachep; /* urb_priv */
static LIST_HEAD(uhci_list);
static int rh_submit_urb(urb_t *urb);
static int rh_unlink_urb(urb_t *urb);
static int uhci_get_current_frame_number(struct usb_device *dev);
-static void uhci_stop_hc_schedule(struct uhci *uhci);
-static void uhci_start_hc_schedule(struct uhci *uhci);
+static int uhci_unlink_generic(urb_t *urb);
static int uhci_unlink_urb(urb_t *urb);
#define min(a,b) (((a)<(b))?(a):(b))
+/* If a transfer is still active after this much time, turn off FSBR */
+#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */
+
/*
* Only the USB core should call uhci_alloc_dev and uhci_free_dev
*/
@@ -78,7 +79,7 @@ static int uhci_free_dev(struct usb_device *dev)
{
urb_t *u;
struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
- struct list_head *tmp, *head = &uhci->urb_list;
+ struct list_head *tmp, *next, *head = &uhci->urb_list;
unsigned long flags;
/* Walk through the entire URB list and forcefully remove any */
@@ -88,38 +89,18 @@ static int uhci_free_dev(struct usb_device *dev)
while (tmp != head) {
u = list_entry(tmp, urb_t, urb_list);
+ next = tmp->next;
+
if (u->dev == dev)
uhci_unlink_urb(u);
+
+ tmp = next;
}
nested_unlock(&uhci->urblist_lock, flags);
return 0;
}
-/*
- * UHCI interrupt list operations..
- */
-static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td)
-{
- unsigned long flags;
-
- nested_lock(&uhci->irqlist_lock, flags);
- list_add(&td->irq_list, &uhci->interrupt_list);
- nested_unlock(&uhci->irqlist_lock, flags);
-}
-
-static void uhci_remove_irq_list(struct uhci *uhci, struct uhci_td *td)
-{
- unsigned long flags;
-
- nested_lock(&uhci->irqlist_lock, flags);
- if (td->irq_list.next != &td->irq_list) {
- list_del(&td->irq_list);
- INIT_LIST_HEAD(&td->irq_list);
- }
- nested_unlock(&uhci->irqlist_lock, flags);
-}
-
static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb)
{
unsigned long flags;
@@ -141,6 +122,54 @@ static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
nested_unlock(&uhci->urblist_lock, flags);
}
+static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
+{
+ struct uhci_td *td;
+
+ td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ if (!td)
+ return NULL;
+
+ td->link = UHCI_PTR_TERM;
+ td->buffer = 0;
+
+ td->frameptr = NULL;
+ td->nexttd = td->prevtd = NULL;
+ td->list.next = td->list.prev = NULL;
+ td->dev = dev;
+
+ usb_inc_dev_use(dev);
+
+ return td;
+}
+
+static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
+ __u32 info, __u32 buffer)
+{
+ td->status = status;
+ td->info = info;
+ td->buffer = buffer;
+}
+
+static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+ /* Fix the linked list pointers */
+ td->nexttd = skeltd->nexttd;
+ td->prevtd = skeltd;
+ if (skeltd->nexttd)
+ skeltd->nexttd->prevtd = td;
+ skeltd->nexttd = td;
+
+ td->link = skeltd->link;
+ skeltd->link = virt_to_bus(td);
+
+ spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
/*
* We insert Isochronous transfers directly into the frame list at the
* beginning
@@ -157,6 +186,7 @@ static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, uns
framenum %= UHCI_NUMFRAMES;
spin_lock_irqsave(&uhci->framelist_lock, flags);
+
td->frameptr = &uhci->fl->frame[framenum];
td->link = uhci->fl->frame[framenum];
if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
@@ -166,6 +196,7 @@ static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, uns
nexttd->frameptr = NULL;
}
uhci->fl->frame[framenum] = virt_to_bus(td);
+
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
}
@@ -173,6 +204,10 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
{
unsigned long flags;
+ /* If it's not inserted, don't remove it */
+ if (!td->frameptr && !td->prevtd && !td->nexttd)
+ return;
+
spin_lock_irqsave(&uhci->framelist_lock, flags);
if (td->frameptr) {
*(td->frameptr) = td->link;
@@ -195,77 +230,41 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
}
-static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&uhci->framelist_lock, flags);
-
- /* Fix the linked list pointers */
- td->nexttd = skeltd->nexttd;
- td->prevtd = skeltd;
- if (skeltd->nexttd)
- skeltd->nexttd->prevtd = td;
- skeltd->nexttd = td;
-
- td->link = skeltd->link;
- skeltd->link = virt_to_bus(td);
-
- spin_unlock_irqrestore(&uhci->framelist_lock, flags);
-}
-
/*
* Inserts a td into qh list at the top.
*/
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *begin)
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
{
- struct uhci_td *td, *prevtd;
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci_td *td, *prevtd = NULL;
- if (!begin) /* Nothing to do */
+ if (!urbp)
return;
- /* Grab the first TD and add it to the QH */
- td = begin;
- qh->element = virt_to_bus(td) | UHCI_PTR_DEPTH;
+ td = urbp->list.begin;
+ if (!td)
+ return;
+
+ /* Add the first TD to the QH element pointer */
+ qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
- /* Go through the rest of the TD's, link them together */
prevtd = td;
- td = td->next;
- while (td) {
- prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
+
+ /* Then link the rest of the TD's */
+ for (td = td->list.next; td; td = td->list.next) {
+ prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
prevtd = td;
- td = td->next;
}
prevtd->link = UHCI_PTR_TERM;
}
-static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
-{
- struct uhci_td *td;
-
- td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
- if (!td)
- return NULL;
-
- td->link = UHCI_PTR_TERM;
- td->buffer = 0;
-
- td->frameptr = NULL;
- td->nexttd = td->prevtd = NULL;
- td->next = NULL;
- td->dev = dev;
- INIT_LIST_HEAD(&td->irq_list);
- INIT_LIST_HEAD(&td->list);
-
- usb_inc_dev_use(dev);
-
- return td;
-}
-
static void uhci_free_td(struct uhci_td *td)
{
+ if (td->list.next || td->list.prev)
+ dbg("td is still in URB list!");
+
kmem_cache_free(uhci_td_cachep, td);
if (td->dev)
@@ -286,7 +285,7 @@ static struct uhci_qh *uhci_alloc_qh(struct usb_device *dev)
qh->dev = dev;
qh->prevqh = qh->nextqh = NULL;
- INIT_LIST_HEAD(&qh->list);
+ INIT_LIST_HEAD(&qh->remove_list);
usb_inc_dev_use(dev);
@@ -333,14 +332,31 @@ static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
qh->nextqh->prevqh = qh->prevqh;
qh->prevqh = qh->nextqh = NULL;
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+
+ spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+ list_add(&qh->remove_list, &uhci->qh_remove_list);
+ spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
}
-static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
- __u32 info, __u32 buffer)
+struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
{
- td->status = status;
- td->info = info;
- td->buffer = buffer;
+ struct urb_priv *urbp;
+
+ urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ if (!urbp)
+ return NULL;
+
+ memset((void *)urbp, 0, sizeof(*urbp));
+
+ urbp->list.begin = urbp->list.end = NULL;
+
+ urb->hcpriv = urbp;
+
+ urbp->inserttime = jiffies;
+
+ usb_inc_dev_use(urb->dev);
+
+ return urbp;
}
static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
@@ -349,35 +365,110 @@ static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
td->urb = urb;
- if (urbp->end)
- urbp->end->next = td;
+ if (!urbp->list.begin)
+ urbp->list.begin = td;
+
+ if (urbp->list.end) {
+ urbp->list.end->list.next = td;
+ td->list.prev = urbp->list.end;
+ }
+ urbp->list.end = td;
+}
+
+static void uhci_remove_td_from_urb(urb_t *urb, struct uhci_td *td)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+ if (!urbp->list.begin && !urbp->list.end)
+ return;
+
+ if (td->list.prev)
+ td->list.prev->list.next = td->list.next;
+ else
+ urbp->list.begin = td->list.next;
+
+ if (td->list.next)
+ td->list.next->list.prev = td->list.prev;
+ else
+ urbp->list.end = td->list.prev;
+
+ td->list.next = td->list.prev = NULL;
+ td->urb = NULL;
+}
+
+static void uhci_destroy_urb_priv(urb_t *urb)
+{
+ struct urb_priv *urbp;
+ struct uhci *uhci;
+ struct uhci_td *td, *nexttd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&urb->lock, flags);
+
+ urbp = (struct urb_priv *)urb->hcpriv;
+ if (!urbp)
+ return;
+
+ if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+ return;
+
+ uhci = urb->dev->bus->hcpriv;
+
+ td = urbp->list.begin;
+ while (td) {
+ nexttd = td->list.next;
+
+ uhci_remove_td_from_urb(urb, td);
+
+ uhci_remove_td(uhci, td);
- urbp->end = td;
+ uhci_free_td(td);
+
+ td = nexttd;
+ }
+
+ urb->hcpriv = NULL;
+ kmem_cache_free(uhci_up_cachep, urbp);
- if (!urbp->begin)
- urbp->begin = td;
+ spin_unlock_irqrestore(&urb->lock, flags);
+
+ usb_dec_dev_use(urb->dev);
}
-void uhci_inc_fsbr(struct uhci *uhci)
+static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
{
unsigned long flags;
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+ if (!urbp)
+ return;
spin_lock_irqsave(&uhci->framelist_lock, flags);
- if (!uhci->fsbr++)
- uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+ if (!urbp->fsbr) {
+ urbp->fsbr = 1;
+ if (!uhci->fsbr++)
+ uhci->skel_term_td.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+ }
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
}
-void uhci_dec_fsbr(struct uhci *uhci)
+static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
{
unsigned long flags;
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+ if (!urbp)
+ return;
spin_lock_irqsave(&uhci->framelist_lock, flags);
- if (!--uhci->fsbr)
- uhci->skel_term_qh.link = UHCI_PTR_TERM;
+ if (urbp->fsbr) {
+ urbp->fsbr = 0;
+ if (!--uhci->fsbr)
+ uhci->skel_term_td.link = UHCI_PTR_TERM;
+ }
spin_unlock_irqrestore(&uhci->framelist_lock, flags);
}
@@ -419,14 +510,14 @@ static int uhci_map_status(int status, int dir_out)
*/
static int uhci_submit_control(urb_t *urb)
{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
struct uhci_td *td;
struct uhci_qh *qh;
unsigned long destination, status;
- struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
int len = urb->transfer_buffer_length;
unsigned char *data = urb->transfer_buffer;
- struct urb_priv *urbp;
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -434,14 +525,6 @@ static int uhci_submit_control(urb_t *urb)
/* 3 errors */
status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
- urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
- if (!urbp)
- return -ENOMEM;
-
- urbp->begin = urbp->end = NULL;
-
- urb->hcpriv = urbp;
-
/*
* Build the TD for the control request
*/
@@ -465,18 +548,16 @@ static int uhci_submit_control(urb_t *urb)
/*
* Build the DATA TD's
*/
- td = uhci_alloc_td(urb->dev);
- if (!td) {
- /* FIXME: Free the TD's */
- return -ENOMEM;
- }
-
while (len > 0) {
int pktsze = len;
if (pktsze > maxsze)
pktsze = maxsze;
+ td = uhci_alloc_td(urb->dev);
+ if (!td)
+ return -ENOMEM;
+
/* Alternate Data0/1 (start with Data1) */
destination ^= 1 << TD_TOKEN_TOGGLE;
@@ -486,16 +567,16 @@ static int uhci_submit_control(urb_t *urb)
data += pktsze;
len -= pktsze;
-
- td = uhci_alloc_td(urb->dev);
- if (!td)
- /* FIXME: Free all of the previously allocated td's */
- return -ENOMEM;
}
/*
* Build the final TD for control status
- *
+ */
+ td = uhci_alloc_td(urb->dev);
+ if (!td)
+ return -ENOMEM;
+
+ /*
* It's IN if the pipe is an output pipe or we're not expecting
* data back.
*/
@@ -513,20 +594,19 @@ static int uhci_submit_control(urb_t *urb)
uhci_fill_td(td, status | TD_CTRL_IOC,
destination | (UHCI_NULL_DATA_SIZE << 21), 0);
- uhci_add_irq_list(uhci, td);
-
qh = uhci_alloc_qh(urb->dev);
- if (!qh) {
- /* FIXME: Free all of the TD's */
+ if (!qh)
return -ENOMEM;
- }
- uhci_insert_tds_in_qh(qh, urbp->begin);
- if (!(urb->pipe & TD_CTRL_LS)) {
- uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
- uhci_inc_fsbr(uhci);
- } else
+ /* Low speed or small transfers gets a different queue and treatment */
+ if (urb->pipe & TD_CTRL_LS) {
+ uhci_insert_tds_in_qh(qh, urb, 0);
uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
+ } else {
+ uhci_insert_tds_in_qh(qh, urb, 1);
+ uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
+ uhci_inc_fsbr(uhci, urb);
+ }
urbp->qh = qh;
@@ -537,66 +617,22 @@ static int uhci_submit_control(urb_t *urb)
return -EINPROGRESS;
}
-/* This is also the uhci_unlink_bulk function */
-static int uhci_unlink_control(urb_t *urb)
+static int uhci_result_control(urb_t *urb)
{
struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td;
- struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
- int notfinished;
+ unsigned int status;
if (!urbp)
return -EINVAL;
- notfinished = (urb->status == -EINPROGRESS);
-
- if (notfinished)
- uhci_stop_hc_schedule(uhci);
-
- if (!(urb->pipe & TD_CTRL_LS))
- uhci_dec_fsbr(uhci);
-
- uhci_remove_qh(uhci, urbp->qh);
- uhci_free_qh(urbp->qh);
-
- /* Go through the rest of the TD's, deleting them, then scheduling */
- /* their deletion */
- td = urbp->begin;
- while (td) {
- struct uhci_td *next = td->next;
-
- if (td->status & TD_CTRL_IOC)
- uhci_remove_irq_list(uhci, td);
-
- uhci_free_td(td);
-
- td = next;
- }
-
- if (notfinished)
- uhci_start_hc_schedule(uhci);
-
- kfree(urbp);
- urb->hcpriv = NULL;
-
- uhci_remove_urb_list(uhci, urb);
-
- return 0;
-}
-
-static int uhci_result_control(urb_t *urb)
-{
- struct urb_priv *urbp = urb->hcpriv;
- struct uhci_td *td;
- unsigned int status;
-
- td = urbp->begin;
- if (!td) /* Nothing to do */
+ td = urbp->list.begin;
+ if (!td)
return -EINVAL;
/* The first TD is the SETUP phase, check the status, but skip */
/* the count */
- status = uhci_status_bits(td->status);
+ status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -605,9 +641,10 @@ static int uhci_result_control(urb_t *urb)
urb->actual_length = 0;
+ td = td->list.next;
+
/* The rest of the TD's (but the last) are data */
- td = td->next;
- while (td && td->next) {
+ while (td && td->list.next) {
status = uhci_status_bits(td->status);
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
@@ -617,13 +654,14 @@ static int uhci_result_control(urb_t *urb)
/* If SPD is set then we received a short packet */
/* There will be no status phase at the end */
/* FIXME: Re-setup the queue to run the STATUS phase? */
- if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
+ if ((td->status & TD_CTRL_SPD) &&
+ (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
return 0;
if (status)
goto td_error;
- td = td->next;
+ td = td->list.next;
}
/* Control status phase */
@@ -648,18 +686,16 @@ static int uhci_result_control(urb_t *urb)
td_error:
/* Some debugging code */
if (debug) {
- dbg("uhci_result_control() failed with status %x",
- status);
+ dbg("uhci_result_control() failed with status %x", status);
/* Print the chain for debugging purposes */
uhci_show_queue(urbp->qh);
}
- if (status & TD_CTRL_STALLED) {
+ if (status & TD_CTRL_STALLED)
/* endpoint has stalled - mark it halted */
usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
uhci_packetout(td->info));
- }
return uhci_map_status(status, uhci_packetout(td->info));
}
@@ -672,7 +708,6 @@ static int uhci_submit_interrupt(urb_t *urb)
struct uhci_td *td;
unsigned long destination, status;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
- struct urb_priv *urbp;
if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
return -EINVAL;
@@ -680,16 +715,7 @@ static int uhci_submit_interrupt(urb_t *urb)
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
- status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD |
- TD_CTRL_IOC;
-
- urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
- if (!urbp)
- return -ENOMEM;
-
- urbp->begin = urbp->end = NULL;
-
- urb->hcpriv = urbp;
+ status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
td = uhci_alloc_td(urb->dev);
if (!td)
@@ -698,72 +724,70 @@ static int uhci_submit_interrupt(urb_t *urb)
destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
destination |= ((urb->transfer_buffer_length - 1) << 21);
+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination,
virt_to_bus(urb->transfer_buffer));
- uhci_add_irq_list(uhci, td);
-
uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td);
uhci_add_urb_list(uhci, urb);
- usb_inc_dev_use(urb->dev);
-
return -EINPROGRESS;
}
-static int uhci_unlink_interrupt(urb_t *urb)
+static int uhci_result_interrupt(urb_t *urb)
{
struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td;
- struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
- int notfinished;
+ unsigned int status;
if (!urbp)
return -EINVAL;
- notfinished = (urb->status == -EINPROGRESS);
+ urb->actual_length = 0;
- if (notfinished)
- uhci_stop_hc_schedule(uhci);
+ for (td = urbp->list.begin; td; td = td->list.next) {
+ status = uhci_status_bits(td->status);
+ if (status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
- td = urbp->begin;
- uhci_remove_td(uhci, td);
- if (td->status & TD_CTRL_IOC)
- uhci_remove_irq_list(uhci, td);
- uhci_free_td(td);
+ urb->actual_length += uhci_actual_length(td->status);
- if (notfinished)
- uhci_start_hc_schedule(uhci);
+ /* If SPD is set then we received a short packet */
+ if ((td->status & TD_CTRL_SPD) &&
+ (uhci_actual_length(td->status) < uhci_expected_length(td->info))) {
+ usb_settoggle(urb->dev, uhci_endpoint(td->info),
+ uhci_packetout(td->info),
+ uhci_toggle(td->info) ^ 1);
- kfree(urbp);
- urb->hcpriv = NULL;
+ return 0;
+ }
- uhci_remove_urb_list(uhci, urb);
+ if (status)
+ goto td_error;
+ }
return 0;
-}
-
-static int uhci_result_interrupt(urb_t *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
- int status;
- if (!urbp)
- return -EINVAL;
-
- td = urbp->begin;
- if (!td)
- return -EINVAL;
+td_error:
+ /* Some debugging code */
+ if (debug) {
+ dbg("uhci_result_interrupt/bulk() failed with status %x",
+ status);
- status = uhci_status_bits(td->status);
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
+ /* Print the chain for debugging purposes */
+ if (urbp->qh)
+ uhci_show_queue(urbp->qh);
+ else
+ uhci_show_td(td);
+ }
- if (!status)
- urb->actual_length = uhci_actual_length(td->status);
+ if (status & TD_CTRL_STALLED)
+ /* endpoint has stalled - mark it halted */
+ usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+ uhci_packetout(td->info));
return uhci_map_status(status, uhci_packetout(td->info));
}
@@ -773,12 +797,17 @@ static void uhci_reset_interrupt(urb_t *urb)
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_td *td;
- td = urbp->begin;
+ if (!urbp)
+ return;
+
+ td = urbp->list.begin;
+ if (!td)
+ return;
- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
td->info &= ~(1 << TD_TOKEN_TOGGLE);
td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+ usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
urb->status = -EINPROGRESS;
}
@@ -795,27 +824,23 @@ static int uhci_submit_bulk(urb_t *urb)
int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
int len = urb->transfer_buffer_length;
unsigned char *data = urb->transfer_buffer;
- struct urb_priv *urbp;
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
if (len < 0)
return -EINVAL;
+ /* Can't have low speed bulk transfers */
+ if (urb->pipe & TD_CTRL_LS)
+ return -EINVAL;
+
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
/* 3 errors */
- status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+ status = TD_CTRL_ACTIVE | (3 << 27);
if (!(urb->transfer_flags & USB_DISABLE_SPD))
status |= TD_CTRL_SPD;
- urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
- if (!urbp)
- return -ENOMEM;
-
- urbp->begin = urbp->end = NULL;
-
- urb->hcpriv = urbp;
-
/*
* Build the DATA TD's
*/
@@ -826,10 +851,8 @@ static int uhci_submit_bulk(urb_t *urb)
pktsze = maxsze;
td = uhci_alloc_td(urb->dev);
- if (!td) {
- /* FIXME: Free the TD's */
+ if (!td)
return -ENOMEM;
- }
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) |
@@ -840,86 +863,31 @@ static int uhci_submit_bulk(urb_t *urb)
data += pktsze;
len -= maxsze;
- if (len <= 0) {
+ if (len <= 0)
td->status |= TD_CTRL_IOC;
- uhci_add_irq_list(uhci, td);
- }
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
}
qh = uhci_alloc_qh(urb->dev);
- if (!qh) {
- /* FIXME: Free all of the TD's */
+ if (!qh)
return -ENOMEM;
- }
- uhci_insert_tds_in_qh(qh, urbp->begin);
+
+ uhci_insert_tds_in_qh(qh, urb, 1);
uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
urbp->qh = qh;
uhci_add_urb_list(uhci, urb);
- usb_inc_dev_use(urb->dev);
-
- uhci_inc_fsbr(uhci);
+ uhci_inc_fsbr(uhci, urb);
return -EINPROGRESS;
}
-/* We can use the control unlink since they're identical */
-#define uhci_unlink_bulk uhci_unlink_control
-
-static int uhci_result_bulk(urb_t *urb)
-{
- struct urb_priv *urbp = urb->hcpriv;
- struct uhci_td *td;
- unsigned int status;
-
- urb->actual_length = 0;
-
- /* The rest of the TD's (but the last) are data */
- for (td = urbp->begin; td; td = td->next) {
- status = uhci_status_bits(td->status);
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
- urb->actual_length += uhci_actual_length(td->status);
-
- /* If SPD is set then we received a short packet */
- if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) {
- usb_settoggle(urb->dev, uhci_endpoint(td->info),
- uhci_packetout(td->info),
- uhci_toggle(td->info) ^ 1);
-
- return 0;
- }
-
- if (status)
- goto td_error;
- }
-
- return 0;
-
-td_error:
- /* Some debugging code */
- if (debug) {
- dbg("uhci_result_bulk() failed with status %x",
- status);
-
- /* Print the chain for debugging purposes */
- uhci_show_queue(urbp->qh);
- }
-
- if (status & TD_CTRL_STALLED) {
- /* endpoint has stalled - mark it halted */
- usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
- uhci_packetout(td->info));
- }
-
- return uhci_map_status(status, uhci_packetout(td->info));
-}
+/* We can use the result interrupt since they're identical */
+#define uhci_result_bulk uhci_result_interrupt
/*
* Isochronous transfers
@@ -929,6 +897,7 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
urb_t *u, *last_urb = NULL;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
struct list_head *tmp, *head = &uhci->urb_list;
+ int ret = 0;
unsigned long flags;
nested_lock(&uhci->urblist_lock, flags);
@@ -945,14 +914,16 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
}
tmp = tmp->next;
}
- nested_unlock(&uhci->urblist_lock, flags);
if (last_urb) {
*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
- return 0;
+ ret = 0;
} else
- return -1; // no previous urb found
+ ret = -1; /* no previous urb found */
+ nested_unlock(&uhci->urblist_lock, flags);
+
+ return ret;
}
static int isochronous_find_start(urb_t *urb)
@@ -985,7 +956,6 @@ static int uhci_submit_isochronous(urb_t *urb)
{
struct uhci_td *td;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
- struct urb_priv *urbp;
int i, ret, framenum;
int status, destination;
@@ -996,85 +966,30 @@ static int uhci_submit_isochronous(urb_t *urb)
if (ret)
return ret;
- urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
- if (!urbp)
- return -ENOMEM;
-
- urbp->begin = urbp->end = NULL;
-
- urb->hcpriv = urbp;
-
framenum = urb->start_frame;
for (i = 0; i < urb->number_of_packets; i++, framenum++) {
if (!urb->iso_frame_desc[i].length)
continue;
td = uhci_alloc_td(urb->dev);
- if (!td) {
- /* FIXME: Free the TD's */
+ if (!td)
return -ENOMEM;
- }
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset));
- if (i + 1 >= urb->number_of_packets) {
+ if (i + 1 >= urb->number_of_packets)
td->status |= TD_CTRL_IOC;
- uhci_add_irq_list(uhci, td);
- }
uhci_insert_td_frame_list(uhci, td, framenum);
}
uhci_add_urb_list(uhci, urb);
- usb_inc_dev_use(urb->dev);
-
return -EINPROGRESS;
}
-static int uhci_unlink_isochronous(urb_t *urb)
-{
- struct urb_priv *urbp = urb->hcpriv;
- struct uhci_td *td;
- struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
- int notfinished;
-
- if (!urbp)
- return -EINVAL;
-
- notfinished = (urb->status == -EINPROGRESS);
-
- if (notfinished)
- uhci_stop_hc_schedule(uhci);
-
- /* Go through the rest of the TD's, deleting them, then scheduling */
- /* their deletion */
- td = urbp->begin;
- while (td) {
- struct uhci_td *next = td->next;
-
- uhci_remove_td(uhci, td);
-
- if (td->status & TD_CTRL_IOC)
- uhci_remove_irq_list(uhci, td);
- uhci_free_td(td);
-
- td = next;
- }
-
- if (notfinished)
- uhci_start_hc_schedule(uhci);
-
- kfree(urbp);
- urb->hcpriv = NULL;
-
- uhci_remove_urb_list(uhci, urb);
-
- return 0;
-}
-
static int uhci_result_isochronous(urb_t *urb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
@@ -1082,19 +997,17 @@ static int uhci_result_isochronous(urb_t *urb)
int status;
int i, ret = 0;
- td = urbp->end;
- if (!td) /* Nothing to do */
+ if (!urbp)
return -EINVAL;
- status = uhci_status_bits(td->status);
- if (status & TD_CTRL_ACTIVE)
- return -EINPROGRESS;
-
urb->actual_length = 0;
- for (i = 0, td = urbp->begin; td; i++, td = td->next) {
+ for (i = 0, td = urbp->list.begin; td; i++, td = td->list.next) {
int actlength;
+ if (td->status & TD_CTRL_ACTIVE)
+ return -EINPROGRESS;
+
actlength = uhci_actual_length(td->status);
urb->iso_frame_desc[i].actual_length = actlength;
urb->actual_length += actlength;
@@ -1114,17 +1027,26 @@ static int uhci_submit_urb(urb_t *urb)
{
int ret = -EINVAL;
struct uhci *uhci;
+ unsigned long flags;
if (!urb)
return -EINVAL;
- if (!urb->dev || !urb->dev->bus)
+ if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
return -ENODEV;
uhci = (struct uhci *)urb->dev->bus->hcpriv;
+ /* Short circuit the virtual root hub */
if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
- return rh_submit_urb(urb); /* Virtual root hub */
+ return rh_submit_urb(urb);
+
+ spin_lock_irqsave(&urb->lock, flags);
+
+ if (!uhci_alloc_urb_priv(urb)) {
+ spin_unlock_irqrestore(&urb->lock, flags);
+ return -ENOMEM;
+ }
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
@@ -1142,20 +1064,30 @@ static int uhci_submit_urb(urb_t *urb)
}
urb->status = ret;
+
+ spin_unlock_irqrestore(&urb->lock, flags);
+
if (ret == -EINPROGRESS)
- return 0;
+ ret = 0;
+ else
+ uhci_unlink_generic(urb);
return ret;
}
/*
* Return the result of a transfer
+ *
+ * Must be called with urblist_lock acquired
*/
static void uhci_transfer_result(urb_t *urb)
{
urb_t *turb;
int proceed = 0, is_ring = 0;
int ret = -EINVAL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&urb->lock, flags);
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
@@ -1173,12 +1105,17 @@ static void uhci_transfer_result(urb_t *urb)
}
urb->status = ret;
- if (urb->status == -EINPROGRESS)
+
+ spin_unlock_irqrestore(&urb->lock, flags);
+
+ if (ret == -EINPROGRESS)
return;
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
- uhci_unlink_control(urb);
+ case PIPE_BULK:
+ case PIPE_ISOCHRONOUS:
+ uhci_unlink_generic(urb);
break;
case PIPE_INTERRUPT:
/* Interrupts are an exception */
@@ -1186,14 +1123,8 @@ static void uhci_transfer_result(urb_t *urb)
if (urb->interval)
uhci_reset_interrupt(urb);
else
- uhci_unlink_interrupt(urb);
- return;
- case PIPE_BULK:
- uhci_unlink_bulk(urb);
- break;
- case PIPE_ISOCHRONOUS:
- uhci_unlink_isochronous(urb);
- break;
+ uhci_unlink_generic(urb);
+ return; /* <-- Note the return */
}
if (urb->next) {
@@ -1231,10 +1162,32 @@ static void uhci_transfer_result(urb_t *urb)
}
}
+static int uhci_unlink_generic(urb_t *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+ struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+ if (!urbp)
+ return -EINVAL;
+
+ uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
+
+ uhci_remove_urb_list(uhci, urb);
+
+ if (urbp->qh)
+ /* The interrupt loop will reclaim the QH's */
+ uhci_remove_qh(uhci, urbp->qh);
+
+ uhci_destroy_urb_priv(urb);
+
+ return 0;
+}
+
static int uhci_unlink_urb(urb_t *urb)
{
struct uhci *uhci;
int ret = 0;
+ unsigned long flags;
if (!urb)
return -EINVAL;
@@ -1244,40 +1197,34 @@ static int uhci_unlink_urb(urb_t *urb)
uhci = (struct uhci *)urb->dev->bus->hcpriv;
+ /* Short circuit the virtual root hub */
if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
return rh_unlink_urb(urb);
if (urb->status == -EINPROGRESS) {
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- ret = uhci_unlink_control(urb);
- break;
- case PIPE_INTERRUPT:
- ret = uhci_unlink_interrupt(urb);
- break;
- case PIPE_BULK:
- ret = uhci_unlink_bulk(urb);
- break;
- case PIPE_ISOCHRONOUS:
- ret = uhci_unlink_isochronous(urb);
- break;
- }
+ uhci_unlink_generic(urb);
- if (urb->complete)
- urb->complete(urb);
+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+ spin_lock_irqsave(&uhci->urb_remove_lock, flags);
+ list_add(&urb->urb_list, &uhci->urb_remove_list);
+ spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
-#ifndef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
- if (in_interrupt()) { /* wait at least 1 frame */
- int errorcount = 10;
+ urb->status = -ECONNABORTED;
+ } else {
+ if (in_interrupt()) { /* wait at least 1 frame */
+ static int errorcount = 10;
- if (errorcount--)
- dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
- udelay(1000);
- } else
- schedule_timeout(1+1*HZ/1000);
-#endif
+ if (errorcount--)
+ dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
+ udelay(1000);
+ } else
+ schedule_timeout(1+1*HZ/1000);
- urb->status = -ENOENT;
+ if (urb->complete)
+ urb->complete(urb);
+
+ urb->status = -ENOENT;
+ }
}
return ret;
@@ -1412,9 +1359,12 @@ static int rh_init_int_timer(urb_t *urb);
static void rh_int_timer_do(unsigned long ptr)
{
- int len;
- urb_t *urb = (urb_t *)ptr;
+ urb_t *urb = (urb_t *)ptr, *u;
struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+ struct list_head *tmp, *head = &uhci->urb_list;
+ struct urb_priv *urbp;
+ int len;
+ unsigned long flags;
if (uhci->rh.send) {
len = rh_send_irq(urb);
@@ -1425,6 +1375,21 @@ static void rh_int_timer_do(unsigned long ptr)
}
}
+ nested_lock(&uhci->urblist_lock, flags);
+ tmp = head->next;
+ while (tmp != head) {
+ u = list_entry(tmp, urb_t, urb_list);
+
+ urbp = (struct urb_priv *)u->hcpriv;
+ if (urbp) {
+ if (urbp->fsbr && time_after(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+ uhci_dec_fsbr(uhci, u);
+ }
+
+ tmp = tmp->next;
+ }
+ nested_unlock(&uhci->urblist_lock, flags);
+
rh_init_int_timer(urb);
}
@@ -1645,6 +1610,27 @@ static int rh_unlink_urb(urb_t *urb)
}
/*-------------------------------------------------------------------*/
+void uhci_free_pending_qhs(struct uhci *uhci)
+{
+ struct list_head *tmp, *head;
+ unsigned long flags;
+
+ /* Free any pending QH's */
+ spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+ head = &uhci->qh_remove_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
+
+ tmp = tmp->next;
+
+ list_del(&qh->remove_list);
+
+ uhci_free_qh(qh);
+ }
+ spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+}
+
static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
{
struct uhci *uhci = __uhci;
@@ -1652,7 +1638,6 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
unsigned short status;
unsigned long flags;
struct list_head *tmp, *head;
- urb_t *urb;
/*
* Read the interrupt status, and write it back to clear the
@@ -1676,55 +1661,36 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
}
}
- /* Walk the list of pending TD's to see which ones completed.. */
- nested_lock(&uhci->irqlist_lock, flags);
- head = &uhci->interrupt_list;
+ uhci_free_pending_qhs(uhci);
+
+ spin_lock(&uhci->urb_remove_lock);
+ head = &uhci->urb_remove_list;
tmp = head->next;
while (tmp != head) {
- struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
-
- urb = td->urb;
+ struct urb *urb = list_entry(tmp, struct urb, urb_list);
tmp = tmp->next;
- /* Checks the status and does all of the magic necessary */
- uhci_transfer_result(urb);
- }
- nested_unlock(&uhci->irqlist_lock, flags);
-}
-
-static void uhci_stop_hc_schedule(struct uhci *uhci)
-{
-#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
- unsigned int cmdreg, timeout = 1000;
-
- cmdreg = inw(uhci->io_addr + USBCMD);
- outw(cmdreg & ~USBCMD_RS, uhci->io_addr + USBCMD);
+ list_del(&urb->urb_list);
- while (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
- if (!--timeout) {
- printk(KERN_ERR "uhci: stop_hc_schedule failed, HC still running\n");
- break;
- }
+ if (urb->complete)
+ urb->complete(urb);
}
-#endif
-}
+ spin_unlock(&uhci->urb_remove_lock);
-static void uhci_start_hc_schedule(struct uhci *uhci)
-{
-#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
- unsigned int cmdreg, timeout = 1000;
+ /* Walk the list of pending TD's to see which ones completed */
+ nested_lock(&uhci->urblist_lock, flags);
+ head = &uhci->urb_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct urb *urb = list_entry(tmp, struct urb, urb_list);
- cmdreg = inw(uhci->io_addr + USBCMD);
- outw(cmdreg | USBCMD_RS, uhci->io_addr + USBCMD);
+ tmp = tmp->next;
- while (inw(uhci->io_addr + USBSTS) & USBSTS_HCH) {
- if (!--timeout) {
- printk(KERN_ERR "uhci: start_hc_schedule failed, HC still halted\n");
- break;
- }
+ /* Checks the status and does all of the magic necessary */
+ uhci_transfer_result(urb);
}
-#endif
+ nested_unlock(&uhci->urblist_lock, flags);
}
static void reset_hc(struct uhci *uhci)
@@ -1780,7 +1746,7 @@ static void start_hc(struct uhci *uhci)
* of the queues. We don't do that here, because
* we'll create the actual TD entries on demand.
* - The first queue is the "interrupt queue".
- * - The second queue is the "control queue".
+ * - The second queue is the "control queue", split into low and high speed
* - The third queue is "bulk data".
*/
static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
@@ -1799,14 +1765,16 @@ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
uhci->io_addr = io_addr;
uhci->io_size = io_size;
- INIT_LIST_HEAD(&uhci->interrupt_list);
- INIT_LIST_HEAD(&uhci->urb_list);
+ spin_lock_init(&uhci->qh_remove_lock);
+ INIT_LIST_HEAD(&uhci->qh_remove_list);
+
+ spin_lock_init(&uhci->urb_remove_lock);
+ INIT_LIST_HEAD(&uhci->urb_remove_list);
- spin_lock_init(&uhci->framelist_lock);
nested_init(&uhci->urblist_lock);
- nested_init(&uhci->irqlist_lock);
+ INIT_LIST_HEAD(&uhci->urb_list);
- uhci->fsbr = 0;
+ spin_lock_init(&uhci->framelist_lock);
/* We need exactly one page (per UHCI specs), how convenient */
/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
@@ -1870,8 +1838,12 @@ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
uhci->skel_bulk_qh.link = virt_to_bus(&uhci->skel_term_qh) | UHCI_PTR_QH;
uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
+ /* This dummy TD is to work around a bug in Intel PIIX controllers */
+ uhci_fill_td(&uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+ uhci->skel_term_td.link = UHCI_PTR_TERM;
+
uhci->skel_term_qh.link = UHCI_PTR_TERM;
- uhci->skel_term_qh.element = UHCI_PTR_TERM;
+ uhci->skel_term_qh.element = virt_to_bus(&uhci->skel_term_td);
/*
* Fill the frame list: make all entries point to
@@ -2022,23 +1994,24 @@ static int found_uhci(struct pci_dev *dev)
dev->resource[i].end - dev->resource[i].start + 1;
/* IO address? */
- if (!(dev->resource[i].flags & 1))
+ if (!(dev->resource[i].flags & IORESOURCE_IO))
continue;
/* Is it already in use? */
if (check_region(io_addr, io_size))
break;
- /* disable legacy emulation */
- pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
- pci_enable_device(dev);
-
if (!dev->irq) {
err("found UHCI device with no IRQ assigned. check BIOS settings!");
continue;
}
+ /* disable legacy emulation */
+ pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+ if (pci_enable_device(dev) < 0)
+ continue;
+
return setup_uhci(dev, dev->irq, io_addr, io_size);
}
@@ -2081,6 +2054,12 @@ int uhci_init(void)
if (!uhci_qh_cachep)
goto qh_failed;
+ uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
+ sizeof(struct urb_priv), 0, 0, NULL, NULL);
+
+ if (!uhci_up_cachep)
+ goto up_failed;
+
retval = -ENODEV;
dev = NULL;
for (;;) {
@@ -2105,6 +2084,10 @@ int uhci_init(void)
return 0;
init_failed:
+ if (kmem_cache_destroy(uhci_up_cachep))
+ printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+up_failed:
if (kmem_cache_destroy(uhci_qh_cachep))
printk(KERN_INFO "uhci: not all QH's were freed\n");
@@ -2118,13 +2101,13 @@ td_failed:
void uhci_cleanup(void)
{
- struct list_head *next, *tmp, *head = &uhci_list;
+ struct list_head *tmp, *head = &uhci_list;
tmp = head->next;
while (tmp != head) {
struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
- next = tmp->next;
+ tmp = tmp->next;
list_del(&uhci->uhci_list);
INIT_LIST_HEAD(&uhci->uhci_list);
@@ -2137,11 +2120,14 @@ void uhci_cleanup(void)
reset_hc(uhci);
release_region(uhci->io_addr, uhci->io_size);
- release_uhci(uhci);
+ uhci_free_pending_qhs(uhci);
- tmp = next;
+ release_uhci(uhci);
}
+ if (kmem_cache_destroy(uhci_up_cachep))
+ printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
if (kmem_cache_destroy(uhci_qh_cachep))
printk(KERN_INFO "uhci: not all QH's were freed\n");
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
index 88891ea89..62d4e772e 100644
--- a/drivers/usb/uhci.h
+++ b/drivers/usb/uhci.h
@@ -2,8 +2,7 @@
#define __LINUX_UHCI_H
#include <linux/list.h>
-
-#include "usb.h"
+#include <linux/usb.h>
/*
* This nested spinlock code is courtesy of Davide Libenzi <dlibenzi@maticad.it>
@@ -106,11 +105,12 @@ struct uhci_qh {
__u32 element; /* Queue element pointer */
/* Software fields */
- struct uhci_qh *prevqh, *nextqh; /* Previous and next TD in queue */
+ /* Can't use list_head since we want a specific order */
+ struct uhci_qh *prevqh, *nextqh;
struct usb_device *dev; /* The owning device */
- struct list_head list;
+ struct list_head remove_list;
} __attribute__((aligned(16)));
struct uhci_framelist {
@@ -184,10 +184,10 @@ struct uhci_td {
struct usb_device *dev;
struct urb *urb; /* URB this TD belongs to */
- struct uhci_td *next; /* List of chained TD's for an URB */
-
- struct list_head irq_list; /* Active interrupt list.. */
- struct list_head list;
+ /* We can't use list_head since we need a specific order */
+ struct ut_list {
+ struct uhci_td *prev, *next;
+ } list;
} __attribute__((aligned(16)));
/*
@@ -233,7 +233,7 @@ struct uhci_td {
* labels (below) are only signficant to the root hub's QH's
*/
-#define UHCI_NUM_SKELTD 9
+#define UHCI_NUM_SKELTD 10
#define skel_int1_td skeltd[0]
#define skel_int2_td skeltd[1]
#define skel_int4_td skeltd[2]
@@ -243,6 +243,7 @@ struct uhci_td {
#define skel_int64_td skeltd[6]
#define skel_int128_td skeltd[7]
#define skel_int256_td skeltd[8]
+#define skel_term_td skeltd[9] /* To work around PIIX UHCI bug */
#define UHCI_NUM_SKELQH 4
#define skel_ls_control_qh skelqh[0]
@@ -306,6 +307,7 @@ struct virt_root_hub {
* a subset of what the full implementation needs.
*/
struct uhci {
+ /* Grabbed from PCI */
int irq;
unsigned int io_addr;
unsigned int io_size;
@@ -317,25 +319,32 @@ struct uhci {
struct uhci_td skeltd[UHCI_NUM_SKELTD]; /* Skeleton TD's */
struct uhci_qh skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
+ spinlock_t framelist_lock;
struct uhci_framelist *fl; /* Frame list */
+ int fsbr; /* Full speed bandwidth reclamation */
- struct s_nested_lock irqlist_lock;
- struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */
+ spinlock_t qh_remove_lock;
+ struct list_head qh_remove_list;
+
+ spinlock_t urb_remove_lock;
+ struct list_head urb_remove_list;
struct s_nested_lock urblist_lock;
struct list_head urb_list;
- spinlock_t framelist_lock;
-
- int fsbr; /* Full speed bandwidth reclamation */
-
struct virt_root_hub rh; /* private data of the virtual root hub */
};
struct urb_priv {
struct uhci_qh *qh; /* QH for this URB */
- struct uhci_td *begin;
- struct uhci_td *end;
+
+ int fsbr;
+
+ unsigned long inserttime; /* In jiffies */
+
+ struct up_list {
+ struct uhci_td *begin, *end;
+ } list;
};
/* -------------------------------------------------------------------------
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index 0d6457965..2bba728d9 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -13,8 +13,7 @@
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/config.h>
-
-#include "usb.h"
+#include <linux/usb.h>
/*
* USB core
diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c
index df72e0abc..bc04d1fca 100644
--- a/drivers/usb/usb-debug.c
+++ b/drivers/usb/usb-debug.c
@@ -9,8 +9,7 @@
#include <linux/mm.h>
#include <linux/malloc.h>
#define DEBUG
-
-#include "usb.h"
+#include <linux/usb.h>
static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
{
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 9bc136420..cf457762a 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -41,16 +41,16 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h> /* for in_interrupt() */
+#undef DEBUG
+#include <linux/usb.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
-#undef DEBUG
#define OHCI_USE_NPS
-#include "usb.h"
#include "usb-ohci.h"
#include <linux/pm.h>
@@ -1675,20 +1675,24 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
static int hc_start_ohci (struct pci_dev * dev)
{
- u32 cmd;
+ unsigned long mem_base;
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
- unsigned long mem_base = dev->resource[0].start;
+ mem_base = dev->resource[0].start;
+ if (pci_enable_device(dev) < 0)
+ return -ENODEV;
#else
- unsigned long mem_base = dev->base_address[0];
+ u16 cmd;
+
+ mem_base = dev->base_address[0];
if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ /* Some Mac firmware will switch memory response off */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
#endif
- /* Some Mac firmware will switch memory response off */
- pci_read_config_dword(dev, PCI_COMMAND, &cmd);
- cmd = (cmd | PCI_COMMAND_MEMORY);
- pci_write_config_dword(dev, PCI_COMMAND, cmd);
-
pci_set_master (dev);
mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index dd340589f..0e2ab20a4 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -30,13 +30,13 @@
#include <linux/malloc.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
+#include <linux/usb.h>
#include <linux/blk.h>
#include "../scsi/scsi.h"
#include "../scsi/hosts.h"
#include "../scsi/sd.h"
-#include "usb.h"
#include "usb-storage.h"
#include "usb-storage-debug.h"
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index 1b72efd92..aed79f849 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -28,6 +28,9 @@
#include <linux/unistd.h>
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/init.h>
+/* This enables debug printks */
+#define DEBUG
+#include <linux/usb.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -37,16 +40,12 @@
/* This enables more detailed sanity checks in submit_iso */
//#define ISO_SANITY_CHECK
-/* This enables debug printks */
-#define DEBUG
-
/* This enables all symbols to be exported, to ease debugging oopses */
//#define DEBUG_SYMBOLS
/* This enables an extra UHCI slab for memory debugging */
#define DEBUG_SLAB
-#include "usb.h"
#include "usb-uhci.h"
#include "usb-uhci-debug.h"
@@ -2408,7 +2407,7 @@ _static int __init start_uhci (struct pci_dev *dev)
unsigned int io_addr = dev->resource[i].start;
unsigned int io_size =
dev->resource[i].end - dev->resource[i].start + 1;
- if (!(dev->resource[i].flags & 1))
+ if (!(dev->resource[i].flags & IORESOURCE_IO))
continue;
#else
unsigned int io_addr = dev->base_address[i];
@@ -2464,7 +2463,8 @@ int __init uhci_init (void)
continue;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
- pci_enable_device (dev);
+ if (pci_enable_device (dev) < 0)
+ continue;
#endif
if(!dev->irq)
{
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 6b9eba17a..df8fe9b38 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -24,10 +24,8 @@
#include <linux/bitops.h>
#include <linux/malloc.h>
#include <linux/interrupt.h> /* for in_interrupt() */
-
#define DEBUG
-
-#include "usb.h"
+#include <linux/usb.h>
/*
* Prototypes for the device driver probing/loading functions
@@ -475,30 +473,34 @@ void usb_inc_dev_use(struct usb_device *dev)
* New USB Core Functions
* -------------------------------------------------------------------------------------*/
-urb_t* usb_alloc_urb(int iso_packets)
+urb_t *usb_alloc_urb(int iso_packets)
{
urb_t *urb;
- urb=(urb_t*)kmalloc(sizeof(urb_t) + iso_packets*sizeof(iso_packet_descriptor_t),
+
+ urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t),
in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
- if (!urb)
- {
+ if (!urb) {
err("alloc_urb: kmalloc failed");
- return 0;
+ return NULL;
}
- memset(urb,0,sizeof(urb_t));
+
+ memset(urb, 0, sizeof(*urb));
+
+ spin_lock_init(&urb->lock);
+
return urb;
}
/*-------------------------------------------------------------------*/
void usb_free_urb(urb_t* urb)
{
- if(urb)
+ if (urb)
kfree(urb);
}
/*-------------------------------------------------------------------*/
int usb_submit_urb(urb_t *urb)
{
- if(urb && urb->dev)
+ if (urb && urb->dev)
return urb->dev->bus->op->submit_urb(urb);
else
return -1;
@@ -507,7 +509,7 @@ int usb_submit_urb(urb_t *urb)
/*-------------------------------------------------------------------*/
int usb_unlink_urb(urb_t *urb)
{
- if(urb && urb->dev)
+ if (urb && urb->dev)
return urb->dev->bus->op->unlink_urb(urb);
else
return -1;
@@ -537,10 +539,10 @@ static void usb_api_blocking_completion(urb_t *urb)
*-------------------------------------------------------------------*/
static void usb_api_async_completion(urb_t *urb)
{
- api_wrapper_data *awd=(api_wrapper_data*)urb->context;
+ api_wrapper_data *awd = (api_wrapper_data *)urb->context;
if (awd->handler)
- awd->handler(urb->status,urb->transfer_buffer,urb->actual_length,awd->stuff);
+ awd->handler(urb->status, urb->transfer_buffer, urb->actual_length, awd->stuff);
}
/*-------------------------------------------------------------------*
@@ -555,13 +557,13 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
api_wrapper_data awd;
int status;
- awd.wakeup=&wqh;
- awd.handler=0;
+ awd.wakeup = &wqh;
+ awd.handler = 0;
init_waitqueue_head(&wqh);
current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&wqh, &wait);
- urb->context=&awd;
- status=usb_submit_urb(urb);
+ urb->context = &awd;
+ status = usb_submit_urb(urb);
if (status) {
// something went wrong
usb_free_urb(urb);
@@ -581,13 +583,12 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
// timeout
printk("usb_control/bulk_msg: timeout\n");
usb_unlink_urb(urb); // remove urb safely
- status=-ETIMEDOUT;
- }
- else
- status=urb->status;
+ status = -ETIMEDOUT;
+ } else
+ status = urb->status;
if (actual_length)
- *actual_length=urb->actual_length;
+ *actual_length = urb->actual_length;
usb_free_urb(urb);
return status;
@@ -602,20 +603,21 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
int retv;
int length;
- urb=usb_alloc_urb(0);
+ urb = usb_alloc_urb(0);
if (!urb)
return -ENOMEM;
FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len, /* build urb */
(usb_complete_t)usb_api_blocking_completion,0);
- retv=usb_start_wait_urb(urb,timeout, &length);
+ retv = usb_start_wait_urb(urb, timeout, &length);
if (retv < 0)
return retv;
else
return length;
}
+
/*-------------------------------------------------------------------*/
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
@@ -623,7 +625,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
int ret;
- if(!dr)
+ if (!dr)
return -ENOMEM;
dr->requesttype = requesttype;
@@ -634,7 +636,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
//dbg("usb_control_msg");
- ret=usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+ ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
kfree(dr);
diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c
index ebc8ab45b..6eb49248c 100644
--- a/drivers/usb/usbkbd.c
+++ b/drivers/usb/usbkbd.c
@@ -33,7 +33,7 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
-#include "usb.h"
+#include <linux/usb.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
diff --git a/drivers/usb/usbmouse.c b/drivers/usb/usbmouse.c
index 75e834649..a6d0fe8cf 100644
--- a/drivers/usb/usbmouse.c
+++ b/drivers/usb/usbmouse.c
@@ -33,7 +33,7 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
-#include "usb.h"
+#include <linux/usb.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
diff --git a/drivers/usb/uss720.c b/drivers/usb/uss720.c
index d4db8546e..bddf6fe57 100644
--- a/drivers/usb/uss720.c
+++ b/drivers/usb/uss720.c
@@ -41,8 +41,7 @@
#include <linux/socket.h>
#include <linux/parport.h>
#include <linux/init.h>
-
-#include "usb.h"
+#include <linux/usb.h>
/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/wacom.c b/drivers/usb/wacom.c
index c67d30a60..6dc9ab480 100644
--- a/drivers/usb/wacom.c
+++ b/drivers/usb/wacom.c
@@ -1,9 +1,10 @@
/*
- * wacom.c Version 0.3
+ * wacom.c Version 0.4
*
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
* Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
+ * Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
*
* USB Wacom Graphire and Wacom Intuos tablet support
*
@@ -13,6 +14,8 @@
* v0.1 (vp) - Initial release
* v0.2 (aba) - Support for all buttons / combinations
* v0.3 (vp) - Support for Intuos added
+ * v0.4 (sm) - Support for more Intuos models, menustrip,
+ * relative mode, proximity.
*/
/*
@@ -40,7 +43,7 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
-#include "usb.h"
+#include <linux/usb.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -72,16 +75,16 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
*
* (0,0) is upper left corner
*
- * Wacom Intuos packet:
+ * Wacom Intuos Status packet:
*
* byte 0: report ID (2)
- * byte 1: bit7 1 ?
- * bit6 tilt (pressure?) data valid
- * bit5 near
+ * byte 1: bit7 1 (Sync Byte)
+ * bit6 Pointer Near
+ * bit5 0 - first proximity report
* bit4 0 ?
* bit3 0 ?
- * bit2 pen button
- * bit1 first packet (contains other infos)
+ * bit2 pen button2
+ * bit1 pen button1
* bit0 0 ?
* byte 2: X high bits
* byte 3: X low bits
@@ -92,22 +95,89 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
* byte 7: bits 0-5: X tilt (bits 1-6)
* byte 8: bit 7: X tilt (bit 0)
* byte 8: bits 0-6: Y tilt (bits 0-6)
- * byte 9: ?
+ * byte 9: bits 4-7: Proximity
*/
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS 0x0021
+#define USB_DEVICE_ID_WACOM_INTUOS45 0x0020 /* Guess */
+#define USB_DEVICE_ID_WACOM_INTUOS68 0x0021
+#define USB_DEVICE_ID_WACOM_INTUOS912 0x0022 /* Guess */
+#define USB_DEVICE_ID_WACOM_INTUOS1212 0x0023
+#define USB_DEVICE_ID_WACOM_INTUOS1218 0x0024 /* Guess */
+
+#define USB_TOOL_ID_WACOM_PEN 0x0022
+#define USB_TOOL_ID_WACOM_ERASER 0x00fa
+#define USB_TOOL_ID_WACOM_STROKE_PEN 0x0032
+#define USB_TOOL_ID_WACOM_INKING_PEN 0x0012
+#define USB_TOOL_ID_WACOM_AIRBRUSH 0x0112
+#define USB_TOOL_ID_WACOM_MOUSE4D 0x0094
+#define USB_TOOL_ID_WACOM_LENS_CURSOR 0x0096
+
+#define INTUOS_PEN_MODE_ABS 0x00
+#define INTUOS_PEN_MODE_REL 0x01
+#define INTUOS_PEN_MODE_QUICKPOINT 0x02
+
+#define INTUOS_PRESSURE_MODE_SOFT 0x00
+#define INTUOS_PRESSURE_MODE_MED 0x01
+#define INTUOS_PRESSURE_MODE_FIRM 0x02
+
+#define INTUOS_MENUSTRIP_Y_ZONE 1400
+#define INTUOS_MENUSTRIP_BTN_YMIN 270
+#define INTUOS_MENUSTRIP_BTN_YMAX 1070
+#define INTUOS_MENUSTRIP_F1_XMIN 40
+#define INTUOS_MENUSTRIP_F7_XMIN 8340
+#define INTUOS_MENUSTRIP_F12_XMIN 15300
+
+#define INTUOS_MENUSTRIP_BTN_WIDTH 1300
+
+#define INTUOS_MENUSTRIP_F7_IX_OFFSET 6 /* offset into wacom_fkeys */
+#define INTUOS_MENUSTRIP_F12_IX_OFFSET 11
struct wacom {
- signed char data[12];
+ signed char data[10];
struct input_dev dev;
struct urb irq;
+
+ int last_x, last_y;
+ unsigned int tool, device;
+ unsigned int ymax, menustrip_touch;
+ unsigned int pen_mode;
+ unsigned int pressure_mode;
};
+static int wacom_fkeys[16] = { KEY_F1, KEY_F2, KEY_F3, KEY_F4,
+ KEY_F5, KEY_F6, KEY_F7, KEY_F8,
+ KEY_F9, KEY_F10, KEY_F11, KEY_F12,
+ KEY_F13, KEY_F14, KEY_F15, KEY_F16};
+
+#define INTUOS_EXTENTS_MAX_X 0x00
+#define INTUOS_EXTENTS_MAX_Y 0x01
+#define INTUOS_EXTENTS_HAS_F7 0x02
+#define INTUOS_EXTENTS_HAS_F12 0x03
+#define INTUOS_EXTENTS_PEN_MODE 0x04
+#define INTUOS_EXTENTS_HAS_QUICKPOINT 0x05
+#define INTUOS_EXTENTS_HAS_PRESSURE_MODE 0x06
+#define INTUOS_EXTENTS_PRESSURE_MODE 0x07
+
+#define WACOM_TRUE 1
+#define WACOM_FALSE 0
+
+static int intuos_extents[5][8] = {
+ { 12700, 10360, WACOM_FALSE, WACOM_FALSE, 8340, WACOM_FALSE, WACOM_FALSE, 0}, /* Intuos 4x5 */
+ { 20320, 15040, WACOM_TRUE, WACOM_FALSE, 15300, WACOM_FALSE, WACOM_TRUE, 18360}, /* Intuos 6x8 */
+ { 30480, 23060, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 9x12 */
+ { 30480, 30480, WACOM_TRUE, WACOM_TRUE, 22280, WACOM_TRUE, WACOM_TRUE, 26640}, /* Intuos 12x12 */
+ { 47720, 30480, WACOM_TRUE, WACOM_TRUE, 29260, WACOM_TRUE, WACOM_TRUE, 33620}}; /* Intuos 12x18 */
+
+static char intuos_names[5][12] = {
+ {"Intuos 4x5 "}, {"Intuos 6x8 "},
+ {"Intuos 9x12 "}, {"Intuos 12x12"},
+ {"Intuos 12x18"}};
+
static void wacom_graphire_irq(struct urb *urb)
{
- struct wacom *wacom = urb->context;
+ struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
@@ -123,65 +193,204 @@ static void wacom_graphire_irq(struct urb *urb)
switch ((data[1] >> 5) & 3) {
- case 0: /* Pen */
- input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80);
- input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
- break;
+ case 0: /* Pen */
+ input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x80);
+ input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
+ input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
+ input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
+ input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+ break;
+
+ case 1: /* Rubber */
+ input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
+ input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
+ input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
+ input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
+ input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+ break;
+
+ case 2: /* Mouse */
+ input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24);
+ input_report_btn(dev, BTN_LEFT, data[1] & 0x01);
+ input_report_btn(dev, BTN_RIGHT, data[1] & 0x02);
+ input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04);
+ input_report_abs(dev, ABS_DISTANCE, data[7]);
+ input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+ break;
+ }
+}
- case 1: /* Rubber */
- input_report_btn(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
- input_report_btn(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
- break;
+static void intuos_menustrip( unsigned int x, unsigned int y, struct wacom *wacom )
+{
+ struct input_dev *dev = &wacom->dev;
+ unsigned int local_x = x;
+ unsigned int local_y = y - ( wacom->ymax - INTUOS_MENUSTRIP_Y_ZONE );
+ unsigned int fkey_index ;
+
+ /* Ensure we are in the vertical strip for the buttons */
+ if ( (local_y > INTUOS_MENUSTRIP_BTN_YMIN) && (local_y < INTUOS_MENUSTRIP_BTN_YMAX) ) {
+
+ /* Handle Pressure Mode */
+ if ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_PRESSURE_MODE] ) {
+ int pressure_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PRESSURE_MODE])
+ / INTUOS_MENUSTRIP_BTN_WIDTH );
+ if ( ( pressure_mode >= INTUOS_PRESSURE_MODE_SOFT ) &&
+ ( pressure_mode <= INTUOS_PRESSURE_MODE_FIRM ) ) {
+ wacom->pressure_mode = pressure_mode;
+ return;
+ }
+ }
+
+ /* Handle Pen Mode */
+ {
+ int pen_mode = ( (local_x - intuos_extents[wacom->device][INTUOS_EXTENTS_PEN_MODE])
+ / INTUOS_MENUSTRIP_BTN_WIDTH );
+ if ( ( pen_mode == INTUOS_PEN_MODE_ABS ) ||
+ ( pen_mode == INTUOS_PEN_MODE_REL ) ||
+ ( ( pen_mode == INTUOS_PEN_MODE_QUICKPOINT ) &&
+ ( intuos_extents[wacom->device][INTUOS_EXTENTS_HAS_QUICKPOINT] ) ) ) {
+ wacom->pen_mode = pen_mode;
+ return;
+ }
+ }
+
+ /* Handle Function Keys */
+ if ( local_x > INTUOS_MENUSTRIP_F12_XMIN ) {
+ fkey_index = INTUOS_MENUSTRIP_F12_IX_OFFSET
+ + ( (local_x - INTUOS_MENUSTRIP_F12_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
+ fkey_index = ( fkey_index > 16 ) ? 16 : fkey_index; /* Ensure in range */
+ }
+ else if ( local_x > INTUOS_MENUSTRIP_F7_XMIN ) {
+ fkey_index = INTUOS_MENUSTRIP_F7_IX_OFFSET
+ + ( (local_x - INTUOS_MENUSTRIP_F7_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
+ fkey_index = ( fkey_index > 11 ) ? 11 : fkey_index;
+ }
+ else {
+ fkey_index = ( (local_x - INTUOS_MENUSTRIP_F1_XMIN) / INTUOS_MENUSTRIP_BTN_WIDTH );
+ fkey_index = ( fkey_index > 6 ) ? 6 : fkey_index;
+ }
+ input_report_key(dev, wacom_fkeys[fkey_index], 1);
+ input_report_key(dev, wacom_fkeys[fkey_index], 0);
- case 2: /* Mouse */
- input_report_btn(dev, BTN_TOOL_MOUSE, data[7] > 24);
- input_report_btn(dev, BTN_LEFT, data[1] & 0x01);
- input_report_btn(dev, BTN_RIGHT, data[1] & 0x02);
- input_report_btn(dev, BTN_MIDDLE, data[1] & 0x04);
- input_report_abs(dev, ABS_DISTANCE, data[7]);
- input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
- break;
+ return;
}
}
-
+
static void wacom_intuos_irq(struct urb *urb)
{
- struct wacom *wacom = urb->context;
+ struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
unsigned int t;
+ int x, y;
if (urb->status) return;
if (data[0] != 2)
dbg("received unknown report #%d", data[0]);
- if (data[1] & 0x02) /* First record, weird data */
+ if ( ((data[1] >> 5) & 0x3) == 0x2 ) /* First record, feature report */
+ {
+ wacom->tool = (((char)data[2] << 4) | (char)data[3] >> 4) & 0xff ;
+ /* Report tool type */
+ switch ( wacom->tool ) {
+ case USB_TOOL_ID_WACOM_PEN:
+ input_report_btn(dev, BTN_TOOL_PEN, 1);
+ break;
+ case USB_TOOL_ID_WACOM_ERASER:
+ input_report_btn(dev, BTN_TOOL_RUBBER, 1);
+ break;
+ case USB_TOOL_ID_WACOM_STROKE_PEN:
+ input_report_btn(dev, BTN_TOOL_BRUSH, 1);
+ break;
+ case USB_TOOL_ID_WACOM_INKING_PEN:
+ input_report_btn(dev, BTN_TOOL_PENCIL, 1);
+ break;
+ case USB_TOOL_ID_WACOM_AIRBRUSH:
+ input_report_btn(dev, BTN_TOOL_AIRBRUSH, 1);
+ break;
+ case USB_TOOL_ID_WACOM_MOUSE4D:
+ case USB_TOOL_ID_WACOM_LENS_CURSOR:
+ input_report_btn(dev, BTN_TOOL_MOUSE, 1);
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+
+ if ( ( data[1] | data[2] | data[3] | data[4] | data[5] | data[6]
+ | data[7] | data[8] | data[9] ) == 0x80 ) { /* exit report */
+ switch ( wacom->tool ) {
+ case USB_TOOL_ID_WACOM_PEN:
+ input_report_btn(dev, BTN_TOOL_PEN, 0);
+ break;
+ case USB_TOOL_ID_WACOM_ERASER:
+ input_report_btn(dev, BTN_TOOL_RUBBER, 0);
+ break;
+ case USB_TOOL_ID_WACOM_STROKE_PEN:
+ input_report_btn(dev, BTN_TOOL_BRUSH, 0);
+ break;
+ case USB_TOOL_ID_WACOM_INKING_PEN:
+ input_report_btn(dev, BTN_TOOL_PENCIL, 0);
+ break;
+ case USB_TOOL_ID_WACOM_AIRBRUSH:
+ input_report_btn(dev, BTN_TOOL_AIRBRUSH, 0);
+ break;
+ case USB_TOOL_ID_WACOM_MOUSE4D:
+ case USB_TOOL_ID_WACOM_LENS_CURSOR:
+ input_report_btn(dev, BTN_TOOL_MOUSE, 0);
+ break;
+ default:
+ break;
+ }
return;
-
- if (data[1] & 0x20) { /* Near */
- input_report_abs(dev, ABS_X, (((unsigned int) data[2]) << 8) | data[3]);
- input_report_abs(dev, ABS_Y, 16240 - ((((unsigned int) data[4]) << 8) | data[5]));
}
- input_report_btn(dev, BTN_TOOL_PEN, data[1] & 0x20);
- input_report_btn(dev, BTN_STYLUS, data[1] & 0x04);
+ x = (((unsigned int) data[2]) << 8) | data[3] ;
+ y = wacom->dev.absmax[ABS_Y] - ((((unsigned int) data[4]) << 8) | data[5]);
t = (((unsigned int) data[6]) << 2) | ((data[7] & 0xC0) >> 6);
+ /* Handle touch near menustrip */
+ if ( y > ( wacom->dev.absmax[ABS_Y] - INTUOS_MENUSTRIP_Y_ZONE ) ) {
+ if ( t > 10 ) /* Touch */
+ wacom->menustrip_touch = 1;
+ if ( (wacom->menustrip_touch) && (t <= 10) ) { /* Pen Up */
+ intuos_menustrip( x, y, wacom );
+ wacom->menustrip_touch = 0;
+ }
+ return;
+ }
+ else
+ wacom->menustrip_touch = 0;
+
+ switch ( wacom->pen_mode ) {
+ case INTUOS_PEN_MODE_ABS:
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ break;
+ case INTUOS_PEN_MODE_REL:
+ input_report_rel(dev, REL_X, ( x - wacom->last_x) / 8 );
+ input_report_rel(dev, REL_Y, - ( y - wacom->last_y) / 8 );
+ break;
+ default: break;
+ }
+
+ wacom->last_x = x;
+ wacom->last_y = y;
+
+ input_report_btn(dev, BTN_STYLUS, data[1] & 0x02);
+ input_report_btn(dev, BTN_STYLUS2, data[1] & 0x04);
+
input_report_btn(dev, BTN_TOUCH, t > 10);
input_report_abs(dev, ABS_PRESSURE, t);
- if (data[1] & 0x40) { /* Tilt data */
- input_report_abs(dev, ABS_TILT_X, ((((unsigned int) data[7]) & 0x3f) << 1) | ((data[8] & 0x80) >> 7));
- input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
- }
+ input_report_abs(dev, ABS_DISTANCE, ( data[9] & 0xf0 ) >> 4 );
+
+ input_report_abs(dev, ABS_TILT_X, ((((unsigned int) data[7]) & 0x3f) << 1) | ((data[8] & 0x80) >> 7));
+ input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+
}
static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
@@ -191,8 +400,12 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
char *name;
if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM ||
- (dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_GRAPHIRE &&
- dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS))
+ (dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_GRAPHIRE &&
+ dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS45 &&
+ dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS68 &&
+ dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS912 &&
+ dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1212 &&
+ dev->descriptor.idProduct != USB_DEVICE_ID_WACOM_INTUOS1218))
return NULL;
endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
@@ -200,49 +413,57 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
memset(wacom, 0, sizeof(struct wacom));
- switch (dev->descriptor.idProduct) {
+ if ( dev->descriptor.idProduct == USB_DEVICE_ID_WACOM_GRAPHIRE ) {
+ wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
+ wacom->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE);
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+ wacom->dev.relbit[0] |= BIT(REL_WHEEL);
+ wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
- case USB_DEVICE_ID_WACOM_GRAPHIRE:
+ wacom->dev.absmax[ABS_X] = 10206;
+ wacom->dev.absmax[ABS_Y] = 7422;
+ wacom->dev.absmax[ABS_PRESSURE] = 511;
+ wacom->dev.absmax[ABS_DISTANCE] = 32;
- wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
- wacom->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
- wacom->dev.relbit[0] |= BIT(REL_WHEEL);
- wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+ FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ wacom->data, 8, wacom_graphire_irq, wacom, endpoint->bInterval);
- wacom->dev.absmax[ABS_X] = 10206;
- wacom->dev.absmax[ABS_Y] = 7422;
- wacom->dev.absmax[ABS_PRESSURE] = 511;
- wacom->dev.absmax[ABS_DISTANCE] = 32;
+ name = "Graphire";
+ }
+ else { /* Intuos */
- FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, 8, wacom_graphire_irq, wacom, endpoint->bInterval);
+ wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+ wacom->dev.keybit[LONG(KEY_F1)] |= BIT(KEY_F1) | BIT(KEY_F2) | BIT(KEY_F3) | BIT(KEY_F4) | BIT(KEY_F5);
+ wacom->dev.keybit[LONG(KEY_F6)] |= BIT(KEY_F6) | BIT(KEY_F7) | BIT(KEY_F8);
+ wacom->dev.keybit[LONG(KEY_F9)] |= BIT(KEY_F9) | BIT(KEY_F10) | BIT(KEY_F11) | BIT(KEY_F12);
+ wacom->dev.keybit[LONG(KEY_F13)] |= BIT(KEY_F13) | BIT(KEY_F14) | BIT(KEY_F15) | BIT(KEY_F16);
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_BRUSH);
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_MOUSE);
+ wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+ wacom->dev.absbit[0] |= BIT(ABS_TILT_X) | BIT(ABS_TILT_Y);
+ wacom->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
- name = "Graphire";
- break;
+ wacom->dev.absmax[ABS_PRESSURE] = 1023;
+ wacom->dev.absmax[ABS_DISTANCE] = 15;
+ wacom->dev.absmax[ABS_TILT_X] = 127;
+ wacom->dev.absmax[ABS_TILT_Y] = 127;
- case USB_DEVICE_ID_WACOM_INTUOS:
+ wacom->device = dev->descriptor.idProduct - USB_DEVICE_ID_WACOM_INTUOS45;
- wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
- wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
- wacom->dev.absbit[0] |= BIT(ABS_TILT_X) | BIT(ABS_TILT_Y);
+ wacom->dev.absmax[ABS_X] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_X];
+ wacom->dev.absmax[ABS_Y] = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y];
- wacom->dev.absmax[ABS_X] = 20320;
- wacom->dev.absmax[ABS_Y] = 16240;
- wacom->dev.absmax[ABS_PRESSURE] = 1024;
- wacom->dev.absmax[ABS_TILT_X] = 127;
- wacom->dev.absmax[ABS_TILT_Y] = 127;
+ wacom->ymax = intuos_extents[wacom->device][INTUOS_EXTENTS_MAX_Y];
+ wacom->pen_mode = INTUOS_PEN_MODE_ABS;
+ wacom->pressure_mode = INTUOS_PRESSURE_MODE_SOFT;
- FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, 8, wacom_intuos_irq, wacom, endpoint->bInterval);
+ name = intuos_names[wacom->device];
- name = "Intuos";
- break;
+ FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ wacom->data, 10, wacom_intuos_irq, wacom, endpoint->bInterval);
- default:
- return NULL;
}
if (usb_submit_urb(&wacom->irq)) {
diff --git a/drivers/usb/wmforce.c b/drivers/usb/wmforce.c
index 06ddeb5b2..1d8402f97 100644
--- a/drivers/usb/wmforce.c
+++ b/drivers/usb/wmforce.c
@@ -33,7 +33,7 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
-#include "usb.h"
+#include <linux/usb.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
diff --git a/drivers/video/Config.in b/drivers/video/Config.in
index 4de32c098..2b46f14d9 100644
--- a/drivers/video/Config.in
+++ b/drivers/video/Config.in
@@ -40,7 +40,7 @@ if [ "$CONFIG_FB" = "y" ]; then
define_bool CONFIG_FB_Q40 y
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
- bool ' Amiga native chipset support' CONFIG_FB_AMIGA
+ tristate ' Amiga native chipset support' CONFIG_FB_AMIGA
if [ "$CONFIG_FB_AMIGA" != "n" ]; then
bool ' Amiga OCS chipset support' CONFIG_FB_AMIGA_OCS
bool ' Amiga ECS chipset support' CONFIG_FB_AMIGA_ECS
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index c3d442e22..12918c1b5 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -16,7 +16,7 @@ M_OBJS :=
# All of the (potential) objects that export symbols.
# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
-export-objs := fbmem.o fbcmap.o fbcon.o fbcon-afb.o fbcon-ilbm.o \
+export-objs := fbmem.o fbcmap.o fbcon.o fbmon.o fbcon-afb.o fbcon-ilbm.o \
fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index af0a0d7c8..97df72fd2 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -53,6 +53,7 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -1131,6 +1132,7 @@ static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
*/
int amifb_init(void);
+static void amifb_deinit(void);
static int amifbcon_switch(int con, struct fb_info *info);
static int amifbcon_updatevar(int con, struct fb_info *info);
static void amifbcon_blank(int blank, struct fb_info *info);
@@ -1143,6 +1145,7 @@ static void do_install_cmap(int con, struct fb_info *info);
static int flash_cursor(void);
static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
static u_long chipalloc(u_long size);
+static void chipfree(void);
static char *strtoke(char *s,const char *ct);
/*
@@ -1181,13 +1184,6 @@ static void ami_build_copper(void);
static void ami_rebuild_copper(void);
- /*
- * External references
- */
-
-extern unsigned short ami_intena_vals[];
-
-
static struct fb_ops amifb_ops = {
amifb_open, amifb_release, amifb_get_fix, amifb_get_var,
amifb_set_var, amifb_get_cmap, amifb_set_cmap,
@@ -1599,12 +1595,35 @@ static int amifb_set_cursorstate(struct fb_cursorstate *state, int con)
/*
+ * Allocate, Clear and Align a Block of Chip Memory
+ */
+
+static u_long unaligned_chipptr = 0;
+
+static inline u_long __init chipalloc(u_long size)
+{
+ size += PAGE_SIZE-1;
+ if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
+ "amifb [RAM]")))
+ panic("No Chip RAM for frame buffer");
+ memset((void *)unaligned_chipptr, 0, size);
+ return PAGE_ALIGN(unaligned_chipptr);
+}
+
+static inline void chipfree(void)
+{
+ if (unaligned_chipptr)
+ amiga_chip_free((void *)unaligned_chipptr);
+}
+
+
+ /*
* Initialisation
*/
int __init amifb_init(void)
{
- int tag, i;
+ int tag, i, err = 0;
u_long chipptr;
u_int defmode;
struct fb_var_screeninfo var;
@@ -1625,6 +1644,13 @@ int __init amifb_init(void)
}
#endif
+ /*
+ * We request all registers starting from bplpt[0]
+ */
+ if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
+ "amifb [Denise/Lisa]"))
+ return -EBUSY;
+
custom.dmacon = DMAF_ALL | DMAF_MASTER;
switch (amiga_chipset) {
@@ -1688,7 +1714,8 @@ default_chipset:
strcat(amifb_name, "Unknown");
goto default_chipset;
#else /* CONFIG_FB_AMIGA_OCS */
- return -ENXIO;
+ err = -ENXIO;
+ goto amifb_error;
#endif /* CONFIG_FB_AMIGA_OCS */
break;
}
@@ -1738,9 +1765,37 @@ default_chipset:
fb_info.flags = FBINFO_FLAG_DEFAULT;
memset(&var, 0, sizeof(var));
+#ifdef MODULE
+ var.xres = ami_modedb[defmode].xres;
+ var.yres = ami_modedb[defmode].yres;
+ var.xres_virtual = ami_modedb[defmode].xres;
+ var.yres_virtual = ami_modedb[defmode].yres;
+ var.xoffset = 0;
+ var.yoffset = 0;
+ var.bits_per_pixel = 4;
+ var.activate |= FB_ACTIVATE_TEST;
+ var.pixclock = ami_modedb[defmode].pixclock;
+ var.left_margin = ami_modedb[defmode].left_margin;
+ var.right_margin = ami_modedb[defmode].right_margin;
+ var.upper_margin = ami_modedb[defmode].upper_margin;
+ var.lower_margin = ami_modedb[defmode].lower_margin;
+ var.hsync_len = ami_modedb[defmode].hsync_len;
+ var.vsync_len = ami_modedb[defmode].vsync_len;
+ var.sync = ami_modedb[defmode].sync;
+ var.vmode = ami_modedb[defmode].vmode;
+ err = fb_info.fbops->fb_set_var(&var, -1, &fb_info);
+ var.activate &= ~FB_ACTIVATE_TEST;
+ if (err) {
+ err = -EINVAL;
+ goto amifb_error;
+ }
+#else
if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
- NUM_TOTAL_MODES, &ami_modedb[defmode], 4))
- panic("Can't find any usable video mode");
+ NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
+ err = -EINVAL;
+ goto amifb_error;
+ }
+#endif
round_down_bpp = 0;
chipptr = chipalloc(videomemorysize+
@@ -1762,9 +1817,7 @@ default_chipset:
* access the videomem with writethrough cache
*/
videomemory_phys = (u_long)ZTWO_PADDR(videomemory);
-#if 1
videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
-#endif
if (!videomemory) {
printk("amifb: WARNING! unable to map videomem cached writethrough\n");
videomemory = ZTWO_VADDR(videomemory_phys);
@@ -1786,26 +1839,38 @@ default_chipset:
ami_init_copper();
if (request_irq(IRQ_AMIGA_AUTO_3, amifb_interrupt, 0,
- "fb vertb handler", NULL))
- panic("Couldn't add vblank interrupt\n");
- ami_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
- ami_intena_vals[IRQ_AMIGA_COPPER] = 0;
+ "fb vertb handler", NULL)) {
+ err = -EBUSY;
+ goto amifb_error;
+ }
+ amiga_intena_vals[IRQ_AMIGA_VERTB] = IF_COPER;
+ amiga_intena_vals[IRQ_AMIGA_COPPER] = 0;
custom.intena = IF_VERTB;
custom.intena = IF_SETCLR | IF_COPER;
amifb_set_var(&var, -1, &fb_info);
- if (register_framebuffer(&fb_info) < 0)
- return -EINVAL;
+ if (register_framebuffer(&fb_info) < 0) {
+ err = -EINVAL;
+ goto amifb_error;
+ }
printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
GET_FB_IDX(fb_info.node), fb_info.modename,
videomemorysize>>10);
- /* TODO: This driver cannot be unloaded yet */
- MOD_INC_USE_COUNT;
-
return 0;
+
+amifb_error:
+ amifb_deinit();
+ return err;
+}
+
+static void amifb_deinit(void)
+{
+ chipfree();
+ release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
+ custom.dmacon = DMAF_ALL | DMAF_MASTER;
}
static int amifbcon_switch(int con, struct fb_info *info)
@@ -1931,23 +1996,6 @@ static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
}
/*
- * Allocate, Clear and Align a Block of Chip Memory
- */
-
-static u_long __init chipalloc(u_long size)
-{
- u_long ptr;
-
- size += PAGE_SIZE-1;
- if (!(ptr = (u_long)amiga_chip_alloc(size, "amifb")))
- panic("No Chip RAM for frame buffer");
- memset((void *)ptr, 0, size);
- ptr = PAGE_ALIGN(ptr);
-
- return ptr;
-}
-
- /*
* A strtok which returns empty strings, too
*/
@@ -3373,9 +3421,7 @@ int init_module(void)
void cleanup_module(void)
{
- /* Not reached because the usecount will never
- be decremented to zero */
unregister_framebuffer(&fb_info);
- /* TODO: clean up ... */
+ amifb_deinit();
}
#endif /* MODULE */
diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c
index ceb289eb8..d7d4116c0 100644
--- a/drivers/video/aty128fb.c
+++ b/drivers/video/aty128fb.c
@@ -1358,7 +1358,7 @@ aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
}
#ifdef CONFIG_FB_COMPAT_XPMAC
- if (console_fb_info == &info->fb_info) {
+ if (!console_fb_info || console_fb_info == &info->fb_info) {
int vmode, cmode;
display_info.width = var->xres;
@@ -1429,13 +1429,8 @@ aty128_encode_fix(struct fb_fix_screeninfo *fix,
strcpy(fix->id, aty128fb_name);
-#ifdef CONFIG_PPC /* why? I don't know */
- *fix->smem_start = (long)info->frame_buffer_phys;
- *fix->mmio_start = (long)info->regbase_phys;
-#else
fix->smem_start = (long)info->frame_buffer_phys;
fix->mmio_start = (long)info->regbase_phys;
-#endif
fix->smem_len = (u32)info->vram_size;
fix->mmio_len = 0x1fff;
@@ -1676,7 +1671,7 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
/* put a name with the face */
- while (info->pdev->device != aci->device) { aci++; }
+ while (aci->name && info->pdev->device != aci->device) { aci++; }
video_card = (char *)aci->name;
printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] [card rev %x] ",
@@ -1723,7 +1718,10 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
if (default_cmode == CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
#endif
- }
+ } else if (_machine == _MACH_Pmac)
+ if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+ var = default_var;
+
#endif
#endif /* MODULE */
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index 5b78c939c..f7fe19965 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -2689,15 +2689,6 @@ static int encode_fix(struct fb_fix_screeninfo *fix,
fix->smem_start = info->frame_buffer_phys;
fix->smem_len = (u32)info->total_vram;
-#ifdef __LITTLE_ENDIAN
- /*
- * Last page of 8 MB little-endian aperture is MMIO
- * FIXME: we should use the auxiliary aperture instead so we can acces the
- * full 8 MB of video RAM on 8 MB boards
- */
- if (fix->smem_len > 0x800000-GUI_RESERVE)
- fix->smem_len = 0x800000-GUI_RESERVE;
-#endif
/*
* Reg Block 0 (CT-compatible block) is at ati_regbase_phys
* Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
@@ -3501,14 +3492,17 @@ static int __init aty_init(struct fb_info_aty *info, const char *name)
}
#endif
- if (info->bus_type == ISA)
- if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
- /* protect GUI-regs if complete Aperture is VRAM */
+ /*
+ * Last page of 8 MB (4 MB on ISA) aperture is MMIO
+ * FIXME: we should use the auxiliary aperture instead so we can acces the
+ * full 8 MB of video RAM on 8 MB boards
+ */
+ if (info->total_vram == 0x800000 ||
+ (info->bus_type == ISA && info->total_vram == 0x400000))
info->total_vram -= GUI_RESERVE;
- }
/* Clear the video memory */
- memset_io(info->frame_buffer, 0, info->total_vram);
+ fb_memset((void *)info->frame_buffer, 0, info->total_vram);
disp = &info->disp;
@@ -3634,14 +3628,14 @@ int __init atyfb_init(void)
struct pci_dev *pdev = NULL;
struct fb_info_aty *info;
unsigned long addr, res_start, res_size;
+ int i;
#ifdef __sparc__
extern void (*prom_palette) (int);
extern int con_is_present(void);
struct pcidev_cookie *pcp;
char prop[128];
- int node, len;
+ int node, len, j;
u32 mem, chip_id;
- int i, j;
/* Do not attach when we have a serial console. */
if (!con_is_present())
@@ -3654,6 +3648,12 @@ int __init atyfb_init(void)
if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
struct resource *rp;
+ for (i = sizeof(aty_features)/sizeof(*aty_features)-1; i >= 0; i--)
+ if (pdev->device == aty_features[i].pci_id)
+ break;
+ if (i < 0)
+ continue;
+
info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
if (!info) {
printk("atyfb_init: can't alloc fb_info_aty\n");
diff --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c
index aedbc8b17..8da8117c9 100644
--- a/drivers/video/fbcon.c
+++ b/drivers/video/fbcon.c
@@ -111,6 +111,10 @@
#define LOGO_W 80
#define LOGO_LINE (LOGO_W/8)
+static int first_fb_vc = 0;
+static int last_fb_vc = MAX_NR_CONSOLES-1;
+static int fbcon_is_default = 1;
+
struct display fb_display[MAX_NR_CONSOLES];
char con2fb_map[MAX_NR_CONSOLES];
static int logo_lines;
@@ -128,6 +132,8 @@ static int softback_lines;
#define FNTSUM(fd) (((int *)(fd))[-4])
#define FONT_EXTRA_WORDS 4
+static char fontname[40] __initdata = { 0 }; /* default font name */
+
#define CM_SOFTBACK (8)
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * conp->vc_size_row)
@@ -197,7 +203,8 @@ static int fbcon_scrolldelta(struct vc_data *conp, int lines);
* Internal routines
*/
-static void fbcon_setup(int con, int init, int logo);
+static int __init fbcon_setup(char *options);
+static void fbcon_set_disp(int con, int init, int logo);
static __inline__ int real_y(struct display *p, int ypos);
static void fbcon_vbl_handler(int irq, void *dummy, struct pt_regs *fp);
static __inline__ void updatescrollmode(struct display *p);
@@ -293,6 +300,8 @@ void set_con2fb_map(int unit, int newidx)
newfb = registered_fb[newidx];
if (newfb->fbops->fb_open(newfb,0))
return;
+ newfb->count++;
+ oldfb->count--;
oldfb->fbops->fb_release(oldfb,0);
conp = fb_display[unit].conp;
fontdata = fb_display[unit].fontdata;
@@ -323,6 +332,57 @@ void set_con2fb_map(int unit, int newidx)
}
}
+static int __init fbcon_setup(char *options)
+{
+ int i, j;
+
+ if (!options || !*options)
+ return 0;
+
+ if (!strncmp(options, "font:", 5))
+ strcpy(fontname, options+5);
+
+ if (!strncmp(options, "scrollback:", 11)) {
+ options += 11;
+ if (*options) {
+ fbcon_softback_size = simple_strtoul(options, &options, 0);
+ if (*options == 'k' || *options == 'K') {
+ fbcon_softback_size *= 1024;
+ options++;
+ }
+ if (*options != ',')
+ return 0;
+ options++;
+ } else
+ return 0;
+ }
+
+ if (!strncmp(options, "map:", 4)) {
+ options += 4;
+ if (*options)
+ for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!options[j])
+ j = 0;
+ con2fb_map[i] = (options[j++]-'0') % FB_MAX;
+ }
+ return 0;
+ }
+
+ if (!strncmp(options, "vc:", 3)) {
+ options += 3;
+ if (*options)
+ first_fb_vc = simple_strtoul(options, &options, 10) - 1;
+ if (first_fb_vc < 0)
+ first_fb_vc = 0;
+ if (*options++ == '-')
+ last_fb_vc = simple_strtoul(options, &options, 10) - 1;
+ fbcon_is_default = 0;
+ }
+ return 0;
+}
+
+__setup("fbcon=", fbcon_setup);
+
/*
* Low Level Operations
*/
@@ -419,15 +479,23 @@ static const char *fbcon_startup(void)
return display_desc;
}
-
static void fbcon_init(struct vc_data *conp, int init)
{
- int unit = conp->vc_num;
+ int j, unit = conp->vc_num;
struct fb_info *info;
-
+
/* on which frame buffer will we open this console? */
info = registered_fb[(int)con2fb_map[unit]];
+ /*
+ * We assume initial frame buffer devices can be opened this
+ * many times
+ */
+ for (j = 0; j < (last_fb_vc - first_fb_vc + 1); j++) {
+ info->fbops->fb_open(info,0);
+ info->count++;
+ }
+
info->changevar = &fbcon_changevar;
fb_display[unit] = *(info->disp); /* copy from default */
DPRINTK("mode: %s\n",info->modename);
@@ -443,8 +511,8 @@ static void fbcon_init(struct vc_data *conp, int init)
fb_display[unit].cmap.green = 0;
fb_display[unit].cmap.blue = 0;
fb_display[unit].cmap.transp = 0;
- fbcon_setup(unit, init, !init);
- /* Must be done after fbcon_setup to prevent excess updates */
+ fbcon_set_disp(unit, init, !init);
+ /* Must be done after fbcon_set_disp to prevent excess updates */
conp->vc_display_fg = &info->display_fg;
if (!info->display_fg)
info->display_fg = conp;
@@ -458,6 +526,7 @@ static void fbcon_deinit(struct vc_data *conp)
fbcon_free_font(p);
p->dispsw = &fbcon_dummy;
+ p->fb_info->count = 0;
p->conp = 0;
}
@@ -465,7 +534,7 @@ static void fbcon_deinit(struct vc_data *conp)
static int fbcon_changevar(int con)
{
if (fb_display[con].conp)
- fbcon_setup(con, 0, 0);
+ fbcon_set_disp(con, 0, 0);
return 0;
}
@@ -504,7 +573,7 @@ static void fbcon_font_widths(struct display *p)
#define fontwidthvalid(p,w) ((p)->dispsw->fontwidthmask & FONTWIDTH(w))
-static void fbcon_setup(int con, int init, int logo)
+static void fbcon_set_disp(int con, int init, int logo)
{
struct display *p = &fb_display[con];
struct vc_data *conp = p->conp;
@@ -568,9 +637,8 @@ static void fbcon_setup(int con, int init, int logo)
}
if (!p->fontdata) {
- if (!p->fb_info->fontname[0] ||
- !(font = fbcon_find_font(p->fb_info->fontname)))
- font = fbcon_get_default_font(p->var.xres, p->var.yres);
+ if (!fontname[0] || !(font = fbcon_find_font(fontname)))
+ font = fbcon_get_default_font(p->var.xres, p->var.yres);
p->_fontwidth = font->width;
p->_fontheight = font->height;
p->fontdata = font->data;
@@ -586,7 +654,7 @@ static void fbcon_setup(int con, int init, int logo)
#endif
{
/* ++Geert: changed from panic() to `correct and continue' */
- printk(KERN_ERR "fbcon_setup: No support for fontwidth %d\n", fontwidth(p));
+ printk(KERN_ERR "fbcon_set_disp: No support for fontwidth %d\n", fontwidth(p));
p->dispsw = &fbcon_dummy;
}
}
@@ -669,7 +737,7 @@ static void fbcon_setup(int con, int init, int logo)
}
if (p->dispsw == &fbcon_dummy)
- printk(KERN_WARNING "fbcon_setup: type %d (aux %d, depth %d) not "
+ printk(KERN_WARNING "fbcon_set_disp: type %d (aux %d, depth %d) not "
"supported\n", p->type, p->type_aux, p->var.bits_per_pixel);
p->dispsw->setup(p);
@@ -2394,6 +2462,13 @@ struct consw fb_con = {
con_getxy: fbcon_getxy,
};
+void __init fbconsole_init(void)
+{
+ if (!num_registered_fb || (first_fb_vc > last_fb_vc))
+ return;
+
+ take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
+}
/*
* Dummy Low Level Operations
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 3bbf334b0..1f5492d4f 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -239,14 +239,8 @@ extern const char *global_mode_option;
static initcall_t pref_init_funcs[FB_MAX];
static int num_pref_init_funcs __initdata = 0;
-
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb = 0;
-extern int fbcon_softback_size;
-
-static int first_fb_vc = 0;
-static int last_fb_vc = MAX_NR_CONSOLES-1;
-static int fbcon_is_default = 1;
static int fbmem_read_proc(char *buf, char **start, off_t offset,
int len, int *eof, void *private)
@@ -556,6 +550,8 @@ fb_open(struct inode *inode, struct file *file)
#endif /* CONFIG_KMOD */
if (!(info = registered_fb[fbidx]))
return -ENODEV;
+ if (info->flags & FBINFO_FLAG_OPEN) return -EBUSY;
+ info->flags |= FBINFO_FLAG_OPEN;
return info->fbops->fb_open(info,1);
}
@@ -566,6 +562,7 @@ fb_release(struct inode *inode, struct file *file)
struct fb_info *info = registered_fb[fbidx];
info->fbops->fb_release(info,1);
+ info->flags &= ~FBINFO_FLAG_OPEN;
return 0;
}
@@ -583,10 +580,8 @@ static devfs_handle_t devfs_handle = NULL;
int
register_framebuffer(struct fb_info *fb_info)
{
- int i, j;
char name_buf[8];
- static int fb_ever_opened[FB_MAX];
- static int first = 1;
+ int i;
if (num_registered_fb == FB_MAX)
return -ENXIO;
@@ -595,22 +590,9 @@ register_framebuffer(struct fb_info *fb_info)
if (!registered_fb[i])
break;
fb_info->node = MKDEV(FB_MAJOR, i);
+ fb_info->flags &= ~FBINFO_FLAG_OPEN;
+ fb_info->count = 0;
registered_fb[i] = fb_info;
- if (!fb_ever_opened[i]) {
- /*
- * We assume initial frame buffer devices can be opened this
- * many times
- */
- for (j = 0; j < MAX_NR_CONSOLES; j++)
- if (con2fb_map[j] == i)
- fb_info->fbops->fb_open(fb_info,0);
- fb_ever_opened[i] = 1;
- }
-
- if (first) {
- first = 0;
- take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
- }
sprintf (name_buf, "%d", i);
fb_info->devfs_handle =
devfs_register (devfs_handle, name_buf, 0, DEVFS_FL_NONE,
@@ -623,12 +605,12 @@ register_framebuffer(struct fb_info *fb_info)
int
unregister_framebuffer(struct fb_info *fb_info)
{
- int i, j;
+ int i;
i = GET_FB_IDX(fb_info->node);
- for (j = 0; j < MAX_NR_CONSOLES; j++)
- if (con2fb_map[j] == i)
- return -EBUSY;
+
+ if (fb_info->count || (fb_info->flags & FBINFO_FLAG_OPEN))
+ return -EBUSY;
if (!registered_fb[i])
return -EINVAL;
devfs_unregister (fb_info->devfs_handle);
@@ -672,43 +654,6 @@ int __init video_setup(char *options)
if (!options || !*options)
return 0;
-
- if (!strncmp(options, "scrollback:", 11)) {
- options += 11;
- if (*options) {
- fbcon_softback_size = simple_strtoul(options, &options, 0);
- if (*options == 'k' || *options == 'K') {
- fbcon_softback_size *= 1024;
- options++;
- }
- if (*options != ',')
- return 0;
- options++;
- } else
- return 0;
- }
-
- if (!strncmp(options, "map:", 4)) {
- options += 4;
- if (*options)
- for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
- if (!options[j])
- j = 0;
- con2fb_map[i] = (options[j++]-'0') % FB_MAX;
- }
- return 0;
- }
-
- if (!strncmp(options, "vc:", 3)) {
- options += 3;
- if (*options)
- first_fb_vc = simple_strtoul(options, &options, 10) - 1;
- if (first_fb_vc < 0)
- first_fb_vc = 0;
- if (*options++ == '-')
- last_fb_vc = simple_strtoul(options, &options, 10) - 1;
- fbcon_is_default = 0;
- }
if (num_pref_init_funcs == FB_MAX)
return 0;
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 38fb6adc9..77a796109 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -41,6 +41,7 @@
*/
#include <linux/tty.h>
#include <linux/fb.h>
+#include <linux/module.h>
int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
const struct fb_info *fb_info)
@@ -72,3 +73,5 @@ int fbmon_dpms(const struct fb_info *fb_info)
{
return fb_info->monspecs.dpms;
}
+
+EXPORT_SYMBOL(fbmon_valid_timings);
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index bbb695223..b92ce4055 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -287,6 +287,9 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
matroxfb_DAC_unlock_irqrestore(flags);
memset(m2info, 0, sizeof(*m2info));
+ m2info->maven.minfo = m2info;
+ m2info->ddc1.minfo = m2info;
+ m2info->ddc2.minfo = m2info;
m2info->primary_dev = minfo;
if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W ||
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 978dba156..e7d515ec2 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -892,11 +892,8 @@ static struct matrox_altout maven_altout = {
static int maven_init_client(struct i2c_client* clnt) {
struct i2c_adapter* a = clnt->adapter;
- /* data are set to primary head... maybe I should change it */
- struct matroxfb_dh_maven_info* m2info =
- (struct matroxfb_dh_maven_info*)(((u_int8_t*)a) - offsetof(struct matroxfb_dh_maven_info, maven.adapter));
+ struct matroxfb_dh_maven_info* m2info = ((struct i2c_bit_adapter*)a)->minfo;
struct maven_data* md = clnt->data;
- /* add some checks that m2info is matroxfb_dh_fb_info here... */
struct matrox_fb_info* minfo = m2info->primary_dev;
md->mode = MODE_MONITOR;
diff --git a/drivers/video/matrox/matroxfb_maven.h b/drivers/video/matrox/matroxfb_maven.h
index cbf340e0a..060aa0b81 100644
--- a/drivers/video/matrox/matroxfb_maven.h
+++ b/drivers/video/matrox/matroxfb_maven.h
@@ -6,10 +6,13 @@
#include <linux/i2c-algo-bit.h>
#include "matroxfb_base.h"
+struct matroxfb_dh_maven_info;
+
struct i2c_bit_adapter {
struct i2c_adapter adapter;
int initialized;
struct i2c_algo_bit_data bac;
+ struct matroxfb_dh_maven_info *minfo;
};
struct matroxfb_dh_maven_info {
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 68e6201cc..f734c4f9f 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -293,9 +293,6 @@ static int offb_ioctl(struct inode *inode, struct file *file, u_int cmd,
}
-#ifdef CONFIG_FB_ATY128
-extern void aty128fb_of_init(struct device_node *dp);
-#endif /* CONFIG_FB_ATY */
#ifdef CONFIG_FB_S3TRIO
extern void s3triofb_init_of(struct device_node *dp);
#endif /* CONFIG_FB_S3TRIO */
@@ -423,12 +420,6 @@ int __init offb_init(void)
static int __init offb_init_driver(struct device_node *dp)
{
-#ifdef CONFIG_FB_ATY128
- if (!strncmp(dp->name, "ATY,Rage128", 11)) {
- aty128fb_of_init(dp);
- return 1;
- }
-#endif
#ifdef CONFIG_FB_S3TRIO
if (!strncmp(dp->name, "S3Trio", 6)) {
s3triofb_init_of(dp);
diff --git a/drivers/video/vgacon.c b/drivers/video/vgacon.c
index 56a052647..1180d3ee0 100644
--- a/drivers/video/vgacon.c
+++ b/drivers/video/vgacon.c
@@ -94,8 +94,6 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink,
static void vgacon_invert_region(struct vc_data *c, u16 *p, int count);
static unsigned long vgacon_uni_pagedir[2];
-void clear_status_line( void );
-
/* Description of the hardware situation */
static unsigned long vga_vram_base; /* Base of video memory */
@@ -351,7 +349,6 @@ static void vgacon_init(struct vc_data *c, int init)
static inline void vga_set_mem_top(struct vc_data *c)
{
write_vga(12, (c->vc_visible_origin-vga_vram_base)/2);
- clear_status_line();
}
static void vgacon_deinit(struct vc_data *c)
@@ -1060,80 +1057,3 @@ struct consw vga_con = {
vgacon_build_attr,
vgacon_invert_region
};
-
-
-int inited = 0;
-
-void
-clear_status_line( void )
-{
-#if CONFIG_COMMENT_INT==3
- u16 *org;
- int i;
- int currcons = fg_console;
- struct vc_data *c = vc_cons[fg_console].d;
- if (!inited) return;
- if (vga_is_gfx) return;
- if (c->vc_origin != c->vc_visible_origin) return;
- org = screen_pos( fg_console, video_num_lines*video_num_columns, 1 );
- for (i=0; i<video_num_columns; i++)
- scr_writew( (0x0f << 8) + ' ', org++ );
-#endif
-}
-
-#if CONFIG_COMMENT_INT==3
-void
-paint_status_line( int timer )
-{
- u16 *org;
- int i,j;
- int currcons = fg_console;
- struct vc_data *c = vc_cons[fg_console].d;
-
- if (!inited) return;
- if (vga_is_gfx) /* We don't play origin tricks in graphic modes */
- return;
- if (c->vc_origin != c->vc_visible_origin) return;
-
- org = screen_pos( fg_console, video_num_lines*video_num_columns, 1 );
-
- /* Are we busy? */
- {
- i = current->pid;
- j = 0;
- if (i)
- j = (i>16) ? ((current->priority < DEF_PRIORITY) ? 0xA0:0xE0) : 0xC0;
- scr_writew( (j<<8) + ' ', org++ );
-
-#if 0
- org++;
-
-#define DISP( x ) scr_writew( (((i&x) ? 0x90:0) << 8) + ' ', org++ );
- DISP( 0x80 );
- DISP( 0x40 );
- DISP( 0x20 );
- DISP( 0x10 );
- DISP( 0x08 );
- DISP( 0x04 );
- DISP( 0x02 );
- DISP( 0x01 );
-#endif
- }
-
- if (!timer) return;
-
- org++;
- /* Serial? */
- {
- j = (ledflags & 0x10) ? 0x90 : 0x00;
- scr_writew( (j<<8) + 'S', org++ );
- }
-
- org++;
- /* NE2000? */
- {
- j = (ledflags & 0x20) ? 0x90 : 0x00;
- scr_writew( (j<<8) + 'N', org++ );
- }
-}
-#endif
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 7c80a6958..da2cc0788 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -158,7 +158,6 @@ static void adfs_put_super(struct super_block *sb)
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
brelse(sb->u.adfs_sb.s_map[i].dm_bh);
kfree(sb->u.adfs_sb.s_map);
- MOD_DEC_USE_COUNT;
}
static int parse_options(struct super_block *sb, char *options)
@@ -213,21 +212,20 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data)
return parse_options(sb, data);
}
-static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int adfs_statfs(struct super_block *sb, struct statfs *buf)
{
struct adfs_sb_info *asb = &sb->u.adfs_sb;
- struct statfs tmp;
-
- tmp.f_type = ADFS_SUPER_MAGIC;
- tmp.f_namelen = asb->s_namelen;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = asb->s_size;
- tmp.f_files = asb->s_ids_per_zone * asb->s_map_size;
- tmp.f_bavail =
- tmp.f_bfree = adfs_map_free(sb);
- tmp.f_ffree = tmp.f_bfree * tmp.f_files / tmp.f_blocks;
-
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+
+ buf->f_type = ADFS_SUPER_MAGIC;
+ buf->f_namelen = asb->s_namelen;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = asb->s_size;
+ buf->f_files = asb->s_ids_per_zone * asb->s_map_size;
+ buf->f_bavail =
+ buf->f_bfree = adfs_map_free(sb);
+ buf->f_ffree = buf->f_bfree * buf->f_files / buf->f_blocks;
+
+ return 0;
}
static struct super_operations adfs_sops = {
@@ -317,8 +315,6 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
if (parse_options(sb, data))
goto error;
- MOD_INC_USE_COUNT;
- lock_super(sb);
set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread(dev, ADFS_DISCRECORD / BLOCK_SIZE, BLOCK_SIZE))) {
adfs_error(sb, "unable to read superblock");
@@ -396,7 +392,6 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
* set up enough so that we can read an inode
*/
sb->s_op = &adfs_sops;
- unlock_super(sb);
dr = (struct adfs_discrecord *)(sb->u.adfs_sb.s_map[0].dm_bh->b_data + 4);
@@ -440,31 +435,24 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
error_free_bh:
brelse(bh);
error_unlock:
- unlock_super(sb);
error_dec_use:
- MOD_DEC_USE_COUNT;
error:
- sb->s_dev = 0;
return NULL;
}
-static struct file_system_type adfs_fs_type = {
- "adfs", FS_REQUIRES_DEV, adfs_read_super, NULL
-};
+static DECLARE_FSTYPE_DEV(adfs_fs_type, "adfs", adfs_read_super);
-int __init init_adfs_fs(void)
+static int __init init_adfs_fs(void)
{
return register_filesystem(&adfs_fs_type);
}
-#ifdef MODULE
-int init_module(void)
-{
- return init_adfs_fs();
-}
-
-void cleanup_module(void)
+static void __exit exit_adfs_fs(void)
{
unregister_filesystem(&adfs_fs_type);
}
-#endif
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_adfs_fs)
+module_exit(exit_adfs_fs)
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 38e5bccbe..c1a849a70 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -368,7 +368,7 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
goto rmdir_done;
retval = -EBUSY;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
goto rmdir_done;
if ((retval = affs_remove_header(bh,inode)) < 0)
@@ -557,6 +557,9 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
if (S_ISDIR(old_inode->i_mode)) {
if (new_inode) {
+ retval = -EBUSY;
+ if (!d_unhashed(new_dentry))
+ goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
goto end_rename;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 9eed5c09e..5f2387bde 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -35,7 +35,7 @@ extern struct timezone sys_tz;
#define MIN(a,b) (((a)<(b))?(a):(b))
-static int affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int affs_statfs(struct super_block *sb, struct statfs *buf);
static int affs_remount (struct super_block *sb, int *flags, char *data);
static void
@@ -65,7 +65,6 @@ affs_put_super(struct super_block *sb)
*/
set_blocksize(sb->s_dev, sb->u.affs_sb.s_blksize);
- MOD_DEC_USE_COUNT;
return;
}
@@ -262,8 +261,6 @@ affs_read_super(struct super_block *s, void *data, int silent)
pr_debug("AFFS: read_super(%s)\n",data ? (const char *)data : "no options");
- MOD_INC_USE_COUNT;
- lock_super(s);
s->s_magic = AFFS_SUPER_MAGIC;
s->s_op = &affs_sops;
s->u.affs_sb.s_bitmap = NULL;
@@ -547,7 +544,6 @@ nobitmap:
goto out_no_root;
s->s_root->d_op = &affs_dentry_operations;
- unlock_super(s);
/* Record date of last change if the bitmap was truncated and
* create data zones if the volume is writable.
*/
@@ -615,9 +611,6 @@ out_free_prefix:
if (s->u.affs_sb.s_prefix)
kfree(s->u.affs_sb.s_prefix);
out_fail:
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
return NULL;
}
@@ -661,31 +654,23 @@ affs_remount(struct super_block *sb, int *flags, char *data)
}
static int
-affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+affs_statfs(struct super_block *sb, struct statfs *buf)
{
int free;
- struct statfs tmp;
pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size,
sb->u.affs_sb.s_reserved);
free = affs_count_free_blocks(sb);
- tmp.f_type = AFFS_SUPER_MAGIC;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
- tmp.f_bfree = free;
- tmp.f_bavail = free;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- return copy_to_user(buf,&tmp,bufsiz) ? -EFAULT : 0;
+ buf->f_type = AFFS_SUPER_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
+ buf->f_bfree = free;
+ buf->f_bavail = free;
+ return 0;
}
-static struct file_system_type affs_fs_type = {
- "affs",
- FS_REQUIRES_DEV,
- affs_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(affs_fs_type, "affs", affs_read_super);
int __init init_affs_fs(void)
{
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index 4c9e8fe76..0aaa8134a 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -14,12 +14,7 @@
#include <linux/init.h>
#include "autofs_i.h"
-static struct file_system_type autofs_fs_type = {
- "autofs",
- 0,
- autofs_read_super,
- NULL
-};
+static DECLARE_FSTYPE(autofs_fs_type, "autofs", autofs_read_super, 0);
static int __init init_autofs_fs(void)
{
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index a67ca9822..1aa665d1c 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -49,13 +49,9 @@ static void autofs_put_super(struct super_block *sb)
kfree(sb->u.generic_sbp);
DPRINTK(("autofs: shutting down\n"));
-
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
}
-static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int autofs_statfs(struct super_block *sb, struct statfs *buf);
static void autofs_read_inode(struct inode *inode);
static void autofs_write_inode(struct inode *inode);
@@ -141,9 +137,6 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
struct autofs_sb_info *sbi;
int minproto, maxproto;
- MOD_INC_USE_COUNT;
-
- lock_super(s);
/* Super block already completed? */
if (s->s_root)
goto out_unlock;
@@ -167,7 +160,6 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs_sops;
s->s_root = NULL;
- unlock_super(s); /* shouldn't we keep it locked a while longer? */
/*
* Get the root inode and dentry, but defer checking for errors.
@@ -224,7 +216,6 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
* Success ... somebody else completed the super block for us.
*/
out_unlock:
- unlock_super(s);
goto out_dec;
out_fput:
if (pipe)
@@ -235,7 +226,6 @@ out_dput:
else
iput(root_inode);
out_dec:
- MOD_DEC_USE_COUNT;
return s;
/*
@@ -246,14 +236,12 @@ fail_fput:
/*
* fput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
fput(pipe);
/* fall through */
fail_dput:
/*
* dput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
dput(root);
goto fail_free;
fail_iput:
@@ -261,32 +249,23 @@ fail_iput:
/*
* iput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
iput(root_inode);
fail_free:
kfree(sbi);
- goto fail_dec;
fail_unlock:
- unlock_super(s);
fail_dec:
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
-static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int autofs_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = AUTOFS_SUPER_MAGIC;
- tmp.f_bsize = 1024;
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = AUTOFS_SUPER_MAGIC;
+ buf->f_bsize = 1024;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
static void autofs_read_inode(struct inode *inode)
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 35afe3cdc..1540ceda8 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -227,7 +227,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr
* doesn't do the right thing for all system calls, but it should
* be OK for the operations we permit from an autofs.
*/
- if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+ if ( dentry->d_inode && d_unhashed(dentry) )
return ERR_PTR(-ENOENT);
return NULL;
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
index 48bf60b5f..baf12d913 100644
--- a/fs/autofs4/init.c
+++ b/fs/autofs4/init.c
@@ -14,12 +14,7 @@
#include <linux/init.h>
#include "autofs_i.h"
-static struct file_system_type autofs_fs_type = {
- "autofs",
- 0,
- autofs4_read_super,
- NULL
-};
+static DECLARE_FSTYPE(autofs_fs_type, "autofs", autofs4_read_super, 0);
static int __init init_autofs4_fs(void)
{
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 40d149272..b4ea73fdb 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -103,10 +103,6 @@ static void autofs4_put_super(struct super_block *sb)
kfree(sbi);
DPRINTK(("autofs: shutting down\n"));
-
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
}
static void autofs4_umount_begin(struct super_block *sb)
@@ -117,7 +113,7 @@ static void autofs4_umount_begin(struct super_block *sb)
autofs4_catatonic_mode(sbi);
}
-static int autofs4_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int autofs4_statfs(struct super_block *sb, struct statfs *buf);
static void autofs4_read_inode(struct inode *inode);
static void autofs4_write_inode(struct inode *inode);
@@ -219,9 +215,6 @@ struct super_block *autofs4_read_super(struct super_block *s, void *data,
struct autofs_sb_info *sbi;
int minproto, maxproto;
- MOD_INC_USE_COUNT;
-
- lock_super(s);
/* Super block already completed? */
if (s->s_root)
goto out_unlock;
@@ -248,7 +241,6 @@ struct super_block *autofs4_read_super(struct super_block *s, void *data,
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs4_sops;
s->s_root = NULL;
- unlock_super(s); /* shouldn't we keep it locked a while longer? */
/*
* Get the root inode and dentry, but defer checking for errors.
@@ -315,7 +307,6 @@ struct super_block *autofs4_read_super(struct super_block *s, void *data,
* Success ... somebody else completed the super block for us.
*/
out_unlock:
- unlock_super(s);
goto out_dec;
out_fput:
if (pipe)
@@ -326,7 +317,6 @@ out_dput:
else
iput(root_inode);
out_dec:
- MOD_DEC_USE_COUNT;
return s;
/*
@@ -337,14 +327,12 @@ fail_fput:
/*
* fput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
fput(pipe);
/* fall through */
fail_dput:
/*
* dput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
dput(root);
goto fail_free;
fail_iput:
@@ -352,32 +340,22 @@ fail_iput:
/*
* iput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
iput(root_inode);
fail_free:
kfree(sbi);
- goto fail_dec;
fail_unlock:
- unlock_super(s);
-fail_dec:
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
-static int autofs4_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int autofs4_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = AUTOFS_SUPER_MAGIC;
- tmp.f_bsize = 1024;
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = AUTOFS_SUPER_MAGIC;
+ buf->f_bsize = 1024;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
static void autofs4_read_inode(struct inode *inode)
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 05045d408..8ff33b344 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -353,7 +353,7 @@ static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dent
* doesn't do the right thing for all system calls, but it should
* be OK for the operations we permit from an autofs.
*/
- if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+ if ( dentry->d_inode && d_unhashed(dentry) )
return ERR_PTR(-ENOENT);
return NULL;
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 44e96e101..38881a1b6 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -182,7 +182,7 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
}
de->ino = 0;
dir->i_version = ++event;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh, 0);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
inode->i_nlink--;
@@ -242,7 +242,7 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
new_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(new_inode);
}
- mark_buffer_dirty(old_bh, 1);
+ mark_buffer_dirty(old_bh, 0);
error = 0;
end_rename:
@@ -294,7 +294,7 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
de->ino = ino;
for (i=0; i<BFS_NAMELEN; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh, 0);
brelse(bh);
return 0;
}
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index aba9cefd1..f5ef5e652 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -33,7 +33,7 @@ static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev)
return -EIO;
new = getblk(dev, to, BFS_BSIZE);
memcpy(new->b_data, bh->b_data, bh->b_size);
- mark_buffer_dirty(new, 1);
+ mark_buffer_dirty(new, 0);
bforget(bh);
brelse(new);
return 0;
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 79c7c6507..2c38ccafe 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -124,7 +124,7 @@ static void bfs_write_inode(struct inode * inode)
di->i_eblock = inode->iu_eblock;
di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh, 0);
brelse(bh);
}
@@ -165,7 +165,7 @@ static void bfs_delete_inode(struct inode * inode)
}
di->i_ino = 0;
di->i_sblock = 0;
- mark_buffer_dirty(bh, 1);
+ mark_buffer_dirty(bh, 0);
brelse(bh);
/* if this was the last file, make the previous
@@ -182,22 +182,19 @@ static void bfs_put_super(struct super_block *s)
{
brelse(s->su_sbh);
kfree(s->su_imap);
- MOD_DEC_USE_COUNT;
}
-static int bfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
+static int bfs_statfs(struct super_block *s, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = BFS_MAGIC;
- tmp.f_bsize = s->s_blocksize;
- tmp.f_blocks = s->su_blocks;
- tmp.f_bfree = tmp.f_bavail = s->su_freeb;
- tmp.f_files = s->su_lasti + 1 - BFS_ROOT_INO;
- tmp.f_ffree = s->su_freei;
- tmp.f_fsid.val[0] = s->s_dev;
- tmp.f_namelen = BFS_NAMELEN;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = BFS_MAGIC;
+ buf->f_bsize = s->s_blocksize;
+ buf->f_blocks = s->su_blocks;
+ buf->f_bfree = buf->f_bavail = s->su_freeb;
+ buf->f_files = s->su_lasti + 1 - BFS_ROOT_INO;
+ buf->f_ffree = s->su_freei;
+ buf->f_fsid.val[0] = s->s_dev;
+ buf->f_namelen = BFS_NAMELEN;
+ return 0;
}
static void bfs_write_super(struct super_block *s)
@@ -245,8 +242,6 @@ static struct super_block * bfs_read_super(struct super_block * s,
struct inode * inode;
int i, imap_len;
- MOD_INC_USE_COUNT;
- lock_super(s);
dev = s->s_dev;
set_blocksize(dev, BFS_BSIZE);
s->s_blocksize = BFS_BSIZE;
@@ -318,22 +313,14 @@ static struct super_block * bfs_read_super(struct super_block * s,
s->s_dirt = 1;
}
dump_imap("read_super", s);
- unlock_super(s);
return s;
out:
brelse(bh);
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
return NULL;
}
-static struct file_system_type bfs_fs_type = {
- name: "bfs",
- fs_flags: FS_REQUIRES_DEV,
- read_super: bfs_read_super,
-};
+static DECLARE_FSTYPE_DEV( bfs_fs_type, "bfs", bfs_read_super);
#ifdef MODULE
#define init_bfs_fs init_module
diff --git a/fs/buffer.c b/fs/buffer.c
index 4e79483e4..dabf1d39c 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1754,10 +1754,10 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
mark_buffer_uptodate(bh, uptodate);
kiobuf = bh->b_kiobuf;
- if (!uptodate)
- kiobuf->errno = -EIO;
- if (atomic_dec_and_test(&kiobuf->io_count))
- kiobuf->end_io(kiobuf);
+ unlock_buffer(bh);
+
+ kiobuf = bh->b_kiobuf;
+ end_kio_request(kiobuf, uptodate);
}
@@ -1766,8 +1766,7 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
* for them to complete. Clean up the buffer_heads afterwards.
*/
-static int do_kio(struct kiobuf *kiobuf,
- int rw, int nr, struct buffer_head *bh[], int size)
+static int do_kio(int rw, int nr, struct buffer_head *bh[], int size)
{
int iosize;
int i;
@@ -1778,18 +1777,20 @@ static int do_kio(struct kiobuf *kiobuf,
if (rw == WRITE)
rw = WRITERAW;
- atomic_add(nr, &kiobuf->io_count);
- kiobuf->errno = 0;
ll_rw_block(rw, nr, bh);
- kiobuf_wait_for_io(kiobuf);
-
- spin_lock(&unused_list_lock);
-
iosize = 0;
+ spin_lock(&unused_list_lock);
+
for (i = nr; --i >= 0; ) {
iosize += size;
tmp = bh[i];
+ if (buffer_locked(tmp)) {
+ spin_unlock(&unused_list_lock);
+ wait_on_buffer(tmp);
+ spin_lock(&unused_list_lock);
+ }
+
if (!buffer_uptodate(tmp)) {
/* We are traversing bh'es in reverse order so
clearing iosize on error calculates the
@@ -1801,11 +1802,7 @@ static int do_kio(struct kiobuf *kiobuf,
spin_unlock(&unused_list_lock);
- if (iosize)
- return iosize;
- if (kiobuf->errno)
- return kiobuf->errno;
- return -EIO;
+ return iosize;
}
/*
@@ -1847,8 +1844,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
if ((iobuf->offset & (size-1)) ||
(iobuf->length & (size-1)))
return -EINVAL;
- if (!iobuf->locked)
- panic("brw_kiovec: iobuf not locked for I/O");
if (!iobuf->nr_pages)
panic("brw_kiovec: iobuf not initialised");
}
@@ -1861,10 +1856,15 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
iobuf = iovec[i];
offset = iobuf->offset;
length = iobuf->length;
-
+ iobuf->errno = 0;
+
for (pageind = 0; pageind < iobuf->nr_pages; pageind++) {
map = iobuf->maplist[pageind];
-
+ if (!map) {
+ err = -EFAULT;
+ goto error;
+ }
+
while (length > 0) {
blocknr = b[bufind++];
tmp = get_unused_buffer_head(0);
@@ -1893,11 +1893,13 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
length -= size;
offset += size;
+ atomic_inc(&iobuf->io_count);
+
/*
* Start the IO if we have got too much
*/
if (bhind >= KIO_MAX_SECTORS) {
- err = do_kio(iobuf, rw, bhind, bh, size);
+ err = do_kio(rw, bhind, bh, size);
if (err >= 0)
transferred += err;
else
@@ -1915,7 +1917,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
/* Is there any IO still left to submit? */
if (bhind) {
- err = do_kio(iobuf, rw, bhind, bh, size);
+ err = do_kio(rw, bhind, bh, size);
if (err >= 0)
transferred += err;
else
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 8e25fccd6..1e39811e6 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -451,7 +451,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
dircnp = ITOC(dir);
- if (!list_empty(&de->d_hash))
+ if (!d_unhashed(de))
return -EBUSY;
error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 1f82ef5bd..7f163acf9 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -37,8 +37,7 @@ static void coda_read_inode(struct inode *);
static void coda_put_inode(struct inode *);
static void coda_delete_inode(struct inode *);
static void coda_put_super(struct super_block *);
-static int coda_statfs(struct super_block *sb, struct statfs *buf,
- int bufsiz);
+static int coda_statfs(struct super_block *sb, struct statfs *buf);
/* exported operations */
struct super_operations coda_super_operations =
@@ -61,16 +60,13 @@ static struct super_block * coda_read_super(struct super_block *sb,
int error;
ENTRY;
- MOD_INC_USE_COUNT;
vc = &coda_upc_comm;
sbi = &coda_super_info;
if ( sbi->sbi_sb ) {
printk("Already mounted\n");
- unlock_super(sb);
EXIT;
- MOD_DEC_USE_COUNT;
return NULL;
}
@@ -80,7 +76,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
INIT_LIST_HEAD(&(sbi->sbi_cchead));
INIT_LIST_HEAD(&(sbi->sbi_volroothead));
- lock_super(sb);
sb->u.generic_sbp = sbi;
sb->s_blocksize = 1024; /* XXXXX what do we put here?? */
sb->s_blocksize_bits = 10;
@@ -93,7 +88,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
if ( error ) {
printk("coda_read_super: coda_get_rootfid failed with %d\n",
error);
- sb->s_dev = 0;
goto error;
}
printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
@@ -102,7 +96,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
error = coda_cnode_make(&root, &fid, sb);
if ( error || !root ) {
printk("Failure of coda_cnode_make for root: error %d\n", error);
- sb->s_dev = 0;
goto error;
}
@@ -110,14 +103,11 @@ static struct super_block * coda_read_super(struct super_block *sb,
root->i_ino, root->i_dev);
sbi->sbi_root = root;
sb->s_root = d_alloc_root(root);
- unlock_super(sb);
EXIT;
return sb;
error:
- unlock_super(sb);
EXIT;
- MOD_DEC_USE_COUNT;
if (sbi) {
sbi->sbi_vcomm = NULL;
sbi->sbi_root = NULL;
@@ -126,7 +116,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
if (root) {
iput(root);
}
- sb->s_dev = 0;
return NULL;
}
@@ -136,15 +125,12 @@ static void coda_put_super(struct super_block *sb)
ENTRY;
-
- sb->s_dev = 0;
coda_cache_clear_all(sb);
sb_info = coda_sbp(sb);
coda_super_info.sbi_sb = NULL;
printk("Coda: Bye bye.\n");
memset(sb_info, 0, sizeof(* sb_info));
- MOD_DEC_USE_COUNT;
EXIT;
}
@@ -235,31 +221,25 @@ int coda_notify_change(struct dentry *de, struct iattr *iattr)
return error;
}
-static int coda_statfs(struct super_block *sb, struct statfs *buf,
- int bufsiz)
+static int coda_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
int error;
- memset(&tmp, 0, sizeof(struct statfs));
-
- error = venus_statfs(sb, &tmp);
+ error = venus_statfs(sb, buf);
if (error) {
/* fake something like AFS does */
- tmp.f_blocks = 9000000;
- tmp.f_bfree = 9000000;
- tmp.f_bavail = 9000000;
- tmp.f_files = 9000000;
- tmp.f_ffree = 9000000;
+ buf->f_blocks = 9000000;
+ buf->f_bfree = 9000000;
+ buf->f_bavail = 9000000;
+ buf->f_files = 9000000;
+ buf->f_ffree = 9000000;
}
/* and fill in the rest */
- tmp.f_type = CODA_SUPER_MAGIC;
- tmp.f_bsize = 1024;
- tmp.f_namelen = CODA_MAXNAMLEN;
-
- copy_to_user(buf, &tmp, bufsiz);
+ buf->f_type = CODA_SUPER_MAGIC;
+ buf->f_bsize = 1024;
+ buf->f_namelen = CODA_MAXNAMLEN;
return 0;
}
@@ -267,9 +247,7 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf,
/* init_coda: used by filesystems.c to register coda */
-struct file_system_type coda_fs_type = {
- "coda", 0, coda_read_super, NULL
-};
+DECLARE_FSTYPE( coda_fs_type, "coda", coda_read_super, 0);
int init_coda_fs(void)
{
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 89b9719f5..237c7d9aa 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -153,7 +153,6 @@ static struct super_block * cramfs_read_super(struct super_block *sb, void *data
unsigned long root_offset;
struct super_block * retval = NULL;
- lock_super(sb);
set_blocksize(sb->s_dev, PAGE_CACHE_SIZE);
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -198,7 +197,6 @@ static struct super_block * cramfs_read_super(struct super_block *sb, void *data
retval = sb;
out:
- unlock_super(sb);
return retval;
}
@@ -208,20 +206,15 @@ static void cramfs_put_super(struct super_block *sb)
return;
}
-static int cramfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+static int cramfs_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- /* Unsupported fields set to -1 as per man page. */
- memset(&tmp, 0xff, sizeof(tmp));
-
- tmp.f_type = CRAMFS_MAGIC;
- tmp.f_bsize = PAGE_CACHE_SIZE;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = 255;
- return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+ buf->f_type = CRAMFS_MAGIC;
+ buf->f_bsize = PAGE_CACHE_SIZE;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = 255;
+ return 0;
}
/*
@@ -372,12 +365,7 @@ static struct super_operations cramfs_ops = {
statfs: cramfs_statfs,
};
-static struct file_system_type cramfs_fs_type = {
- "cramfs",
- FS_REQUIRES_DEV,
- cramfs_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super);
static int __init init_cramfs_fs(void)
{
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index f2e09cd6e..ab1e9ee83 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -2305,27 +2305,21 @@ static void devfs_put_super (struct super_block *sb)
if (devfs_debug & DEBUG_S_PUT)
printk ("%s: put_super(): devfs ptr: %p\n", DEVFS_NAME, fs_info);
#endif
- sb->s_dev = 0;
#ifdef CONFIG_DEVFS_TUNNEL
dput (fs_info->table[0]->covered);
#endif
delete_fs (fs_info);
- MOD_DEC_USE_COUNT;
} /* End Function devfs_put_super */
-static int devfs_statfs (struct super_block *sb, struct statfs *buf,int bufsiz)
+static int devfs_statfs (struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = DEVFS_SUPER_MAGIC;
- tmp.f_bsize = PAGE_SIZE / sizeof (long);
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user (buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = DEVFS_SUPER_MAGIC;
+ buf->f_bsize = PAGE_SIZE / sizeof (long);
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
} /* End Function devfs_statfs */
static struct super_operations devfs_sops =
@@ -3152,7 +3146,6 @@ static struct super_block *devfs_read_super (struct super_block *sb,
{
if (strcmp (aopt, "explicit") == 0) fs_info->require_explicit = TRUE;
}
- lock_super (sb);
sb->u.generic_sbp = fs_info;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
@@ -3173,32 +3166,22 @@ static struct super_block *devfs_read_super (struct super_block *sb,
#ifdef CONFIG_DEVFS_TUNNEL
di->covered = dget (sb->s_root->d_covered);
#endif
- unlock_super (sb);
#ifdef CONFIG_DEVFS_DEBUG
if (devfs_debug & DEBUG_DISABLED)
printk ("%s: read super, made devfs ptr: %p\n",
DEVFS_NAME, sb->u.generic_sbp);
#endif
- MOD_INC_USE_COUNT;
return sb;
out_no_root:
printk ("devfs_read_super: get root inode failed\n");
delete_fs (fs_info);
if (root_inode) iput (root_inode);
- sb->s_dev = 0;
- unlock_super (sb);
return NULL;
} /* End Function devfs_read_super */
-static struct file_system_type devfs_fs_type =
-{
- DEVFS_NAME,
- 0,
- devfs_read_super,
- NULL,
-};
+static DECLARE_FSTYPE(devfs_fs_type, DEVFS_NAME, devfs_read_super, 0);
/* File operations for devfsd follow */
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index dab1864cb..67cc1c7b1 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -51,19 +51,13 @@ static void devpts_put_super(struct super_block *sb)
kfree(sbi->inodes);
kfree(sbi);
-
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
}
-static int devpts_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int devpts_statfs(struct super_block *sb, struct statfs *buf);
static void devpts_read_inode(struct inode *inode);
-static void devpts_write_inode(struct inode *inode);
static struct super_operations devpts_sops = {
read_inode: devpts_read_inode,
- write_inode: devpts_write_inode,
put_super: devpts_put_super,
statfs: devpts_statfs,
};
@@ -125,9 +119,6 @@ struct super_block *devpts_read_super(struct super_block *s, void *data,
struct dentry * root;
struct devpts_sb_info *sbi;
- MOD_INC_USE_COUNT;
-
- lock_super(s);
/* Super block already completed? */
if (s->s_root)
goto out_unlock;
@@ -151,7 +142,6 @@ struct super_block *devpts_read_super(struct super_block *s, void *data,
s->s_magic = DEVPTS_SUPER_MAGIC;
s->s_op = &devpts_sops;
s->s_root = NULL;
- unlock_super(s); /* shouldn't we keep it locked a while longer? */
/*
* Get the root inode and dentry, but defer checking for errors.
@@ -183,7 +173,6 @@ struct super_block *devpts_read_super(struct super_block *s, void *data,
/*
* Success! Install the root dentry now to indicate completion.
*/
- lock_super(s);
s->s_root = root;
sbi->next = mounts;
@@ -192,14 +181,12 @@ struct super_block *devpts_read_super(struct super_block *s, void *data,
sbi->back = &mounts;
mounts = s;
- unlock_super(s);
return s;
/*
* Success ... somebody else completed the super block for us.
*/
out_unlock:
- unlock_super(s);
goto out_dec;
out_dput:
if (root)
@@ -207,7 +194,6 @@ out_dput:
else
iput(root_inode);
out_dec:
- MOD_DEC_USE_COUNT;
return s;
/*
@@ -217,7 +203,6 @@ fail_dput:
/*
* dput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
dput(root);
goto fail_free;
fail_iput:
@@ -225,32 +210,22 @@ fail_iput:
/*
* iput() can block, so we clear the super block first.
*/
- s->s_dev = 0;
iput(root_inode);
fail_free:
kfree(sbi);
- goto fail_dec;
fail_unlock:
- unlock_super(s);
-fail_dec:
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
-static int devpts_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int devpts_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = DEVPTS_SUPER_MAGIC;
- tmp.f_bsize = 1024;
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = DEVPTS_SUPER_MAGIC;
+ buf->f_bsize = 1024;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
static void devpts_read_inode(struct inode *inode)
@@ -284,16 +259,7 @@ static void devpts_read_inode(struct inode *inode)
return;
}
-static void devpts_write_inode(struct inode *inode)
-{
-}
-
-static struct file_system_type devpts_fs_type = {
- "devpts",
- 0,
- devpts_read_super,
- NULL
-};
+static DECLARE_FSTYPE(devpts_fs_type, "devpts", devpts_read_super, 0);
void devpts_pty_new(int number, kdev_t device)
{
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 4522b2cfe..092c2f0a7 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -13,12 +13,7 @@
#include <linux/efs_vh.h>
#include <linux/efs_fs_sb.h>
-static struct file_system_type efs_fs_type = {
- "efs", /* filesystem name */
- FS_REQUIRES_DEV, /* fs_flags */
- efs_read_super, /* entry function pointer */
- NULL /* next */
-};
+static DECLARE_FSTYPE_DEV(efs_fs_type, "efs", efs_read_super);
static struct super_operations efs_superblock_operations = {
read_inode: efs_read_inode,
@@ -145,9 +140,6 @@ struct super_block *efs_read_super(struct super_block *s, void *d, int silent) {
struct efs_sb_info *sb;
struct buffer_head *bh;
- MOD_INC_USE_COUNT;
- lock_super(s);
-
sb = SUPER_INFO(s);
set_blocksize(dev, EFS_BLOCKSIZE);
@@ -199,7 +191,6 @@ struct super_block *efs_read_super(struct super_block *s, void *d, int silent) {
s->s_op = &efs_superblock_operations;
s->s_dev = dev;
s->s_root = d_alloc_root(iget(s, EFS_ROOTINODE));
- unlock_super(s);
if (!(s->s_root)) {
printk(KERN_ERR "EFS: get root inode failed\n");
@@ -214,35 +205,30 @@ struct super_block *efs_read_super(struct super_block *s, void *d, int silent) {
return(s);
out_no_fs_ul:
- unlock_super(s);
out_no_fs:
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
return(NULL);
}
void efs_put_super(struct super_block *s) {
- MOD_DEC_USE_COUNT;
}
-int efs_statfs(struct super_block *s, struct statfs *buf, int bufsiz) {
- struct statfs ret;
+int efs_statfs(struct super_block *s, struct statfs *buf) {
struct efs_sb_info *sb = SUPER_INFO(s);
- ret.f_type = EFS_SUPER_MAGIC; /* efs magic number */
- ret.f_bsize = EFS_BLOCKSIZE; /* blocksize */
- ret.f_blocks = sb->total_groups * /* total data blocks */
+ buf->f_type = EFS_SUPER_MAGIC; /* efs magic number */
+ buf->f_bsize = EFS_BLOCKSIZE; /* blocksize */
+ buf->f_blocks = sb->total_groups * /* total data blocks */
(sb->group_size - sb->inode_blocks);
- ret.f_bfree = sb->data_free; /* free data blocks */
- ret.f_bavail = sb->data_free; /* free blocks for non-root */
- ret.f_files = sb->total_groups * /* total inodes */
+ buf->f_bfree = sb->data_free; /* free data blocks */
+ buf->f_bavail = sb->data_free; /* free blocks for non-root */
+ buf->f_files = sb->total_groups * /* total inodes */
sb->inode_blocks *
(EFS_BLOCKSIZE / sizeof(struct efs_dinode));
- ret.f_ffree = sb->inode_free; /* free inodes */
- ret.f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
- ret.f_fsid.val[1] = sb->fs_magic & 0xffff; /* fs ID */
- ret.f_namelen = EFS_MAXNAMELEN; /* max filename length */
+ buf->f_ffree = sb->inode_free; /* free inodes */
+ buf->f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */
+ buf->f_fsid.val[1] = sb->fs_magic & 0xffff; /* fs ID */
+ buf->f_namelen = EFS_MAXNAMELEN; /* max filename length */
- return copy_to_user(buf, &ret, bufsiz) ? -EFAULT : 0;
+ return 0;
}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 43a425bbb..904f5cb8f 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -679,6 +679,7 @@ int ext2_group_sparse(int group)
test_root(group, 7));
}
+/* Called at mount-time, super-block is locked */
void ext2_check_blocks_bitmap (struct super_block * sb)
{
struct buffer_head * bh;
@@ -689,7 +690,6 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
struct ext2_group_desc * gdp;
int i, j;
- lock_super (sb);
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
@@ -752,5 +752,4 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
"Wrong free blocks count in super block, "
"stored = %lu, counted = %lu",
(unsigned long) le32_to_cpu(es->s_free_blocks_count), bitmap_count);
- unlock_super (sb);
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 72437bb89..3a3e4a69c 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -527,6 +527,7 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
#endif
}
+/* Called at mount-time, super-block is locked */
void ext2_check_inodes_bitmap (struct super_block * sb)
{
struct ext2_super_block * es;
@@ -535,7 +536,6 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
struct ext2_group_desc * gdp;
int i;
- lock_super (sb);
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
@@ -564,5 +564,4 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
"stored = %lu, counted = %lu",
(unsigned long) le32_to_cpu(es->s_free_inodes_count),
bitmap_count);
- unlock_super (sb);
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index b4cdc5868..73be71e61 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -116,7 +116,6 @@ void ext2_put_super (struct super_block * sb)
brelse (sb->u.ext2_sb.s_block_bitmap[i]);
brelse (sb->u.ext2_sb.s_sbh);
- MOD_DEC_USE_COUNT;
return;
}
@@ -402,12 +401,9 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL);
if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
&sb->u.ext2_sb.s_mount_opt)) {
- sb->s_dev = 0;
return NULL;
}
- MOD_INC_USE_COUNT;
- lock_super (sb);
set_blocksize (dev, blocksize);
/*
@@ -421,10 +417,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
}
if (!(bh = bread (dev, logic_sb_block, blocksize))) {
- sb->s_dev = 0;
- unlock_super (sb);
printk ("EXT2-fs: unable to read superblock\n");
- MOD_DEC_USE_COUNT;
return NULL;
}
/*
@@ -439,11 +432,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
printk ("VFS: Can't find an ext2 filesystem on dev "
"%s.\n", bdevname(dev));
failed_mount:
- sb->s_dev = 0;
- unlock_super (sb);
if (bh)
brelse(bh);
- MOD_DEC_USE_COUNT;
return NULL;
}
if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) {
@@ -616,7 +606,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
sb->u.ext2_sb.s_loaded_inode_bitmaps = 0;
sb->u.ext2_sb.s_loaded_block_bitmaps = 0;
sb->u.ext2_sb.s_db_per_group = db_count;
- unlock_super (sb);
/*
* set up enough so that it can read an inode
*/
@@ -624,7 +613,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
sb->s_op = &ext2_sops;
sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
if (!sb->s_root) {
- sb->s_dev = 0;
for (i = 0; i < db_count; i++)
if (sb->u.ext2_sb.s_group_desc[i])
brelse (sb->u.ext2_sb.s_group_desc[i]);
@@ -632,7 +620,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
db_count * sizeof (struct buffer_head *));
brelse (bh);
printk ("EXT2-fs: get root inode failed\n");
- MOD_DEC_USE_COUNT;
return NULL;
}
ext2_setup_super (sb, es);
@@ -725,10 +712,9 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
return 0;
}
-int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
+int ext2_statfs (struct super_block * sb, struct statfs * buf)
{
unsigned long overhead;
- struct statfs tmp;
int ngroups, i;
if (test_opt (sb, MINIX_DF))
@@ -768,25 +754,20 @@ int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
(2 + sb->u.ext2_sb.s_itb_per_group));
}
- tmp.f_type = EXT2_SUPER_MAGIC;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = le32_to_cpu(sb->u.ext2_sb.s_es->s_blocks_count) - overhead;
- tmp.f_bfree = ext2_count_free_blocks (sb);
- tmp.f_bavail = tmp.f_bfree - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count);
- if (tmp.f_bfree < le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count))
- tmp.f_bavail = 0;
- tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
- tmp.f_ffree = ext2_count_free_inodes (sb);
- tmp.f_namelen = EXT2_NAME_LEN;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = EXT2_SUPER_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = le32_to_cpu(sb->u.ext2_sb.s_es->s_blocks_count) - overhead;
+ buf->f_bfree = ext2_count_free_blocks (sb);
+ buf->f_bavail = buf->f_bfree - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count);
+ if (buf->f_bfree < le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count))
+ buf->f_bavail = 0;
+ buf->f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
+ buf->f_ffree = ext2_count_free_inodes (sb);
+ buf->f_namelen = EXT2_NAME_LEN;
+ return 0;
}
-static struct file_system_type ext2_fs_type = {
- "ext2",
- FS_REQUIRES_DEV /* | FS_IBASKET */, /* ibaskets have unresolved bugs */
- ext2_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(ext2_fs_type, "ext2", ext2_read_super);
static int __init init_ext2_fs(void)
{
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 63af738a3..f95adc0fd 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -194,11 +194,6 @@ void fat_put_super(struct super_block *sb)
kfree(MSDOS_SB(sb)->options.iocharset);
MSDOS_SB(sb)->options.iocharset = NULL;
}
-
- if (MSDOS_SB(sb)->put_super_callback)
- MSDOS_SB(sb)->put_super_callback(sb);
- MOD_DEC_USE_COUNT;
- return;
}
@@ -444,9 +439,7 @@ fat_read_super(struct super_block *sb, void *data, int silent,
sbi->cvf_format = NULL;
sbi->private_data = NULL;
- MOD_INC_USE_COUNT;
sbi->dir_ops = fs_dir_inode_ops;
- sbi->put_super_callback = NULL;
sb->s_op = &fat_sops;
if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)];
@@ -465,7 +458,6 @@ fat_read_super(struct super_block *sb, void *data, int silent,
memcpy(&(sbi->options), &opts, sizeof(struct fat_mount_options));
fat_cache_init();
- lock_super(sb);
if( blksize > 1024 )
{
/* Force the superblock to a larger size here. */
@@ -479,7 +471,6 @@ fat_read_super(struct super_block *sb, void *data, int silent,
set_blocksize(sb->s_dev, 1024);
}
bh = bread(sb->s_dev, 0, sb->s_blocksize);
- unlock_super(sb);
if (bh == NULL || !buffer_uptodate(bh)) {
brelse (bh);
goto out_no_bread;
@@ -693,23 +684,21 @@ out_fail:
printk("VFS: freeing iocharset=%s\n", opts.iocharset);
kfree(opts.iocharset);
}
- sb->s_dev = 0;
if(sbi->private_data)
kfree(sbi->private_data);
sbi->private_data=NULL;
- MOD_DEC_USE_COUNT;
return NULL;
}
-int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
+int fat_statfs(struct super_block *sb,struct statfs *buf)
{
int free,nr;
- struct statfs tmp;
if (MSDOS_SB(sb)->cvf_format &&
MSDOS_SB(sb)->cvf_format->cvf_statfs)
- return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz);
+ return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,
+ sizeof(struct statfs));
lock_fat(sb);
if (MSDOS_SB(sb)->free_clusters != -1)
@@ -721,15 +710,13 @@ int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
MSDOS_SB(sb)->free_clusters = free;
}
unlock_fat(sb);
- tmp.f_type = sb->s_magic;
- tmp.f_bsize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
- tmp.f_blocks = MSDOS_SB(sb)->clusters;
- tmp.f_bfree = free;
- tmp.f_bavail = free;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = MSDOS_SB(sb)->options.isvfat ? 260 : 12;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = sb->s_magic;
+ buf->f_bsize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
+ buf->f_blocks = MSDOS_SB(sb)->clusters;
+ buf->f_bfree = free;
+ buf->f_bavail = free;
+ buf->f_namelen = MSDOS_SB(sb)->options.isvfat ? 260 : 12;
+ return 0;
}
static int is_exec(char *extension)
diff --git a/fs/filesystems.c b/fs/filesystems.c
index d0a446c6e..807f8306d 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -32,7 +32,6 @@
#include <linux/hfs_fs.h>
#include <linux/devpts_fs.h>
#include <linux/bfs_fs.h>
-#include <linux/adfs_fs.h>
#include <linux/openprom_fs.h>
#include <linux/major.h>
#include <linux/smp.h>
@@ -89,10 +88,6 @@ void __init filesystem_setup(void)
init_devfs_fs(); /* Header file may make this empty */
-#ifdef CONFIG_LOCKD
- nlmxdr_init();
-#endif
-
#ifdef CONFIG_NFS_FS
init_nfs_fs();
#endif
@@ -141,10 +136,6 @@ void __init filesystem_setup(void)
init_efs_fs();
#endif
-#ifdef CONFIG_ADFS_FS
- init_adfs_fs();
-#endif
-
#ifdef CONFIG_DEVPTS_FS
init_devpts_fs();
#endif
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 40f8d2e5f..debe0a967 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -311,7 +311,7 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry)
goto hfs_rmdir_put;
error = -EBUSY;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
goto hfs_rmdir_put;
if (/* we only have to worry about 2 and 3 for mount points */
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 3ed8307a0..251690dc8 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -36,7 +36,7 @@
static void hfs_read_inode(struct inode *);
static void hfs_put_super(struct super_block *);
-static int hfs_statfs(struct super_block *, struct statfs *, int);
+static int hfs_statfs(struct super_block *, struct statfs *);
static void hfs_write_super(struct super_block *);
/*================ Global variables ================*/
@@ -51,11 +51,7 @@ static struct super_operations hfs_super_operations = {
/*================ File-local variables ================*/
-static struct file_system_type hfs_fs = {
- "hfs",
- FS_REQUIRES_DEV,
- hfs_read_super,
- NULL};
+static DECLARE_FSTYPE_DEV(hfs_fs, "hfs", hfs_read_super);
/*================ File-local functions ================*/
@@ -126,8 +122,6 @@ static void hfs_put_super(struct super_block *sb)
/* restore default blocksize for the device */
set_blocksize(sb->s_dev, BLOCK_SIZE);
-
- MOD_DEC_USE_COUNT;
}
/*
@@ -139,21 +133,20 @@ static void hfs_put_super(struct super_block *sb)
*
* changed f_files/f_ffree to reflect the fs_ablock/free_ablocks.
*/
-static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len)
+static int hfs_statfs(struct super_block *sb, struct statfs *buf)
{
struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
- struct statfs tmp;
-
- tmp.f_type = HFS_SUPER_MAGIC;
- tmp.f_bsize = HFS_SECTOR_SIZE;
- tmp.f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
- tmp.f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
- tmp.f_bavail = tmp.f_bfree;
- tmp.f_files = mdb->fs_ablocks;
- tmp.f_ffree = mdb->free_ablocks;
- tmp.f_namelen = HFS_NAMELEN;
-
- return copy_to_user(buf, &tmp, len) ? -EFAULT : 0;
+
+ buf->f_type = HFS_SUPER_MAGIC;
+ buf->f_bsize = HFS_SECTOR_SIZE;
+ buf->f_blocks = mdb->alloc_blksz * mdb->fs_ablocks;
+ buf->f_bfree = mdb->alloc_blksz * mdb->free_ablocks;
+ buf->f_bavail = buf->f_bfree;
+ buf->f_files = mdb->fs_ablocks;
+ buf->f_ffree = mdb->free_ablocks;
+ buf->f_namelen = HFS_NAMELEN;
+
+ return 0;
}
/*
@@ -407,11 +400,6 @@ struct super_block *hfs_read_super(struct super_block *s, void *data,
goto bail3;
}
- /* in case someone tries to unload the module while we wait on I/O */
- MOD_INC_USE_COUNT;
-
- lock_super(s);
-
/* set the device driver to 512-byte blocks */
set_blocksize(dev, HFS_SECTOR_SIZE);
@@ -471,7 +459,6 @@ struct super_block *hfs_read_super(struct super_block *s, void *data,
s->s_root->d_op = &hfs_dentry_operations;
/* everything's okay */
- unlock_super(s);
return s;
bail_no_root:
@@ -481,10 +468,7 @@ bail1:
hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
bail2:
set_blocksize(dev, BLOCK_SIZE);
- unlock_super(s);
- MOD_DEC_USE_COUNT;
bail3:
- s->s_dev = 0;
return NULL;
}
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index 44d1037cf..677fda52c 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -311,7 +311,7 @@ int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
int hpfs_remount_fs(struct super_block *, int *, char *);
void hpfs_put_super(struct super_block *);
unsigned hpfs_count_one_bitmap(struct super_block *, secno);
-int hpfs_statfs(struct super_block *, struct statfs *, int);
+int hpfs_statfs(struct super_block *, struct statfs *);
struct super_block *hpfs_read_super(struct super_block *, void *, int);
extern struct address_space_operations hpfs_aops;
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 663817085..f02239eae 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -375,7 +375,7 @@ int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
hpfs_unlock_2inodes(dir, inode);
return -ENOTDIR;
}
- if (!list_empty(&dentry->d_hash)) {
+ if (!d_unhashed(dentry)) {
hpfs_brelse4(&qbh);
hpfs_unlock_2inodes(dir, inode);
return -EBUSY;
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 8937bb90e..d29f6e574 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -102,8 +102,6 @@ void hpfs_put_super(struct super_block *s)
if (s->s_hpfs_cp_table) kfree(s->s_hpfs_cp_table);
if (s->s_hpfs_bmp_dir) kfree(s->s_hpfs_bmp_dir);
unmark_dirty(s);
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
}
unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno)
@@ -132,22 +130,21 @@ static unsigned count_bitmaps(struct super_block *s)
return count;
}
-int hpfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
+int hpfs_statfs(struct super_block *s, struct statfs *buf)
{
- struct statfs tmp;
/*if (s->s_hpfs_n_free == -1) {*/
s->s_hpfs_n_free = count_bitmaps(s);
s->s_hpfs_n_free_dnodes = hpfs_count_one_bitmap(s, s->s_hpfs_dmap);
/*}*/
- tmp.f_type = s->s_magic;
- tmp.f_bsize = 512;
- tmp.f_blocks = s->s_hpfs_fs_size;
- tmp.f_bfree = s->s_hpfs_n_free;
- tmp.f_bavail = s->s_hpfs_n_free;
- tmp.f_files = s->s_hpfs_dirband_size / 4;
- tmp.f_ffree = s->s_hpfs_n_free_dnodes;
- tmp.f_namelen = 254;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = s->s_magic;
+ buf->f_bsize = 512;
+ buf->f_blocks = s->s_hpfs_fs_size;
+ buf->f_bfree = s->s_hpfs_n_free;
+ buf->f_bavail = s->s_hpfs_n_free;
+ buf->f_files = s->s_hpfs_dirband_size / 4;
+ buf->f_ffree = s->s_hpfs_n_free_dnodes;
+ buf->f_namelen = 254;
+ return 0;
}
/* Super operations */
@@ -369,8 +366,6 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options,
int o;
- MOD_INC_USE_COUNT;
-
s->s_hpfs_bmp_dir = NULL;
s->s_hpfs_cp_table = NULL;
@@ -400,7 +395,6 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options,
}
/*s->s_hpfs_mounting = 1;*/
- lock_super(s);
dev = s->s_dev;
set_blocksize(dev, 512);
s->s_hpfs_fs_size = -1;
@@ -524,7 +518,6 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options,
hpfs_lock_iget(s, 1);
s->s_root = d_alloc_root(iget(s, s->s_hpfs_root));
hpfs_unlock_iget(s);
- unlock_super(s);
if (!s->s_root || !s->s_root->d_inode) {
printk("HPFS: iget failed. Why???\n");
goto bail0;
@@ -555,17 +548,14 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options,
bail4: brelse(bh2);
bail3: brelse(bh1);
bail2: brelse(bh0);
-bail1: unlock_super(s);
-bail0: s->s_dev = 0;
+bail1:
+bail0:
if (s->s_hpfs_bmp_dir) kfree(s->s_hpfs_bmp_dir);
if (s->s_hpfs_cp_table) kfree(s->s_hpfs_cp_table);
- MOD_DEC_USE_COUNT;
return NULL;
}
-struct file_system_type hpfs_fs_type = {
- "hpfs", FS_REQUIRES_DEV, hpfs_read_super, NULL
-};
+DECLARE_FSTYPE_DEV(hpfs_fs_type, "hpfs", hpfs_read_super);
int init_hpfs_fs(void)
{
diff --git a/fs/inode.c b/fs/inode.c
index 9b216857d..c4915bba1 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -94,6 +94,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
INIT_LIST_HEAD(&inode->i_data.pages);
INIT_LIST_HEAD(&inode->i_dentry);
sema_init(&inode->i_sem, 1);
+ sema_init(&inode->i_zombie, 1);
spin_lock_init(&inode->i_data.i_shared_lock);
}
}
diff --git a/fs/iobuf.c b/fs/iobuf.c
index 4eaefe723..4be225870 100644
--- a/fs/iobuf.c
+++ b/fs/iobuf.c
@@ -12,18 +12,21 @@
static kmem_cache_t *kiobuf_cachep;
-/*
- * The default IO completion routine for kiobufs: just wake up
- * the kiobuf, nothing more.
- */
-void simple_wakeup_kiobuf(struct kiobuf *kiobuf)
+void end_kio_request(struct kiobuf *kiobuf, int uptodate)
{
- wake_up(&kiobuf->wait_queue);
+ if ((!uptodate) && !kiobuf->errno)
+ kiobuf->errno = -EIO;
+
+ if (atomic_dec_and_test(&kiobuf->io_count)) {
+ if (kiobuf->end_io)
+ kiobuf->end_io(kiobuf);
+ wake_up(&kiobuf->wait_queue);
+ }
}
-void __init kiobuf_init(void)
+void __init kiobuf_setup(void)
{
kiobuf_cachep = kmem_cache_create("kiobuf",
sizeof(struct kiobuf),
@@ -33,6 +36,13 @@ void __init kiobuf_init(void)
panic("Cannot create kernel iobuf cache\n");
}
+void kiobuf_init(struct kiobuf *iobuf)
+{
+ memset(iobuf, 0, sizeof(*iobuf));
+ init_waitqueue_head(&iobuf->wait_queue);
+ iobuf->array_len = KIO_STATIC_PAGES;
+ iobuf->maplist = iobuf->map_array;
+}
int alloc_kiovec(int nr, struct kiobuf **bufp)
{
@@ -45,12 +55,7 @@ int alloc_kiovec(int nr, struct kiobuf **bufp)
free_kiovec(i, bufp);
return -ENOMEM;
}
-
- memset(iobuf, 0, sizeof(*iobuf));
- init_waitqueue_head(&iobuf->wait_queue);
- iobuf->end_io = simple_wakeup_kiobuf;
- iobuf->array_len = KIO_STATIC_PAGES;
- iobuf->maplist = iobuf->map_array;
+ kiobuf_init(iobuf);
*bufp++ = iobuf;
}
@@ -64,6 +69,8 @@ void free_kiovec(int nr, struct kiobuf **bufp)
for (i = 0; i < nr; i++) {
iobuf = bufp[i];
+ if (iobuf->locked)
+ unlock_kiovec(1, &iobuf);
if (iobuf->array_len > KIO_STATIC_PAGES)
kfree (iobuf->maplist);
kmem_cache_free(kiobuf_cachep, bufp[i]);
@@ -104,6 +111,9 @@ void kiobuf_wait_for_io(struct kiobuf *kiobuf)
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
+ if (atomic_read(&kiobuf->io_count) == 0)
+ return;
+
add_wait_queue(&kiobuf->wait_queue, &wait);
repeat:
run_task_queue(&tq_disk);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 996d5ba68..b13ee0285 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -69,12 +69,11 @@ static void isofs_put_super(struct super_block *sb)
check_malloc, check_bread);
#endif
- MOD_DEC_USE_COUNT;
return;
}
static void isofs_read_inode(struct inode *);
-static int isofs_statfs (struct super_block *, struct statfs *, int);
+static int isofs_statfs (struct super_block *, struct statfs *);
static struct super_operations isofs_sops = {
read_inode: isofs_read_inode,
@@ -487,10 +486,6 @@ static struct super_block *isofs_read_super(struct super_block *s, void *data,
struct inode * inode;
struct iso9660_options opt;
- MOD_INC_USE_COUNT;
- /* lock before any blocking operations */
- lock_super(s);
-
if (!parse_options((char *) data, &opt))
goto out_unlock;
@@ -825,7 +820,6 @@ root_found:
if (opt.check == 'r') table++;
s->s_root->d_op = &isofs_dentry_ops[table];
- unlock_super(s);
return s;
/*
@@ -868,26 +862,21 @@ out_unknown_format:
out_freebh:
brelse(bh);
out_unlock:
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
return NULL;
}
-static int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+static int isofs_statfs (struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = ISOFS_SUPER_MAGIC;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = (sb->u.isofs_sb.s_nzones
+ buf->f_type = ISOFS_SUPER_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = (sb->u.isofs_sb.s_nzones
<< (sb->u.isofs_sb.s_log_zone_size - sb->s_blocksize_bits));
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = sb->u.isofs_sb.s_ninodes;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_files = sb->u.isofs_sb.s_ninodes;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
/* Life is simpler than for other filesystem since we never
@@ -1440,12 +1429,7 @@ void leak_check_brelse(struct buffer_head * bh){
#endif
-static struct file_system_type iso9660_fs_type = {
- "iso9660",
- FS_REQUIRES_DEV,
- isofs_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(iso9660_fs_type, "iso9660", isofs_read_super);
int __init init_iso9660_fs(void)
{
diff --git a/fs/lockd/lockd_syms.c b/fs/lockd/lockd_syms.c
index db36300ba..b3990ed98 100644
--- a/fs/lockd/lockd_syms.c
+++ b/fs/lockd/lockd_syms.c
@@ -39,15 +39,4 @@ EXPORT_SYMBOL(nlmsvc_ops);
EXPORT_SYMBOL(nlmsvc_grace_period);
EXPORT_SYMBOL(nlmsvc_timeout);
-#ifdef CONFIG_LOCKD_V4
-
-/* NLM4 exported symbols */
-EXPORT_SYMBOL(nlm4_rofs);
-EXPORT_SYMBOL(nlm4_stale_fh);
-EXPORT_SYMBOL(nlm4_deadlock);
-EXPORT_SYMBOL(nlm4_failed);
-EXPORT_SYMBOL(nlm4_fbig);
-
-#endif
-
#endif /* CONFIG_MODULES */
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 62401adbd..264c19c2e 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -322,7 +322,6 @@ init_module(void)
init_MUTEX(&nlmsvc_sema);
nlmsvc_users = 0;
nlmsvc_pid = 0;
- nlmxdr_init();
return 0;
}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index b3489a88d..c6395a54f 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -25,15 +25,17 @@
/*
* Global file hash table
*/
-#define FILE_NRHASH 32
#define FILE_HASH_BITS 5
+#define FILE_NRHASH (1<<FILE_HASH_BITS)
static struct nlm_file * nlm_files[FILE_NRHASH];
static DECLARE_MUTEX(nlm_file_sema);
-static unsigned int file_hash(dev_t dev, ino_t ino)
+static inline unsigned int file_hash(struct nfs_fh *f)
{
- unsigned long tmp = (unsigned long) ino | (unsigned long) dev;
- tmp = tmp + (tmp >> FILE_HASH_BITS) + (tmp >> FILE_HASH_BITS*2);
+ unsigned int tmp=0;
+ int i;
+ for (i=0; i<NFS_FHSIZE;i++)
+ tmp += f->data[i];
return tmp & (FILE_NRHASH - 1);
}
@@ -50,34 +52,35 @@ u32
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
struct nfs_fh *f)
{
- struct knfs_fh *fh = (struct knfs_fh *) f;
struct nlm_file *file;
unsigned int hash;
u32 nfserr;
+ u32 *fhp = (u32*)f->data;
- dprintk("lockd: nlm_file_lookup(%s/%u)\n",
- kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino);
+ dprintk("lockd: nlm_file_lookup(%08x %08x %08x %08x %08x %08x)\n",
+ fhp[0], fhp[1], fhp[2], fhp[3], fhp[4], fhp[5]);
- hash = file_hash(u32_to_kdev_t(fh->fh_dev), u32_to_ino_t(fh->fh_ino));
+
+ hash = file_hash(f);
/* Lock file table */
down(&nlm_file_sema);
- for (file = nlm_files[hash]; file; file = file->f_next) {
- if (file->f_handle.fh_dcookie == fh->fh_dcookie &&
- !memcmp(&file->f_handle, fh, sizeof(*fh)))
+ for (file = nlm_files[hash]; file; file = file->f_next)
+ if (!memcmp(&file->f_handle, f, sizeof(*f)))
goto found;
- }
- dprintk("lockd: creating file for %s/%u\n",
- kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino);
+ dprintk("lockd: creating file for (%08x %08x %08x %08x %08x %08x)\n",
+ fhp[0], fhp[1], fhp[2], fhp[3], fhp[4], fhp[5]);
+
nfserr = nlm_lck_denied_nolocks;
file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL);
if (!file)
goto out_unlock;
memset(file, 0, sizeof(*file));
- file->f_handle = *fh;
+ file->f_handle = *f;
+ file->f_hash = hash;
init_MUTEX(&file->f_sema);
/* Open the file. Note that this must not sleep for too long, else
@@ -86,7 +89,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
* We have to make sure we have the right credential to open
* the file.
*/
- if ((nfserr = nlmsvc_ops->fopen(rqstp, fh, &file->f_file)) != 0) {
+ if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) {
dprintk("lockd: open failed (nfserr %d)\n", ntohl(nfserr));
goto out_free;
}
@@ -126,7 +129,7 @@ nlm_delete_file(struct nlm_file *file)
dprintk("lockd: closing file %s/%ld\n",
kdevname(inode->i_dev), inode->i_ino);
- fp = nlm_files + file_hash(inode->i_dev, inode->i_ino);
+ fp = nlm_files + file->f_hash;
while ((f = *fp) != NULL) {
if (f == file) {
*fp = file->f_next;
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index c0797a16f..eba3aaef6 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -20,44 +20,7 @@
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_XDR
-#define NLM_MAXSTRLEN 1024
-#define QUADLEN(len) (((len) + 3) >> 2)
-
-
-u32 nlm_granted, nlm_lck_denied, nlm_lck_denied_nolocks,
- nlm_lck_blocked, nlm_lck_denied_grace_period;
-
-
-typedef struct nlm_args nlm_args;
-
-/*
- * Initialization of NFS status variables
- */
-void
-nlmxdr_init(void)
-{
- static int inited = 0;
-
- if (inited)
- return;
-
- nlm_granted = htonl(NLM_LCK_GRANTED);
- nlm_lck_denied = htonl(NLM_LCK_DENIED);
- nlm_lck_denied_nolocks = htonl(NLM_LCK_DENIED_NOLOCKS);
- nlm_lck_blocked = htonl(NLM_LCK_BLOCKED);
- nlm_lck_denied_grace_period = htonl(NLM_LCK_DENIED_GRACE_PERIOD);
-
-#ifdef CONFIG_LOCKD_V4
- nlm4_deadlock = htonl(NLM_DEADLCK);
- nlm4_rofs = htonl(NLM_ROFS);
- nlm4_stale_fh = htonl(NLM_STALE_FH);
- nlm4_fbig = htonl(NLM_FBIG);
- nlm4_failed = htonl(NLM_FAILED);
-#endif
-
- inited = 1;
-}
/*
* XDR functions for basic NLM types
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 7cedcd849..025e3c5b0 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -20,16 +20,8 @@
#include <linux/lockd/sm_inter.h>
#define NLMDBG_FACILITY NLMDBG_XDR
-#define NLM_MAXSTRLEN 1024
#define OFFSET_MAX ((off_t)LONG_MAX)
-#define QUADLEN(len) (((len) + 3) >> 2)
-
-u32 nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig,
- nlm4_failed;
-
-
-typedef struct nlm_args nlm_args;
static inline off_t
size_to_off_t(__s64 size)
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 1d9ebb062..31d4c99c7 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -23,14 +23,13 @@
#include <linux/highuid.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/minix_fs.h>
static void minix_read_inode(struct inode * inode);
static void minix_write_inode(struct inode * inode);
-static int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static int minix_statfs(struct super_block *sb, struct statfs *buf);
static int minix_remount (struct super_block * sb, int * flags, char * data);
static void minix_delete_inode(struct inode *inode)
@@ -80,7 +79,6 @@ static void minix_put_super(struct super_block *sb)
brelse (sb->u.minix_sb.s_sbh);
kfree(sb->u.minix_sb.s_imap);
- MOD_DEC_USE_COUNT;
return;
}
@@ -189,13 +187,10 @@ static struct super_block *minix_read_super(struct super_block *s, void *data,
if (64 != sizeof(struct minix2_inode))
panic("bad V2 i-node size");
- MOD_INC_USE_COUNT;
-
hblock = get_hardblocksize(dev);
if (hblock && hblock > BLOCK_SIZE)
goto out_bad_hblock;
- lock_super(s);
set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread(dev,1,BLOCK_SIZE)))
goto out_bad_sb;
@@ -287,7 +282,6 @@ static struct super_block *minix_read_super(struct super_block *s, void *data,
mark_buffer_dirty(bh, 1);
s->s_dirt = 1;
}
- unlock_super(s);
if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS))
printk ("MINIX-fs: mounting unchecked file system, "
"running fsck is recommended.\n");
@@ -329,7 +323,7 @@ out_no_fs:
"%s.\n", kdevname(dev));
out_release:
brelse(bh);
- goto out_unlock;
+ goto out;
out_bad_hblock:
printk("MINIX-fs: blocksize too small for device.\n");
@@ -337,27 +331,21 @@ out_bad_hblock:
out_bad_sb:
printk("MINIX-fs: unable to read superblock\n");
- out_unlock:
- unlock_super(s);
out:
- s->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
-static int minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int minix_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = sb->s_magic;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = (sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone) << sb->u.minix_sb.s_log_zone_size;
- tmp.f_bfree = minix_count_free_blocks(sb);
- tmp.f_bavail = tmp.f_bfree;
- tmp.f_files = sb->u.minix_sb.s_ninodes;
- tmp.f_ffree = minix_count_free_inodes(sb);
- tmp.f_namelen = sb->u.minix_sb.s_namelen;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = sb->s_magic;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = (sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone) << sb->u.minix_sb.s_log_zone_size;
+ buf->f_bfree = minix_count_free_blocks(sb);
+ buf->f_bavail = buf->f_bfree;
+ buf->f_files = sb->u.minix_sb.s_ninodes;
+ buf->f_ffree = minix_count_free_inodes(sb);
+ buf->f_namelen = sb->u.minix_sb.s_namelen;
+ return 0;
}
/*
@@ -1277,12 +1265,7 @@ int minix_sync_inode(struct inode * inode)
return err;
}
-static struct file_system_type minix_fs_type = {
- "minix",
- FS_REQUIRES_DEV,
- minix_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(minix_fs_type,"minix",minix_read_super);
int __init init_minix_fs(void)
{
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index c18b46a37..211556d4a 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -399,7 +399,7 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
retval = -ENOENT;
goto end_rmdir;
}
- if (!list_empty(&dentry->d_hash)) {
+ if (!d_unhashed(dentry)) {
retval = -EBUSY;
goto end_rmdir;
}
@@ -569,6 +569,9 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
}
if (S_ISDIR(old_inode->i_mode)) {
if (new_inode) {
+ retval = -EBUSY;
+ if (!d_unhashed(new_dentry))
+ goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
diff --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c
index df865b482..8e9897f2f 100644
--- a/fs/msdos/msdosfs_syms.c
+++ b/fs/msdos/msdosfs_syms.c
@@ -27,12 +27,7 @@ EXPORT_SYMBOL(msdos_read_super);
EXPORT_SYMBOL(msdos_put_super);
-struct file_system_type msdos_fs_type = {
- "msdos",
- FS_REQUIRES_DEV,
- msdos_read_super,
- NULL
-};
+DECLARE_FSTYPE_DEV(msdos_fs_type, "msdos", msdos_read_super);
int __init init_msdos_fs(void)
{
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 87a49fb47..7febeaa8b 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -326,7 +326,7 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
* whether it is empty.
*/
res = -EBUSY;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
goto rmdir_done;
res = fat_dir_empty(inode);
if (res)
@@ -463,6 +463,9 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
goto degenerate_case;
if (is_dir) {
if (new_inode) {
+ error = -EBUSY;
+ if (!d_unhashed(new_dentry))
+ goto out;
error = fat_dir_empty(new_inode);
if (error)
goto out;
@@ -590,28 +593,18 @@ struct inode_operations msdos_dir_inode_operations = {
setattr: fat_notify_change,
};
-static void msdos_put_super_callback(struct super_block *sb)
-{
- MOD_DEC_USE_COUNT;
-}
-
struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
{
struct super_block *res;
- MOD_INC_USE_COUNT;
-
MSDOS_SB(sb)->options.isvfat = 0;
res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
if (res == NULL)
goto out_fail;
- MSDOS_SB(sb)->put_super_callback=msdos_put_super_callback;
sb->s_root->d_op = &msdos_dentry_operations;
return res;
out_fail:
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
diff --git a/fs/namei.c b/fs/namei.c
index 5f148b5a8..97c239929 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -580,6 +580,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG;
+ down(&dir->i_zombie);
error = may_create(dir, dentry);
if (error)
goto exit_lock;
@@ -591,6 +592,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
DQUOT_INIT(dir);
error = dir->i_op->create(dir, dentry, mode);
exit_lock:
+ up(&dir->i_zombie);
return error;
}
@@ -745,7 +747,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
mode &= ~current->fs->umask;
- if (!S_ISFIFO(mode) && !capable(CAP_MKNOD))
+ down(&dir->i_zombie);
+ if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
goto exit_lock;
error = may_create(dir, dentry);
@@ -759,6 +762,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
DQUOT_INIT(dir);
error = dir->i_op->mknod(dir, dentry, mode, dev);
exit_lock:
+ up(&dir->i_zombie);
return error;
}
@@ -836,6 +840,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
+ down(&dir->i_zombie);
error = may_create(dir, dentry);
if (error)
goto exit_lock;
@@ -849,6 +854,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
error = dir->i_op->mkdir(dir, dentry, mode);
exit_lock:
+ up(&dir->i_zombie);
return error;
}
@@ -901,6 +907,34 @@ asmlinkage long sys_mkdir(const char * pathname, int mode)
return error;
}
+/*
+ * We try to drop the dentry early: we should have
+ * a usage count of 2 if we're the only user of this
+ * dentry, and if that is true (possibly after pruning
+ * the dcache), then we drop the dentry now.
+ *
+ * A low-level filesystem can, if it choses, legally
+ * do a
+ *
+ * if (!d_unhashed(dentry))
+ * return -EBUSY;
+ *
+ * if it cannot handle the case of removing a directory
+ * that is still in use by something else..
+ */
+static void d_unhash(struct dentry *dentry)
+{
+ dget(dentry);
+ switch (dentry->d_count) {
+ default:
+ shrink_dcache_parent(dentry);
+ if (dentry->d_count != 2)
+ break;
+ case 2:
+ d_drop(dentry);
+ }
+}
+
int vfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
@@ -914,31 +948,11 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
DQUOT_INIT(dir);
- /*
- * We try to drop the dentry early: we should have
- * a usage count of 2 if we're the only user of this
- * dentry, and if that is true (possibly after pruning
- * the dcache), then we drop the dentry now.
- *
- * A low-level filesystem can, if it choses, legally
- * do a
- *
- * if (!list_empty(&dentry->d_hash))
- * return -EBUSY;
- *
- * if it cannot handle the case of removing a directory
- * that is still in use by something else..
- */
- switch (dentry->d_count) {
- default:
- shrink_dcache_parent(dentry);
- if (dentry->d_count != 2)
- break;
- case 2:
- d_drop(dentry);
- }
-
+ double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
+ d_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry);
+ double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
+ dput(dentry);
return error;
}
@@ -954,27 +968,11 @@ static inline int do_rmdir(const char * name)
if (IS_ERR(dentry))
goto exit;
- error = -ENOENT;
- if (!dentry->d_inode)
- goto exit_dput;
-
- dir = dget(dentry->d_parent);
-
- /*
- * The dentry->d_count stuff confuses d_delete() enough to
- * not kill the inode from under us while it is locked. This
- * wouldn't be needed, except the dentry semaphore is really
- * in the inode, not in the dentry..
- */
- dentry->d_count++;
- double_lock(dir, dentry);
-
+ dir = lock_parent(dentry);
error = -ENOENT;
if (check_parent(dir, dentry))
error = vfs_rmdir(dir->d_inode, dentry);
-
- double_unlock(dentry, dir);
-exit_dput:
+ unlock_dir(dir);
dput(dentry);
exit:
return error;
@@ -1001,6 +999,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
{
int error;
+ down(&dir->i_zombie);
error = may_delete(dir, dentry, 0);
if (!error) {
error = -EPERM;
@@ -1009,10 +1008,11 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
error = dir->i_op->unlink(dir, dentry);
}
}
+ up(&dir->i_zombie);
return error;
}
-static inline int do_unlink(const char * name)
+int do_unlink(const char * name)
{
int error;
struct dentry *dir;
@@ -1054,6 +1054,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
{
int error;
+ down(&dir->i_zombie);
error = may_create(dir, dentry);
if (error)
goto exit_lock;
@@ -1066,6 +1067,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
error = dir->i_op->symlink(dir, dentry, oldname);
exit_lock:
+ up(&dir->i_zombie);
return error;
}
@@ -1121,6 +1123,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
struct inode *inode;
int error;
+ down(&dir->i_zombie);
error = -ENOENT;
inode = old_dentry->d_inode;
if (!inode)
@@ -1147,6 +1150,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
error = dir->i_op->link(old_dentry, dir, new_dentry);
exit_lock:
+ up(&dir->i_zombie);
return error;
}
@@ -1212,11 +1216,37 @@ asmlinkage long sys_link(const char * oldname, const char * newname)
return error;
}
+/*
+ * The worst of all namespace operations - renaming directory. "Perverted"
+ * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
+ * Problems:
+ * a) we can get into loop creation. Check is done in is_subdir().
+ * b) race potential - two innocent renames can create a loop together.
+ * That's where 4.4 screws up. Current fix: serialization on
+ * sb->s_vfs_rename_sem. We might be more accurate, but that's another
+ * story.
+ * c) we have to lock _three_ objects - parents and victim (if it exists).
+ * And that - after we got ->i_sem on parents (until then we don't know
+ * whether the target exists at all, let alone whether it is a directory
+ * or not). Solution: ->i_zombie. Taken only after ->i_sem. Always taken
+ * on link creation/removal of any kind. And taken (without ->i_sem) on
+ * directory that will be removed (both in rmdir() and here).
+ * d) some filesystems don't support opened-but-unlinked directories,
+ * either because of layout or because they are not ready to deal with
+ * all cases correctly. The latter will be fixed (taking this sort of
+ * stuff into VFS), but the former is not going away. Solution: the same
+ * trick as in rmdir().
+ * e) conversion from fhandle to dentry may come in the wrong moment - when
+ * we are removing the target. Solution: we will have to grab ->i_zombie
+ * in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
+ * ->i_sem on parents, which works but leads to some truely excessive
+ * locking].
+ */
int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
int error;
- int need_rehash = 0;
+ struct inode *target;
if (old_dentry->d_inode == new_dentry->d_inode)
return 0;
@@ -1254,15 +1284,26 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
error = -EINVAL;
if (is_subdir(new_dentry, old_dentry))
goto out_unlock;
- if (new_dentry->d_inode) {
- error = -EBUSY;
- if (d_invalidate(new_dentry)<0)
- goto out_unlock;
- need_rehash = 1;
- }
+ target = new_dentry->d_inode;
+ if (target) { /* Hastur! Hastur! Hastur! */
+ triple_down(&old_dir->i_zombie,
+ &new_dir->i_zombie,
+ &target->i_zombie);
+ d_unhash(new_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 (need_rehash)
+ if (target) {
+ triple_up(&old_dir->i_zombie,
+ &new_dir->i_zombie,
+ &target->i_zombie);
d_rehash(new_dentry);
+ dput(new_dentry);
+ } else
+ double_up(&old_dir->i_zombie,
+ &new_dir->i_zombie);
+
if (!error)
d_move(old_dentry,new_dentry);
out_unlock:
@@ -1297,7 +1338,9 @@ 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);
+ double_up(&old_dir->i_zombie, &new_dir->i_zombie);
if (error)
return error;
/* The following d_move() should become unconditional */
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index ae5c13962..f5a5856f3 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -929,7 +929,7 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
goto out;
error = -EBUSY;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
goto out;
error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
@@ -1072,7 +1072,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
case 0x00:
DPRINTK("ncp renamed %s -> %s.\n",
old_dentry->d_name.name,new_dentry->d_name.name);
- /* d_move(old_dentry, new_dentry); */
break;
case 0x9E:
error = -ENAMETOOLONG;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 85cc9bd39..349eec589 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -34,7 +34,7 @@
static void ncp_put_inode(struct inode *);
static void ncp_delete_inode(struct inode *);
static void ncp_put_super(struct super_block *);
-static int ncp_statfs(struct super_block *, struct statfs *, int);
+static int ncp_statfs(struct super_block *, struct statfs *);
static struct super_operations ncp_sops =
{
@@ -273,7 +273,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
#endif
struct ncp_entry_info finfo;
- MOD_INC_USE_COUNT;
if (raw_data == NULL)
goto out_no_data;
switch (*(int*)raw_data) {
@@ -323,8 +322,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
if (!S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode))
goto out_bad_file2;
- lock_super(sb);
-
sb->s_blocksize = 1024; /* Eh... Is this correct? */
sb->s_blocksize_bits = 10;
sb->s_magic = NCP_SUPER_MAGIC;
@@ -441,7 +438,6 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
if (!sb->s_root)
goto out_no_root;
sb->s_root->d_op = &ncp_dentry_operations;
- unlock_super(sb);
return sb;
out_no_root:
@@ -473,7 +469,6 @@ out_free_server:
* it doesn't proper unlocking.
*/
fput(ncp_filp);
- unlock_super(sb);
goto out;
out_bad_file2:
@@ -488,8 +483,6 @@ out_bad_mount:
out_no_data:
printk(KERN_ERR "ncp_read_super: missing data argument\n");
out:
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
@@ -524,28 +517,23 @@ static void ncp_put_super(struct super_block *sb)
ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
ncp_kfree_s(server->packet, server->packet_size);
- MOD_DEC_USE_COUNT;
}
-static int ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int ncp_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
/* We cannot say how much disk space is left on a mounted
NetWare Server, because free space is distributed over
volumes, and the current user might have disk quotas. So
free space is not that simple to determine. Our decision
here is to err conservatively. */
- tmp.f_type = NCP_SUPER_MAGIC;
- tmp.f_bsize = NCP_BLOCK_SIZE;
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = -1;
- tmp.f_ffree = -1;
- tmp.f_namelen = 12;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = NCP_SUPER_MAGIC;
+ buf->f_bsize = NCP_BLOCK_SIZE;
+ buf->f_blocks = 0;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_namelen = 12;
+ return 0;
}
int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
@@ -708,12 +696,7 @@ int ncp_malloced;
int ncp_current_malloced;
#endif
-static struct file_system_type ncp_fs_type = {
- "ncpfs",
- 0 /* FS_NO_DCACHE doesn't work correctly */,
- ncp_read_super,
- NULL
-};
+static DECLARE_FSTYPE(ncp_fs_type, "ncpfs", ncp_read_super, 0);
int __init init_ncp_fs(void)
{
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index d111076c0..37b2b682b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -672,7 +672,7 @@ static void show_dentry(struct list_head * dlist)
struct dentry * dentry = list_entry(tmp, struct dentry, d_alias);
const char * unhashed = "";
- if (list_empty(&dentry->d_hash))
+ if (d_unhashed(dentry))
unhashed = "(unhashed)";
printk("show_dentry: %s/%s, d_count=%d%s\n",
@@ -1027,7 +1027,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
/*
* Unhash the dentry while we remove the file ...
*/
- if (!list_empty(&dentry->d_hash)) {
+ if (!d_unhashed(dentry)) {
d_drop(dentry);
rehash = 1;
}
@@ -1194,11 +1194,13 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* For files, make a copy of the dentry and then do a
* silly-rename. If the silly-rename succeeds, the
* copied dentry is hashed and becomes the new target.
- *
- * With directories check is done in VFS.
*/
+ if (!new_inode)
+ goto go_ahead;
error = -EBUSY;
- if (new_dentry->d_count > 1 && new_inode) {
+ if (S_ISDIR(new_inode->i_mode))
+ goto out;
+ else if (new_dentry->d_count > 1) {
int err;
/* copy the target dentry's name */
dentry = d_alloc(new_dentry->d_parent,
@@ -1227,6 +1229,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
}
+go_ahead:
/*
* ... prune child dentries and writebacks if needed.
*/
@@ -1235,21 +1238,11 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
shrink_dcache_parent(old_dentry);
}
- if (new_dentry->d_count > 1 && new_inode) {
-#ifdef NFS_PARANOIA
- printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
- new_dentry->d_parent->d_name.name,
- new_dentry->d_name.name,
- new_dentry->d_count);
-#endif
- goto out;
- }
-
/*
* To prevent any new references to the target during the rename,
* we unhash the dentry and free the inode in advance.
*/
- if (!list_empty(&new_dentry->d_hash)) {
+ if (!d_unhashed(new_dentry)) {
d_drop(new_dentry);
rehash = 1;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 7d2a6c146..441d62edc 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -46,7 +46,7 @@ static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
static void nfs_put_super(struct super_block *);
static void nfs_umount_begin(struct super_block *);
-static int nfs_statfs(struct super_block *, struct statfs *, int);
+static int nfs_statfs(struct super_block *, struct statfs *);
static struct super_operations nfs_sops = {
read_inode: nfs_read_inode,
@@ -143,8 +143,6 @@ nfs_put_super(struct super_block *sb)
rpciod_down(); /* release rpciod */
kfree(server->hostname);
-
- MOD_DEC_USE_COUNT;
}
void
@@ -209,7 +207,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
struct rpc_timeout timeparms;
struct nfs_fattr fattr;
- MOD_INC_USE_COUNT;
if (!data)
goto out_miss_args;
@@ -227,8 +224,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
if (srvaddr.sin_addr.s_addr == INADDR_ANY)
goto out_no_remote;
- lock_super(sb);
-
sb->s_flags |= MS_ODD_RENAME; /* This should go away */
sb->s_magic = NFS_SUPER_MAGIC;
@@ -312,7 +307,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
sb->s_root->d_fsdata = root_fh;
/* We're airborne */
- unlock_super(sb);
/* Check whether to start the lockd process */
if (!(server->flags & NFS_MOUNT_NONLM))
@@ -350,7 +344,6 @@ out_no_xprt:
out_free_host:
kfree(server->hostname);
out_unlock:
- unlock_super(sb);
goto out_fail;
out_no_remote:
@@ -361,33 +354,28 @@ out_miss_args:
printk("nfs_read_super: missing data argument\n");
out_fail:
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
static int
-nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+nfs_statfs(struct super_block *sb, struct statfs *buf)
{
int error;
struct nfs_fsinfo res;
- struct statfs tmp;
error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
&res);
if (error) {
printk("nfs_statfs: statfs error = %d\n", -error);
- res.bsize = res.blocks = res.bfree = res.bavail = 0;
+ res.bsize = res.blocks = res.bfree = res.bavail = -1;
}
- tmp.f_type = NFS_SUPER_MAGIC;
- tmp.f_bsize = res.bsize;
- tmp.f_blocks = res.blocks;
- tmp.f_bfree = res.bfree;
- tmp.f_bavail = res.bavail;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = NFS_SUPER_MAGIC;
+ buf->f_bsize = res.bsize;
+ buf->f_blocks = res.blocks;
+ buf->f_bfree = res.bfree;
+ buf->f_bavail = res.bavail;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
/*
@@ -413,7 +401,7 @@ restart:
struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- dentry->d_count, !list_empty(&dentry->d_hash));
+ dentry->d_count, !d_unhashed(dentry));
if (!list_empty(&dentry->d_subdirs))
shrink_dcache_parent(dentry);
if (!dentry->d_count) {
@@ -422,7 +410,7 @@ restart:
dput(dentry);
goto restart;
}
- if (list_empty(&dentry->d_hash))
+ if (d_unhashed(dentry))
unhashed++;
}
return unhashed;
@@ -934,12 +922,7 @@ printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
/*
* File system information
*/
-static struct file_system_type nfs_fs_type = {
- "nfs",
- 0 /* FS_NO_DCACHE - this doesn't work right now*/,
- nfs_read_super,
- NULL
-};
+static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, 0);
extern int nfs_init_fhcache(void);
extern int nfs_init_wreqcache(void);
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 24a8208bb..8d2b610a8 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -66,8 +66,6 @@ static int want_lock = 0;
static int hash_count = 0;
static DECLARE_WAIT_QUEUE_HEAD( hash_wait );
-#define READLOCK 0
-#define WRITELOCK 1
/*
* Find a client's export for a device.
@@ -435,7 +433,7 @@ out:
*/
int
exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
- char *path, struct knfs_fh *f)
+ char *path, struct knfsd_fh *f, int maxsize)
{
struct svc_export *exp;
struct dentry *dentry = NULL;
@@ -484,11 +482,11 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
/*
* fh must be initialized before calling fh_compose
*/
- fh_init(&fh);
- fh_compose(&fh, exp, dentry);
- memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
+ fh_init(&fh, maxsize);
+ err = fh_compose(&fh, exp, dentry);
+ memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
fh_put(&fh);
- return 0;
+ return err;
out:
dput(dentry);
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 4062410c6..c45d494ba 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -20,14 +20,14 @@
* Note: we hold the dentry use count while the file is open.
*/
static u32
-nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp)
+nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file *filp)
{
u32 nfserr;
struct svc_fh fh;
- /* must initialize before using! */
- fh_init(&fh);
- fh.fh_handle = *f;
+ /* must initialize before using! but maxsize doesn't matter */
+ fh_init(&fh,0);
+ memcpy((char*)&fh.fh_handle.fh_base, (char*)f, NFS_FHSIZE);
fh.fh_export = NULL;
nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
@@ -39,11 +39,14 @@ nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp)
* 1 = stale file handle
* 2 = other error
*/
- if (nfserr == 0)
+ switch (nfserr) {
+ case nfs_ok:
return 0;
- else if (nfserr == nfserr_stale)
+ case nfserr_stale:
return 1;
- else return 2;
+ default:
+ return 2;
+ }
}
static void
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 3b0de5545..8f69cb53e 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -28,7 +28,7 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC
-#define RETURN(st) { resp->status = (st); return (st); }
+#define RETURN_STATUS(st) { resp->status = (st); return (st); }
static int nfs3_ftypes[] = {
0, /* NF3NON */
@@ -69,13 +69,12 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
{
int nfserr;
- dprintk("nfsd: GETATTR(3) %x/%ld\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh));
+ dprintk("nfsd: GETATTR(3) %s\n",
+ SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -87,13 +86,12 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
{
int nfserr;
- dprintk("nfsd: SETATTR(3) %x/%ld\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh));
+ dprintk("nfsd: SETATTR(3) %s\n",
+ SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -105,17 +103,18 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
{
int nfserr;
- dprintk("nfsd: LOOKUP(3) %x/%ld %s\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: LOOKUP(3) %s %s\n",
+ SVCFH_fmt(&argp->fh),
argp->name);
fh_copy(&resp->dirfh, &argp->fh);
+ fh_init(&resp->fh, NFS3_FHSIZE);
+
nfserr = nfsd_lookup(rqstp, &resp->dirfh,
argp->name,
argp->len,
&resp->fh);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -127,15 +126,14 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
{
int nfserr;
- dprintk("nfsd: ACCESS(3) %x/%ld 0x%x\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: ACCESS(3) %s 0x%x\n",
+ SVCFH_fmt(&argp->fh),
argp->access);
fh_copy(&resp->fh, &argp->fh);
resp->access = argp->access;
nfserr = nfsd_access(rqstp, &resp->fh, &resp->access);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -148,9 +146,7 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
u32 *path;
int dummy, nfserr;
- dprintk("nfsd: READLINK(3) %x/%ld\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh));
+ dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
/* Reserve room for status, post_op_attr, and path length */
svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy,
@@ -160,7 +156,7 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
fh_copy(&resp->fh, &argp->fh);
resp->len = NFS3_MAXPATHLEN;
nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -173,9 +169,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
u32 * buffer;
int nfserr, avail;
- dprintk("nfsd: READ(3) %x/%ld %lu bytes at %lu\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
+ SVCFH_fmt(&argp->fh),
(unsigned long) argp->count,
(unsigned long) argp->offset);
@@ -201,7 +196,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
resp->eof = (argp->offset + resp->count) >= inode->i_size;
}
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -213,22 +208,21 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
{
int nfserr;
- dprintk("nfsd: WRITE(3) %x/%ld %d bytes at %ld%s\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
+ SVCFH_fmt(&argp->fh),
argp->len,
(unsigned long) argp->offset,
argp->stable? " stable" : "");
fh_copy(&resp->fh, &argp->fh);
+ resp->committed = argp->stable;
nfserr = nfsd_write(rqstp, &resp->fh,
argp->offset,
argp->data,
argp->len,
- argp->stable);
- resp->committed = argp->stable;
+ &resp->committed);
resp->count = argp->count;
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -244,19 +238,18 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
struct iattr *attr;
u32 nfserr;
- dprintk("nfsd: CREATE(3) %x/%ld %s\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: CREATE(3) %s %s\n",
+ SVCFH_fmt(&argp->fh),
argp->name);
dirfhp = fh_copy(&resp->dirfh, &argp->fh);
- newfhp = fh_init(&resp->fh);
+ newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
attr = &argp->attrs;
/* Get the directory inode */
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE);
if (nfserr)
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
/* Unfudge the mode bits */
attr->ia_mode &= ~S_IFMT;
@@ -272,7 +265,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
attr, newfhp,
argp->createmode, argp->verf);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -284,18 +277,17 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
{
int nfserr;
- dprintk("nfsd: MKDIR(3) %x/%ld %s\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: MKDIR(3) %s %s\n",
+ SVCFH_fmt(&argp->fh),
argp->name);
argp->attrs.ia_valid &= ~ATTR_SIZE;
fh_copy(&resp->dirfh, &argp->fh);
- fh_init(&resp->fh);
+ fh_init(&resp->fh, NFS3_FHSIZE);
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
static int
@@ -304,17 +296,16 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
{
int nfserr;
- dprintk("nfsd: SYMLINK(3) %x/%ld %s -> %s\n",
- SVCFH_DEV(&argp->ffh),
- (long)SVCFH_INO(&argp->ffh),
+ dprintk("nfsd: SYMLINK(3) %s %s -> %s\n",
+ SVCFH_fmt(&argp->ffh),
argp->fname, argp->tname);
fh_copy(&resp->dirfh, &argp->ffh);
- fh_init(&resp->fh);
+ fh_init(&resp->fh, NFS3_FHSIZE);
nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
argp->tname, argp->tlen,
&resp->fh, &argp->attrs);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -327,31 +318,30 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
int nfserr, type;
dev_t rdev = 0;
- dprintk("nfsd: MKNOD(3) %x/%ld %s\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: MKNOD(3) %s %s\n",
+ SVCFH_fmt(&argp->fh),
argp->name);
fh_copy(&resp->dirfh, &argp->fh);
- fh_init(&resp->fh);
+ fh_init(&resp->fh, NFS3_FHSIZE);
if (argp->ftype == 0 || argp->ftype >= NF3BAD)
- return nfserr_inval;
+ RETURN_STATUS(nfserr_inval);
if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
if ((argp->ftype == NF3CHR && argp->major >= MAX_CHRDEV)
|| (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV)
|| argp->minor > 0xFF)
- return nfserr_inval;
+ RETURN_STATUS(nfserr_inval);
rdev = ((argp->major) << 8) | (argp->minor);
} else
if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
- return nfserr_inval;
+ RETURN_STATUS(nfserr_inval);
type = nfs3_ftypes[argp->ftype];
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
&argp->attrs, type, rdev, &resp->fh);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -363,15 +353,14 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
{
int nfserr;
- dprintk("nfsd: REMOVE(3) %x/%ld %s\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: REMOVE(3) %s %s\n",
+ SVCFH_fmt(&argp->fh),
argp->name);
/* Unlink. -S_IFDIR means file must not be a directory */
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -383,14 +372,13 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
{
int nfserr;
- dprintk("nfsd: RMDIR(3) %x/%ld %s\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: RMDIR(3) %s %s\n",
+ SVCFH_fmt(&argp->fh),
argp->name);
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
static int
@@ -399,19 +387,18 @@ nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
{
int nfserr;
- dprintk("nfsd: RENAME(3) %x/%ld %s -> %x/%ld %s\n",
- SVCFH_DEV(&argp->ffh),
- (long)SVCFH_INO(&argp->ffh),
- argp->fname,
- SVCFH_DEV(&argp->tfh),
- (long)SVCFH_INO(&argp->tfh),
+ dprintk("nfsd: RENAME(3) %s %s ->\n",
+ SVCFH_fmt(&argp->ffh),
+ argp->fname);
+ dprintk("nfsd: -> %s %s\n",
+ SVCFH_fmt(&argp->tfh),
argp->tname);
fh_copy(&resp->ffh, &argp->ffh);
fh_copy(&resp->tfh, &argp->tfh);
nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
&resp->tfh, argp->tname, argp->tlen);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
static int
@@ -420,18 +407,17 @@ nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
{
int nfserr;
- dprintk("nfsd: LINK(3) %x/%ld -> %x/%ld %s\n",
- SVCFH_DEV(&argp->ffh),
- (long)SVCFH_INO(&argp->ffh),
- SVCFH_DEV(&argp->tfh),
- (long)SVCFH_INO(&argp->tfh),
+ dprintk("nfsd: LINK(3) %s ->\n",
+ SVCFH_fmt(&argp->ffh));
+ dprintk("nfsd: -> %s %s\n",
+ SVCFH_fmt(&argp->tfh),
argp->tname);
fh_copy(&resp->fh, &argp->ffh);
fh_copy(&resp->tfh, &argp->tfh);
nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
&resp->fh);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -445,9 +431,8 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
int nfserr, count;
unsigned int want;
- dprintk("nfsd: READDIR(3) %x/%ld %d bytes at %d\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
+ SVCFH_fmt(&argp->fh),
argp->count, (u32) argp->cookie);
/* Reserve buffer space for status, attributes and verifier */
@@ -467,7 +452,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
memcpy(resp->verf, argp->verf, 8);
resp->count = count;
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -481,9 +466,8 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
u32 * buffer;
int nfserr, count, want;
- dprintk("nfsd: READDIR+(3) %x/%ld %d bytes at %d\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
+ SVCFH_fmt(&argp->fh),
argp->count, (u32) argp->cookie);
/* Reserve buffer space for status, attributes and verifier */
@@ -503,7 +487,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
memcpy(resp->verf, argp->verf, 8);
resp->count = count;
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -515,13 +499,12 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
{
int nfserr;
- dprintk("nfsd: FSSTAT(3) %x/%ld\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh));
+ dprintk("nfsd: FSSTAT(3) %s\n",
+ SVCFH_fmt(&argp->fh));
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
fh_put(&argp->fh);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -533,9 +516,8 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
{
int nfserr;
- dprintk("nfsd: FSINFO(3) %x/%ld\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh));
+ dprintk("nfsd: FSINFO(3) %s\n",
+ SVCFH_fmt(&argp->fh));
resp->f_rtmax = NFSSVC_MAXBLKSIZE;
resp->f_rtpref = NFSSVC_MAXBLKSIZE;
@@ -562,7 +544,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
}
fh_put(&argp->fh);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
/*
@@ -574,9 +556,8 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
{
int nfserr;
- dprintk("nfsd: PATHCONF(3) %x/%ld\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh));
+ dprintk("nfsd: PATHCONF(3) %s\n",
+ SVCFH_fmt(&argp->fh));
/* Set default pathconf */
resp->p_link_max = 255; /* at least */
@@ -605,7 +586,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
}
fh_put(&argp->fh);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
@@ -618,19 +599,18 @@ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
{
int nfserr;
- dprintk("nfsd: COMMIT(3) %x/%ld %d@%ld\n",
- SVCFH_DEV(&argp->fh),
- (long)SVCFH_INO(&argp->fh),
+ dprintk("nfsd: COMMIT(3) %s %d@%ld\n",
+ SVCFH_fmt(&argp->fh),
argp->count,
(unsigned long) argp->offset);
if (argp->offset > NFS_OFFSET_MAX)
- return nfserr_inval;
+ RETURN_STATUS(nfserr_inval);
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
- RETURN(nfserr);
+ RETURN_STATUS(nfserr);
}
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 84ef13ded..7dc5739eb 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -21,10 +21,6 @@
# define inline
#endif
-/*
- * Size of encoded NFS3 file handle, in words
- */
-#define NFS3_FHANDLE_WORDS (1 + XDR_QUADLEN(sizeof(struct knfs_fh)))
/*
* Mapping of S_IF* types to NFS file types
@@ -64,19 +60,36 @@ decode_time3(u32 *p, time_t *secp)
static inline u32 *
decode_fh(u32 *p, struct svc_fh *fhp)
{
- if (ntohl(*p++) != sizeof(struct knfs_fh))
+ int size;
+ fh_init(fhp, NFS3_FHSIZE);
+ size = ntohl(*p++);
+ if (size > NFS3_FHSIZE)
return NULL;
- memcpy(&fhp->fh_handle, p, sizeof(struct knfs_fh));
- return p + (sizeof(struct knfs_fh) >> 2);
+ memcpy(&fhp->fh_handle.fh_base, p, size);
+ fhp->fh_handle.fh_size = size;
+ return p + XDR_QUADLEN(size);
}
static inline u32 *
encode_fh(u32 *p, struct svc_fh *fhp)
{
- *p++ = htonl(sizeof(struct knfs_fh));
- memcpy(p, &fhp->fh_handle, sizeof(struct knfs_fh));
- return p + (sizeof(struct knfs_fh) >> 2);
+#if 0
+ int size = fhp->fh_handle.fh_size;
+ *p++ = htonl(size);
+ if (size) p[XDR_QUADLEN(size)-1]=0;
+ memcpy(p, &fhp->fh_handle.fh_base, size);
+ return p + XDR_QUADLEN(size);
+#else
+ /* until locked knows about var-length file handles,
+ * we always return NFS_FHSIZE handles
+ */
+ int size = fhp->fh_handle.fh_size;
+ *p++ = htonl(NFS_FHSIZE);
+ memset(p, 0, NFS_FHSIZE);
+ memcpy(p, &fhp->fh_handle.fh_base, size);
+ return p + XDR_QUADLEN(NFS_FHSIZE);
+#endif
}
/*
@@ -698,6 +711,7 @@ encode_entry(struct readdir_cd *cd, const char *name,
}
*p++ = xdr_one; /* mark entry present */
p = xdr_encode_hyper(p, ino); /* file id */
+ p[slen - 1] = 0; /* don't leak kernel data */
#ifdef XDR_ENCODE_STRING_TAKES_LENGTH
p = xdr_encode_string(p, name, namlen); /* name length & name */
#else
@@ -706,7 +720,6 @@ encode_entry(struct readdir_cd *cd, const char *name,
memcpy(p, name, namlen);
p += slen;
#endif
- p[slen - 1] = 0; /* don't leak kernel data */
cd->offset = p; /* remember pointer */
p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
@@ -715,7 +728,7 @@ encode_entry(struct readdir_cd *cd, const char *name,
if (plus) {
struct svc_fh fh;
- fh_init(&fh);
+ fh_init(&fh, NFS3_FHSIZE);
/* Disabled for now because of lock-up */
if (0 && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh) == 0) {
p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index b0aac3280..815208e09 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -40,8 +40,9 @@ static int nfsctl_addclient(struct nfsctl_client *data);
static int nfsctl_delclient(struct nfsctl_client *data);
static int nfsctl_export(struct nfsctl_export *data);
static int nfsctl_unexport(struct nfsctl_export *data);
-static int nfsctl_getfh(struct nfsctl_fhparm *, struct knfs_fh *);
-static int nfsctl_getfd(struct nfsctl_fdparm *, struct knfs_fh *);
+static int nfsctl_getfh(struct nfsctl_fhparm *, __u8 *);
+static int nfsctl_getfd(struct nfsctl_fdparm *, __u8 *);
+static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
/* static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); */
static int initialized = 0;
@@ -63,7 +64,6 @@ void proc_export_init(void)
static void
nfsd_init(void)
{
- nfsd_xdr_init(); /* XDR */
nfsd_stat_init(); /* Statistics */
nfsd_cache_init(); /* RPC reply cache */
nfsd_export_init(); /* Exports table */
@@ -110,12 +110,37 @@ nfsctl_ugidupdate(nfs_ugidmap *data)
}
#endif
+#ifdef notyet
+static inline int
+nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
+{
+ struct sockaddr_in *sin;
+ struct svc_client *clp;
+ int err = 0;
+
+ if (data->gd_addr.sa_family != AF_INET)
+ return -EPROTONOSUPPORT;
+ sin = (struct sockaddr_in *)&data->gd_addr;
+ if (data->gd_maxlen > NFS3_FHSIZE)
+ data->gd_maxlen = NFS3_FHSIZE;
+ exp_readlock();
+ if (!(clp = exp_getclient(sin)))
+ err = -EPERM;
+ else
+ err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
+ exp_unlock();
+
+ return err;
+}
+#endif
+
static inline int
-nfsctl_getfd(struct nfsctl_fdparm *data, struct knfs_fh *res)
+nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res)
{
struct sockaddr_in *sin;
struct svc_client *clp;
int err = 0;
+ struct knfsd_fh fh;
if (data->gd_addr.sa_family != AF_INET)
return -EPROTONOSUPPORT;
@@ -127,18 +152,28 @@ nfsctl_getfd(struct nfsctl_fdparm *data, struct knfs_fh *res)
if (!(clp = exp_getclient(sin)))
err = -EPERM;
else
- err = exp_rootfh(clp, 0, 0, data->gd_path, res);
+ err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE);
exp_unlock();
+ if (err == 0) {
+ if (fh.fh_size > NFS_FHSIZE)
+ err = -EINVAL;
+ else {
+ memset(res,0, NFS_FHSIZE);
+ memcpy(res, fh.fh_base.fh_pad, fh.fh_size);
+ }
+ }
+
return err;
}
static inline int
-nfsctl_getfh(struct nfsctl_fhparm *data, struct knfs_fh *res)
+nfsctl_getfh(struct nfsctl_fhparm *data, __u8 *res)
{
struct sockaddr_in *sin;
struct svc_client *clp;
int err = 0;
+ struct knfsd_fh fh;
if (data->gf_addr.sa_family != AF_INET)
return -EPROTONOSUPPORT;
@@ -150,9 +185,18 @@ nfsctl_getfh(struct nfsctl_fhparm *data, struct knfs_fh *res)
if (!(clp = exp_getclient(sin)))
err = -EPERM;
else
- err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, res);
+ err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, &fh, NFS_FHSIZE);
exp_unlock();
+ if (err == 0) {
+ if (fh.fh_size > NFS_FHSIZE)
+ err = -EINVAL;
+ else {
+ memset(res,0, NFS_FHSIZE);
+ memcpy(res, fh.fh_base.fh_pad, fh.fh_size);
+ }
+ }
+
return err;
}
@@ -218,11 +262,15 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
break;
#endif
case NFSCTL_GETFH:
- err = nfsctl_getfh(&arg->ca_getfh, &res->cr_getfh);
+ err = nfsctl_getfh(&arg->ca_getfh, res->cr_getfh);
break;
case NFSCTL_GETFD:
- err = nfsctl_getfd(&arg->ca_getfd, &res->cr_getfh);
+ err = nfsctl_getfd(&arg->ca_getfd, res->cr_getfh);
break;
+#ifdef notyet
+ case NFSCTL_GETFS:
+ err = nfsctl_getfs(&arg->ca_getfs, &res->cr_getfs);
+#endif
default:
err = -EINVAL;
}
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 084a17d9b..4a7e63dcb 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -328,7 +328,7 @@ static struct dentry *splice(struct dentry *child, struct dentry *parent)
* connection if made.
*/
static struct dentry *
-find_fh_dentry(struct super_block *sb, struct knfs_fh *fh, int needpath)
+find_fh_dentry(struct super_block *sb, ino_t ino, int generation, ino_t dirino, int needpath)
{
struct dentry *dentry, *result = NULL;
struct dentry *tmp;
@@ -347,7 +347,7 @@ find_fh_dentry(struct super_block *sb, struct knfs_fh *fh, int needpath)
* Attempt to find the inode.
*/
retry:
- result = nfsd_iget(sb, fh->fh_ino, fh->fh_generation);
+ result = nfsd_iget(sb, ino, generation);
err = PTR_ERR(result);
if (IS_ERR(result))
goto err_out;
@@ -370,10 +370,10 @@ find_fh_dentry(struct super_block *sb, struct knfs_fh *fh, int needpath)
/* It's a directory, or we are required to confirm the file's
* location in the tree.
*/
- dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,fh->fh_ino);
+ dprintk("nfs_fh: need to look harder for %d/%ld\n",sb->s_dev,ino);
down(&sb->s_nfsd_free_path_sem);
- /* claiming the semaphore might have allow things to get fixed up */
+ /* claiming the semaphore might have allowed things to get fixed up */
if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
up(&sb->s_nfsd_free_path_sem);
return result;
@@ -383,11 +383,11 @@ find_fh_dentry(struct super_block *sb, struct knfs_fh *fh, int needpath)
found = 0;
if (!S_ISDIR(result->d_inode->i_mode)) {
nfsdstats.fh_nocache_nondir++;
- if (fh->fh_dirino == 0)
+ if (dirino == 0)
goto err_result; /* don't know how to find parent */
else {
- /* need to iget fh->fh_dirino and make sure this inode is in that directory */
- dentry = nfsd_iget(sb, fh->fh_dirino, 0);
+ /* need to iget dirino and make sure this inode is in that directory */
+ dentry = nfsd_iget(sb, dirino, 0);
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto err_result;
@@ -490,38 +490,58 @@ err_out:
u32
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
{
- struct knfs_fh *fh = &fhp->fh_handle;
+ struct knfsd_fh *fh = &fhp->fh_handle;
struct svc_export *exp;
struct dentry *dentry;
struct inode *inode;
u32 error = 0;
- dprintk("nfsd: fh_verify(exp %s/%u file (%s/%u dir %u)\n",
- kdevname(fh->fh_xdev),
- fh->fh_xino,
- kdevname(fh->fh_dev),
- fh->fh_ino,
- fh->fh_dirino);
+ dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
if (!fhp->fh_dverified) {
- /*
- * Security: Check that the fh is internally consistant (from <gam3@acm.org>)
- */
- if (fh->fh_dev != fh->fh_xdev) {
- printk("fh_verify: Security: export on other device (%s, %s).\n",
- kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
- error = nfserr_stale;
- nfsdstats.fh_stale++;
- goto out;
+ 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;
+ if (--data_left<0) goto out;
+ switch (fh->fh_auth_type) {
+ case 0: break;
+ default: goto out;
+ }
+
+ switch (fh->fh_fsid_type) {
+ case 0:
+ if ((data_left-=2)<0) goto out;
+ nfsdev = ntohl(*datap++);
+ xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
+ xino = *datap++;
+ break;
+ default:
+ goto out;
+ }
+ } else {
+ if (fh->fh_size != NFS_FHSIZE)
+ goto out;
+ /* assume old filehandle format */
+ xdev = u32_to_kdev_t(fh->ofh_xdev);
+ xino = u32_to_ino_t(fh->ofh_xino);
}
/*
* Look up the export entry.
*/
error = nfserr_stale;
- exp = exp_get(rqstp->rq_client,
- u32_to_kdev_t(fh->fh_xdev),
- u32_to_ino_t(fh->fh_xino));
+ exp = exp_get(rqstp->rq_client, xdev, xino);
+
if (!exp) {
/* export entry revoked */
nfsdstats.fh_stale++;
@@ -544,13 +564,44 @@ 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
- dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
- fh,
- !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+ if (fh->fh_version == 1) {
+ /* if fileid_type != 0, and super_operations provide fh_to_dentry lookup,
+ * then should use that */
+ switch (fh->fh_fileid_type) {
+ case 0:
+ dentry = dget(exp->ex_dentry);
+ break;
+ case 1:
+ if ((data_left-=2)<0) goto out;
+ dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
+ datap[0], datap[1],
+ 0,
+ !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+ break;
+ case 2:
+ if ((data_left-=3)<0) goto out;
+ dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
+ datap[0], datap[1],
+ datap[2],
+ !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+ break;
+ default: goto out;
+ }
+ } else {
+ dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
+ fh->ofh_ino, fh->ofh_generation,
+ fh->ofh_dirino,
+ !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+ }
if (IS_ERR(dentry)) {
- error = nfserrno(-PTR_ERR(dentry));
+ error = nfserrno(PTR_ERR(dentry));
goto out;
}
#ifdef NFSD_PARANOIA
@@ -652,72 +703,96 @@ out:
* an inode. In this case a call to fh_update should be made
* before the fh goes out on the wire ...
*/
-void
+inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
+ __u32 **datapp, int maxsize)
+{
+ __u32 *datap= *datapp;
+ if (dentry == exp->ex_dentry)
+ return 0;
+ /* if super_operations provides dentry_to_fh lookup, should use that */
+
+ *datap++ = ino_t_to_u32(dentry->d_inode->i_ino);
+ *datap++ = dentry->d_inode->i_generation;
+ if (S_ISDIR(dentry->d_inode->i_mode) || (exp->ex_flags & NFSEXP_NOSUBTREECHECK)){
+ *datapp = datap;
+ return 1;
+ }
+ *datap++ = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
+ *datapp = datap;
+ return 2;
+}
+
+int
fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
struct dentry *parent = dentry->d_parent;
+ __u32 *datap;
dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
exp->ex_dev, (long) exp->ex_ino,
parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0));
- /*
- * N.B. We shouldn't need to init the fh -- the call to fh_compose
- * may not be done on error paths, but the cleanup must call fh_put.
- * Fix this soon!
- */
if (fhp->fh_dverified || 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);
}
- fh_init(fhp);
-
- fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino);
- fhp->fh_handle.fh_dev = kdev_t_to_u32(parent->d_inode->i_dev);
- fhp->fh_handle.fh_xdev = kdev_t_to_u32(exp->ex_dev);
- fhp->fh_handle.fh_xino = ino_t_to_u32(exp->ex_ino);
- fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
- if (inode) {
- fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
- fhp->fh_handle.fh_generation = inode->i_generation;
- if (S_ISDIR(inode->i_mode) || (exp->ex_flags & NFSEXP_NOSUBTREECHECK))
- fhp->fh_handle.fh_dirino = 0;
- }
+ if (fhp->fh_maxsize < NFS_FHSIZE)
+ printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
+ fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name);
fhp->fh_dentry = dentry; /* our internal copy */
fhp->fh_export = exp;
+ fhp->fh_handle.fh_version = 1;
+ fhp->fh_handle.fh_auth_type = 0;
+ fhp->fh_handle.fh_fsid_type = 0;
+ datap = fhp->fh_handle.fh_auth+0;
+ /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
+ *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+ *datap++ = ino_t_to_u32(exp->ex_ino);
+
+ if (inode)
+ fhp->fh_handle.fh_fileid_type =
+ _fh_update(dentry, exp, &datap, fhp->fh_maxsize-3);
+
+ 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;
+ return 0;
}
/*
* Update file handle information after changing a dentry.
- * This is only called by nfsd_create
+ * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
*/
-void
+int
fh_update(struct svc_fh *fhp)
{
struct dentry *dentry;
- struct inode *inode;
-
+ __u32 *datap;
+
if (!fhp->fh_dverified)
goto out_bad;
dentry = fhp->fh_dentry;
- inode = dentry->d_inode;
- if (!inode)
+ if (!dentry->d_inode)
goto out_negative;
- fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
- fhp->fh_handle.fh_generation = inode->i_generation;
- if (S_ISDIR(inode->i_mode) || (fhp->fh_export->ex_flags & NFSEXP_NOSUBTREECHECK))
- fhp->fh_handle.fh_dirino = 0;
-
+ if (fhp->fh_handle.fh_fileid_type != 0)
+ goto out_uptodate;
+ datap = fhp->fh_handle.fh_auth+
+ fhp->fh_handle.fh_size/4 -1;
+ fhp->fh_handle.fh_fileid_type =
+ _fh_update(dentry, fhp->fh_export, &datap, fhp->fh_maxsize-fhp->fh_handle.fh_size);
+ fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4;
out:
- return;
+ return 0;
out_bad:
printk(KERN_ERR "fh_update: fh not verified!\n");
@@ -726,6 +801,10 @@ out_negative:
printk(KERN_ERR "fh_update: %s/%s still negative!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
goto out;
+out_uptodate:
+ printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ goto out;
}
/*
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index ef69be746..7d570299f 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -30,7 +30,6 @@ typedef struct svc_buf svc_buf;
#define NFSDDBG_FACILITY NFSDDBG_PROC
-#define RETURN(st) return st
static void
svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
@@ -42,7 +41,7 @@ svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
static int
nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
- RETURN(nfs_ok);
+ return nfs_ok;
}
/*
@@ -53,11 +52,10 @@ static int
nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
struct nfsd_attrstat *resp)
{
- dprintk("nfsd: GETATTR %d/%d\n",
- SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh));
+ dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
- RETURN(fh_verify(rqstp, &resp->fh, 0, MAY_NOP));
+ return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
}
/*
@@ -68,12 +66,12 @@ static int
nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
struct nfsd_attrstat *resp)
{
- dprintk("nfsd: SETATTR %d/%d, valid=%x, size=%ld\n",
- SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
+ dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
+ SVCFH_fmt(&argp->fh),
argp->attrs.ia_valid, (long) argp->attrs.ia_size);
fh_copy(&resp->fh, &argp->fh);
- RETURN(nfsd_setattr(rqstp, &resp->fh, &argp->attrs));
+ return nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
}
/*
@@ -88,14 +86,15 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
{
int nfserr;
- dprintk("nfsd: LOOKUP %d/%d %s\n",
- SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh), argp->name);
+ dprintk("nfsd: LOOKUP %s %s\n",
+ SVCFH_fmt(&argp->fh), argp->name);
+ fh_init(&resp->fh, NFS_FHSIZE);
nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
&resp->fh);
fh_put(&argp->fh);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -108,7 +107,7 @@ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
u32 *path;
int dummy, nfserr;
- dprintk("nfsd: READLINK %p\n", SVCFH_DENTRY(&argp->fh));
+ dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
/* Reserve room for status and path length */
svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, 2);
@@ -118,7 +117,7 @@ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
fh_put(&argp->fh);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -132,8 +131,8 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
u32 * buffer;
int nfserr, avail;
- dprintk("nfsd: READ %d/%d %d bytes at %d\n",
- SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
+ dprintk("nfsd: READ %s %d bytes at %d\n",
+ SVCFH_fmt(&argp->fh),
argp->count, argp->offset);
/* Obtain buffer pointer for payload. 19 is 1 word for
@@ -156,7 +155,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
(char *) buffer,
&resp->count);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -168,17 +167,18 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
struct nfsd_attrstat *resp)
{
int nfserr;
+ int stable = 1;
- dprintk("nfsd: WRITE %d/%d %d bytes at %d\n",
- SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
+ dprintk("nfsd: WRITE %s %d bytes at %d\n",
+ SVCFH_fmt(&argp->fh),
argp->len, argp->offset);
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset,
argp->data,
argp->len,
- 0);
- RETURN(nfserr);
+ &stable);
+ return nfserr;
}
/*
@@ -198,8 +198,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
int nfserr, type, mode, rdonly = 0;
dev_t rdev = NODEV;
- dprintk("nfsd: CREATE %d/%d %s\n",
- SVCFH_DEV(dirfhp), SVCFH_INO(dirfhp), argp->name);
+ dprintk("nfsd: CREATE %s %s\n",
+ SVCFH_fmt(dirfhp), argp->name);
/* First verify the parent file handle */
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
@@ -217,6 +217,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
/*
* Do a lookup to verify the new file handle.
*/
+ fh_init(newfhp, NFS_FHSIZE);
nfserr = nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
if (nfserr) {
if (nfserr != nfserr_noent)
@@ -240,9 +241,11 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
if (nfserr)
goto done;
inode = newfhp->fh_dentry->d_inode;
- if (inode && newfhp->fh_handle.fh_ino == 0)
+ if (inode && newfhp->fh_handle.fh_fileid_type == 0)
/* inode might have been instantiated while we slept */
- fh_update(newfhp);
+ nfserr = fh_update(newfhp);
+ if (nfserr)
+ goto done;
/* Unfudge the mode bits */
if (attr->ia_valid & ATTR_MODE) {
@@ -321,7 +324,7 @@ out_unlock:
done:
fh_put(dirfhp);
- RETURN(nfserr);
+ return nfserr;
}
static int
@@ -330,12 +333,12 @@ nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
{
int nfserr;
- dprintk("nfsd: REMOVE %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
+ dprintk("nfsd: REMOVE %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
/* Unlink. -SIFDIR means file must not be a directory */
nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
fh_put(&argp->fh);
- RETURN(nfserr);
+ return nfserr;
}
static int
@@ -344,15 +347,16 @@ nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
{
int nfserr;
- dprintk("nfsd: RENAME %p %s -> %p %s\n",
- SVCFH_DENTRY(&argp->ffh), argp->fname,
- SVCFH_DENTRY(&argp->tfh), argp->tname);
+ dprintk("nfsd: RENAME %s %s -> \n",
+ SVCFH_fmt(&argp->ffh), argp->fname);
+ dprintk("nfsd: -> %s %s\n",
+ SVCFH_fmt(&argp->tfh), argp->tname);
nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
&argp->tfh, argp->tname, argp->tlen);
fh_put(&argp->ffh);
fh_put(&argp->tfh);
- RETURN(nfserr);
+ return nfserr;
}
static int
@@ -361,16 +365,17 @@ nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
{
int nfserr;
- dprintk("nfsd: LINK %p -> %p %s\n",
- SVCFH_DENTRY(&argp->ffh),
- SVCFH_DENTRY(&argp->tfh),
+ dprintk("nfsd: LINK %s ->\n",
+ SVCFH_fmt(&argp->ffh));
+ dprintk("nfsd: %s %s\n",
+ SVCFH_fmt(&argp->tfh),
argp->tname);
nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
&argp->ffh);
fh_put(&argp->ffh);
fh_put(&argp->tfh);
- RETURN(nfserr);
+ return nfserr;
}
static int
@@ -380,10 +385,10 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
struct svc_fh newfh;
int nfserr;
- dprintk("nfsd: SYMLINK %p %s -> %s\n",
- SVCFH_DENTRY(&argp->ffh), argp->fname, argp->tname);
+ dprintk("nfsd: SYMLINK %s %s -> %s\n",
+ SVCFH_fmt(&argp->ffh), argp->fname, argp->tname);
- memset(&newfh, 0, sizeof(struct svc_fh));
+ fh_init(&newfh, NFS_FHSIZE);
/*
* Create the link, look up new file and set attrs.
*/
@@ -394,7 +399,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
fh_put(&argp->ffh);
fh_put(&newfh);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -407,7 +412,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
{
int nfserr;
- dprintk("nfsd: MKDIR %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
+ dprintk("nfsd: MKDIR %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
if (resp->fh.fh_dverified) {
printk(KERN_WARNING
@@ -415,10 +420,11 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
}
argp->attrs.ia_valid &= ~ATTR_SIZE;
+ fh_init(&resp->fh, NFS_FHSIZE);
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
&argp->attrs, S_IFDIR, 0, &resp->fh);
fh_put(&argp->fh);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -430,11 +436,11 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
{
int nfserr;
- dprintk("nfsd: RMDIR %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
+ dprintk("nfsd: RMDIR %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
fh_put(&argp->fh);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -447,8 +453,8 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
u32 * buffer;
int nfserr, count;
- dprintk("nfsd: READDIR %d/%d %d bytes at %d\n",
- SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
+ dprintk("nfsd: READDIR %s %d bytes at %d\n",
+ SVCFH_fmt(&argp->fh),
argp->count, argp->cookie);
/* Reserve buffer space for status */
@@ -470,7 +476,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
resp->count = count;
fh_put(&argp->fh);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -482,11 +488,11 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
{
int nfserr;
- dprintk("nfsd: STATFS %p\n", SVCFH_DENTRY(&argp->fh));
+ dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
fh_put(&argp->fh);
- RETURN(nfserr);
+ return nfserr;
}
/*
@@ -539,36 +545,36 @@ nfserrno (int errno)
int nfserr;
int syserr;
} nfs_errtbl[] = {
- { NFS_OK, 0 },
- { NFSERR_PERM, EPERM },
- { NFSERR_NOENT, ENOENT },
- { NFSERR_IO, EIO },
- { NFSERR_NXIO, ENXIO },
- { NFSERR_ACCES, EACCES },
- { NFSERR_EXIST, EEXIST },
- { NFSERR_XDEV, EXDEV },
- { NFSERR_MLINK, EMLINK },
- { NFSERR_NODEV, ENODEV },
- { NFSERR_NOTDIR, ENOTDIR },
- { NFSERR_ISDIR, EISDIR },
- { NFSERR_INVAL, EINVAL },
- { NFSERR_FBIG, EFBIG },
- { NFSERR_NOSPC, ENOSPC },
- { NFSERR_ROFS, EROFS },
- { NFSERR_MLINK, EMLINK },
- { NFSERR_NAMETOOLONG, ENAMETOOLONG },
- { NFSERR_NOTEMPTY, ENOTEMPTY },
+ { nfs_ok, 0 },
+ { nfserr_perm, -EPERM },
+ { nfserr_noent, -ENOENT },
+ { nfserr_io, -EIO },
+ { nfserr_nxio, -ENXIO },
+ { nfserr_acces, -EACCES },
+ { nfserr_exist, -EEXIST },
+ { nfserr_xdev, -EXDEV },
+ { nfserr_mlink, -EMLINK },
+ { nfserr_nodev, -ENODEV },
+ { nfserr_notdir, -ENOTDIR },
+ { nfserr_isdir, -EISDIR },
+ { nfserr_inval, -EINVAL },
+ { nfserr_fbig, -EFBIG },
+ { nfserr_nospc, -ENOSPC },
+ { nfserr_rofs, -EROFS },
+ { nfserr_mlink, -EMLINK },
+ { nfserr_nametoolong, -ENAMETOOLONG },
+ { nfserr_notempty, -ENOTEMPTY },
#ifdef EDQUOT
- { NFSERR_DQUOT, EDQUOT },
+ { nfserr_dquot, -EDQUOT },
#endif
- { NFSERR_STALE, ESTALE },
- { -1, EIO }
+ { nfserr_stale, -ESTALE },
+ { -1, -EIO }
};
int i;
for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
if (nfs_errtbl[i].syserr == errno)
- return htonl(nfs_errtbl[i].nfserr);
+ return nfs_errtbl[i].nfserr;
}
printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
return nfserr_io;
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 3afe9f83e..2984f0330 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -17,15 +17,6 @@
#define NFSDDBG_FACILITY NFSDDBG_XDR
-u32 nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio,
- nfserr_acces, nfserr_exist, nfserr_xdev, nfserr_nodev,
- nfserr_notdir, nfserr_isdir, nfserr_inval, nfserr_fbig,
- nfserr_nospc, nfserr_rofs, nfserr_mlink,
- nfserr_nametoolong, nfserr_notempty, nfserr_dquot, nfserr_stale,
- nfserr_remote, nfserr_badhandle, nfserr_notsync,
- nfserr_badcookie, nfserr_notsupp, nfserr_toosmall,
- nfserr_serverfault, nfserr_badtype, nfserr_jukebox;
-
#ifdef NFSD_OPTIMIZE_SPACE
# define inline
@@ -41,51 +32,6 @@ static u32 nfs_ftypes[] = {
NFSOCK, NFBAD, NFLNK, NFBAD,
};
-/*
- * Initialization of NFS status variables
- */
-void
-nfsd_xdr_init(void)
-{
- static int inited = 0;
-
- if (inited)
- return;
-
- nfs_ok = htonl(NFS_OK);
- nfserr_perm = htonl(NFSERR_PERM);
- nfserr_noent = htonl(NFSERR_NOENT);
- nfserr_io = htonl(NFSERR_IO);
- nfserr_inval = htonl(NFSERR_INVAL);
- nfserr_nxio = htonl(NFSERR_NXIO);
- nfserr_acces = htonl(NFSERR_ACCES);
- nfserr_exist = htonl(NFSERR_EXIST);
- nfserr_xdev = htonl(NFSERR_XDEV);
- nfserr_nodev = htonl(NFSERR_NODEV);
- nfserr_notdir = htonl(NFSERR_NOTDIR);
- nfserr_isdir = htonl(NFSERR_ISDIR);
- nfserr_inval = htonl(NFSERR_INVAL);
- nfserr_fbig = htonl(NFSERR_FBIG);
- nfserr_nospc = htonl(NFSERR_NOSPC);
- nfserr_rofs = htonl(NFSERR_ROFS);
- nfserr_mlink = htonl(NFSERR_MLINK);
- nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG);
- nfserr_notempty = htonl(NFSERR_NOTEMPTY);
- nfserr_dquot = htonl(NFSERR_DQUOT);
- nfserr_stale = htonl(NFSERR_STALE);
- nfserr_remote = htonl(NFSERR_REMOTE);
- nfserr_badhandle = htonl(NFSERR_BADHANDLE);
- nfserr_notsync = htonl(NFSERR_NOT_SYNC);
- nfserr_badcookie = htonl(NFSERR_BAD_COOKIE);
- nfserr_notsupp = htonl(NFSERR_NOTSUPP);
- nfserr_toosmall = htonl(NFSERR_TOOSMALL);
- nfserr_serverfault = htonl(NFSERR_SERVERFAULT);
- nfserr_badtype = htonl(NFSERR_BADTYPE);
- nfserr_jukebox = htonl(NFSERR_JUKEBOX);
-
-
- inited = 1;
-}
/*
* XDR functions for basic NFS types
@@ -93,19 +39,20 @@ nfsd_xdr_init(void)
static inline u32 *
decode_fh(u32 *p, struct svc_fh *fhp)
{
- fh_init(fhp);
- memcpy(&fhp->fh_handle, p, sizeof(struct knfs_fh));
+ fh_init(fhp, NFS_FHSIZE);
+ memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
+ fhp->fh_handle.fh_size = NFS_FHSIZE;
/* FIXME: Look up export pointer here and verify
* Sun Secure RPC if requested */
- return p + (sizeof(struct knfs_fh) >> 2);
+ return p + (NFS_FHSIZE >> 2);
}
static inline u32 *
encode_fh(u32 *p, struct svc_fh *fhp)
{
- memcpy(p, &fhp->fh_handle, sizeof(struct knfs_fh));
- return p + (sizeof(struct knfs_fh) >> 2);
+ memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
+ return p + (NFS_FHSIZE>> 2);
}
/*
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index c8389381f..06a795841 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -16,6 +16,7 @@
#include <linux/config.h>
#include <linux/version.h>
+#include <linux/string.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/locks.h>
@@ -92,7 +93,7 @@ static struct raparms * raparm_cache = NULL;
* the check_parent in linux/fs/namei.c.
*/
#define nfsd_check_parent(dir, dentry) \
- ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash))
+ ((dir) == (dentry)->d_parent && !d_unhashed(dentry))
/*
* Lock a parent directory following the VFS locking protocol.
@@ -137,7 +138,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
struct dentry *dparent, *dchild;
int err;
- dprintk("nfsd: nfsd_lookup(fh %p, %s)\n", SVCFH_DENTRY(fhp), name);
+ dprintk("nfsd: nfsd_lookup(fh %s, %s)\n", SVCFH_fmt(fhp), name);
/* Obtain dentry and export. */
err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
@@ -155,7 +156,10 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
err = nfserr_acces;
/* Lookup the name, but don't follow links */
- dchild = lookup_dentry(name, dget(dparent), 0);
+ if (strcmp(name,"..")==0 && dparent->d_covers != dparent)
+ dchild = dget(dparent);
+ else
+ dchild = lookup_dentry(name, dget(dparent), 0);
if (IS_ERR(dchild))
goto out_nfserr;
/*
@@ -187,15 +191,14 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
* Note: we compose the file handle now, but as the
* dentry may be negative, it may need to be updated.
*/
- fh_compose(resfh, exp, dchild);
- err = nfserr_noent;
- if (dchild->d_inode)
- err = 0;
+ err = fh_compose(resfh, exp, dchild);
+ if (!err && !dchild->d_inode)
+ err = nfserr_noent;
out:
return err;
out_nfserr:
- err = nfserrno(-PTR_ERR(dchild));
+ err = nfserrno(PTR_ERR(dchild));
goto out;
}
@@ -261,8 +264,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
/* The size case is special. It changes the file as well as the attributes. */
if (iap->ia_valid & ATTR_SIZE) {
-if (!S_ISREG(inode->i_mode))
-printk("nfsd_setattr: size change??\n");
if (iap->ia_size < inode->i_size) {
err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
if (err)
@@ -326,7 +327,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
@@ -393,18 +394,19 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access)
if (map->access & query) {
unsigned int err2;
err2 = nfsd_permission(export, dentry, map->how);
- /* cannot use a "switch" as nfserr_* are variables, even though they are constant :-( */
- if (err2 == 0)
+ switch (err2) {
+ case nfs_ok:
result |= map->access;
+ break;
+
/* the following error codes just mean the access was not allowed,
* rather than an error occurred */
- else if (err2 == nfserr_rofs ||
- err2 == nfserr_acces ||
- err2 == nfserr_perm
- )
+ case nfserr_rofs:
+ case nfserr_acces:
+ case nfserr_perm:
/* simply don't "or" in the access bit. */
- ;
- else {
+ break;
+ default:
error = err2;
goto out;
}
@@ -482,7 +484,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
}
out_nfserr:
if (err)
- err = nfserrno(-err);
+ err = nfserrno(err);
out:
return err;
}
@@ -587,7 +589,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
goto out_close;
/* Get readahead parameters */
- ra = nfsd_get_raparms(fhp->fh_handle.fh_dev, fhp->fh_handle.fh_ino);
+ ra = nfsd_get_raparms(fhp->fh_export->ex_dev, fhp->fh_dentry->d_inode->i_ino);
if (ra) {
file.f_reada = ra->p_reada;
file.f_ramax = ra->p_ramax;
@@ -618,7 +620,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
*count = err;
err = 0;
} else
- err = nfserrno(-err);
+ err = nfserrno(err);
out_close:
nfsd_close(&file);
out:
@@ -632,7 +634,7 @@ out:
*/
int
nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
- char *buf, unsigned long cnt, int stable)
+ char *buf, unsigned long cnt, int *stablep)
{
struct svc_export *exp;
struct file file;
@@ -640,6 +642,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
struct inode *inode;
mm_segment_t oldfs;
int err = 0;
+ int stable = *stablep;
#ifdef CONFIG_QUOTA
uid_t saved_euid;
#endif
@@ -666,10 +669,12 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
* flushing the data to disk is handled separately below.
*/
#ifdef CONFIG_NFSD_V3
- if (rqstp->rq_vers == 2)
- stable = EX_ISSYNC(exp);
- else if (file.f_op->fsync == 0)
- stable = 1;
+ 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
@@ -749,7 +754,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
if (err >= 0)
err = 0;
else
- err = nfserrno(-err);
+ err = nfserrno(err);
out_close:
nfsd_close(&file);
out:
@@ -774,11 +779,12 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0)
return err;
-
- if (file.f_op && file.f_op->fsync) {
- nfsd_sync(&file);
- } else {
- err = nfserr_notsupp;
+ if (EX_ISSYNC(fhp->fh_export)) {
+ if (file.f_op && file.f_op->fsync) {
+ nfsd_sync(&file);
+ } else {
+ err = nfserr_notsupp;
+ }
}
nfsd_close(&file);
@@ -827,11 +833,13 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = PTR_ERR(dchild);
if (IS_ERR(dchild))
goto out_nfserr;
- fh_compose(resfhp, fhp->fh_export, dchild);
/* Lock the parent and check for errors ... */
err = fh_lock_parent(fhp, dchild);
if (err)
goto out;
+ err = fh_compose(resfhp, fhp->fh_export, dchild);
+ if (err)
+ goto out;
} else {
/* called from nfsd_proc_create */
dchild = resfhp->fh_dentry;
@@ -888,10 +896,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
write_inode_now(dchild->d_inode);
}
- /*
- * Update the file handle to get the new inode info.
- */
- fh_update(resfhp);
/* Set file attributes. Mode has already been set and
* setting uid/gid works only for root. Irix appears to
@@ -901,11 +905,16 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = 0;
if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
err = nfsd_setattr(rqstp, resfhp, iap);
+ /*
+ * Update the file handle to get the new inode info.
+ */
+ if (!err)
+ err = fh_update(resfhp);
out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
@@ -947,22 +956,20 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = PTR_ERR(dchild);
if(IS_ERR(dchild))
goto out_nfserr;
- fh_compose(resfhp, fhp->fh_export, dchild);
/*
* We must lock the directory before we check for the inode.
*/
err = fh_lock_parent(fhp, dchild);
if (err)
- goto out;
+ goto out;
+ err = fh_compose(resfhp, fhp->fh_export, dchild);
+ if (err)
+ goto out;
if (dchild->d_inode) {
err = 0;
- if (resfhp->fh_handle.fh_ino == 0)
- /* inode might have been instantiated while we slept */
- fh_update(resfhp);
-
switch (createmode) {
case NFS3_CREATE_UNCHECKED:
if (! S_ISREG(dchild->d_inode->i_mode))
@@ -997,8 +1004,9 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
/*
* Update the filehandle to get the new inode info.
*/
- fh_update(resfhp);
- err = 0;
+ err = fh_update(resfhp);
+ if (err)
+ goto out;
if (createmode == NFS3_CREATE_EXCLUSIVE) {
/* Cram the verifier into atime/mtime */
@@ -1021,7 +1029,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
#endif /* CONFIG_NFSD_V3 */
@@ -1067,7 +1075,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
@@ -1083,7 +1091,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct iattr *iap)
{
struct dentry *dentry, *dnew;
- int err;
+ int err, cerr;
err = nfserr_noent;
if (!flen || !plen)
@@ -1122,17 +1130,18 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
}
} else
- err = nfserrno(-err);
+ err = nfserrno(err);
fh_unlock(fhp);
/* Compose the fh so the dentry will be freed ... */
out_compose:
- fh_compose(resfhp, fhp->fh_export, dnew);
+ cerr = fh_compose(resfhp, fhp->fh_export, dnew);
+ if (err==0) err = cerr;
out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
@@ -1186,7 +1195,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
if (err == -EXDEV && rqstp->rq_vers == 2)
err = nfserr_acces;
else
- err = nfserrno(-err);
+ err = nfserrno(err);
}
fh_unlock(ffhp);
@@ -1196,7 +1205,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
@@ -1318,7 +1327,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
@@ -1356,47 +1365,21 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
goto out;
}
-
- if (type != S_IFDIR) {
- /* It's UNLINK */
-
- err = fh_lock_parent(fhp, rdentry);
- if (err)
- goto out;
-
- err = vfs_unlink(dirp, rdentry);
-
- fh_unlock(fhp);
-
+ err = fh_lock_parent(fhp, rdentry);
+ if (err) {
dput(rdentry);
+ goto out;
+ }
- } else {
- /* It's RMDIR */
- /* See comments in fs/namei.c:do_rmdir */
-
- rdentry->d_count++;
- nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem);
-
-#ifdef CONFIG_NFSD_V3
- fill_pre_wcc(fhp);
-#else
- fhp->fh_locked = 1;
-#endif /* CONFIG_NFSD_V3 */
+ if (type != S_IFDIR) { /* It's UNLINK */
+ err = vfs_unlink(dirp, rdentry);
+ } else { /* It's RMDIR */
+ err = vfs_rmdir(dirp, rdentry);
+ }
- err = -ENOENT;
- if (nfsd_check_parent(dentry, rdentry))
- err = vfs_rmdir(dirp, rdentry);
+ fh_unlock(fhp);
- rdentry->d_count--;
-#ifdef CONFIG_NFSD_V3
- fill_post_wcc(fhp);
-#else
- fhp->fh_locked = 0;
-#endif /* CONFIG_NFSD_V3 */
- nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem);
-
- dput(rdentry);
- }
+ dput(rdentry);
if (err)
goto out_nfserr;
@@ -1409,7 +1392,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out;
}
@@ -1499,7 +1482,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(-err);
+ err = nfserrno(err);
goto out_close;
}
@@ -1510,29 +1493,9 @@ out_nfserr:
int
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat)
{
- struct dentry *dentry;
- struct inode *inode;
- struct super_block *sb;
- mm_segment_t oldfs;
- int err;
-
- err = fh_verify(rqstp, fhp, 0, MAY_NOP);
- if (err)
- goto out;
- dentry = fhp->fh_dentry;
- inode = dentry->d_inode;
-
- err = nfserr_io;
- if (!(sb = inode->i_sb) || !sb->s_op->statfs)
- goto out;
-
- oldfs = get_fs();
- set_fs (KERNEL_DS);
- sb->s_op->statfs(sb, stat, sizeof(*stat));
- set_fs (oldfs);
- err = 0;
-
-out:
+ int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+ if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat))
+ err = nfserr_io;
return err;
}
@@ -1617,7 +1580,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
if (current->fsuid != 0)
current->cap_effective = saved_cap;
- return err? nfserrno(-err) : 0;
+ return err? nfserrno(err) : 0;
}
void
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index 89888bb60..a24faac65 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -746,13 +746,11 @@ static void ntfs_put_super(struct super_block *sb)
ntfs_free(vol);
#endif
ntfs_debug(DEBUG_OTHER, "ntfs_put_super: done\n");
- MOD_DEC_USE_COUNT;
}
/* Called by the kernel when asking for stats */
-static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize)
+static int ntfs_statfs(struct super_block *sb, struct statfs *sf)
{
- struct statfs fs;
struct inode *mft;
ntfs_volume *vol;
ntfs_u64 size;
@@ -760,30 +758,26 @@ static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize)
ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n");
vol=NTFS_SB2VOL(sb);
- memset(&fs,0,sizeof(fs));
- fs.f_type=NTFS_SUPER_MAGIC;
- fs.f_bsize=vol->clustersize;
+ sf->f_type=NTFS_SUPER_MAGIC;
+ sf->f_bsize=vol->clustersize;
error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &size );
if( error )
return -error;
- fs.f_blocks = size; /* volumesize is in clusters */
- fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
- fs.f_bavail=fs.f_bfree;
+ sf->f_blocks = size; /* volumesize is in clusters */
+ sf->f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
+ sf->f_bavail=sf->f_bfree;
- /* Number of files is limited by free space only, so we lie here */
- fs.f_ffree=0;
mft=iget(sb,FILE_MFT);
if (!mft)
return -EIO;
/* So ... we lie... thus this following cast of loff_t value
is ok here.. */
- fs.f_files = (unsigned long)mft->i_size / vol->mft_recordsize;
+ sf->f_files = (unsigned long)mft->i_size / vol->mft_recordsize;
iput(mft);
/* should be read from volume */
- fs.f_namelen=255;
- copy_to_user(sf,&fs,bufsize);
+ sf->f_namelen=255;
return 0;
}
@@ -823,14 +817,6 @@ struct super_block * ntfs_read_super(struct super_block *sb,
struct buffer_head *bh;
int i;
- /* When the driver is compiled as a module, kmod must know when it
- * can safely remove it from memory. To do this, each module owns a
- * reference counter.
- */
- MOD_INC_USE_COUNT;
- /* Don't put ntfs_debug() before MOD_INC_USE_COUNT, printk() can block
- * so this could lead to a race condition with kmod.
- */
ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");
#ifdef NTFS_IN_LINUX_KERNEL
@@ -844,9 +830,6 @@ struct super_block * ntfs_read_super(struct super_block *sb,
if(!parse_options(vol,(char*)options))
goto ntfs_read_super_vol;
- /* Ensure that the super block won't be used until it is completed */
- lock_super(sb);
- ntfs_debug(DEBUG_OTHER, "lock_super\n");
#if 0
/* Set to read only, user option might reset it */
sb->s_flags |= MS_RDONLY;
@@ -919,48 +902,24 @@ struct super_block * ntfs_read_super(struct super_block *sb,
ntfs_error("Could not get root dir inode\n");
goto ntfs_read_super_mft;
}
- unlock_super(sb);
- ntfs_debug(DEBUG_OTHER, "unlock_super\n");
ntfs_debug(DEBUG_OTHER, "read_super: done\n");
return sb;
ntfs_read_super_mft:
ntfs_free(vol->mft);
ntfs_read_super_unl:
- sb->s_dev = 0;
- unlock_super(sb);
- ntfs_debug(DEBUG_OTHER, "unlock_super\n");
ntfs_read_super_vol:
#ifndef NTFS_IN_LINUX_KERNEL
ntfs_free(vol);
ntfs_read_super_dec:
#endif
ntfs_debug(DEBUG_OTHER, "read_super: done\n");
- MOD_DEC_USE_COUNT;
return NULL;
}
/* Define the filesystem
- *
- * Define SECOND if you cannot unload ntfs, and want to avoid rebooting
- * for just one more test
*/
-static struct file_system_type ntfs_fs_type = {
-/* Filesystem name, as used after mount -t */
-#ifndef SECOND
- "ntfs",
-#else
- "ntfs2",
-#endif
-/* This filesystem requires a device (a hard disk)
- * May want to add FS_IBASKET when it works
- */
- FS_REQUIRES_DEV,
-/* Entry point of the filesystem */
- ntfs_read_super,
-/* Will point to the next filesystem in the kernel table */
- NULL
-};
+static DECLARE_FSTYPE_DEV(ntfs_fs_type, "ntfs", ntfs_read_super);
/* When this code is not compiled as a module, this is the main entry point,
* called by do_sys_setup() in fs/filesystems.c
diff --git a/fs/open.c b/fs/open.c
index e7b119df7..6b11f4ab0 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -4,6 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/string.h>
#include <linux/mm.h>
#include <linux/utime.h>
#include <linux/file.h>
@@ -21,13 +22,10 @@ asmlinkage long sys_statfs(const char * path, struct statfs * buf)
dentry = namei(path);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
- struct inode * inode = dentry->d_inode;
- struct super_block * sb = inode->i_sb;
-
- error = -ENODEV;
- if (sb && sb->s_op && sb->s_op->statfs)
- error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
-
+ struct statfs tmp;
+ error = vfs_statfs(dentry->d_inode->i_sb, &tmp);
+ if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
+ error = -EFAULT;
dput(dentry);
}
unlock_kernel();
@@ -37,18 +35,17 @@ asmlinkage long sys_statfs(const char * path, struct statfs * buf)
asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf)
{
struct file * file;
- struct super_block * sb;
+ struct statfs tmp;
int error;
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
- error = -ENODEV;
- sb = file->f_dentry->d_inode->i_sb;
lock_kernel();
- if (sb && sb->s_op && sb->s_op->statfs)
- error = sb->s_op->statfs(sb, buf, sizeof(struct statfs));
+ error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp);
+ if (!error && copy_to_user(buf, &tmp, sizeof(struct statfs)))
+ error = -EFAULT;
unlock_kernel();
fput(file);
out:
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index 1f9139a51..a95ad1acd 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.6 2000/02/27 08:19:47 davem Exp $
+/* $Id: inode.c,v 1.7 2000/03/10 04:45:50 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
@@ -982,22 +982,17 @@ static void openprom_read_inode(struct inode * inode)
static void openprom_put_super(struct super_block *sb)
{
- MOD_DEC_USE_COUNT;
}
-static int openprom_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int openprom_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = OPENPROM_SUPER_MAGIC;
- tmp.f_bsize = PAGE_SIZE/sizeof(long); /* ??? */
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = OPENPROM_SUPER_MAGIC;
+ buf->f_bsize = PAGE_SIZE/sizeof(long); /* ??? */
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
static struct super_operations openprom_sops = {
@@ -1011,8 +1006,6 @@ struct super_block *openprom_read_super(struct super_block *s,void *data,
{
struct inode * root_inode;
- MOD_INC_USE_COUNT;
- lock_super(s);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = OPENPROM_SUPER_MAGIC;
@@ -1023,24 +1016,15 @@ struct super_block *openprom_read_super(struct super_block *s,void *data,
s->s_root = d_alloc_root(root_inode);
if (!s->s_root)
goto out_no_root;
- unlock_super(s);
return s;
out_no_root:
printk("openprom_read_super: get root inode failed\n");
iput(root_inode);
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
return NULL;
}
-static struct file_system_type openprom_fs_type = {
- "openpromfs",
- 0,
- openprom_read_super,
- NULL
-};
+static DECLARE_FSTYPE(openprom_fs_type, "openpromfs", openprom_read_super, 0);
int init_openprom_fs(void)
{
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 65bc80c88..3e1c58ad7 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -151,12 +151,13 @@ static inline char * task_state(struct task_struct *p, char *buffer)
"State:\t%s\n"
"Pid:\t%d\n"
"PPid:\t%d\n"
+ "TracerPid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n"
"FDSize:\t%d\n"
"Groups:\t",
get_task_state(p),
- p->pid, p->p_pptr->pid,
+ p->pid, p->p_opptr->pid, p->p_pptr->pid != p->p_opptr->pid ? p->p_opptr->pid : 0,
p->uid, p->euid, p->suid, p->fsuid,
p->gid, p->egid, p->sgid, p->fsgid,
p->files ? p->files->max_fds : 0);
@@ -327,7 +328,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
task->pid,
task->comm,
state,
- task->p_pptr->pid,
+ task->p_opptr->pid,
task->pgrp,
task->session,
task->tty ? kdev_t_to_nr(task->tty->device) : 0,
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 84a23a7f5..90ed410b7 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -100,19 +100,15 @@ static void proc_read_inode(struct inode * inode)
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
-static int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int proc_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = PROC_SUPER_MAGIC;
- tmp.f_bsize = PAGE_SIZE/sizeof(long);
- tmp.f_blocks = 0;
- tmp.f_bfree = 0;
- tmp.f_bavail = 0;
- tmp.f_files = 0;
- tmp.f_ffree = 0;
- tmp.f_namelen = NAME_MAX;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = PROC_SUPER_MAGIC;
+ buf->f_bsize = PAGE_SIZE/sizeof(long);
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_ffree = 0;
+ buf->f_namelen = NAME_MAX;
+ return 0;
}
static struct super_operations proc_sops = {
@@ -209,7 +205,6 @@ struct super_block *proc_read_super(struct super_block *s,void *data,
struct inode * root_inode;
struct task_struct *p;
- lock_super(s);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = PROC_SUPER_MAGIC;
@@ -229,13 +224,10 @@ struct super_block *proc_read_super(struct super_block *s,void *data,
parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
s->u.generic_sbp = (void*) proc_super_blocks;
proc_super_blocks = s;
- unlock_super(s);
return s;
out_no_root:
printk("proc_read_super: get root inode failed\n");
iput(root_inode);
- s->s_dev = 0;
- unlock_super(s);
return NULL;
}
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index cc1ae7d96..0203b9776 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -20,12 +20,7 @@ EXPORT_SYMBOL(proc_net);
EXPORT_SYMBOL(proc_bus);
EXPORT_SYMBOL(proc_root_driver);
-static struct file_system_type proc_fs_type = {
- "proc",
- 0 /* FS_NO_DCACHE doesn't work correctly */,
- proc_read_super,
- NULL
-};
+static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, 0);
int __init init_proc_fs(void)
{
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 49bad450e..b85483d3d 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -117,7 +117,7 @@ static struct super_block *qnx4_read_super(struct super_block *, void *, int);
static void qnx4_put_super(struct super_block *sb);
static void qnx4_read_inode(struct inode *);
static int qnx4_remount(struct super_block *sb, int *flags, char *data);
-static int qnx4_statfs(struct super_block *, struct statfs *, int);
+static int qnx4_statfs(struct super_block *, struct statfs *);
static struct super_operations qnx4_sops =
{
@@ -269,22 +269,16 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
return block;
}
-static int qnx4_statfs(struct super_block *sb,
- struct statfs *buf, int bufsize)
+static int qnx4_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- memset(&tmp, 0, sizeof tmp);
- tmp.f_type = sb->s_magic;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
- tmp.f_bfree = qnx4_count_free_blocks(sb);
- tmp.f_bavail = tmp.f_bfree;
- tmp.f_files = -1; /* we don't count files */
- tmp.f_ffree = -1; /* inodes are allocated dynamically */
- tmp.f_namelen = QNX4_NAME_MAX;
-
- return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+ buf->f_type = sb->s_magic;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
+ buf->f_bfree = qnx4_count_free_blocks(sb);
+ buf->f_bavail = buf->f_bfree;
+ buf->f_namelen = QNX4_NAME_MAX;
+
+ return 0;
}
/*
@@ -343,8 +337,6 @@ static struct super_block *qnx4_read_super(struct super_block *s,
struct inode *root;
const char *errmsg;
- MOD_INC_USE_COUNT;
- lock_super(s);
set_blocksize(dev, QNX4_BLOCK_SIZE);
s->s_blocksize = QNX4_BLOCK_SIZE;
s->s_blocksize_bits = QNX4_BLOCK_SIZE_BITS;
@@ -399,7 +391,6 @@ static struct super_block *qnx4_read_super(struct super_block *s,
goto outi;
brelse(bh);
- unlock_super(s);
s->s_dirt = 1;
return s;
@@ -409,9 +400,6 @@ static struct super_block *qnx4_read_super(struct super_block *s,
out:
brelse(bh);
outnobh:
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
return NULL;
}
@@ -419,7 +407,6 @@ static struct super_block *qnx4_read_super(struct super_block *s,
static void qnx4_put_super(struct super_block *sb)
{
kfree_s( sb->u.qnx4_sb.BitMap, sizeof( struct qnx4_inode_entry ) );
- MOD_DEC_USE_COUNT;
return;
}
@@ -502,13 +489,7 @@ static void qnx4_read_inode(struct inode *inode)
brelse(bh);
}
-static struct file_system_type qnx4_fs_type =
-{
- "qnx4",
- FS_REQUIRES_DEV,
- qnx4_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(qnx4_fs_type, "qnx4", qnx4_read_super);
int __init init_qnx4_fs(void)
{
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index 0defa3dcb..a25200b14 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -171,7 +171,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
goto end_rmdir;
}
#endif
- if (!list_empty(&dentry->d_hash)) {
+ if (!d_unhashed(dentry)) {
retval = -EBUSY;
goto end_rmdir;
}
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index b95dfa219..15e80519f 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -105,11 +105,8 @@ romfs_read_super(struct super_block *s, void *data, int silent)
struct romfs_super_block *rsb;
int sz;
- MOD_INC_USE_COUNT;
-
/* I would parse the options here, but there are none.. :) */
- lock_super(s);
set_blocksize(dev, ROMBSIZE);
s->s_blocksize = ROMBSIZE;
s->s_blocksize_bits = ROMBSBITS;
@@ -153,16 +150,11 @@ romfs_read_super(struct super_block *s, void *data, int silent)
if (!s->s_root)
goto outnobh;
- unlock_super(s);
-
/* Ehrhm; sorry.. :) And thanks to Hans-Joachim Widmaier :) */
if (0) {
out:
brelse(bh);
outnobh:
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
s = NULL;
}
@@ -174,23 +166,20 @@ outnobh:
static void
romfs_put_super(struct super_block *sb)
{
- MOD_DEC_USE_COUNT;
return;
}
/* That's simple too. */
static int
-romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+romfs_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.f_type = ROMFS_MAGIC;
- tmp.f_bsize = ROMBSIZE;
- tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
- tmp.f_namelen = ROMFS_MAXFN;
- return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
+ buf->f_type = ROMFS_MAGIC;
+ buf->f_bsize = ROMBSIZE;
+ buf->f_bfree = buf->f_bavail = buf->f_ffree;
+ buf->f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
+ buf->f_namelen = ROMFS_MAXFN;
+ return 0;
}
/* some helper routines */
@@ -541,12 +530,7 @@ static struct super_operations romfs_ops = {
statfs: romfs_statfs,
};
-static struct file_system_type romfs_fs_type = {
- "romfs",
- FS_REQUIRES_DEV,
- romfs_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(romfs_fs_type, "romfs", romfs_read_super);
int __init init_romfs_fs(void)
{
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 91061a28f..a29e55c7a 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -443,7 +443,7 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
* Check that nobody else is using the directory..
*/
error = -EBUSY;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
goto out;
smb_invalid_dir_cache(dir);
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 3b13fdd80..94923fbad 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -32,7 +32,7 @@
static void smb_put_inode(struct inode *);
static void smb_delete_inode(struct inode *);
static void smb_put_super(struct super_block *);
-static int smb_statfs(struct super_block *, struct statfs *, int);
+static int smb_statfs(struct super_block *, struct statfs *);
static void smb_set_inode_attr(struct inode *, struct smb_fattr *);
static struct super_operations smb_sops =
@@ -315,8 +315,6 @@ smb_put_super(struct super_block *sb)
kfree(sb->u.smbfs_sb.temp_buf);
if (server->packet)
smb_vfree(server->packet);
-
- MOD_DEC_USE_COUNT;
}
struct super_block *
@@ -326,15 +324,11 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
struct inode *root_inode;
struct smb_fattr root;
- MOD_INC_USE_COUNT;
-
if (!raw_data)
goto out_no_data;
if (((struct smb_mount_data *) raw_data)->version != SMB_MOUNT_VERSION)
goto out_wrong_data;
- lock_super(sb);
-
sb->s_blocksize = 1024; /* Eh... Is this correct? */
sb->s_blocksize_bits = 10;
sb->s_magic = SMB_SUPER_MAGIC;
@@ -389,7 +383,6 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
if (!sb->s_root)
goto out_no_root;
- unlock_super(sb);
return sb;
out_no_root:
@@ -401,7 +394,6 @@ out_no_temp:
smb_vfree(sb->u.smbfs_sb.packet);
out_no_mem:
printk(KERN_ERR "smb_read_super: allocation failure\n");
- unlock_super(sb);
goto out_fail;
out_wrong_data:
printk(KERN_ERR "SMBFS: need mount version %d\n", SMB_MOUNT_VERSION);
@@ -409,25 +401,17 @@ out_wrong_data:
out_no_data:
printk("smb_read_super: missing data argument\n");
out_fail:
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
static int
-smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+smb_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs attr;
+ smb_proc_dskattr(sb, buf);
- memset(&attr, 0, sizeof(attr));
-
- smb_proc_dskattr(sb, &attr);
-
- attr.f_type = SMB_SUPER_MAGIC;
- attr.f_files = -1;
- attr.f_ffree = -1;
- attr.f_namelen = SMB_MAXPATHLEN;
- return copy_to_user(buf, &attr, bufsiz) ? -EFAULT : 0;
+ buf->f_type = SMB_SUPER_MAGIC;
+ buf->f_namelen = SMB_MAXPATHLEN;
+ return 0;
}
int
@@ -550,12 +534,7 @@ int smb_current_kmalloced;
int smb_current_vmalloced;
#endif
-static struct file_system_type smb_fs_type = {
- "smbfs",
- 0 /* FS_NO_DCACHE doesn't work correctly */,
- smb_read_super,
- NULL
-};
+static DECLARE_FSTYPE( smb_fs_type, "smbfs", smb_read_super, 0);
int __init init_smb_fs(void)
{
diff --git a/fs/super.c b/fs/super.c
index e41e1d71d..c365c556c 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -19,6 +19,7 @@
*/
#include <linux/config.h>
+#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/locks.h>
#include <linux/smp_lock.h>
@@ -34,9 +35,9 @@
#include <linux/nfs_fs_sb.h>
#include <linux/nfs_mount.h>
-#ifdef CONFIG_KMOD
#include <linux/kmod.h>
-#endif
+#define __NO_VERSION__
+#include <linux/module.h>
/*
* We use a semaphore to synchronize all mount/umount
@@ -59,7 +60,194 @@ int nr_super_blocks = 0;
int max_super_blocks = NR_SUPER;
LIST_HEAD(super_blocks);
+/*
+ * Handling of filesystem drivers list.
+ * Rules:
+ * Inclusion to/removals from/scanning of list are protected by spinlock.
+ * During the unload module must call unregister_filesystem().
+ * We can access the fields of list element if:
+ * 1) spinlock is held or
+ * 2) we hold the reference to the module.
+ * The latter can be guaranteed by call of try_inc_mod_count(); if it
+ * returned 0 we must skip the element, otherwise we got the reference.
+ * Once the reference is obtained we can drop the spinlock.
+ */
+
static struct file_system_type *file_systems = NULL;
+static spinlock_t file_systems_lock = SPIN_LOCK_UNLOCKED;
+
+static void put_filesystem(struct file_system_type *fs)
+{
+ if (fs->owner)
+ __MOD_DEC_USE_COUNT(fs->owner);
+}
+
+static struct file_system_type **find_filesystem(const char *name)
+{
+ struct file_system_type **p;
+ for (p=&file_systems; *p; p=&(*p)->next)
+ if (strcmp((*p)->name,name) == 0)
+ break;
+ return p;
+}
+
+int register_filesystem(struct file_system_type * fs)
+{
+ int res = 0;
+ struct file_system_type ** p;
+
+ if (!fs)
+ return -EINVAL;
+ if (fs->next)
+ return -EBUSY;
+ spin_lock(&file_systems_lock);
+ p = find_filesystem(fs->name);
+ if (*p)
+ res = -EBUSY;
+ else
+ *p = fs;
+ spin_unlock(&file_systems_lock);
+ return res;
+}
+
+int unregister_filesystem(struct file_system_type * fs)
+{
+ struct file_system_type ** tmp;
+
+ spin_lock(&file_systems_lock);
+ tmp = &file_systems;
+ while (*tmp) {
+ if (fs == *tmp) {
+ *tmp = fs->next;
+ fs->next = NULL;
+ spin_unlock(&file_systems_lock);
+ return 0;
+ }
+ tmp = &(*tmp)->next;
+ }
+ spin_unlock(&file_systems_lock);
+ return -EINVAL;
+}
+
+static int fs_index(const char * __name)
+{
+ struct file_system_type * tmp;
+ char * name;
+ int err, index;
+
+ name = getname(__name);
+ err = PTR_ERR(name);
+ if (IS_ERR(name))
+ return err;
+
+ err = -EINVAL;
+ spin_lock(&file_systems_lock);
+ for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
+ if (strcmp(tmp->name,name) == 0) {
+ err = index;
+ break;
+ }
+ index++;
+ }
+ spin_unlock(&file_systems_lock);
+ putname(name);
+ return err;
+}
+
+static int fs_name(unsigned int index, char * buf)
+{
+ struct file_system_type * tmp;
+ int len, res;
+
+ spin_lock(&file_systems_lock);
+ for (tmp = file_systems; tmp; tmp = tmp->next, index--)
+ if (index <= 0 && try_inc_mod_count(tmp->owner))
+ break;
+ spin_unlock(&file_systems_lock);
+ if (!tmp)
+ return -EINVAL;
+
+ /* OK, we got the reference, so we can safely block */
+ len = strlen(tmp->name) + 1;
+ res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
+ put_filesystem(tmp);
+ return res;
+}
+
+static int fs_maxindex(void)
+{
+ struct file_system_type * tmp;
+ int index;
+
+ spin_lock(&file_systems_lock);
+ for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++)
+ ;
+ spin_unlock(&file_systems_lock);
+ return index;
+}
+
+/*
+ * Whee.. Weird sysv syscall.
+ */
+asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
+{
+ int retval = -EINVAL;
+
+ lock_kernel();
+ switch (option) {
+ case 1:
+ retval = fs_index((const char *) arg1);
+ break;
+
+ case 2:
+ retval = fs_name(arg1, (char *) arg2);
+ break;
+
+ case 3:
+ retval = fs_maxindex();
+ break;
+ }
+ unlock_kernel();
+ return retval;
+}
+
+int get_filesystem_list(char * buf)
+{
+ int len = 0;
+ struct file_system_type * tmp;
+
+ spin_lock(&file_systems_lock);
+ tmp = file_systems;
+ while (tmp && len < PAGE_SIZE - 80) {
+ len += sprintf(buf+len, "%s\t%s\n",
+ (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
+ tmp->name);
+ tmp = tmp->next;
+ }
+ spin_unlock(&file_systems_lock);
+ return len;
+}
+
+static struct file_system_type *get_fs_type(const char *name)
+{
+ struct file_system_type *fs;
+
+ spin_lock(&file_systems_lock);
+ fs = *(find_filesystem(name));
+ if (fs && !try_inc_mod_count(fs->owner))
+ fs = NULL;
+ spin_unlock(&file_systems_lock);
+ if (!fs && (request_module(name) == 0)) {
+ spin_lock(&file_systems_lock);
+ fs = *(find_filesystem(name));
+ if (fs && !try_inc_mod_count(fs->owner))
+ fs = NULL;
+ spin_unlock(&file_systems_lock);
+ }
+ return fs;
+}
+
+
struct vfsmount *vfsmntlist = NULL;
static struct vfsmount *vfsmnttail = NULL, *mru_vfsmnt = NULL;
@@ -164,115 +352,6 @@ void remove_vfsmnt(kdev_t dev)
kfree_s(tofree, sizeof(struct vfsmount));
}
-int register_filesystem(struct file_system_type * fs)
-{
- struct file_system_type ** tmp;
-
- if (!fs)
- return -EINVAL;
- if (fs->next)
- return -EBUSY;
- tmp = &file_systems;
- while (*tmp) {
- if (strcmp((*tmp)->name, fs->name) == 0)
- return -EBUSY;
- tmp = &(*tmp)->next;
- }
- *tmp = fs;
- return 0;
-}
-
-int unregister_filesystem(struct file_system_type * fs)
-{
- struct file_system_type ** tmp;
-
- tmp = &file_systems;
- while (*tmp) {
- if (fs == *tmp) {
- *tmp = fs->next;
- fs->next = NULL;
- return 0;
- }
- tmp = &(*tmp)->next;
- }
- return -EINVAL;
-}
-
-static int fs_index(const char * __name)
-{
- struct file_system_type * tmp;
- char * name;
- int err, index;
-
- name = getname(__name);
- err = PTR_ERR(name);
- if (IS_ERR(name))
- return err;
-
- index = 0;
- for (tmp = file_systems ; tmp ; tmp = tmp->next) {
- if (strcmp(tmp->name, name) == 0) {
- putname(name);
- return index;
- }
- index++;
- }
- putname(name);
- return -EINVAL;
-}
-
-static int fs_name(unsigned int index, char * buf)
-{
- struct file_system_type * tmp;
- int len;
-
- tmp = file_systems;
- while (tmp && index > 0) {
- tmp = tmp->next;
- index--;
- }
- if (!tmp)
- return -EINVAL;
- len = strlen(tmp->name) + 1;
- return copy_to_user(buf, tmp->name, len) ? -EFAULT : 0;
-}
-
-static int fs_maxindex(void)
-{
- struct file_system_type * tmp;
- int index;
-
- index = 0;
- for (tmp = file_systems ; tmp ; tmp = tmp->next)
- index++;
- return index;
-}
-
-/*
- * Whee.. Weird sysv syscall.
- */
-asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
-{
- int retval = -EINVAL;
-
- lock_kernel();
- switch (option) {
- case 1:
- retval = fs_index((const char *) arg1);
- break;
-
- case 2:
- retval = fs_name(arg1, (char *) arg2);
- break;
-
- case 3:
- retval = fs_maxindex();
- break;
- }
- unlock_kernel();
- return retval;
-}
-
static struct proc_fs_info {
int flag;
char *str;
@@ -379,39 +458,6 @@ int get_filesystem_info( char *buf )
return len;
}
-int get_filesystem_list(char * buf)
-{
- int len = 0;
- struct file_system_type * tmp;
-
- tmp = file_systems;
- while (tmp && len < PAGE_SIZE - 80) {
- len += sprintf(buf+len, "%s\t%s\n",
- (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
- tmp->name);
- tmp = tmp->next;
- }
- return len;
-}
-
-struct file_system_type *get_fs_type(const char *name)
-{
- struct file_system_type * fs = file_systems;
-
- if (!name)
- return fs;
- for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
- ;
-#ifdef CONFIG_KMOD
- if (!fs && (request_module(name) == 0)) {
- for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
- ;
- }
-#endif
-
- return fs;
-}
-
void __wait_on_super(struct super_block * sb)
{
DECLARE_WAITQUEUE(wait, current);
@@ -480,21 +526,15 @@ asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf)
struct super_block *s;
struct ustat tmp;
struct statfs sbuf;
- mm_segment_t old_fs;
int err = -EINVAL;
lock_kernel();
s = get_super(to_kdev_t(dev));
if (s == NULL)
goto out;
- err = -ENOSYS;
- if (!(s->s_op->statfs))
- goto out;
-
- old_fs = get_fs();
- set_fs(get_ds());
- s->s_op->statfs(s,&sbuf,sizeof(struct statfs));
- set_fs(old_fs);
+ err = vfs_statfs(s, &sbuf);
+ if (err)
+ goto out;
memset(&tmp,0,sizeof(struct ustat));
tmp.f_tfree = sbuf.f_bfree;
@@ -538,25 +578,10 @@ struct super_block *get_empty_super(void)
}
static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
- const char *name, int flags,
+ struct file_system_type *type, int flags,
void *data, int silent)
{
struct super_block * s;
- struct file_system_type *type;
-
- if (!dev)
- goto out_null;
- check_disk_change(dev);
- s = get_super(dev);
- if (s)
- goto found; /* ought to set ->s_bdev */
-
- type = get_fs_type(name);
- if (!type) {
- printk("VFS: on device %s: get_fs_type(%s) failed\n",
- kdevname(dev), name);
- goto out;
- }
s = get_empty_super();
if (!s)
goto out;
@@ -566,11 +591,11 @@ static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
s->s_dirt = 0;
sema_init(&s->s_vfs_rename_sem,1);
sema_init(&s->s_nfsd_free_path_sem,1);
- /* N.B. Should lock superblock now ... */
+ s->s_type = type;
+ lock_super(s);
if (!type->read_super(s, data, silent))
goto out_fail;
- s->s_type = type;
-bd_get:
+ unlock_super(s);
/* tell bdcache that we are going to keep this one */
if (bdev)
atomic_inc(&bdev->bd_count);
@@ -580,12 +605,10 @@ out:
out_fail:
s->s_dev = 0;
s->s_bdev = 0;
-out_null:
- s = NULL;
- goto out;
-found:
- s->s_bdev = bdev;
- goto bd_get;
+ s->s_type = NULL;
+ put_filesystem(type);
+ unlock_super(s);
+ return NULL;
}
/*
@@ -725,6 +748,8 @@ static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
sb->s_dev = 0; /* Free the superblock */
bdev = sb->s_bdev;
sb->s_bdev = NULL;
+ put_filesystem(sb->s_type);
+ sb->s_type = NULL;
unlock_super(sb);
remove_vfsmnt(dev);
@@ -859,6 +884,7 @@ int do_mount(struct block_device *bdev, const char *dev_name,
struct dentry * dir_d;
struct super_block * sb;
struct vfsmount *vfsmnt;
+ struct file_system_type *fs_type;
int error;
if (bdev) {
@@ -896,14 +922,27 @@ int do_mount(struct block_device *bdev, const char *dev_name,
if (dir_d->d_covers != dir_d)
goto dput_and_out;
- /*
- * Note: If the superblock already exists,
- * read_super just does a get_super().
- */
error = -EINVAL;
- sb = read_super(dev, bdev, type, flags, data, 0);
- if (!sb)
+ if (!dev)
goto dput_and_out;
+ check_disk_change(dev);
+ sb = get_super(dev);
+ if (sb) {
+ /* Already mounted */
+ error = -EBUSY;
+ goto dput_and_out;
+ }
+
+ fs_type = get_fs_type(type);
+ if (!fs_type) {
+ printk("VFS: on device %s: get_fs_type(%s) failed\n",
+ kdevname(dev), type);
+ goto dput_and_out;
+ }
+
+ sb = read_super(dev, bdev, fs_type, flags, data, 0);
+ if (!sb)
+ goto fsput_and_out;
/*
* We may have slept while reading the super block,
@@ -923,7 +962,12 @@ int do_mount(struct block_device *bdev, const char *dev_name,
}
bdput_and_out:
+ /* FIXME: ->put_super() is needed here */
sb->s_bdev = NULL;
+ sb->s_dev = 0;
+ sb->s_type = NULL;
+fsput_and_out:
+ put_filesystem(fs_type);
if (bdev)
bdput(bdev);
dput_and_out:
@@ -956,7 +1000,9 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
if (!fs_may_remount_ro(sb))
return -EBUSY;
if (sb->s_op && sb->s_op->remount_fs) {
+ lock_super(sb);
retval = sb->s_op->remount_fs(sb, &flags, data);
+ unlock_super(sb);
if (retval)
return retval;
}
@@ -1159,6 +1205,7 @@ void __init mount_root(void)
}
put_unnamed_dev(sb->s_dev);
sb->s_dev = 0;
+ put_filesystem(fs_type);
}
if (!ROOT_DEV) {
printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
@@ -1200,6 +1247,14 @@ void __init mount_root(void)
devfs_get_maj_min (handle, &major, &minor);
ROOT_DEV = MKDEV (major, minor);
}
+
+ /*
+ * Probably pure paranoia, but I'm less than happy about delving into
+ * devfs crap and checking it right now. Later.
+ */
+ if (!ROOT_DEV)
+ panic("I have no root and I want to sream");
+
bdev = bdget(kdev_t_to_nr(ROOT_DEV));
if (!bdev)
panic(__FUNCTION__ ": unable to allocate root device");
@@ -1221,37 +1276,57 @@ void __init mount_root(void)
printk ("VFS: Cannot open root device \"%s\" or %s\n",
root_device_name, kdevname (ROOT_DEV));
printk ("Please append a correct \"root=\" boot option\n");
+ panic("VFS: Unable to mount root fs on %s",
+ kdevname(ROOT_DEV));
}
- else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
+
+ check_disk_change(ROOT_DEV);
+
+ spin_lock(&file_systems_lock);
+ for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
continue;
- sb = read_super(ROOT_DEV,bdev,fs_type->name,root_mountflags,NULL,1);
+ if (!try_inc_mod_count(fs_type->owner))
+ continue;
+ spin_unlock(&file_systems_lock);
+ sb = get_super(ROOT_DEV);
if (sb) {
- sb->s_flags = root_mountflags;
- current->fs->root = dget(sb->s_root);
- current->fs->pwd = dget(sb->s_root);
- printk ("VFS: Mounted root (%s filesystem)%s.\n",
- fs_type->name,
- (sb->s_flags & MS_RDONLY) ? " readonly" : "");
- if (path_start >= 0) {
- devfs_mk_symlink (NULL,
- "root", 0, DEVFS_FL_DEFAULT,
- path + 5 + path_start, 0,
- NULL, NULL);
- memcpy (path + path_start, "/dev/", 5);
- vfsmnt = add_vfsmnt (sb, path + path_start,
- "/");
- }
- else vfsmnt = add_vfsmnt (sb, "/dev/root", "/");
- if (vfsmnt) {
- bdput(bdev); /* sb holds a reference */
- return;
- }
- panic("VFS: add_vfsmnt failed for root fs");
+ /* Shouldn't we fail here? Oh, well... */
+ sb->s_bdev = bdev;
+ goto mount_it;
}
+ sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);
+ if (sb)
+ goto mount_it;
+ spin_lock(&file_systems_lock);
+ put_filesystem(fs_type);
}
+ spin_unlock(&file_systems_lock);
panic("VFS: Unable to mount root fs on %s",
kdevname(ROOT_DEV));
+
+mount_it:
+ sb->s_flags = root_mountflags;
+ current->fs->root = dget(sb->s_root);
+ current->fs->pwd = dget(sb->s_root);
+ printk ("VFS: Mounted root (%s filesystem)%s.\n",
+ fs_type->name,
+ (sb->s_flags & MS_RDONLY) ? " readonly" : "");
+ if (path_start >= 0) {
+ devfs_mk_symlink (NULL,
+ "root", 0, DEVFS_FL_DEFAULT,
+ path + 5 + path_start, 0,
+ NULL, NULL);
+ memcpy (path + path_start, "/dev/", 5);
+ vfsmnt = add_vfsmnt (sb, path + path_start,
+ "/");
+ }
+ else vfsmnt = add_vfsmnt (sb, "/dev/root", "/");
+ if (vfsmnt) {
+ bdput(bdev); /* sb holds a reference */
+ return;
+ }
+ panic("VFS: add_vfsmnt failed for root fs");
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 2c79b3c71..c1b95f28d 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -68,7 +68,7 @@ static void sysv_delete_inode(struct inode *inode)
static void sysv_put_super(struct super_block *);
static void sysv_write_super(struct super_block *);
static void sysv_read_inode(struct inode *);
-static int sysv_statfs(struct super_block *, struct statfs *, int);
+static int sysv_statfs(struct super_block *, struct statfs *);
static struct super_operations sysv_sops = {
read_inode: sysv_read_inode,
@@ -360,8 +360,6 @@ static struct super_block *sysv_read_super(struct super_block *sb,
panic("Coherent FS: bad super-block size");
if (64 != sizeof (struct sysv_inode))
panic("sysv fs: bad i-node size");
- MOD_INC_USE_COUNT;
- lock_super(sb);
set_blocksize(dev,BLOCK_SIZE);
sb->sv_block_base = 0;
@@ -407,13 +405,10 @@ static struct super_block *sysv_read_super(struct super_block *sb,
}
}
bad_shift:
- sb->s_dev = 0;
- unlock_super(sb);
if (!silent)
printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device "
"%s\n", kdevname(dev));
failed:
- MOD_DEC_USE_COUNT;
return NULL;
ok:
@@ -442,8 +437,6 @@ static struct super_block *sysv_read_super(struct super_block *sb,
goto superblock_ok;
bad_superblock:
brelse(bh);
- sb->s_dev = 0;
- unlock_super(sb);
printk("SysV FS: cannot read superblock in %d byte mode\n", sb->sv_block_size);
goto failed;
superblock_ok:
@@ -489,8 +482,6 @@ static struct super_block *sysv_read_super(struct super_block *sb,
brelse(bh1);
brelse(bh2);
set_blocksize(sb->s_dev,BLOCK_SIZE);
- sb->s_dev = 0;
- unlock_super(sb);
printk("SysV FS: cannot read superblock in 512 byte mode\n");
goto failed;
}
@@ -511,14 +502,11 @@ static struct super_block *sysv_read_super(struct super_block *sb,
if (!sb->s_root) {
printk("SysV FS: get root inode failed\n");
sysv_put_super(sb);
- sb->s_dev = 0;
- unlock_super(sb);
return NULL;
}
#ifndef CONFIG_SYSV_FS_WRITE
sb->s_flags |= MS_RDONLY;
#endif
- unlock_super(sb);
sb->s_dirt = 1;
/* brelse(bh); resp. brelse(bh1); brelse(bh2);
occurs when the disk is unmounted. */
@@ -558,24 +546,20 @@ static void sysv_put_super(struct super_block *sb)
/* switch back to default block size */
if (sb->s_blocksize != BLOCK_SIZE)
set_blocksize(sb->s_dev,BLOCK_SIZE);
-
- MOD_DEC_USE_COUNT;
}
-static int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int sysv_statfs(struct super_block *sb, struct statfs *buf)
{
- struct statfs tmp;
-
- tmp.f_type = sb->s_magic; /* type of filesystem */
- tmp.f_bsize = sb->sv_block_size; /* block size */
- tmp.f_blocks = sb->sv_ndatazones; /* total data blocks in file system */
- tmp.f_bfree = sysv_count_free_blocks(sb); /* free blocks in fs */
- tmp.f_bavail = tmp.f_bfree; /* free blocks available to non-superuser */
- tmp.f_files = sb->sv_ninodes; /* total file nodes in file system */
- tmp.f_ffree = sysv_count_free_inodes(sb); /* free file nodes in fs */
- tmp.f_namelen = SYSV_NAMELEN;
- /* Don't know what value to put in tmp.f_fsid */ /* file system id */
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_type = sb->s_magic; /* type of filesystem */
+ buf->f_bsize = sb->sv_block_size; /* block size */
+ buf->f_blocks = sb->sv_ndatazones; /* total data blocks in file system */
+ buf->f_bfree = sysv_count_free_blocks(sb); /* free blocks in fs */
+ buf->f_bavail = buf->f_bfree; /* free blocks available to non-superuser */
+ buf->f_files = sb->sv_ninodes; /* total file nodes in file system */
+ buf->f_ffree = sysv_count_free_inodes(sb); /* free file nodes in fs */
+ buf->f_namelen = SYSV_NAMELEN;
+ /* Don't know what value to put in buf->f_fsid */ /* file system id */
+ return 0;
}
@@ -1202,20 +1186,11 @@ int sysv_sync_inode(struct inode * inode)
/* Every kernel module contains stuff like this. */
-static struct file_system_type sysv_fs_type[] = {
- {"sysv", FS_REQUIRES_DEV, sysv_read_super, NULL}
-};
+static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super);
int __init init_sysv_fs(void)
{
- int i;
- int ouch = 0;
-
- for (i = 0; i < sizeof(sysv_fs_type)/sizeof(sysv_fs_type[0]); i++) {
- if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0)
- break;
- }
- return ouch;
+ return register_filesystem(&sysv_fs_type);
}
#ifdef MODULE
@@ -1228,11 +1203,7 @@ int init_module(void)
void cleanup_module(void)
{
- int i;
-
- for (i = 0; i < sizeof(sysv_fs_type)/sizeof(sysv_fs_type[0]); i++)
- /* No error message if this breaks... that's OK... */
- unregister_filesystem(&sysv_fs_type[i]);
+ unregister_filesystem(&sysv_fs_type);
}
#endif
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index a7b871073..6a7fbf34b 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -389,7 +389,7 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
retval = -ENOTEMPTY;
goto end_rmdir;
}
- if (!list_empty(&dentry->d_hash)) {
+ if (!d_unhashed(dentry)) {
retval = -EBUSY;
goto end_rmdir;
}
@@ -552,6 +552,9 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
}
if (S_ISDIR(old_inode->i_mode)) {
if (new_inode) {
+ retval = -EBUSY;
+ if (!d_unhashed(new_dentry))
+ goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index db140e66e..c371b5d52 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -1165,6 +1165,9 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
if (new_inode)
{
+ retval = -EBUSY;
+ if (!d_unhashed(new_dentry))
+ goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 6b3e32f03..761cdcb6c 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -93,25 +93,21 @@ static void udf_load_partdesc(struct super_block *, struct buffer_head *);
static void udf_open_lvid(struct super_block *);
static void udf_close_lvid(struct super_block *);
static unsigned int udf_count_free(struct super_block *);
-static int udf_statfs(struct super_block *, struct statfs *, int);
+static int udf_statfs(struct super_block *, struct statfs *);
/* UDF filesystem type */
-static struct file_system_type udf_fstype = {
- name: "udf",
- fs_flags: FS_REQUIRES_DEV,
- read_super: udf_read_super,
-};
+static DECLARE_FSTYPE_DEV(udf_fstype, "udf", udf_read_super);
/* Superblock operations */
static struct super_operations udf_sb_ops = {
- read_inode: udf_read_inode,
+ read_inode: udf_read_inode,
write_inode: udf_write_inode,
- put_inode: udf_put_inode,
+ put_inode: udf_put_inode,
delete_inode: udf_delete_inode,
- put_super: udf_put_super,
+ put_super: udf_put_super,
write_super: udf_write_super,
- statfs: udf_statfs,
- remount_fs: udf_remount_fs,
+ statfs: udf_statfs,
+ remount_fs: udf_remount_fs,
};
struct udf_options
@@ -1326,10 +1322,6 @@ udf_read_super(struct super_block *sb, void *options, int silent)
uopt.gid = -1;
uopt.umask = 0;
- /* Lock the module in memory (if applicable) */
- MOD_INC_USE_COUNT;
-
- lock_super(sb);
memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
#if CONFIG_UDF_RW != 1
@@ -1438,7 +1430,6 @@ udf_read_super(struct super_block *sb, void *options, int silent)
}
if (!(sb->s_flags & MS_RDONLY))
udf_open_lvid(sb);
- unlock_super(sb);
/* Assign the root inode */
/* assign inodes by physical block number */
@@ -1470,8 +1461,6 @@ error_out:
udf_close_lvid(sb);
udf_release_data(UDF_SB_LVIDBH(sb));
UDF_SB_FREE(sb);
- unlock_super(sb);
- MOD_DEC_USE_COUNT;
return NULL;
}
@@ -1530,8 +1519,6 @@ udf_put_super(struct super_block *sb)
for (i=0; i<UDF_MAX_BLOCK_LOADED; i++)
udf_release_data(UDF_SB_BLOCK_BITMAP(sb, i));
UDF_SB_FREE(sb);
-
- MOD_DEC_USE_COUNT;
}
/*
@@ -1548,29 +1535,21 @@ udf_put_super(struct super_block *sb)
* Written, tested, and released.
*/
static int
-udf_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+udf_statfs(struct super_block *sb, struct statfs *buf)
{
- int size;
- struct statfs tmp;
- int rc;
-
- size = (bufsize < sizeof(tmp)) ? bufsize: sizeof(tmp);
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.f_type = UDF_SUPER_MAGIC;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
- tmp.f_bfree = udf_count_free(sb);
- tmp.f_bavail = tmp.f_bfree;
- tmp.f_files = (UDF_SB_LVIDBH(sb) ?
+ buf->f_type = UDF_SUPER_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
+ buf->f_bfree = udf_count_free(sb);
+ buf->f_bavail = buf->f_bfree;
+ buf->f_files = (UDF_SB_LVIDBH(sb) ?
(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
- le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + tmp.f_bfree;
- tmp.f_ffree = tmp.f_bfree;
+ le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
+ buf->f_ffree = buf->f_bfree;
/* __kernel_fsid_t f_fsid */
- tmp.f_namelen = UDF_NAME_LEN;
+ buf->f_namelen = UDF_NAME_LEN;
- rc= copy_to_user(buf, &tmp, size) ? -EFAULT: 0;
- return rc;
+ return 0;
}
static unsigned char udf_bitmap_lookup[16] = {
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 80e97bb06..1fe9de9bd 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -451,9 +451,6 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
UFSD(("ENTER\n"))
- MOD_INC_USE_COUNT;
- lock_super (sb);
-
UFSD(("flag %u\n", (int)(sb->s_flags & MS_RDONLY)))
#ifndef CONFIG_UFS_FS_WRITE
@@ -790,16 +787,12 @@ magic_found:
if (!ufs_read_cylinder_structures(sb))
goto failed;
- unlock_super(sb);
UFSD(("EXIT\n"))
return(sb);
failed:
if (ubh) ubh_brelse_uspi (uspi);
if (uspi) kfree (uspi);
- sb->s_dev = 0;
- unlock_super (sb);
- MOD_DEC_USE_COUNT;
UFSD(("EXIT (FAILED)\n"))
return(NULL);
}
@@ -843,8 +836,6 @@ void ufs_put_super (struct super_block * sb)
ubh_brelse_uspi (uspi);
kfree (sb->u.ufs_sb.s_uspi);
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
return;
}
@@ -924,28 +915,27 @@ int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
return 0;
}
-int ufs_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
+int ufs_statfs (struct super_block * sb, struct statfs * buf)
{
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
- struct statfs tmp;
unsigned swab;
swab = sb->u.ufs_sb.s_swab;
uspi = sb->u.ufs_sb.s_uspi;
usb1 = ubh_get_usb_first (USPI_UBH);
- tmp.f_type = UFS_MAGIC;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = uspi->s_dsize;
- tmp.f_bfree = ufs_blkstofrags(SWAB32(usb1->fs_cstotal.cs_nbfree)) +
+ buf->f_type = UFS_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = uspi->s_dsize;
+ buf->f_bfree = ufs_blkstofrags(SWAB32(usb1->fs_cstotal.cs_nbfree)) +
SWAB32(usb1->fs_cstotal.cs_nffree);
- tmp.f_bavail = (tmp.f_bfree > ((tmp.f_blocks / 100) * uspi->s_minfree))
- ? (tmp.f_bfree - ((tmp.f_blocks / 100) * uspi->s_minfree)) : 0;
- tmp.f_files = uspi->s_ncg * uspi->s_ipg;
- tmp.f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
- tmp.f_namelen = UFS_MAXNAMLEN;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+ buf->f_bavail = (buf->f_bfree > ((buf->f_blocks / 100) * uspi->s_minfree))
+ ? (buf->f_bfree - ((buf->f_blocks / 100) * uspi->s_minfree)) : 0;
+ buf->f_files = uspi->s_ncg * uspi->s_ipg;
+ buf->f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
+ buf->f_namelen = UFS_MAXNAMLEN;
+ return 0;
}
static struct super_operations ufs_super_ops = {
@@ -959,12 +949,7 @@ static struct super_operations ufs_super_ops = {
remount_fs: ufs_remount,
};
-static struct file_system_type ufs_fs_type = {
- "ufs",
- FS_REQUIRES_DEV,
- ufs_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(ufs_fs_type, "ufs", ufs_read_super);
int __init init_ufs_fs(void)
{
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 7908144d7..61c832ed4 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -75,7 +75,6 @@ saved_root->d_count);
pseudo_root = NULL;
}
msdos_put_super (sb);
- MOD_DEC_USE_COUNT;
}
@@ -334,7 +333,6 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
struct super_block *res;
struct dentry *new_root;
- MOD_INC_USE_COUNT;
MSDOS_SB(sb)->options.isvfat = 0;
/*
* Call msdos-fs to mount the disk.
@@ -381,8 +379,6 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
out_fail:
printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
@@ -437,13 +433,7 @@ out_noroot:
}
-static struct file_system_type umsdos_fs_type =
-{
- "umsdos",
- FS_REQUIRES_DEV,
- UMSDOS_read_super,
- NULL
-};
+static DECLARE_FSTYPE_DEV(umsdos_fs_type, "umsdos", UMSDOS_read_super);
int __init init_umsdos_fs (void)
{
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 08bb7b340..75715116f 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -876,7 +876,7 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
goto out;
ret = -EBUSY;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
goto out;
/* check whether the EMD is empty */
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index d05dfed73..8c71dd727 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -157,7 +157,7 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
goto out;
ret = -EBUSY;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
goto out;
ret = msdos_rmdir (dir, dentry);
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 476a09e9c..212494142 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -78,11 +78,6 @@ static struct dentry_operations vfat_dentry_ops[4] = {
}
};
-static void vfat_put_super_callback(struct super_block *sb)
-{
- MOD_DEC_USE_COUNT;
-}
-
static int vfat_revalidate(struct dentry *dentry, int flags)
{
PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name));
@@ -978,7 +973,7 @@ static struct dentry *find_alias(struct inode *inode)
tmp = next;
next = tmp->next;
alias = list_entry(tmp, struct dentry, d_alias);
- if (!list_empty(&alias->d_hash))
+ if (!d_unhashed(alias))
return dget(alias);
}
return NULL;
@@ -1085,7 +1080,7 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry)
struct buffer_head *bh = NULL;
struct msdos_dir_entry *de;
- if (!list_empty(&dentry->d_hash))
+ if (!d_unhashed(dentry))
return -EBUSY;
res = fat_dir_empty(dentry->d_inode);
@@ -1207,6 +1202,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
}
if (is_dir) {
+ res =-EBUSY;
+ if (!d_unhashed(new_dentry))
+ goto rename_done;
res = fat_dir_empty(new_inode);
if (res)
goto rename_done;
@@ -1274,21 +1272,13 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
{
struct super_block *res;
- MOD_INC_USE_COUNT;
-
MSDOS_SB(sb)->options.isvfat = 1;
res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
- if (res == NULL) {
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
+ if (res == NULL)
return NULL;
- }
- if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
- MOD_DEC_USE_COUNT;
- } else {
- MSDOS_SB(sb)->put_super_callback=vfat_put_super_callback;
+ if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
MSDOS_SB(sb)->options.dotsOK = 0;
if (MSDOS_SB(sb)->options.posixfs) {
MSDOS_SB(sb)->options.name_check = 's';
diff --git a/fs/vfat/vfatfs_syms.c b/fs/vfat/vfatfs_syms.c
index bccd300e7..d57d153ed 100644
--- a/fs/vfat/vfatfs_syms.c
+++ b/fs/vfat/vfatfs_syms.c
@@ -12,12 +12,7 @@
#include <linux/mm.h>
#include <linux/msdos_fs.h>
-struct file_system_type vfat_fs_type = {
- "vfat",
- FS_REQUIRES_DEV,
- vfat_read_super,
- NULL
-};
+DECLARE_FSTYPE_DEV(vfat_fs_type, "vfat", vfat_read_super);
EXPORT_SYMBOL(vfat_create);
EXPORT_SYMBOL(vfat_unlink);
diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h
index 1947b62c0..886eebb91 100644
--- a/include/asm-i386/ide.h
+++ b/include/asm-i386/ide.h
@@ -16,7 +16,11 @@
#include <linux/config.h>
#ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
#define MAX_HWIFS 10
+# else
+#define MAX_HWIFS 6
+# endif
#endif
#define ide__sti() __sti()
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index ac0ff6e1e..36f2c8855 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -279,6 +279,8 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
#define __cli() __asm__ __volatile__("cli": : :"memory")
#define __sti() __asm__ __volatile__("sti": : :"memory")
+/* used in the idle loop; sti takes one instruction cycle to complete */
+#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory")
/* For spinlocks etc */
#define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
diff --git a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h
index a1ec41e3b..5230bcc15 100644
--- a/include/asm-ia64/atomic.h
+++ b/include/asm-ia64/atomic.h
@@ -91,6 +91,7 @@ atomic_add_negative (int i, atomic_t *v)
#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) != 0)
#define atomic_add(i,v) atomic_add_return((i), (v))
#define atomic_sub(i,v) atomic_sub_return((i), (v))
diff --git a/include/asm-ia64/efi.h b/include/asm-ia64/efi.h
index a3549e0c4..543132486 100644
--- a/include/asm-ia64/efi.h
+++ b/include/asm-ia64/efi.h
@@ -180,7 +180,7 @@ typedef struct {
} efi_config_table_t;
#define EFI_SYSTEM_TABLE_SIGNATURE 0x5453595320494249
-#define EFI_SYSTEM_TABLE_REVISION ((0 << 16) | (91))
+#define EFI_SYSTEM_TABLE_REVISION ((0 << 16) | (92))
typedef struct {
efi_table_hdr_t hdr;
diff --git a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h
index 567243650..cd256f403 100644
--- a/include/asm-ia64/hardirq.h
+++ b/include/asm-ia64/hardirq.h
@@ -2,77 +2,100 @@
#define _ASM_IA64_HARDIRQ_H
/*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
#include <linux/config.h>
+
#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+ unsigned int __local_irq_count;
+ unsigned int __local_bh_count;
+ atomic_t __nmi_counter;
+# if NR_CPUS > 1
+ unsigned int __pad[13]; /* this assumes 64-byte cache-lines... */
+# endif
+} ____cacheline_aligned irq_cpustat_t;
-extern unsigned int local_irq_count[NR_CPUS];
-extern unsigned long hardirq_no[NR_CPUS];
+extern irq_cpustat_t irq_stat[NR_CPUS];
+
+/*
+ * Simple wrappers reducing source bloat
+ */
+#define local_irq_count(cpu) (irq_stat[(cpu)].__local_irq_count)
+#define local_bh_count(cpu) (irq_stat[(cpu)].__local_bh_count)
+#define nmi_counter(cpu) (irq_stat[(cpu)].__nmi_counter)
/*
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
*/
-
-#define in_irq() (local_irq_count[smp_processor_id()] != 0)
-
#define in_interrupt() \
({ \
int __cpu = smp_processor_id(); \
- (local_irq_count[__cpu] + local_bh_count[__cpu]) != 0; \
+ (local_irq_count(__cpu) + local_bh_count(__cpu)) != 0; \
})
-
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
#ifndef CONFIG_SMP
-# define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
-# define hardirq_endlock(cpu) ((void) 0)
+# define hardirq_trylock(cpu) (local_irq_count(cpu) == 0)
+# define hardirq_endlock(cpu) do { } while (0)
-# define hardirq_enter(cpu, irq) (local_irq_count[cpu]++)
-# define hardirq_exit(cpu, irq) (local_irq_count[cpu]--)
+# define irq_enter(cpu, irq) (++local_irq_count(cpu))
+# define irq_exit(cpu, irq) (--local_irq_count(cpu))
# define synchronize_irq() barrier()
#else
-#include <linux/spinlock.h>
-
#include <asm/atomic.h>
#include <asm/smp.h>
-extern int global_irq_holder;
-extern spinlock_t global_irq_lock;
-extern atomic_t global_irq_count;
+extern unsigned char global_irq_holder;
+extern unsigned volatile int global_irq_lock;
+
+static inline int irqs_running (void)
+{
+ int i;
+
+ for (i = 0; i < smp_num_cpus; i++)
+ if (local_irq_count(i))
+ return 1;
+ return 0;
+}
static inline void release_irqlock(int cpu)
{
/* if we didn't own the irq lock, just ignore.. */
if (global_irq_holder == cpu) {
global_irq_holder = NO_PROC_ID;
- spin_unlock(&global_irq_lock);
+ clear_bit(0,&global_irq_lock);
}
}
-static inline void hardirq_enter(int cpu, int irq)
+static inline void irq_enter(int cpu, int irq)
{
- ++local_irq_count[cpu];
- atomic_inc(&global_irq_count);
+ ++local_irq_count(cpu);
+
+ while (test_bit(0,&global_irq_lock)) {
+ /* nothing */;
+ }
}
-static inline void hardirq_exit(int cpu, int irq)
+static inline void irq_exit(int cpu, int irq)
{
- atomic_dec(&global_irq_count);
- --local_irq_count[cpu];
+ --local_irq_count(cpu);
}
static inline int hardirq_trylock(int cpu)
{
- return !local_irq_count[cpu] && !test_bit(0,&global_irq_lock);
+ return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock);
}
-#define hardirq_endlock(cpu) ((void)0)
+#define hardirq_endlock(cpu) do { } while (0)
extern void synchronize_irq(void);
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
new file mode 100644
index 000000000..b897bea30
--- /dev/null
+++ b/include/asm-ia64/hw_irq.h
@@ -0,0 +1,76 @@
+#ifndef _ASM_IA64_HW_IRQ_H
+#define _ASM_IA64_HW_IRQ_H
+
+/*
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <linux/config.h>
+
+#include <linux/types.h>
+
+#include <asm/ptrace.h>
+
+#define NR_ISA_IRQS 16
+
+/*
+ * 0 special
+ *
+ * 1,3-14 are reserved from firmware
+ *
+ * 16-255 (vectored external interrupts) are available
+ *
+ * 15 spurious interrupt (see IVR)
+ *
+ * 16 lowest priority, 255 highest priority
+ *
+ * 15 classes of 16 interrupts each.
+ */
+#define IA64_MIN_VECTORED_IRQ 16
+#define IA64_MAX_VECTORED_IRQ 255
+
+#define IA64_SPURIOUS_INT 0x0f
+
+#define IA64_MIN_VECTORED_IRQ 16
+#define IA64_MAX_VECTORED_IRQ 255
+
+#define PERFMON_IRQ 0x28 /* performanc monitor interrupt vector */
+#define TIMER_IRQ 0xef /* use highest-prio group 15 interrupt for timer */
+#define IPI_IRQ 0xfe /* inter-processor interrupt vector */
+#define CMC_IRQ 0xff /* correctable machine-check interrupt vector */
+
+/* IA64 inter-cpu interrupt related definitions */
+
+/* Delivery modes for inter-cpu interrupts */
+enum {
+ IA64_IPI_DM_INT = 0x0, /* pend an external interrupt */
+ IA64_IPI_DM_PMI = 0x2, /* pend a PMI */
+ IA64_IPI_DM_NMI = 0x4, /* pend an NMI (vector 2) */
+ IA64_IPI_DM_INIT = 0x5, /* pend an INIT interrupt */
+ IA64_IPI_DM_EXTINT = 0x7, /* pend an 8259-compatible interrupt. */
+};
+
+#define IA64_BUS_ID(cpu) (cpu >> 8)
+#define IA64_LOCAL_ID(cpu) (cpu & 0xff)
+
+extern __u8 isa_irq_to_vector_map[16];
+#define isa_irq_to_vector(x) isa_irq_to_vector_map[(x)]
+
+extern struct hw_interrupt_type irq_type_ia64_internal; /* CPU-internal interrupt controller */
+
+extern void ipi_send (int cpu, int vector, int delivery_mode);
+
+#ifdef CONFIG_SMP
+extern void handle_IPI(int irq, void *dev_id, struct pt_regs *regs);
+
+static inline void
+hw_resend_irq (struct hw_interrupt_type *h, unsigned int i)
+{
+ send_IPI_self(i);
+}
+#else
+# define hw_resend_irq(h,i)
+#endif
+
+#endif /* _ASM_IA64_HW_IRQ_H */
diff --git a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h
index 6ec01ecd4..023203dc3 100644
--- a/include/asm-ia64/ide.h
+++ b/include/asm-ia64/ide.h
@@ -16,7 +16,11 @@
#include <linux/config.h>
#ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
#define MAX_HWIFS 10
+# else
+#define MAX_HWIFS 6
+# endif
#endif
#define ide__sti() __sti()
diff --git a/include/asm-ia64/irq.h b/include/asm-ia64/irq.h
index 137670219..61bb7aedb 100644
--- a/include/asm-ia64/irq.h
+++ b/include/asm-ia64/irq.h
@@ -8,113 +8,24 @@
*
* 11/24/98 S.Eranian updated TIMER_IRQ and irq_cannonicalize
* 01/20/99 S.Eranian added keyboard interrupt
+ * 02/29/00 D.Mosberger moved most things into hw_irq.h
*/
-#include <linux/config.h>
-#include <linux/spinlock.h>
-
-#include <asm/ptrace.h>
-
#define NR_IRQS 256
-#define NR_ISA_IRQS 16
-
-/*
- * 0 special
- *
- * 1,3-14 are reserved from firmware
- *
- * 16-255 (vectored external interrupts) are available
- *
- * 15 spurious interrupt (see IVR)
- *
- * 16 lowest priority, 255 highest priority
- *
- * 15 classes of 16 interrupts each.
- */
-#define IA64_MIN_VECTORED_IRQ 16
-#define IA64_MAX_VECTORED_IRQ 255
-
-#define IA64_SPURIOUS_INT 0x0f
-#define PERFMON_IRQ 0x28 /* performanc monitor interrupt vector */
-#define TIMER_IRQ 0xef /* use highest-prio group 15 interrupt for timer */
-#define IPI_IRQ 0xfe /* inter-processor interrupt vector */
-#define CMC_IRQ 0xff /* correctable machine-check interrupt vector */
-
-#define IA64_MIN_VECTORED_IRQ 16
-#define IA64_MAX_VECTORED_IRQ 255
-
-extern __u8 irq_to_vector_map[IA64_MIN_VECTORED_IRQ];
-#define map_legacy_irq(x) (((x) < IA64_MIN_VECTORED_IRQ) ? irq_to_vector_map[(x)] : (x))
-
-#define IRQ_INPROGRESS (1 << 0) /* irq handler active */
-#define IRQ_ENABLED (1 << 1) /* irq enabled */
-#define IRQ_PENDING (1 << 2) /* irq pending */
-#define IRQ_REPLAY (1 << 3) /* irq has been replayed but not acked yet */
-#define IRQ_AUTODETECT (1 << 4) /* irq is being autodetected */
-#define IRQ_WAITING (1 << 5) /* used for autodetection: irq not yet seen yet */
-
-struct hw_interrupt_type {
- const char *typename;
- void (*init) (unsigned long addr);
- void (*startup) (unsigned int irq);
- void (*shutdown) (unsigned int irq);
- int (*handle) (unsigned int irq, struct pt_regs *regs);
- void (*enable) (unsigned int irq);
- void (*disable) (unsigned int irq);
-};
-
-extern struct hw_interrupt_type irq_type_default; /* dummy interrupt controller */
-extern struct hw_interrupt_type irq_type_ia64_internal; /* CPU-internal interrupt controller */
-
-struct irq_desc {
- unsigned int type; /* type of interrupt (level vs. edge triggered) */
- unsigned int status; /* see above */
- unsigned int depth; /* disable depth for nested irq disables */
- struct hw_interrupt_type *handler;
- struct irqaction *action; /* irq action list */
-};
-
-extern struct irq_desc irq_desc[NR_IRQS];
-
-extern spinlock_t irq_controller_lock;
-
-/* IA64 inter-cpu interrupt related definitions */
-
-/* Delivery modes for inter-cpu interrupts */
-enum {
- IA64_IPI_DM_INT = 0x0, /* pend an external interrupt */
- IA64_IPI_DM_PMI = 0x2, /* pend a PMI */
- IA64_IPI_DM_NMI = 0x4, /* pend an NMI (vector 2) */
- IA64_IPI_DM_INIT = 0x5, /* pend an INIT interrupt */
- IA64_IPI_DM_EXTINT = 0x7, /* pend an 8259-compatible interrupt. */
-};
-
-#define IA64_BUS_ID(cpu) (cpu >> 8)
-#define IA64_LOCAL_ID(cpu) (cpu & 0xff)
static __inline__ int
irq_cannonicalize (int irq)
{
/*
* We do the legacy thing here of pretending that irqs < 16
- * are 8259 irqs.
+ * are 8259 irqs. This really shouldn't be necessary at all,
+ * but we keep it here as serial.c still uses it...
*/
return ((irq == 2) ? 9 : irq);
}
-extern int invoke_irq_handlers (unsigned int irq, struct pt_regs *regs, struct irqaction *action);
extern void disable_irq (unsigned int);
extern void disable_irq_nosync (unsigned int);
extern void enable_irq (unsigned int);
-extern void ipi_send (int cpu, int vector, int delivery_mode);
-
-#ifdef CONFIG_SMP
- extern void irq_enter(int cpu, int irq);
- extern void irq_exit(int cpu, int irq);
- extern void handle_IPI(int irq, void *dev_id, struct pt_regs *regs);
-#else
-# define irq_enter(cpu, irq) (++local_irq_count[cpu])
-# define irq_exit(cpu, irq) (--local_irq_count[cpu])
-#endif
#endif /* _ASM_IA64_IRQ_H */
diff --git a/include/asm-ia64/keyboard.h b/include/asm-ia64/keyboard.h
index c77324377..38dbbc7bb 100644
--- a/include/asm-ia64/keyboard.h
+++ b/include/asm-ia64/keyboard.h
@@ -13,7 +13,7 @@
#include <linux/config.h>
-#define KEYBOARD_IRQ 1
+#define KEYBOARD_IRQ isa_irq_to_vector(1)
#define DISABLE_KBD_DURING_INTERRUPTS 0
extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
@@ -59,7 +59,7 @@ extern unsigned char pckbd_sysrq_xlate[128];
* Machine specific bits for the PS/2 driver
*/
-#define AUX_IRQ 12
+#define AUX_IRQ isa_irq_to_vector(12)
#define aux_request_irq(hand, dev_id) \
request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index 4b369dc4c..890224329 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -23,7 +23,7 @@ struct timeval;
struct vm_area_struct;
typedef void ia64_mv_setup_t (char **);
-typedef void ia64_mv_irq_init_t (struct irq_desc *);
+typedef void ia64_mv_irq_init_t (void);
typedef void ia64_mv_pci_fixup_t (void);
typedef unsigned long ia64_mv_map_nr_t (unsigned long);
typedef void ia64_mv_mca_init_t (void);
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index 1ebcba0f4..1289930fc 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -7,13 +7,14 @@
* This is based on version 2.4 of the manual "Enhanced Mode Processor
* Abstraction Layer".
*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
* Copyright (C) 1999 Srinivasa Prasad Thirumalachar <sprasad@sprasad.engr.sgi.com>
*
* 99/10/01 davidm Make sure we pass zero for reserved parameters.
+ * 00/03/07 davidm Updated pal_cache_flush() to be in sync with PAL v2.6.
*/
/*
@@ -105,8 +106,8 @@ typedef u64 pal_cache_type_t;
#define PAL_CACHE_TYPE_INSTRUCTION_DATA 3 /* Both Data & Instruction */
-#define PAL_CACHE_FLUSH_NO_INVALIDATE 0 /* Don't invalidate clean lines */
#define PAL_CACHE_FLUSH_INVALIDATE 1 /* Invalidate clean lines */
+#define PAL_CACHE_FLUSH_CHK_INTRS 2 /* check for interrupts/mc while flushing */
/* Processor cache line size in bytes */
typedef int pal_cache_line_size_t;
@@ -723,12 +724,16 @@ ia64_pal_bus_set_features (pal_bus_features_u_t feature_select)
return iprv.status;
}
-/* Flush the processor instruction or data caches */
+/*
+ * Flush the processor instruction or data caches. *PROGRESS must be
+ * initialized to zero before calling this for the first time..
+ */
extern inline s64
-ia64_pal_cache_flush (u64 cache_type, u64 invalidate, u64 plat_ack)
+ia64_pal_cache_flush (u64 cache_type, u64 invalidate, u64 *progress)
{
struct ia64_pal_retval iprv;
- PAL_CALL(iprv, PAL_CACHE_FLUSH, cache_type, invalidate, plat_ack);
+ PAL_CALL(iprv, PAL_CACHE_FLUSH, cache_type, invalidate, *progress);
+ *progress = iprv.v1;
return iprv.status;
}
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index a076bca9f..7c3fbdd95 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -343,6 +343,7 @@ extern void __handle_bad_pmd (pmd_t *pmd);
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern void paging_init (void);
/*
* IA-64 doesn't have any external MMU info: the page tables contain
diff --git a/include/asm-ia64/ptrace_offsets.h b/include/asm-ia64/ptrace_offsets.h
index 5965e826d..46e8bccb1 100644
--- a/include/asm-ia64/ptrace_offsets.h
+++ b/include/asm-ia64/ptrace_offsets.h
@@ -167,9 +167,9 @@
#define PT_CR_IIP 0x0838
#define PT_CR_IFS 0x0840
#define PT_AR_UNAT 0x0848
-#define PT_AR_PFS 0x0858
+#define PT_AR_PFS 0x0850
#define PT_AR_RSC 0x0858
-#define PT_AR_RNAT 0x0868
+#define PT_AR_RNAT 0x0860
#define PT_AR_BSPSTORE 0x0868
#define PT_PR 0x0870
#define PT_B6 0x0878
diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h
index a6ea5c17d..0fd137267 100644
--- a/include/asm-ia64/smp.h
+++ b/include/asm-ia64/smp.h
@@ -9,12 +9,13 @@
#include <linux/config.h>
+#ifdef CONFIG_SMP
+
#include <linux/init.h>
#include <linux/threads.h>
#include <linux/kernel.h>
#include <asm/ptrace.h>
-#include <asm/spinlock.h>
#include <asm/io.h>
#define IPI_DEFAULT_BASE_ADDR 0xfee00000
@@ -99,4 +100,5 @@ hard_smp_processor_id(void)
extern void __init init_smp_config (void);
extern void smp_do_timer (struct pt_regs *regs);
+#endif /* CONFIG_SMP */
#endif /* _ASM_IA64_SMP_H */
diff --git a/include/asm-ia64/socket.h b/include/asm-ia64/socket.h
index 8c1f4d80a..69e4c8774 100644
--- a/include/asm-ia64/socket.h
+++ b/include/asm-ia64/socket.h
@@ -4,8 +4,8 @@
/*
* Socket related defines. This mostly mirrors the Linux/x86 version.
*
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2000 Hewlett-Packard Co
+ * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*/
#include <asm/sockios.h>
@@ -40,11 +40,13 @@
#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
#define SO_SECURITY_ENCRYPTION_NETWORK 24
-#define SO_BINDTODEVICE 25
+#define SO_BINDTODEVICE 25
/* Socket filtering */
-#define SO_ATTACH_FILTER 26
-#define SO_DETACH_FILTER 27
+#define SO_ATTACH_FILTER 26
+#define SO_DETACH_FILTER 27
+
+#define SO_PEERNAME 28
#define SO_PEERNAME 28
diff --git a/include/asm-ia64/softirq.h b/include/asm-ia64/softirq.h
index fb40999e2..b67776edb 100644
--- a/include/asm-ia64/softirq.h
+++ b/include/asm-ia64/softirq.h
@@ -7,14 +7,12 @@
*/
#include <asm/hardirq.h>
-extern unsigned int local_bh_count[NR_CPUS];
-
-#define cpu_bh_disable(cpu) do { local_bh_count[(cpu)]++; barrier(); } while (0)
-#define cpu_bh_enable(cpu) do { barrier(); local_bh_count[(cpu)]--; } while (0)
+#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
+#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
#define local_bh_disable() cpu_bh_disable(smp_processor_id())
#define local_bh_enable() cpu_bh_enable(smp_processor_id())
-#define in_softirq() (local_bh_count[smp_processor_id()] != 0)
+#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
#endif /* _ASM_IA64_SOFTIRQ_H */
diff --git a/include/asm-mips/ide.h b/include/asm-mips/ide.h
index 43f33e4a2..d66835618 100644
--- a/include/asm-mips/ide.h
+++ b/include/asm-mips/ide.h
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.5 1999/06/17 13:30:36 ralf Exp $
+/* $Id: ide.h,v 1.6 1999/10/09 00:01:42 ralf Exp $
*
* linux/include/asm-mips/ide.h
*
@@ -17,7 +17,11 @@
#include <linux/config.h>
#ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
+#define MAX_HWIFS 10
+# else
#define MAX_HWIFS 6
+# endif
#endif
#define ide__sti() __sti()
diff --git a/include/asm-mips64/dma.h b/include/asm-mips64/dma.h
index ef380f1d4..df2f47f6c 100644
--- a/include/asm-mips64/dma.h
+++ b/include/asm-mips64/dma.h
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.4 2000/01/29 01:42:28 ralf Exp $
+/* $Id: dma.h,v 1.5 2000/03/07 15:45:42 ralf Exp $
*
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
@@ -295,4 +295,12 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy (0)
+#endif
+
#endif /* _ASM_DMA_H */
diff --git a/include/asm-mips64/ide.h b/include/asm-mips64/ide.h
index 879f6c8a9..bb3a32200 100644
--- a/include/asm-mips64/ide.h
+++ b/include/asm-mips64/ide.h
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: ide.h,v 1.1 1999/08/21 22:19:17 ralf Exp $
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -14,8 +14,14 @@
#ifdef __KERNEL__
+#include <linux/config.h>
+
#ifndef MAX_HWIFS
+# ifdef CONFIG_BLK_DEV_IDEPCI
+#define MAX_HWIFS 10
+# else
#define MAX_HWIFS 6
+# endif
#endif
#define ide__sti() __sti()
@@ -64,7 +70,7 @@ ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
*/
static inline void ide_init_default_hwifs(void)
{
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
hw_regs_t hw;
int index;
@@ -73,7 +79,7 @@ static inline void ide_init_default_hwifs(void)
hw.irq = ide_default_irq(ide_default_io_base(index));
ide_register_hw(&hw, NULL);
}
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
}
typedef union {
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index 40deb121b..66eaedda5 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -83,3 +83,6 @@ extern unsigned char *get_property(struct device_node *node, const char *name,
extern void print_properties(struct device_node *node);
extern int call_rtas(const char *service, int nargs, int nret,
unsigned long *outputs, ...);
+extern void prom_drawstring(const char *c);
+extern void prom_drawhex(unsigned long v);
+extern void prom_drawchar(char c);
diff --git a/include/asm-sparc/ide.h b/include/asm-sparc/ide.h
index bec4233e6..3a4ac776a 100644
--- a/include/asm-sparc/ide.h
+++ b/include/asm-sparc/ide.h
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.2 2000/01/21 04:56:27 zaitcev Exp $
+/* $Id: ide.h,v 1.3 2000/03/10 04:46:47 davem Exp $
* ide.h: SPARC PCI specific IDE glue.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,7 @@
#ifdef __KERNEL__
+#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/hdreg.h>
@@ -59,7 +60,7 @@ static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
*/
static __inline__ void ide_init_default_hwifs(void)
{
-#ifdef __DO_I_NEED_THIS
+#ifndef CONFIG_BLK_DEV_IDEPCI
hw_regs_t hw;
int index;
@@ -68,7 +69,7 @@ static __inline__ void ide_init_default_hwifs(void)
hw.irq = ide_default_irq(ide_default_io_base(index));
ide_register_hw(&hw, NULL);
}
-#endif /* __DO_I_NEED_THIS */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
}
typedef union {
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index de78c266c..112145b0b 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.80 1999/12/16 12:58:31 anton Exp $ */
+/* $Id: system.h,v 1.81 2000/02/28 04:00:44 anton Exp $ */
#include <linux/config.h>
#ifndef __SPARC_SYSTEM_H
@@ -251,16 +251,10 @@ extern __inline__ unsigned long read_psr_and_cli(void)
#ifdef __SMP__
-/* This goes away after lockups have been found... */
-#ifndef DEBUG_IRQLOCK
-#define DEBUG_IRQLOCK
-#endif
-
extern unsigned char global_irq_holder;
#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
-#ifdef DEBUG_IRQLOCK
extern void __global_cli(void);
extern void __global_sti(void);
extern unsigned long __global_save_flags(void);
@@ -269,42 +263,6 @@ extern void __global_restore_flags(unsigned long flags);
#define sti() __global_sti()
#define save_flags(flags) ((flags)=__global_save_flags())
#define restore_flags(flags) __global_restore_flags(flags)
-#else
-
-#error For combined sun4[md] smp, we need to get rid of the rdtbr.
-
-/* Visit arch/sparc/lib/irqlock.S for all the fun details... */
-#define cli() __asm__ __volatile__("mov %%o7, %%g4\n\t" \
- "call ___f_global_cli\n\t" \
- " rd %%tbr, %%g7" : : \
- : "g1", "g2", "g3", "g4", "g5", "g7", \
- "memory", "cc")
-
-#define sti() \
-do { register unsigned long bits asm("g7"); \
- bits = 0; \
- __asm__ __volatile__("mov %%o7, %%g4\n\t" \
- "call ___f_global_sti\n\t" \
- " rd %%tbr, %%g2" \
- : /* no outputs */ \
- : "r" (bits) \
- : "g1", "g2", "g3", "g4", "g5", \
- "memory", "cc"); \
-} while(0)
-
-#define restore_flags(flags) \
-do { register unsigned long bits asm("g7"); \
- bits = flags; \
- __asm__ __volatile__("mov %%o7, %%g4\n\t" \
- "call ___f_global_restore_flags\n\t" \
- " andcc %%g7, 0x1, %%g0" \
- : "=&r" (bits) \
- : "0" (bits) \
- : "g1", "g2", "g3", "g4", "g5", \
- "memory", "cc"); \
-} while(0)
-
-#endif /* DEBUG_IRQLOCK */
#else
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
index 22281b176..d1141d105 100644
--- a/include/asm-sparc64/pbm.h
+++ b/include/asm-sparc64/pbm.h
@@ -1,4 +1,4 @@
-/* $Id: pbm.h,v 1.20 2000/02/18 13:50:55 davem Exp $
+/* $Id: pbm.h,v 1.21 2000/03/10 02:42:17 davem Exp $
* pbm.h: UltraSparc PCI controller software state.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -63,12 +63,21 @@ struct pci_iommu {
*/
unsigned long write_complete_reg;
+ /* The lowest used consistent mapping entry. Since
+ * we allocate consistent maps out of cluster 0 this
+ * is relative to the beginning of closter 0.
+ */
+ u32 lowest_consistent_map;
+
/* If PBM_NCLUSTERS is ever decreased to 4 or lower,
* or if largest supported page_table_sz * 8K goes above
* 2GB, you must increase the size of the type of
* these counters. You have been duly warned. -DaveM
*/
- u16 lowest_free[PBM_NCLUSTERS];
+ struct {
+ u16 next;
+ u16 flush;
+ } alloc_info[PBM_NCLUSTERS];
/* Here a PCI controller driver describes the areas of
* PCI memory space where DMA to/from physical memory
diff --git a/include/linux/adfs_fs.h b/include/linux/adfs_fs.h
index ae1e69173..c881f0fd6 100644
--- a/include/linux/adfs_fs.h
+++ b/include/linux/adfs_fs.h
@@ -61,6 +61,4 @@ extern inline int adfs_checkbblk(unsigned char *ptr)
#endif
-extern int init_adfs_fs (void);
-
#endif
diff --git a/include/linux/brlock.h b/include/linux/brlock.h
index f28ac1eb7..e68940b0f 100644
--- a/include/linux/brlock.h
+++ b/include/linux/brlock.h
@@ -45,7 +45,7 @@ enum brlock_indices {
#include <linux/cache.h>
#include <linux/spinlock.h>
-#if defined(__i386__)
+#if defined(__i386__) || defined(__ia64__)
#define __BRLOCK_USE_ATOMICS
#else
#undef __BRLOCK_USE_ATOMICS
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 3dcad3357..c5ef464b4 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -191,6 +191,11 @@ static __inline__ struct dentry * dget(struct dentry *dentry)
return dentry;
}
+static __inline__ int d_unhashed(struct dentry *dentry)
+{
+ return list_empty(&dentry->d_hash);
+}
+
extern void dput(struct dentry *);
#endif /* __KERNEL__ */
diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
index 2ba621bc2..cc23e2e0c 100644
--- a/include/linux/efs_fs.h
+++ b/include/linux/efs_fs.h
@@ -53,7 +53,7 @@ extern int init_module(void);
extern void cleanup_module(void);
extern struct super_block *efs_read_super(struct super_block *, void *, int);
extern void efs_put_super(struct super_block *);
-extern int efs_statfs(struct super_block *, struct statfs *, int);
+extern int efs_statfs(struct super_block *, struct statfs *);
extern void efs_read_inode(struct inode *);
extern efs_block_t efs_map_block(struct inode *, efs_block_t);
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 67c6fac14..85e8d092f 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -590,7 +590,7 @@ extern void ext2_put_super (struct super_block *);
extern void ext2_write_super (struct super_block *);
extern int ext2_remount (struct super_block *, int *, char *);
extern struct super_block * ext2_read_super (struct super_block *,void *,int);
-extern int ext2_statfs (struct super_block *, struct statfs *, int);
+extern int ext2_statfs (struct super_block *, struct statfs *);
/* truncate.c */
extern void ext2_truncate (struct inode *);
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 0b55b363b..43bf69f86 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -283,15 +283,19 @@ struct fb_ops {
int (*fb_rasterimg)(struct fb_info *info, int start);
};
+/* fb_info flags */
+#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
+#define FBINFO_FLAG_OPEN 2 /* Has this been open already ? */
+
struct fb_info {
char modename[40]; /* default video mode */
kdev_t node;
int flags;
- int open; /* Has this been open already ? */
-#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
+ int count; /* How many using the hardware */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
+ struct fb_cmap cmap; /* Current cmap */
struct fb_ops *fbops;
char *screen_base; /* Virtual address */
struct display *disp; /* initial display variable */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 45ec949e1..0d472ec6e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -20,6 +20,7 @@
#include <linux/stat.h>
#include <linux/cache.h>
#include <linux/stddef.h>
+#include <linux/string.h>
#include <asm/atomic.h>
#include <asm/bitops.h>
@@ -181,8 +182,6 @@ extern void inode_init(void);
extern void file_table_init(void);
extern void dcache_init(void);
-typedef char buffer_block[BLOCK_SIZE];
-
/* bh state bits */
#define BH_Uptodate 0 /* 1 if the buffer contains valid data */
#define BH_Dirty 1 /* 1 if the buffer is dirty */
@@ -384,6 +383,7 @@ struct inode {
unsigned long i_blocks;
unsigned long i_version;
struct semaphore i_sem;
+ struct semaphore i_zombie;
struct inode_operations *i_op;
struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
@@ -704,7 +704,7 @@ struct super_operations {
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
void (*write_super) (struct super_block *);
- int (*statfs) (struct super_block *, struct statfs *, int);
+ int (*statfs) (struct super_block *, struct statfs *);
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
@@ -724,12 +724,43 @@ struct file_system_type {
const char *name;
int fs_flags;
struct super_block *(*read_super) (struct super_block *, void *, int);
+ struct module *owner;
struct file_system_type * next;
};
+#ifdef MODULE
+#define DECLARE_FSTYPE(var,type,read,flags) \
+struct file_system_type var = { \
+ name: type, \
+ read_super: read, \
+ fs_flags: flags, \
+ owner: THIS_MODULE, \
+}
+#else
+#define DECLARE_FSTYPE(var,type,read,flags) \
+struct file_system_type var = { \
+ name: type, \
+ read_super: read, \
+ fs_flags: flags, \
+}
+#endif
+
+#define DECLARE_FSTYPE_DEV(var,type,read) \
+ DECLARE_FSTYPE(var,type,read,FS_REQUIRES_DEV)
+
extern int register_filesystem(struct file_system_type *);
extern int unregister_filesystem(struct file_system_type *);
+static inline int vfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ if (!sb)
+ return -ENODEV;
+ if (!sb->s_op || !sb->s_op->statfs)
+ return -ENOSYS;
+ memset(buf, 0xff, sizeof(struct statfs));
+ return sb->s_op->statfs(sb, buf);
+}
+
/* Return value for VFS lock functions - tells locks.c to lock conventionally
* REALLY kosha for root NFS and nfs_lock
*/
@@ -830,8 +861,6 @@ extern struct file_operations read_pipe_fops;
extern struct file_operations write_pipe_fops;
extern struct file_operations rdwr_pipe_fops;
-extern struct file_system_type *get_fs_type(const char *);
-
extern int fs_may_remount_ro(struct super_block *);
extern int fs_may_mount(kdev_t);
@@ -907,6 +936,7 @@ extern void put_write_access(struct inode *);
extern struct dentry * open_namei(const char *, int, int);
extern struct dentry * do_mknod(const char *, int, dev_t);
extern int do_pipe(int *);
+extern int do_unlink(const char * name);
/* fs/dcache.c -- generic fs support functions */
extern int is_subdir(struct dentry *, struct dentry *);
@@ -1085,7 +1115,7 @@ extern void inode_setattr(struct inode *, struct iattr *);
* other process will be too late..
*/
#define check_parent(dir, dentry) \
- ((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash))
+ ((dir) == (dentry)->d_parent && !d_unhashed(dentry))
/*
* Locking the parent is needed to:
@@ -1122,11 +1152,8 @@ static inline void unlock_dir(struct dentry *dir)
* Whee.. Deadlock country. Happily there are only two VFS
* operations that does this..
*/
-static inline void double_lock(struct dentry *d1, struct dentry *d2)
+static inline void double_down(struct semaphore *s1, struct semaphore *s2)
{
- struct semaphore *s1 = &d1->d_inode->i_sem;
- struct semaphore *s2 = &d2->d_inode->i_sem;
-
if (s1 != s2) {
if ((unsigned long) s1 < (unsigned long) s2) {
struct semaphore *tmp = s2;
@@ -1137,19 +1164,76 @@ static inline void double_lock(struct dentry *d1, struct dentry *d2)
down(s2);
}
-static inline void double_unlock(struct dentry *d1, struct dentry *d2)
+/*
+ * Ewwwwwwww... _triple_ lock. We are guaranteed that the 3rd argument is
+ * not equal to 1st and not equal to 2nd - the first case (target is parent of
+ * source) would be already caught, the second is plain impossible (target is
+ * its own parent and that case would be caught even earlier). Very messy.
+ * I _think_ that it works, but no warranties - please, look it through.
+ * Pox on bloody lusers who mandated overwriting rename() for directories...
+ */
+
+static inline void triple_down(struct semaphore *s1,
+ struct semaphore *s2,
+ struct semaphore *s3)
+{
+ if (s1 != s2) {
+ if ((unsigned long) s1 < (unsigned long) s2) {
+ if ((unsigned long) s1 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s1; s1 = tmp;
+ }
+ if ((unsigned long) s1 < (unsigned long) s2) {
+ struct semaphore *tmp = s2;
+ s2 = s1; s1 = tmp;
+ }
+ } else {
+ if ((unsigned long) s1 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s1; s1 = tmp;
+ }
+ if ((unsigned long) s2 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s2; s2 = tmp;
+ }
+ }
+ down(s1);
+ } else if ((unsigned long) s2 < (unsigned long) s3) {
+ struct semaphore *tmp = s3;
+ s3 = s2; s2 = tmp;
+ }
+ down(s2);
+ down(s3);
+}
+
+static inline void double_up(struct semaphore *s1, struct semaphore *s2)
{
- struct semaphore *s1 = &d1->d_inode->i_sem;
- struct semaphore *s2 = &d2->d_inode->i_sem;
+ up(s1);
+ if (s1 != s2)
+ up(s2);
+}
+static inline void triple_up(struct semaphore *s1,
+ struct semaphore *s2,
+ struct semaphore *s3)
+{
up(s1);
if (s1 != s2)
up(s2);
- dput(d1);
- dput(d2);
+ up(s3);
}
+static inline void double_lock(struct dentry *d1, struct dentry *d2)
+{
+ double_down(&d1->d_inode->i_sem, &d2->d_inode->i_sem);
+}
+static inline void double_unlock(struct dentry *d1, struct dentry *d2)
+{
+ double_up(&d1->d_inode->i_sem,&d2->d_inode->i_sem);
+ dput(d1);
+ dput(d2);
+}
#endif /* __KERNEL__ */
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 64136c732..248c37b39 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -414,6 +414,7 @@ typedef struct hwif_s {
#if (DISK_RECOVERY_TIME > 0)
unsigned long last_time; /* time when previous rq was done */
#endif
+ byte straight8; /* Alan's straight 8 check */
} ide_hwif_t;
/*
diff --git a/include/linux/if_ec.h b/include/linux/if_ec.h
index 4883f16a7..8de2f6b69 100644
--- a/include/linux/if_ec.h
+++ b/include/linux/if_ec.h
@@ -34,6 +34,19 @@ struct sockaddr_ec
#ifdef __KERNEL__
+#define EC_HLEN 6
+
+/* This is what an Econet frame looks like on the wire. */
+struct ec_framehdr
+{
+ unsigned char dst_stn;
+ unsigned char dst_net;
+ unsigned char src_stn;
+ unsigned char src_net;
+ unsigned char cb;
+ unsigned char port;
+};
+
struct econet_opt
{
unsigned char cb;
@@ -42,6 +55,14 @@ struct econet_opt
unsigned char net;
};
+struct ec_device
+{
+ unsigned char station, net; /* Econet protocol address */
+};
+
+extern struct sock *ec_listening_socket(unsigned char port, unsigned char
+ station, unsigned char net);
+
#endif
#endif
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 8e33913d3..96974638a 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -5,8 +5,10 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/cache.h>
+
#include <asm/bitops.h>
#include <asm/atomic.h>
+#include <asm/ptrace.h>
struct irqaction {
void (*handler)(int, void *, struct pt_regs *);
diff --git a/include/linux/iobuf.h b/include/linux/iobuf.h
index 420285faf..3de43c924 100644
--- a/include/linux/iobuf.h
+++ b/include/linux/iobuf.h
@@ -29,6 +29,8 @@
#define KIO_STATIC_PAGES (KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1)
#define KIO_MAX_SECTORS (KIO_MAX_ATOMIC_IO * 2)
+/* The main kiobuf struct used for all our IO! */
+
struct kiobuf
{
int nr_pages; /* Pages actually referenced */
@@ -46,7 +48,6 @@ struct kiobuf
unsigned int locked : 1; /* If set, pages has been locked */
/* Always embed enough struct pages for 64k of IO */
- unsigned long page_array[KIO_STATIC_PAGES];
struct page * map_array[KIO_STATIC_PAGES];
/* Dynamic state for IO completion: */
@@ -61,10 +62,14 @@ struct kiobuf
int map_user_kiobuf(int rw, struct kiobuf *, unsigned long va, size_t len);
void unmap_kiobuf(struct kiobuf *iobuf);
+int lock_kiovec(int nr, struct kiobuf *iovec[], int wait);
+int unlock_kiovec(int nr, struct kiobuf *iovec[]);
/* fs/iobuf.c */
-void __init kiobuf_init(void);
+void __init kiobuf_setup(void);
+void kiobuf_init(struct kiobuf *);
+void end_kio_request(struct kiobuf *, int);
void simple_wakeup_kiobuf(struct kiobuf *);
int alloc_kiovec(int nr, struct kiobuf **);
void free_kiovec(int nr, struct kiobuf **);
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 7407d39db..69040207e 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -1,7 +1,12 @@
#ifndef __irq_h
#define __irq_h
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+
#include <asm/irq.h>
+#include <asm/ptrace.h>
+
/*
* IRQ line status.
*/
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 83abfcf92..f42566696 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -9,7 +9,7 @@
extern int request_module(const char * name);
extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
#else
-#define request_module(x) do {} while(0)
+static inline int request_module(const char * name) { return -ENOSYS; }
extern inline int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
{
return -EACCES;
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 4e0aebedb..40dd93194 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -13,7 +13,6 @@
/* Dummy declarations */
struct svc_rqst;
-struct knfs_fh;
struct svc_client; /* opaque type */
/*
@@ -24,7 +23,7 @@ struct nlmsvc_binding {
void (*exp_unlock)(void);
struct svc_client * (*exp_getclient)(struct sockaddr_in *);
u32 (*fopen)(struct svc_rqst *,
- struct knfs_fh *,
+ struct nfs_fh *,
struct file *);
void (*fclose)(struct file *);
void (*detach)(void);
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index cb2c148f1..d949bd649 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -75,13 +75,14 @@ struct nlm_rqst {
*/
struct nlm_file {
struct nlm_file * f_next; /* linked list */
- struct knfs_fh f_handle; /* NFS file handle */
+ struct nfs_fh f_handle; /* NFS file handle */
struct file f_file; /* VFS file pointer */
struct nlm_share * f_shares; /* DOS shares */
struct nlm_block * f_blocks; /* blocked locks */
unsigned int f_locks; /* guesstimate # of locks */
unsigned int f_count; /* reference count */
struct semaphore f_sema; /* avoid concurrent access */
+ int f_hash; /* hash of f_handle */
};
/*
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index f397306c4..72752441e 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -13,8 +13,15 @@
#include <linux/nfs.h>
#include <linux/sunrpc/xdr.h>
-extern u32 nlm_granted, nlm_lck_denied, nlm_lck_denied_nolocks,
- nlm_lck_blocked, nlm_lck_denied_grace_period;
+#define NLM_MAXSTRLEN 1024
+
+#define QUADLEN(len) (((len) + 3) >> 2)
+
+#define nlm_granted __constant_htonl(NLM_LCK_GRANTED)
+#define nlm_lck_denied __constant_htonl(NLM_LCK_DENIED)
+#define nlm_lck_denied_nolocks __constant_htonl(NLM_LCK_DENIED_NOLOCKS)
+#define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED)
+#define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
/* Lock info passed via NLM */
struct nlm_lock {
@@ -49,6 +56,8 @@ struct nlm_args {
u32 fsm_mode;
};
+typedef struct nlm_args nlm_args;
+
/*
* Generic lockd result
*/
diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h
index d9d7e3f75..cee36e7c0 100644
--- a/include/linux/lockd/xdr4.h
+++ b/include/linux/lockd/xdr4.h
@@ -15,7 +15,12 @@
#include <linux/lockd/xdr.h>
/* error codes new to NLMv4 */
-extern u32 nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig, nlm4_failed;
+#define nlm4_deadlock __constant_htonl(NLM_DEADLCK)
+#define nlm4_rofs __constant_htonl(NLM_ROFS)
+#define nlm4_stale_fh __constant_htonl(NLM_STALE_FH)
+#define nlm4_fbig __constant_htonl(NLM_FBIG)
+#define nlm4_failed __constant_htonl(NLM_FAILED)
+
int nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
diff --git a/include/linux/module.h b/include/linux/module.h
index 56d29ce62..915342edd 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -145,6 +145,8 @@ struct module_info
/* Find a symbol exported by the kernel or another module */
extern unsigned long get_module_symbol(char *, char *);
+extern int try_inc_mod_count(struct module *mod);
+
#if defined(MODULE) && !defined(__GENKSYMS__)
/* Embedded module documentation macros. */
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index de2ccffbd..ce7837f1d 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -247,7 +247,7 @@ extern struct inode *fat_iget(struct super_block*,int);
extern struct inode *fat_build_inode(struct super_block*,struct msdos_dir_entry*,int,int*);
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, int);
+extern int fat_statfs(struct super_block *sb,struct statfs *buf);
extern void fat_write_inode(struct inode *inode);
/* dir.c */
diff --git a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h
index 93053c6b6..de8913cd3 100644
--- a/include/linux/msdos_fs_sb.h
+++ b/include/linux/msdos_fs_sb.h
@@ -53,7 +53,6 @@ struct msdos_sb_info {
struct nls_table *nls_io; /* Charset used for input and display */
struct cvf_format* cvf_format;
void *dir_ops; /* Opaque; default directory operations */
- void (*put_super_callback)(struct super_block *);
void *private_data;
};
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index e5194b28f..cdd77e932 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -30,22 +30,35 @@ extern int requests_in;
extern int requests_out;
#endif
-static void
+static int
nbd_end_request(struct request *req)
{
unsigned long flags;
+ int ret = 0;
#ifdef PARANOIA
requests_out++;
#endif
+ /*
+ * This is a very dirty hack that we have to do to handle
+ * merged requests because end_request stuff is a bit
+ * broken. The fact we have to do this only if there
+ * aren't errors looks even more silly.
+ */
+ if (!req->errors) {
+ req->sector += req->current_nr_sectors;
+ req->nr_sectors -= req->current_nr_sectors;
+ }
+
spin_lock_irqsave(&io_request_lock, flags);
if (end_that_request_first( req, !req->errors, "nbd" ))
goto out;
+ ret = 1;
end_that_request_last( req );
out:
spin_unlock_irqrestore(&io_request_lock, flags);
- return;
+ return ret;
}
#define MAX_NBD 128
@@ -56,7 +69,6 @@ struct nbd_device {
int harderror; /* Code of hard error */
#define NBD_READ_ONLY 0x0001
#define NBD_WRITE_NOCHK 0x0002
-#define NBD_INITIALISED 0x0004
struct socket * sock;
struct file * file; /* If == NULL, device is not ready, yet */
int magic; /* FIXME: not if debugging is off */
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 0704c88e1..45f6dd0e0 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -89,7 +89,7 @@ struct svc_client * exp_getclient(struct sockaddr_in *sin);
void exp_putclient(struct svc_client *clp);
struct svc_export * exp_get(struct svc_client *clp, kdev_t dev, ino_t ino);
int exp_rootfh(struct svc_client *, kdev_t, ino_t,
- char *path, struct knfs_fh *);
+ char *path, struct knfsd_fh *, int maxsize);
int nfserrno(int errno);
void exp_nlmdetach(void);
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index d71a6923b..a2f4897fc 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -100,7 +100,7 @@ void nfsd_close(struct file *);
int nfsd_read(struct svc_rqst *, struct svc_fh *,
loff_t, char *, unsigned long *);
int nfsd_write(struct svc_rqst *, struct svc_fh *,
- loff_t, char *, unsigned long, int);
+ loff_t, char *, unsigned long, int *);
int nfsd_readlink(struct svc_rqst *, struct svc_fh *,
char *, int *);
int nfsd_symlink(struct svc_rqst *, struct svc_fh *,
@@ -129,8 +129,6 @@ int nfsd_commit(struct svc_rqst *, struct svc_fh *,
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
-/* nfsd/nfsctl.c */
-void nfsd_modcount(struct inode *, int);
/*
* lockd binding
@@ -140,43 +138,39 @@ void nfsd_lockd_shutdown(void);
void nfsd_lockd_unexport(struct svc_client *);
-#ifndef makedev
-#define makedev(maj, min) (((maj) << 8) | (min))
-#endif
-
/*
- * These variables contain pre-xdr'ed values for faster operation.
- * FIXME: should be replaced by macros for big-endian machines.
+ * These macros provide pre-xdr'ed values for faster operation.
*/
-extern u32 nfs_ok,
- nfserr_perm,
- nfserr_noent,
- nfserr_io,
- nfserr_nxio,
- nfserr_acces,
- nfserr_exist,
- nfserr_xdev,
- nfserr_nodev,
- nfserr_notdir,
- nfserr_isdir,
- nfserr_inval,
- nfserr_fbig,
- nfserr_nospc,
- nfserr_rofs,
- nfserr_mlink,
- nfserr_nametoolong,
- nfserr_notempty,
- nfserr_dquot,
- nfserr_stale,
- nfserr_remote,
- nfserr_badhandle,
- nfserr_notsync,
- nfserr_badcookie,
- nfserr_notsupp,
- nfserr_toosmall,
- nfserr_serverfault,
- nfserr_badtype,
- nfserr_jukebox;
+#define nfs_ok __constant_htonl(NFS_OK)
+#define nfserr_perm __constant_htonl(NFSERR_PERM)
+#define nfserr_noent __constant_htonl(NFSERR_NOENT)
+#define nfserr_io __constant_htonl(NFSERR_IO)
+#define nfserr_nxio __constant_htonl(NFSERR_NXIO)
+#define nfserr_acces __constant_htonl(NFSERR_ACCES)
+#define nfserr_exist __constant_htonl(NFSERR_EXIST)
+#define nfserr_xdev __constant_htonl(NFSERR_XDEV)
+#define nfserr_nodev __constant_htonl(NFSERR_NODEV)
+#define nfserr_notdir __constant_htonl(NFSERR_NOTDIR)
+#define nfserr_isdir __constant_htonl(NFSERR_ISDIR)
+#define nfserr_inval __constant_htonl(NFSERR_INVAL)
+#define nfserr_fbig __constant_htonl(NFSERR_FBIG)
+#define nfserr_nospc __constant_htonl(NFSERR_NOSPC)
+#define nfserr_rofs __constant_htonl(NFSERR_ROFS)
+#define nfserr_mlink __constant_htonl(NFSERR_MLINK)
+#define nfserr_opnotsupp __constant_htonl(NFSERR_OPNOTSUPP)
+#define nfserr_nametoolong __constant_htonl(NFSERR_NAMETOOLONG)
+#define nfserr_notempty __constant_htonl(NFSERR_NOTEMPTY)
+#define nfserr_dquot __constant_htonl(NFSERR_DQUOT)
+#define nfserr_stale __constant_htonl(NFSERR_STALE)
+#define nfserr_remote __constant_htonl(NFSERR_REMOTE)
+#define nfserr_badhandle __constant_htonl(NFSERR_BADHANDLE)
+#define nfserr_notsync __constant_htonl(NFSERR_NOTSYNC)
+#define nfserr_badcookie __constant_htonl(NFSERR_BADCOOKIE)
+#define nfserr_notsupp __constant_htonl(NFSERR_NOTSUPP)
+#define nfserr_toosmall __constant_htonl(NFSERR_TOOSMALL)
+#define nfserr_serverfault __constant_htonl(NFSERR_SERVERFAULT)
+#define nfserr_badtype __constant_htonl(NFSERR_BADTYPE)
+#define nfserr_jukebox __constant_htonl(NFSERR_JUKEBOX)
/*
* Time of server startup
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index 20e850ec5..83320b810 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -25,34 +25,95 @@
#include <linux/nfsd/debug.h>
/*
- * This is the new "dentry style" Linux NFSv2 file handle.
+ * This is the old "dentry style" Linux NFSv2 file handle.
*
* The xino and xdev fields are currently used to transport the
* ino/dev of the exported inode.
*/
-struct nfs_fhbase {
- struct dentry * fb_dentry; /* dentry cookie */
+struct nfs_fhbase_old {
+ struct dentry * fb_dentry; /* dentry cookie - always 0xfeebbaca */
__u32 fb_ino; /* our inode number */
- __u32 fb_dirino; /* dir inode number */
+ __u32 fb_dirino; /* dir inode number, 0 for directories */
__u32 fb_dev; /* our device */
__u32 fb_xdev;
__u32 fb_xino;
__u32 fb_generation;
};
-#define NFS_FH_PADDING (NFS_FHSIZE - sizeof(struct nfs_fhbase))
-struct knfs_fh {
- struct nfs_fhbase fh_base;
- __u8 fh_cookie[NFS_FH_PADDING];
+/*
+ * This is the new flexible, extensible style NFSv2/v3 file handle.
+ * by Neil Brown <neilb@cse.unsw.edu.au> - March 2000
+ *
+ * The file handle is seens as a list of 4byte words.
+ * The first word contains a version number (1) and four descriptor bytes
+ * that tell how the remaining 3 variable length fields should be handled.
+ * These three bytes are auth_type, fsid_type and fileid_type.
+ *
+ * All 4byte values are in host-byte-order.
+ *
+ * The auth_type field specifies how the filehandle can be authenticated
+ * This might allow a file to be confirmed to be in a writable part of a
+ * filetree without checking the path from it upto the root.
+ * Current values:
+ * 0 - No authentication. fb_auth is 0 bytes long
+ * Possible future values:
+ * 1 - 4 bytes taken from MD5 hash of the remainer of the file handle
+ * prefixed by a secret and with the important export flags.
+ *
+ * The fsid_type identifies how the filesystem (or export point) is
+ * encoded.
+ * Current values:
+ * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number
+ * NOTE: we cannot use the kdev_t device id value, because kdev_t.h
+ * says we mustn't. We must break it up and reassemble.
+ * Possible future encodings:
+ * 1 - 4 byte user specified identifier
+ *
+ * The fileid_type identified how the file within the filesystem is encoded.
+ * This is (will be) passed to, and set by, the underlying filesystem if it supports
+ * filehandle operations. The filesystem must not use the value '0' or '0xff' and may
+ * only use the values 1 and 2 as defined below:
+ * Current values:
+ * 0 - The root, or export point, of the filesystem. fb_fileid is 0 bytes.
+ * 1 - 32bit inode number, 32 bit generation number.
+ * 2 - 32bit inode number, 32 bit generation number, 32 bit parent directory inode number.
+ *
+ */
+struct nfs_fhbase_new {
+ __u8 fb_version; /* == 1, even => nfs_fhbase_old */
+ __u8 fb_auth_type;
+ __u8 fb_fsid_type;
+ __u8 fb_fileid_type;
+ __u32 fb_auth[1];
+/* __u32 fb_fsid[0]; floating */
+/* __u32 fb_fileid[0]; floating */
+};
+
+struct knfsd_fh {
+ int fh_size; /* significant for NFSv3.
+ * Points to the current size while building
+ * a new file handle
+ */
+ union {
+ struct nfs_fhbase_old fh_old;
+ __u32 fh_pad[NFS3_FHSIZE/4];
+ struct nfs_fhbase_new fh_new;
+ } fh_base;
};
-#define fh_dcookie fh_base.fb_dentry
-#define fh_ino fh_base.fb_ino
-#define fh_dirino fh_base.fb_dirino
-#define fh_dev fh_base.fb_dev
-#define fh_xdev fh_base.fb_xdev
-#define fh_xino fh_base.fb_xino
-#define fh_generation fh_base.fb_generation
+#define ofh_dcookie fh_base.fh_old.fb_dentry
+#define ofh_ino fh_base.fh_old.fb_ino
+#define ofh_dirino fh_base.fh_old.fb_dirino
+#define ofh_dev fh_base.fh_old.fb_dev
+#define ofh_xdev fh_base.fh_old.fb_xdev
+#define ofh_xino fh_base.fh_old.fb_xino
+#define ofh_generation fh_base.fh_old.fb_generation
+
+#define fh_version fh_base.fh_new.fb_version
+#define fh_fsid_type fh_base.fh_new.fb_fsid_type
+#define fh_auth_type fh_base.fh_new.fb_auth_type
+#define fh_fileid_type fh_base.fh_new.fb_fileid_type
+#define fh_auth fh_base.fh_new.fb_auth
#ifdef __KERNEL__
@@ -84,9 +145,10 @@ extern inline ino_t u32_to_ino_t(__u32 uino)
* pre_mtime/post_version will be used to support wcc_attr's in NFSv3.
*/
typedef struct svc_fh {
- struct knfs_fh fh_handle; /* FH data */
+ struct knfsd_fh fh_handle; /* FH data */
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
+ int fh_maxsize; /* max size for fh_handle */
#ifdef CONFIG_NFSD_V3
unsigned char fh_post_saved; /* post-op attrs saved */
unsigned char fh_pre_saved; /* pre-op attrs saved */
@@ -119,20 +181,28 @@ typedef struct svc_fh {
/*
* Shorthand for dprintk()'s
*/
-#define SVCFH_DENTRY(f) ((f)->fh_dentry)
-#define SVCFH_INO(f) ((f)->fh_handle.fh_ino)
-#define SVCFH_DEV(f) ((f)->fh_handle.fh_dev)
-
+inline static char * SVCFH_fmt(struct svc_fh *fhp)
+{
+ struct knfsd_fh *fh = &fhp->fh_handle;
+
+ static char buf[80];
+ sprintf(buf, "%d: %08x %08x %08x %08x %08x %08x",
+ fh->fh_size,
+ fh->fh_base.fh_pad[0],
+ fh->fh_base.fh_pad[1],
+ fh->fh_base.fh_pad[2],
+ fh->fh_base.fh_pad[3],
+ fh->fh_base.fh_pad[4],
+ fh->fh_base.fh_pad[5]);
+ return buf;
+}
/*
* Function prototypes
*/
u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
-void fh_compose(struct svc_fh *, struct svc_export *, struct dentry *);
-void fh_update(struct svc_fh *);
+int fh_compose(struct svc_fh *, struct svc_export *, struct dentry *);
+int fh_update(struct svc_fh *);
void fh_put(struct svc_fh *);
-void nfsd_fh_flush(kdev_t);
-void nfsd_fh_init(void);
-void nfsd_fh_free(void);
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
@@ -148,9 +218,10 @@ fh_copy(struct svc_fh *dst, struct svc_fh *src)
}
static __inline__ struct svc_fh *
-fh_init(struct svc_fh *fhp)
+fh_init(struct svc_fh *fhp, int maxsize)
{
memset(fhp, 0, sizeof(*fhp));
+ fhp->fh_maxsize = maxsize;
return fhp;
}
@@ -216,8 +287,8 @@ fh_lock(struct svc_fh *fhp)
struct dentry *dentry = fhp->fh_dentry;
struct inode *inode;
- dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n",
- SVCFH_DEV(fhp), (long)SVCFH_INO(fhp), fhp->fh_locked);
+ dfprintk(FILEOP, "nfsd: fh_lock(%s) locked = %d\n",
+ SVCFH_fmt(fhp), fhp->fh_locked);
if (!fhp->fh_dverified) {
printk(KERN_ERR "fh_lock: fh not verified!\n");
diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h
index 1d42ec550..af723ced8 100644
--- a/include/linux/nfsd/syscall.h
+++ b/include/linux/nfsd/syscall.h
@@ -37,6 +37,7 @@
#define NFSCTL_UGIDUPDATE 5 /* update a client's uid/gid map. */
#define NFSCTL_GETFH 6 /* get an fh by ino (used by mountd) */
#define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */
+#define NFSCTL_GETFS 8 /* get an fh by path with max FH len */
/* SVC */
struct nfsctl_svc {
@@ -91,6 +92,13 @@ struct nfsctl_fdparm {
int gd_version;
};
+/* GETFS - GET Filehandle with Size */
+struct nfsctl_fsparm {
+ struct sockaddr gd_addr;
+ char gd_path[NFS_MAXPATHLEN+1];
+ int gd_maxlen;
+};
+
/*
* This is the argument union.
*/
@@ -103,6 +111,9 @@ struct nfsctl_arg {
struct nfsctl_uidmap u_umap;
struct nfsctl_fhparm u_getfh;
struct nfsctl_fdparm u_getfd;
+#ifdef notyet
+ struct nfsctl_fsparm u_getfs;
+#endif
unsigned int u_debug;
} u;
#define ca_svc u.u_svc
@@ -111,12 +122,16 @@ struct nfsctl_arg {
#define ca_umap u.u_umap
#define ca_getfh u.u_getfh
#define ca_getfd u.u_getfd
+#define ca_getfs u.u_getfs
#define ca_authd u.u_authd
#define ca_debug u.u_debug
};
union nfsctl_res {
- struct knfs_fh cr_getfh;
+ __u8 cr_getfh[NFS_FHSIZE];
+#ifdef notyet
+ struct knfsd_fh cr_getfs;
+#endif
unsigned int cr_debug;
};
diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
index bc47b8bac..323c62b83 100644
--- a/include/linux/nfsd/xdr.h
+++ b/include/linux/nfsd/xdr.h
@@ -121,7 +121,6 @@ union nfsd_xdrstore {
#define NFSSVC_XDRSIZE sizeof(union nfsd_xdrstore)
-void nfsd_xdr_init(void);
int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index b7911143f..d9909e0cc 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -670,7 +670,9 @@
#define PCI_DEVICE_ID_TTI_HPT366 0x0004
#define PCI_VENDOR_ID_VIA 0x1106
+#define PCI_DEVICE_ID_VIA_8371_0 0x0391
#define PCI_DEVICE_ID_VIA_8501_0 0x0501
+#define PCI_DEVICE_ID_VIA_8601_0 0x0601
#define PCI_DEVICE_ID_VIA_82C505 0x0505
#define PCI_DEVICE_ID_VIA_82C561 0x0561
#define PCI_DEVICE_ID_VIA_82C586_1 0x0571
@@ -694,9 +696,12 @@
#define PCI_DEVICE_ID_VIA_82C686_5 0x3058
#define PCI_DEVICE_ID_VIA_82C686_6 0x3068
#define PCI_DEVICE_ID_VIA_86C100A 0x6100
+#define PCI_DEVICE_ID_VIA_8231 0x8231
+#define PCI_DEVICE_ID_VIA_8371_1 0x8391
#define PCI_DEVICE_ID_VIA_8501_1 0x8501
#define PCI_DEVICE_ID_VIA_82C597_1 0x8597
#define PCI_DEVICE_ID_VIA_82C598_1 0x8598
+#define PCI_DEVICE_ID_VIA_8601_1 0x8601
#define PCI_VENDOR_ID_SMC2 0x1113
#define PCI_DEVICE_ID_SMC2_1211TX 0x1211
@@ -1052,6 +1057,9 @@
#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
+#define PCI_VENDOR_ID_AFAVLAB 0x14db
+#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120
+
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_DEVICE_ID_SYMPHONY_101 0x0001
diff --git a/include/linux/shm.h b/include/linux/shm.h
index e8b7d1f7c..c1ab5240b 100644
--- a/include/linux/shm.h
+++ b/include/linux/shm.h
@@ -10,7 +10,7 @@
*/
#define SHMMAX 0x2000000 /* max shared seg size (bytes) */
-#define SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */
+#define SHMMIN 0 /* min shared seg size (bytes) */
#define SHMMNI 128 /* max num of segs system wide */
#define SHMALL (SHMMAX/PAGE_SIZE*SHMMNI) /* max shm system wide (pages) */
#define SHMSEG SHMMNI /* max shared segs per process */
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 1d91cf216..eb51e575f 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -110,7 +110,8 @@ enum
KERN_SPARC_STOP_A=44, /* int: Sparc Stop-A enable */
KERN_SHMMNI=45, /* int: shm array identifiers */
KERN_OVERFLOWUID=46, /* int: overflow UID */
- KERN_OVERFLOWGID=47 /* int: overflow GID */
+ KERN_OVERFLOWGID=47, /* int: overflow GID */
+ KERN_SHMPATH=48, /* string: path to shm fs */
};
diff --git a/drivers/usb/usb.h b/include/linux/usb.h
index d1381c107..69f0189aa 100644
--- a/drivers/usb/usb.h
+++ b/include/linux/usb.h
@@ -364,17 +364,16 @@ struct usb_driver {
*/
typedef int (*usb_device_irq)(int, void *, int, void *);
-/* -------------------------------------------------------------------------------------*
- * New USB Structures *
- * -------------------------------------------------------------------------------------*/
+/* --------------------------------------------------------------------------*
+ * New USB Structures *
+ * --------------------------------------------------------------------------*/
+#define USB_DISABLE_SPD 1
+#define USB_ISO_ASAP 2
+#define USB_URB_EARLY_COMPLETE 4
+#define USB_ASYNC_UNLINK 8
-#define USB_DISABLE_SPD 1
-#define USB_ISO_ASAP 2
-#define USB_URB_EARLY_COMPLETE 4
-
-typedef struct
-{
+typedef struct {
unsigned int offset;
unsigned int length; // expected length
unsigned int actual_length;
@@ -386,9 +385,10 @@ typedef void (*usb_complete_t)(struct urb *);
typedef struct urb
{
+ spinlock_t lock; // lock for the URB
void *hcpriv; // private data for host controller
struct list_head urb_list; // list pointer to all active urbs
- struct urb* next; // pointer to next URB
+ struct urb *next; // pointer to next URB
struct usb_device *dev; // pointer to associated USB device
unsigned int pipe; // pipe information
int status; // returned status
@@ -396,7 +396,7 @@ typedef struct urb
void *transfer_buffer; // associated data buffer
int transfer_buffer_length; // data buffer length
int actual_length; // actual data buffer length
- unsigned char* setup_packet; // setup packet (control only)
+ unsigned char *setup_packet; // setup packet (control only)
//
int start_frame; // start frame (iso/irq only)
int number_of_packets; // number of packets in this request (iso/irq only)
@@ -411,6 +411,7 @@ typedef struct urb
#define FILL_CONTROL_URB(a,aa,b,c,d,e,f,g) \
do {\
+ spin_lock_init(&(a)->lock);\
(a)->dev=aa;\
(a)->pipe=b;\
(a)->setup_packet=c;\
@@ -422,6 +423,7 @@ typedef struct urb
#define FILL_BULK_URB(a,aa,b,c,d,e,f) \
do {\
+ spin_lock_init(&(a)->lock);\
(a)->dev=aa;\
(a)->pipe=b;\
(a)->transfer_buffer=c;\
@@ -432,6 +434,7 @@ typedef struct urb
#define FILL_INT_URB(a,aa,b,c,d,e,f,g) \
do {\
+ spin_lock_init(&(a)->lock);\
(a)->dev=aa;\
(a)->pipe=b;\
(a)->transfer_buffer=c;\
diff --git a/include/linux/videodev.h b/include/linux/videodev.h
index 5919a894e..682620995 100644
--- a/include/linux/videodev.h
+++ b/include/linux/videodev.h
@@ -286,7 +286,7 @@ struct video_code
#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */
#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */
#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */
-#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Set the video overlay window */
+#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */
#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */
#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */
diff --git a/include/net/dn_raw.h b/include/net/dn_raw.h
deleted file mode 100644
index 8232ddf4e..000000000
--- a/include/net/dn_raw.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _NET_DN_RAW_H
-#define _NET_DN_RAW_H
-
-#include <linux/config.h>
-
-#ifdef CONFIG_DECNET_RAW
-
-extern struct proto_ops dn_raw_proto_ops;
-
-extern void dn_raw_rx_nsp(struct sk_buff *skb);
-extern void dn_raw_rx_routing(struct sk_buff *skb);
-
-#ifdef CONFIG_DECNET_MOP
-extern void dn_raw_rx_mop(struct sk_buff *skb);
-#endif /* CONFIG_DECNET_MOP */
-
-#endif /* CONFIG_DECNET_RAW */
-
-#endif /* _NET_DN_RAW_H */
diff --git a/include/net/tcp.h b/include/net/tcp.h
index d2c937f96..569b8b6ea 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -339,12 +339,14 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
#if HZ == 20
# define TCP_TW_RECYCLE_TICK (5+2-TCP_TW_RECYCLE_SLOTS_LOG)
+#elif HZ == 64
+# define TCP_TW_RECYCLE_TICK (6+2-TCP_TW_RECYCLE_SLOTS_LOG)
#elif HZ == 100 || HZ == 128
# define TCP_TW_RECYCLE_TICK (7+2-TCP_TW_RECYCLE_SLOTS_LOG)
-#elif HZ == 1024
+#elif HZ == 1024 || HZ == 1000
# define TCP_TW_RECYCLE_TICK (10+2-TCP_TW_RECYCLE_SLOTS_LOG)
#else
-# error HZ != 20 && HZ != 100 && HZ != 1024.
+# error HZ != 20 && HZ != 64 && HZ != 100 && HZ != 1000 && HZ != 1024
#endif
/*
diff --git a/init/main.c b/init/main.c
index 458143ffb..01834b424 100644
--- a/init/main.c
+++ b/init/main.c
@@ -545,7 +545,7 @@ asmlinkage void __init start_kernel(void)
vma_init();
buffer_init(mempages);
page_cache_init(mempages);
- kiobuf_init();
+ kiobuf_setup();
signals_init();
bdev_init();
inode_init();
diff --git a/ipc/shm.c b/ipc/shm.c
index 6c6fc31d6..d614d3f2f 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -12,6 +12,16 @@
* avoid vmalloc and make shmmax, shmall, shmmni sysctl'able,
* Christoph Rohland <hans-christoph.rohland@sap.com>
* Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
+ * make it a file system, Christoph Rohland <hans-christoph.rohland@sap.com>
+ *
+ * The filesystem has the following restrictions/bugs:
+ * 1) It only can handle one directory.
+ * 2) Because the directory is represented by the SYSV shm array it
+ * can only be mounted one time.
+ * 3) This again leads to SYSV shm not working properly in a chrooted
+ * environment
+ * 4) Read and write are not implemented (should they?)
+ * 5) No special nodes are supported
*/
#include <linux/config.h>
@@ -20,6 +30,9 @@
#include <linux/swap.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/locks.h>
+#include <linux/file.h>
+#include <linux/mman.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
@@ -30,23 +43,61 @@
#include "util.h"
+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 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 *);
+static int shm_unlink (struct inode *,struct dentry *);
+static int shm_setattr (struct dentry *dent, struct iattr *attr);
+static void shm_delete (struct inode *);
+static int shm_mmap (struct file *, struct vm_area_struct *);
+static int shm_readdir (struct file *, void *, filldir_t);
+
+char shm_path[256] = "/var/shm";
+
+#define SHM_NAME_LEN NAME_MAX
+#define SHM_FMT ".IPC_%08x"
+#define SHM_FMT_LEN 13
+
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
size_t shm_segsz;
- time_t shm_atime;
- time_t shm_dtime;
- time_t shm_ctime;
- pid_t shm_cpid;
- pid_t shm_lpid;
unsigned long shm_nattch;
unsigned long shm_npages; /* size of segment (pages) */
- pte_t **shm_dir; /* ptr to array of ptrs to frames -> SHMMAX */
- struct vm_area_struct *attaches; /* descriptors for attaches */
- int id; /* backreference to id for shm_close */
- struct semaphore sem;
+ pte_t **shm_dir; /* ptr to arr of ptrs to frames */
+ int id;
+ union permap {
+ struct shmem {
+ time_t atime;
+ time_t dtime;
+ time_t ctime;
+ pid_t cpid;
+ pid_t lpid;
+ int nlen;
+ char nm[0];
+ } shmem;
+ struct zero {
+ struct semaphore sema;
+ struct list_head list;
+ } zero;
+ } permap;
};
+#define shm_atim permap.shmem.atime
+#define shm_dtim permap.shmem.dtime
+#define shm_ctim permap.shmem.ctime
+#define shm_cprid permap.shmem.cpid
+#define shm_lprid permap.shmem.lpid
+#define shm_namelen permap.shmem.nlen
+#define shm_name permap.shmem.nm
+#define zsem permap.zero.sema
+#define zero_list permap.zero.list
+
static struct ipc_ids shm_ids;
#define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id))
@@ -60,9 +111,8 @@ static struct ipc_ids shm_ids;
#define shm_buildid(id, seq) \
ipc_buildid(&shm_ids, id, seq)
-static int newseg (key_t key, int shmflg, size_t size);
-static int shm_map (struct vm_area_struct *shmd);
-static void killseg (int shmid);
+static int newseg (key_t key, const char *name, int namelen, int shmflg, size_t size);
+static void killseg_core(struct shmid_kernel *shp, int doacc);
static void shm_open (struct vm_area_struct *shmd);
static void shm_close (struct vm_area_struct *shmd);
static struct page * shm_nopage(struct vm_area_struct *, unsigned long, int);
@@ -75,12 +125,57 @@ static void zshm_swap (int prio, int gfp_mask, zone_t *zone);
static void zmap_unuse(swp_entry_t entry, struct page *page);
static void shmzero_open(struct vm_area_struct *shmd);
static void shmzero_close(struct vm_area_struct *shmd);
+static struct page *shmzero_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share);
static int zero_id;
static struct shmid_kernel zshmid_kernel;
+static struct dentry *zdent;
+
+#define SHM_FS_MAGIC 0x02011994
+
+static struct super_block * shm_sb;
+
+static DECLARE_FSTYPE(shm_fs_type, "shm", shm_read_super, 0);
+
+static struct super_operations shm_sops = {
+ read_inode: shm_read_inode,
+ write_inode: shm_write_inode,
+ delete_inode: shm_delete,
+ put_super: shm_put_super,
+ statfs: shm_statfs,
+ remount_fs: shm_remount_fs,
+};
+
+static struct file_operations shm_root_operations = {
+ readdir: shm_readdir,
+};
+
+static struct inode_operations shm_root_inode_operations = {
+ create: shm_create,
+ lookup: shm_lookup,
+ unlink: shm_unlink,
+};
+
+static struct file_operations shm_file_operations = {
+ mmap: shm_mmap,
+};
+
+static struct inode_operations shm_inode_operations = {
+ setattr: shm_setattr,
+};
+
+static struct vm_operations_struct shm_vm_ops = {
+ open: shm_open, /* callback for a new vm-area open */
+ close: shm_close, /* callback for when the vm-area is released */
+ nopage: shm_nopage,
+ swapout:shm_swapout,
+};
size_t shm_ctlmax = SHMMAX;
-int shm_ctlall = SHMALL;
-int shm_ctlmni = SHMMNI;
+
+/* These parameters should be part of the superblock */
+static int shm_ctlall;
+static int shm_ctlmni;
+static int shm_mode;
static int shm_tot = 0; /* total number of shared memory pages */
static int shm_rss = 0; /* number of shared memory pages that are in memory */
@@ -90,7 +185,7 @@ static int shm_swp = 0; /* number of shared memory pages that are in swap */
pagecache_lock
shm_lock()/shm_lockall()
kernel lock
- shp->sem
+ inode->i_sem
sem_ids.sem
mmap_sem
@@ -104,18 +199,318 @@ static int shm_swp = 0; /* number of shared memory pages that are in swap */
/* some statistics */
static ulong swap_attempts = 0;
static ulong swap_successes = 0;
+static ulong used_segs = 0;
void __init shm_init (void)
{
- ipc_init_ids(&shm_ids, shm_ctlmni);
+ ipc_init_ids(&shm_ids, 1);
+
+ register_filesystem (&shm_fs_type);
#ifdef CONFIG_PROC_FS
create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL);
#endif
- zero_id = ipc_addid(&shm_ids, &zshmid_kernel.shm_perm, shm_ctlmni);
+ zero_id = ipc_addid(&shm_ids, &zshmid_kernel.shm_perm, 1);
shm_unlock(zero_id);
+ INIT_LIST_HEAD(&zshmid_kernel.zero_list);
+ zdent = d_alloc_root(get_empty_inode());
return;
}
+static int shm_parse_options(char *options)
+{
+ int blocks = shm_ctlall;
+ int inodes = shm_ctlmni;
+ umode_t mode = shm_mode;
+ char *this_char, *value;
+
+ this_char = NULL;
+ if ( options )
+ this_char = strtok(options,",");
+ for ( ; this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"nr_blocks")) {
+ if (!value || !*value)
+ return 1;
+ blocks = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"nr_inodes")) {
+ if (!value || !*value)
+ return 1;
+ inodes = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"mode")) {
+ if (!value || !*value)
+ return 1;
+ mode = simple_strtoul(value,&value,8);
+ if (*value)
+ return 1;
+ }
+ else
+ return 1;
+ }
+ shm_ctlmni = inodes;
+ shm_ctlall = blocks;
+ shm_mode = mode;
+
+ return 0;
+}
+
+static struct super_block *shm_read_super(struct super_block *s,void *data,
+ int silent)
+{
+ struct inode * root_inode;
+
+ if (shm_sb) {
+ printk ("shm fs already mounted\n");
+ return NULL;
+ }
+
+ shm_ctlall = SHMALL;
+ shm_ctlmni = SHMMNI;
+ shm_mode = S_IRWXUGO | S_ISVTX;
+ if (shm_parse_options (data)) {
+ printk ("shm fs invalid option\n");
+ goto out_unlock;
+ }
+
+ s->s_blocksize = PAGE_SIZE;
+ s->s_blocksize_bits = PAGE_SHIFT;
+ s->s_magic = SHM_FS_MAGIC;
+ s->s_op = &shm_sops;
+ root_inode = iget (s, SEQ_MULTIPLIER);
+ if (!root_inode)
+ goto out_no_root;
+ root_inode->i_op = &shm_root_inode_operations;
+ root_inode->i_sb = s;
+ root_inode->i_nlink = 2;
+ root_inode->i_mode = S_IFDIR | shm_mode;
+ s->s_root = d_alloc_root(root_inode);
+ if (!s->s_root)
+ goto out_no_root;
+ s->u.generic_sbp = (void*) shm_sb;
+ shm_sb = s;
+ return s;
+
+out_no_root:
+ printk("proc_read_super: get root inode failed\n");
+ iput(root_inode);
+out_unlock:
+ return NULL;
+}
+
+static int shm_remount_fs (struct super_block *sb, int *flags, char *data)
+{
+ if (shm_parse_options (data))
+ return -EINVAL;
+ return 0;
+}
+
+static void shm_put_super(struct super_block *sb)
+{
+ struct super_block **p = &shm_sb;
+ int i;
+ struct shmid_kernel *shp;
+
+ while (*p != sb) {
+ if (!*p) /* should never happen */
+ return;
+ p = (struct super_block **)&(*p)->u.generic_sbp;
+ }
+ *p = (struct super_block *)(*p)->u.generic_sbp;
+ down(&shm_ids.sem);
+ for(i = 0; i <= shm_ids.max_id; i++) {
+ if (i == zero_id)
+ continue;
+ if (!(shp = shm_lock (i)))
+ continue;
+ if (shp->shm_nattch)
+ printk ("shm_nattch = %ld\n", shp->shm_nattch);
+ shp = shm_rmid(i);
+ shm_unlock(i);
+ killseg_core(shp, 1);
+ }
+ dput (sb->s_root);
+ up(&shm_ids.sem);
+}
+
+static int shm_statfs(struct super_block *sb, struct statfs *buf)
+{
+ buf->f_type = 0;
+ buf->f_bsize = PAGE_SIZE;
+ buf->f_blocks = shm_ctlall;
+ buf->f_bavail = buf->f_bfree = shm_ctlall - shm_tot;
+ buf->f_files = shm_ctlmni;
+ buf->f_ffree = shm_ctlmni - used_segs;
+ buf->f_namelen = SHM_NAME_LEN;
+ return 0;
+}
+
+static void shm_write_inode(struct inode * inode)
+{
+}
+
+static void shm_read_inode(struct inode * inode)
+{
+ int id;
+ struct shmid_kernel *shp;
+
+ id = inode->i_ino;
+ inode->i_op = NULL;
+ inode->i_mode = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+ if (id < SEQ_MULTIPLIER) {
+ if (!(shp = shm_lock (id)))
+ return;
+ inode->i_mode = shp->shm_perm.mode | S_IFREG;
+ inode->i_uid = shp->shm_perm.uid;
+ inode->i_gid = shp->shm_perm.gid;
+ inode->i_size = shp->shm_segsz;
+ shm_unlock (id);
+ inode->i_op = &shm_inode_operations;
+ inode->i_fop = &shm_file_operations;
+ return;
+ }
+ inode->i_op = &shm_root_inode_operations;
+ inode->i_fop = &shm_root_operations;
+ inode->i_sb = shm_sb;
+ inode->i_nlink = 2;
+ inode->i_mode = S_IFDIR | shm_mode;
+ inode->i_uid = inode->i_gid = 0;
+
+}
+
+static int shm_create (struct inode *dir, struct dentry *dent, int mode)
+{
+ int id, err;
+ struct inode * inode;
+
+ down(&shm_ids.sem);
+ err = id = newseg (IPC_PRIVATE, dent->d_name.name, dent->d_name.len, mode, 0);
+ if (err < 0)
+ goto out;
+
+ err = -ENOMEM;
+ inode = iget (shm_sb, id % SEQ_MULTIPLIER);
+ if (!inode)
+ goto out;
+
+ err = 0;
+ down (&inode->i_sem);
+ inode->i_mode = mode | S_IFREG;
+ inode->i_op = &shm_inode_operations;
+ d_instantiate(dent, inode);
+ up (&inode->i_sem);
+
+out:
+ up(&shm_ids.sem);
+ return err;
+}
+
+static int shm_readdir (struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct shmid_kernel *shp;
+ off_t nr;
+
+ nr = filp->f_pos;
+
+ switch(nr)
+ {
+ case 0:
+ if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ default:
+ down(&shm_ids.sem);
+ for (; nr-2 <= shm_ids.max_id; nr++ ) {
+ if (!(shp = shm_get (nr-2)))
+ continue;
+ if (shp->shm_perm.mode & SHM_DEST)
+ continue;
+ if (filldir(dirent, shp->shm_name, shp->shm_namelen, nr, nr) < 0 )
+ break;;
+ }
+ filp->f_pos = nr;
+ up(&shm_ids.sem);
+ break;
+ }
+
+ UPDATE_ATIME(inode);
+ return 0;
+}
+
+static struct dentry *shm_lookup (struct inode *dir, struct dentry *dent)
+{
+ int i, err = 0;
+ struct shmid_kernel* shp;
+ struct inode *inode = NULL;
+
+ if (dent->d_name.len > SHM_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ down(&shm_ids.sem);
+ for(i = 0; i <= shm_ids.max_id; i++) {
+ if (!(shp = shm_lock(i)))
+ continue;
+ if (!(shp->shm_perm.mode & SHM_DEST) &&
+ dent->d_name.len == shp->shm_namelen &&
+ strncmp(dent->d_name.name, shp->shm_name, shp->shm_namelen) == 0)
+ goto found;
+ shm_unlock(i);
+ }
+
+ /*
+ * prevent the reserved names as negative dentries.
+ * This also prevents object creation through the filesystem
+ */
+ if (dent->d_name.len == SHM_FMT_LEN &&
+ memcmp (SHM_FMT, dent->d_name.name, SHM_FMT_LEN - 8) == 0)
+ err = -EINVAL; /* EINVAL to give IPC_RMID the right error */
+
+ goto out;
+
+found:
+ shm_unlock(i);
+ inode = iget(dir->i_sb, i);
+
+ if (!inode)
+ err = -EACCES;
+out:
+ if (err == 0)
+ d_add (dent, inode);
+ up (&shm_ids.sem);
+ return ERR_PTR(err);
+}
+
+static int shm_unlink (struct inode *dir, struct dentry *dent)
+{
+ struct inode * inode = dent->d_inode;
+ struct shmid_kernel *shp;
+
+ down (&shm_ids.sem);
+ if (!(shp = shm_lock (inode->i_ino)))
+ BUG();
+ shp->shm_perm.mode |= SHM_DEST;
+ shp->shm_perm.key = IPC_PRIVATE; /* Do not find it any more */
+ shm_unlock (inode->i_ino);
+ up (&shm_ids.sem);
+ inode->i_nlink -= 1;
+ d_delete (dent);
+ return 0;
+}
+
#define SHM_ENTRY(shp, index) (shp)->shm_dir[(index)/PTRS_PER_PTE][(index)%PTRS_PER_PTE]
static pte_t **shm_alloc(unsigned long pages)
@@ -124,9 +519,12 @@ static pte_t **shm_alloc(unsigned long pages)
unsigned short last = pages % PTRS_PER_PTE;
pte_t **ret, **ptr;
+ if (pages == 0)
+ return NULL;
+
ret = kmalloc ((dir+1) * sizeof(pte_t *), GFP_KERNEL);
if (!ret)
- goto out;
+ goto nomem;
for (ptr = ret; ptr < ret+dir ; ptr++)
{
@@ -143,7 +541,6 @@ static pte_t **shm_alloc(unsigned long pages)
goto free;
memset (*ptr, 0, last*sizeof(pte_t));
}
-out:
return ret;
free:
@@ -152,48 +549,90 @@ free:
free_page ((unsigned long)*ptr);
kfree (ret);
- return NULL;
+nomem:
+ return ERR_PTR(-ENOMEM);
}
-
static void shm_free(pte_t** dir, unsigned long pages)
{
pte_t **ptr = dir+pages/PTRS_PER_PTE;
+ if (!dir)
+ return;
+
/* first the last page */
if (pages%PTRS_PER_PTE)
kfree (*ptr);
/* now the whole pages */
while (--ptr >= dir)
- free_page ((unsigned long)*ptr);
+ if (*ptr)
+ free_page ((unsigned long)*ptr);
/* Now the indirect block */
kfree (dir);
}
-static int shm_revalidate(struct shmid_kernel* shp, int shmid, int pagecount, int flg)
+static int shm_setattr (struct dentry *dentry, struct iattr *attr)
{
- struct shmid_kernel* new;
- new = shm_lock(shmid);
- if(new==NULL) {
- return -EIDRM;
- }
- if(new!=shp || shm_checkid(shp, shmid) || shp->shm_npages != pagecount) {
- shm_unlock(shmid);
- return -EIDRM;
- }
- if (ipcperms(&shp->shm_perm, flg)) {
- shm_unlock(shmid);
- return -EACCES;
+ int error;
+ struct inode *inode = dentry->d_inode;
+ struct shmid_kernel *shp;
+ unsigned long new_pages, old_pages;
+ pte_t **new_dir, **old_dir;
+
+ if ((error = inode_change_ok(inode, attr)))
+ return error;
+ if (!(attr->ia_valid & ATTR_SIZE))
+ goto set_attr;
+ if (attr->ia_size > shm_ctlmax)
+ return -EFBIG;
+
+ /* We set old_pages and old_dir for easier cleanup */
+ old_pages = new_pages = (attr->ia_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ if (shm_tot + new_pages >= shm_ctlall)
+ return -ENOSPC;
+ if (IS_ERR(old_dir = new_dir = shm_alloc(new_pages)))
+ return PTR_ERR(new_dir);
+
+ if (!(shp = shm_lock(inode->i_ino)))
+ BUG();
+ if (shp->shm_segsz == attr->ia_size)
+ goto out;
+ old_dir = shp->shm_dir;
+ old_pages = shp->shm_npages;
+ if (old_dir){
+ pte_t *swap;
+ int i,j;
+ i = old_pages < new_pages ? old_pages : new_pages;
+ j = i % PTRS_PER_PTE;
+ i /= PTRS_PER_PTE;
+ if (j)
+ memcpy (new_dir[i], old_dir[i], j * sizeof (pte_t));
+ while (i--) {
+ swap = new_dir[i];
+ new_dir[i] = old_dir[i];
+ old_dir[i] = swap;
+ }
}
+ shp->shm_dir = new_dir;
+ shp->shm_npages = new_pages;
+ shp->shm_segsz = attr->ia_size;
+out:
+ shm_unlock(inode->i_ino);
+ shm_lockall();
+ shm_tot += new_pages - old_pages;
+ shm_unlockall();
+ shm_free (old_dir, old_pages);
+set_attr:
+ inode_setattr(inode, attr);
return 0;
}
-static inline struct shmid_kernel *newseg_alloc(int numpages)
+static inline struct shmid_kernel *newseg_alloc(int numpages, size_t namelen)
{
struct shmid_kernel *shp;
- shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_KERNEL);
+ shp = (struct shmid_kernel *) kmalloc (sizeof (*shp) + namelen, GFP_KERNEL);
if (!shp)
return 0;
@@ -203,29 +642,29 @@ static inline struct shmid_kernel *newseg_alloc(int numpages)
return 0;
}
shp->shm_npages = numpages;
- shp->attaches = NULL;
shp->shm_nattch = 0;
- init_MUTEX(&shp->sem);
+ shp->shm_namelen = namelen;
return(shp);
}
-static int newseg (key_t key, int shmflg, size_t size)
+static int newseg (key_t key, const char *name, int namelen,
+ int shmflg, size_t size)
{
struct shmid_kernel *shp;
int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
int id;
- if (size < SHMMIN)
- return -EINVAL;
+ if (namelen > SHM_NAME_LEN)
+ return -ENAMETOOLONG;
if (size > shm_ctlmax)
return -EINVAL;
if (shm_tot + numpages >= shm_ctlall)
return -ENOSPC;
- if (!(shp = newseg_alloc(numpages)))
+ if (!(shp = newseg_alloc(numpages, namelen ? namelen : SHM_FMT_LEN + 1)))
return -ENOMEM;
- id = ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
+ id = ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni+1);
if(id == -1) {
shm_free(shp->shm_dir,numpages);
kfree(shp);
@@ -234,16 +673,23 @@ static int newseg (key_t key, int shmflg, size_t size)
shp->shm_perm.key = key;
shp->shm_perm.mode = (shmflg & S_IRWXUGO);
shp->shm_segsz = size;
- shp->shm_cpid = current->pid;
- shp->shm_lpid = 0;
- shp->shm_atime = shp->shm_dtime = 0;
- shp->shm_ctime = CURRENT_TIME;
+ shp->shm_cprid = current->pid;
+ shp->shm_lprid = 0;
+ shp->shm_atim = shp->shm_dtim = 0;
+ shp->shm_ctim = CURRENT_TIME;
shp->id = shm_buildid(id,shp->shm_perm.seq);
+ if (namelen != 0) {
+ shp->shm_namelen = namelen;
+ memcpy (shp->shm_name, name, namelen);
+ } else {
+ shp->shm_namelen = sprintf (shp->shm_name, SHM_FMT, shp->id);
+ }
shm_tot += numpages;
+ used_segs++;
shm_unlock(id);
-
- return shm_buildid(id,shp->shm_perm.seq);
+
+ return shp->id;
}
asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
@@ -251,21 +697,31 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
struct shmid_kernel *shp;
int err, id = 0;
+ if (!shm_sb) {
+ printk ("shmget: shm filesystem not mounted\n");
+ return -EINVAL;
+ }
+
+ if (size < SHMMIN)
+ return -EINVAL;
+
down(&shm_ids.sem);
if (key == IPC_PRIVATE) {
- err = newseg(key, shmflg, size);
+ err = newseg(key, NULL, 0, shmflg, size);
} else if ((id = ipc_findkey(&shm_ids,key)) == -1) {
if (!(shmflg & IPC_CREAT))
err = -ENOENT;
else
- err = newseg(key, shmflg, size);
+ err = newseg(key, NULL, 0, shmflg, size);
} else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
err = -EEXIST;
} else {
shp = shm_lock(id);
if(shp==NULL)
BUG();
- if (ipcperms(&shp->shm_perm, shmflg))
+ if (shp->shm_segsz < size)
+ err = -EINVAL;
+ else if (ipcperms(&shp->shm_perm, shmflg))
err = -EACCES;
else
err = shm_buildid(id, shp->shm_perm.seq);
@@ -300,40 +756,26 @@ static void killseg_core(struct shmid_kernel *shp, int doacc)
shm_rss -= rss;
shm_swp -= swp;
shm_tot -= numpages;
+ used_segs--;
shm_unlockall();
}
}
-/*
- * Only called after testing nattch and SHM_DEST.
- * Here pages, pgtable and shmid_kernel are freed.
- */
-static void killseg (int shmid)
+static void shm_delete (struct inode *ino)
{
+ int shmid = ino->i_ino;
struct shmid_kernel *shp;
down(&shm_ids.sem);
shp = shm_lock(shmid);
if(shp==NULL) {
-out_up:
- up(&shm_ids.sem);
- return;
- }
- if(shm_checkid(shp,shmid) || shp->shm_nattch > 0 ||
- !(shp->shm_perm.mode & SHM_DEST)) {
- shm_unlock(shmid);
- goto out_up;
+ BUG();
}
shp = shm_rmid(shmid);
- if(shp==NULL)
- BUG();
- if (!shp->shm_dir)
- BUG();
shm_unlock(shmid);
up(&shm_ids.sem);
killseg_core(shp, 1);
-
- return;
+ clear_inode(ino);
}
static inline unsigned long copy_shmid_to_user(void *buf, struct shmid64_ds *in, int version)
@@ -427,12 +869,29 @@ static inline unsigned long copy_shminfo_to_user(void *buf, struct shminfo64 *in
}
}
+char * shm_getname(int id)
+{
+ char *result;
+
+ result = __getname ();
+ if (IS_ERR(result))
+ return result;
+
+ sprintf (result, "%s/" SHM_FMT, shm_path, id);
+ return result;
+}
+
asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
{
struct shm_setbuf setbuf;
struct shmid_kernel *shp;
int err, version;
+ if (!shm_sb) {
+ printk ("shmctl: shm filesystem not mounted\n");
+ return -EINVAL;
+ }
+
if (cmd < 0 || shmid < 0)
return -EINVAL;
@@ -481,14 +940,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
{
struct shmid64_ds tbuf;
int result;
+ if ((shmid % SEQ_MULTIPLIER) == zero_id)
+ return -EINVAL;
memset(&tbuf, 0, sizeof(tbuf));
shp = shm_lock(shmid);
if(shp==NULL)
return -EINVAL;
- if (shp == &zshmid_kernel) {
- shm_unlock(shmid);
- return -EINVAL;
- }
if(cmd==SHM_STAT) {
err = -EINVAL;
if (shmid > shm_ids.max_id)
@@ -505,11 +962,11 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
goto out_unlock;
kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
tbuf.shm_segsz = shp->shm_segsz;
- tbuf.shm_atime = shp->shm_atime;
- tbuf.shm_dtime = shp->shm_dtime;
- tbuf.shm_ctime = shp->shm_ctime;
- tbuf.shm_cpid = shp->shm_cpid;
- tbuf.shm_lpid = shp->shm_lpid;
+ tbuf.shm_atime = shp->shm_atim;
+ tbuf.shm_dtime = shp->shm_dtim;
+ tbuf.shm_ctime = shp->shm_ctim;
+ tbuf.shm_cpid = shp->shm_cprid;
+ tbuf.shm_lpid = shp->shm_lprid;
tbuf.shm_nattch = shp->shm_nattch;
shm_unlock(shmid);
if(copy_shmid_to_user (buf, &tbuf, version))
@@ -523,16 +980,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
/* Should the pages be faulted in here or leave it to user? */
/* need to determine interaction with current->swappable */
struct kern_ipc_perm *ipcp;
+ if ((shmid % SEQ_MULTIPLIER)== zero_id)
+ return -EINVAL;
if (!capable(CAP_IPC_LOCK))
return -EPERM;
shp = shm_lock(shmid);
if(shp==NULL)
return -EINVAL;
- if (shp == &zshmid_kernel) {
- shm_unlock(shmid);
- return -EINVAL;
- }
err=-EIDRM;
if(shm_checkid(shp,shmid))
goto out_unlock;
@@ -552,50 +1007,56 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
return err;
}
case IPC_RMID:
- case IPC_SET:
- break;
- default:
- return -EINVAL;
+ {
+ char *name;
+ if ((shmid % SEQ_MULTIPLIER)== zero_id)
+ return -EINVAL;
+ name = shm_getname(shmid);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
+ lock_kernel();
+ err = do_unlink (name);
+ unlock_kernel();
+ putname (name);
+ if (err == -ENOENT)
+ err = -EINVAL;
+ return err;
}
- if (cmd == IPC_SET) {
+ case IPC_SET:
+ {
+ if ((shmid % SEQ_MULTIPLIER)== zero_id)
+ return -EINVAL;
+
if(copy_shmid_from_user (&setbuf, buf, version))
return -EFAULT;
- }
- down(&shm_ids.sem);
- shp = shm_lock(shmid);
- err=-EINVAL;
- if(shp==NULL)
- goto out_up;
- if (shp == &zshmid_kernel)
- goto out_unlock_up;
- err=-EIDRM;
- if(shm_checkid(shp,shmid))
- goto out_unlock_up;
- err=-EPERM;
- if (current->euid != shp->shm_perm.uid &&
- current->euid != shp->shm_perm.cuid &&
- !capable(CAP_SYS_ADMIN)) {
- goto out_unlock_up;
- }
+ down(&shm_ids.sem);
+ shp = shm_lock(shmid);
+ err=-EINVAL;
+ if(shp==NULL)
+ goto out_up;
+ err=-EIDRM;
+ if(shm_checkid(shp,shmid))
+ goto out_unlock_up;
+ err=-EPERM;
+ if (current->euid != shp->shm_perm.uid &&
+ current->euid != shp->shm_perm.cuid &&
+ !capable(CAP_SYS_ADMIN)) {
+ goto out_unlock_up;
+ }
- switch (cmd) {
- case IPC_SET:
shp->shm_perm.uid = setbuf.uid;
shp->shm_perm.gid = setbuf.gid;
shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
| (setbuf.mode & S_IRWXUGO);
- shp->shm_ctime = CURRENT_TIME;
+ shp->shm_ctim = CURRENT_TIME;
break;
- case IPC_RMID:
- shp->shm_perm.mode |= SHM_DEST;
- if (shp->shm_nattch <= 0) {
- shm_unlock(shmid);
- up(&shm_ids.sem);
- killseg (shmid);
- return 0;
- }
}
+
+ default:
+ return -EINVAL;
+ }
+
err = 0;
out_unlock_up:
shm_unlock(shmid);
@@ -607,65 +1068,24 @@ out_unlock:
return err;
}
-/*
- * The per process internal structure for managing segments is
- * `struct vm_area_struct'.
- * A shmat will add to and shmdt will remove from the list.
- * shmd->vm_mm the attacher
- * shmd->vm_start virt addr of attach, multiple of SHMLBA
- * shmd->vm_end multiple of SHMLBA
- * shmd->vm_next next attach for task
- * shmd->vm_next_share next attach for segment
- * shmd->vm_pgoff offset into segment (in pages)
- * shmd->vm_private_data signature for this attach
- */
-
-static struct vm_operations_struct shm_vm_ops = {
- open: shm_open, /* open - callback for a new vm-area open */
- close: shm_close, /* close - callback for when the vm-area is released */
- nopage: shm_nopage,
- swapout: shm_swapout,
-};
+static inline void shm_inc (int id) {
+ struct shmid_kernel *shp;
-/* Insert shmd into the list shp->attaches */
-static inline void insert_attach (struct shmid_kernel * shp, struct vm_area_struct * shmd)
-{
- if((shmd->vm_next_share = shp->attaches) != NULL)
- shp->attaches->vm_pprev_share = &shmd->vm_next_share;
- shp->attaches = shmd;
- shmd->vm_pprev_share = &shp->attaches;
+ if(!(shp = shm_lock(id)))
+ BUG();
+ shp->shm_atim = CURRENT_TIME;
+ shp->shm_lprid = current->pid;
+ shp->shm_nattch++;
+ shm_unlock(id);
}
-/* Remove shmd from list shp->attaches */
-static inline void remove_attach (struct shmid_kernel * shp, struct vm_area_struct * shmd)
+static int shm_mmap(struct file * file, struct vm_area_struct * vma)
{
- if(shmd->vm_next_share)
- shmd->vm_next_share->vm_pprev_share = shmd->vm_pprev_share;
- *shmd->vm_pprev_share = shmd->vm_next_share;
-}
-
-/*
- * ensure page tables exist
- * mark page table entries with shm_sgn.
- */
-static int shm_map (struct vm_area_struct *shmd)
-{
- unsigned long tmp;
-
- /* clear old mappings */
- do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
-
- /* add new mapping */
- tmp = shmd->vm_end - shmd->vm_start;
- if((current->mm->total_vm << PAGE_SHIFT) + tmp
- > (unsigned long) current->rlim[RLIMIT_AS].rlim_cur)
- return -ENOMEM;
- current->mm->total_vm += tmp >> PAGE_SHIFT;
- vmlist_modify_lock(current->mm);
- insert_vm_struct(current->mm, shmd);
- merge_segments(current->mm, shmd->vm_start, shmd->vm_end);
- vmlist_modify_unlock(current->mm);
-
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL; /* we cannot do private mappings */
+ UPDATE_ATIME(file->f_dentry->d_inode);
+ vma->vm_ops = &shm_vm_ops;
+ shm_inc(file->f_dentry->d_inode->i_ino);
return 0;
}
@@ -674,137 +1094,57 @@ static int shm_map (struct vm_area_struct *shmd)
*/
asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
{
- struct shmid_kernel *shp;
- struct vm_area_struct *shmd;
- int err;
unsigned long addr;
- unsigned long len;
- short flg = shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO;
+ struct file * file;
+ int err;
+ int flags;
+ char *name;
-
- if (shmid < 0)
+ if (!shm_sb || (shmid % SEQ_MULTIPLIER) == zero_id)
return -EINVAL;
- down(&current->mm->mmap_sem);
- err = -EINVAL;
- shp = shm_lock(shmid);
- if (!shp)
- goto out_up;
- if (shp == &zshmid_kernel)
- goto out_unlock_up;
-
- err = -EACCES;
- if (ipcperms(&shp->shm_perm, flg))
- goto out_unlock_up;
-
- err = -EIDRM;
- if (shm_checkid(shp,shmid))
- goto out_unlock_up;
-
- if (!(addr = (ulong) shmaddr)) {
- if (shmflg & SHM_REMAP)
- goto out_unlock_up;
- err = -ENOMEM;
- addr = 0;
- again:
- if (!(addr = get_unmapped_area(addr, (unsigned long)shp->shm_segsz)))
- goto out_unlock_up;
- if(addr & (SHMLBA - 1)) {
- addr = (addr + (SHMLBA - 1)) & ~(SHMLBA - 1);
- goto again;
+ if ((addr = (ulong)shmaddr))
+ {
+ if(addr & (SHMLBA-1)) {
+ if (shmflg & SHM_RND)
+ addr &= ~(SHMLBA-1); /* round down */
+ else
+ return -EINVAL;
}
- } else if (addr & (SHMLBA-1)) {
- err=-EINVAL;
- if (shmflg & SHM_RND)
- addr &= ~(SHMLBA-1); /* round down */
- else
- goto out_unlock_up;
- }
- /*
- * Check if addr exceeds TASK_SIZE (from do_mmap)
- */
- len = PAGE_SIZE*shp->shm_npages;
- err = -EINVAL;
- if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len)
- goto out_unlock_up;
- /*
- * If shm segment goes below stack, make sure there is some
- * space left for the stack to grow (presently 4 pages).
- */
- if (addr < current->mm->start_stack &&
- addr > current->mm->start_stack - PAGE_SIZE*(shp->shm_npages + 4))
- goto out_unlock_up;
- if (!(shmflg & SHM_REMAP) && find_vma_intersection(current->mm, addr, addr + (unsigned long)shp->shm_segsz))
- goto out_unlock_up;
+ flags = MAP_SHARED | MAP_FIXED;
+ } else
+ flags = MAP_SHARED;
- shm_unlock(shmid);
- err = -ENOMEM;
- shmd = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- err = shm_revalidate(shp, shmid, len/PAGE_SIZE,flg);
- if(err) {
- kmem_cache_free(vm_area_cachep, shmd);
- goto out_up;
- }
+ name = shm_getname(shmid);
+ if (IS_ERR (name))
+ return PTR_ERR (name);
- shmd->vm_private_data = shp;
- shmd->vm_start = addr;
- shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE;
- shmd->vm_mm = current->mm;
- shmd->vm_page_prot = (shmflg & SHM_RDONLY) ? PAGE_READONLY : PAGE_SHARED;
- shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED
- | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC
- | ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE);
- shmd->vm_file = NULL;
- shmd->vm_pgoff = 0;
- shmd->vm_ops = &shm_vm_ops;
-
- shp->shm_nattch++; /* prevent destruction */
- shm_unlock(shp->id);
- err = shm_map (shmd);
- shm_lock(shmid); /* cannot fail */
- if (err)
- goto failed_shm_map;
-
- insert_attach(shp,shmd); /* insert shmd into shp->attaches */
-
- shp->shm_lpid = current->pid;
- shp->shm_atime = CURRENT_TIME;
-
- *raddr = addr;
- err = 0;
-out_unlock_up:
- shm_unlock(shmid);
-out_up:
- up(&current->mm->mmap_sem);
+ file = filp_open (name, O_RDWR, 0);
+ putname (name);
+ if (IS_ERR (file))
+ goto bad_file;
+ lock_kernel();
+ *raddr = do_mmap (file, addr, file->f_dentry->d_inode->i_size,
+ (shmflg & SHM_RDONLY ? PROT_READ :
+ PROT_READ | PROT_WRITE), flags, 0);
+ unlock_kernel();
+ if (IS_ERR(*raddr))
+ err = PTR_ERR(*raddr);
+ else
+ err = 0;
+ fput (file);
return err;
-failed_shm_map:
- {
- int delete = 0;
- if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
- delete = 1;
- shm_unlock(shmid);
- up(&current->mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, shmd);
- if(delete)
- killseg(shmid);
- return err;
- }
+bad_file:
+ if ((err = PTR_ERR(file)) == -ENOENT)
+ return -EINVAL;
+ return err;
}
/* This is called by fork, once for every shm attach. */
static void shm_open (struct vm_area_struct *shmd)
{
- struct shmid_kernel *shp;
-
- shp = (struct shmid_kernel *) shmd->vm_private_data;
- if(shp != shm_lock(shp->id))
- BUG();
- insert_attach(shp,shmd); /* insert shmd into shp->attaches */
- shp->shm_nattch++;
- shp->shm_atime = CURRENT_TIME;
- shp->shm_lpid = current->pid;
- shm_unlock(shp->id);
+ shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino);
}
/*
@@ -815,22 +1155,16 @@ static void shm_open (struct vm_area_struct *shmd)
*/
static void shm_close (struct vm_area_struct *shmd)
{
+ int id = shmd->vm_file->f_dentry->d_inode->i_ino;
struct shmid_kernel *shp;
- int id;
/* remove from the list of attaches of the shm segment */
- shp = (struct shmid_kernel *) shmd->vm_private_data;
- if(shp != shm_lock(shp->id))
+ if(!(shp = shm_lock(id)))
BUG();
- remove_attach(shp,shmd); /* remove from shp->attaches */
- shp->shm_lpid = current->pid;
- shp->shm_dtime = CURRENT_TIME;
- id=-1;
- if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
- id=shp->id;
- shm_unlock(shp->id);
- if(id!=-1)
- killseg(id);
+ shp->shm_lprid = current->pid;
+ shp->shm_dtim = CURRENT_TIME;
+ shp->shm_nattch--;
+ shm_unlock(id);
}
/*
@@ -868,31 +1202,13 @@ static int shm_swapout(struct page * page, struct file *file)
/*
* page not present ... go through shm_dir
*/
-static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
+static struct page * shm_nopage_core(struct shmid_kernel *shp, unsigned int idx, int *swp, int *rss)
{
pte_t pte;
- struct shmid_kernel *shp;
- unsigned int idx;
struct page * page;
- int is_shmzero;
-
- shp = (struct shmid_kernel *) shmd->vm_private_data;
- idx = (address - shmd->vm_start) >> PAGE_SHIFT;
- idx += shmd->vm_pgoff;
- is_shmzero = (shp->id == zero_id);
- /*
- * A shared mapping past the last page of the file is an error
- * and results in a SIGBUS, so logically a shared mapping past
- * the end of a shared memory segment should result in SIGBUS
- * as well.
- */
- if (idx >= shp->shm_npages) {
- return NULL;
- }
- down(&shp->sem);
- if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
- BUG();
+ if (idx >= shp->shm_npages)
+ goto sigbus;
pte = SHM_ENTRY(shp,idx);
if (!pte_present(pte)) {
@@ -905,7 +1221,7 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
if (!page)
goto oom;
clear_highpage(page);
- if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
+ if ((shp != shm_lock(shp->id)) && (shp->id != zero_id))
BUG();
} else {
swp_entry_t entry = pte_to_swp_entry(pte);
@@ -923,11 +1239,11 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
delete_from_swap_cache(page);
page = replace_with_highmem(page);
swap_free(entry);
- if ((shp != shm_lock(shp->id)) && (is_shmzero == 0))
+ if ((shp != shm_lock(shp->id)) && (shp->id != zero_id))
BUG();
- if (is_shmzero == 0) shm_swp--;
+ (*swp)--;
}
- if (is_shmzero == 0) shm_rss++;
+ (*rss)++;
pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
SHM_ENTRY(shp, idx) = pte;
} else
@@ -935,14 +1251,32 @@ static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long addr
/* pte_val(pte) == SHM_ENTRY (shp, idx) */
get_page(pte_page(pte));
- shm_unlock(shp->id);
- up(&shp->sem);
current->min_flt++;
return pte_page(pte);
oom:
- up(&shp->sem);
return NOPAGE_OOM;
+sigbus:
+ return NOPAGE_SIGBUS;
+}
+
+static struct page * shm_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
+{
+ struct page * page;
+ struct shmid_kernel *shp;
+ unsigned int idx;
+ struct inode * inode = shmd->vm_file->f_dentry->d_inode;
+
+ idx = (address - shmd->vm_start) >> PAGE_SHIFT;
+ idx += shmd->vm_pgoff;
+
+ down(&inode->i_sem);
+ if(!(shp = shm_lock(inode->i_ino)))
+ BUG();
+ page = shm_nopage_core(shp, idx, &shm_swp, &shm_rss);
+ shm_unlock(inode->i_ino);
+ up(&inode->i_sem);
+ return(page);
}
#define OKAY 0
@@ -1127,38 +1461,40 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l
int i, len = 0;
down(&shm_ids.sem);
- len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n");
+ len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime name\n");
- for(i = 0; i <= shm_ids.max_id; i++) {
- struct shmid_kernel* shp = shm_lock(i);
- if (shp == &zshmid_kernel) {
- shm_unlock(i);
+ for(i = 0; i <= shm_ids.max_id; i++) {
+ struct shmid_kernel* shp;
+
+ if (i == zero_id)
continue;
- }
+ shp = shm_lock(i);
if(shp!=NULL) {
-#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
-#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
+#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu %.*s\n"
+#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu %.*s\n"
char *format;
if (sizeof(size_t) <= sizeof(int))
format = SMALL_STRING;
else
format = BIG_STRING;
- len += sprintf(buffer + len, format,
+ len += sprintf(buffer + len, format,
shp->shm_perm.key,
shm_buildid(i, shp->shm_perm.seq),
shp->shm_perm.mode,
shp->shm_segsz,
- shp->shm_cpid,
- shp->shm_lpid,
+ shp->shm_cprid,
+ shp->shm_lprid,
shp->shm_nattch,
shp->shm_perm.uid,
shp->shm_perm.gid,
shp->shm_perm.cuid,
shp->shm_perm.cgid,
- shp->shm_atime,
- shp->shm_dtime,
- shp->shm_ctime);
+ shp->shm_atim,
+ shp->shm_dtim,
+ shp->shm_ctim,
+ shp->shm_namelen,
+ shp->shm_name);
shm_unlock(i);
pos += len;
@@ -1183,31 +1519,84 @@ done:
}
#endif
-static struct shmid_kernel *zmap_list = 0;
+#define VMA_TO_SHP(vma) ((vma)->vm_file->private_data)
+
static spinlock_t zmap_list_lock = SPIN_LOCK_UNLOCKED;
static unsigned long zswap_idx = 0; /* next to swap */
-static struct shmid_kernel *zswap_shp = 0;
+static struct shmid_kernel *zswap_shp = &zshmid_kernel;
+static int zshm_rss;
static struct vm_operations_struct shmzero_vm_ops = {
open: shmzero_open,
close: shmzero_close,
- nopage: shm_nopage,
+ nopage: shmzero_nopage,
swapout: shm_swapout,
};
+/*
+ * In this implementation, the "unuse" and "swapout" interfaces are
+ * interlocked out via the kernel_lock, as well as shm_lock(zero_id).
+ * "unuse" and "nopage/swapin", as well as "swapout" and "nopage/swapin"
+ * interlock via shm_lock(zero_id). All these interlocks can be based
+ * on a per mapping lock instead of being a global lock.
+ */
+/*
+ * Reference (existance) counting on the file/dentry/inode is done
+ * by generic vm_file code. The zero code does not hold any reference
+ * on the pseudo-file. This is possible because the open/close calls
+ * are bracketed by the file count update calls.
+ */
+static struct file *file_setup(struct file *fzero, struct shmid_kernel *shp)
+{
+ struct file *filp;
+ struct inode *inp;
+
+ if ((filp = get_empty_filp()) == 0)
+ return(filp);
+ if ((inp = get_empty_inode()) == 0) {
+ put_filp(filp);
+ return(0);
+ }
+ if ((filp->f_dentry = d_alloc(zdent, &(const struct qstr) { "dev/zero",
+ 8, 0 })) == 0) {
+ iput(inp);
+ put_filp(filp);
+ return(0);
+ }
+ d_instantiate(filp->f_dentry, inp);
+
+ /*
+ * Copy over /dev/zero dev/ino for benefit of procfs. Use
+ * ino to indicate seperate mappings.
+ */
+ filp->f_dentry->d_inode->i_dev = fzero->f_dentry->d_inode->i_dev;
+ filp->f_dentry->d_inode->i_ino = (unsigned long)shp;
+ fput(fzero); /* release /dev/zero file */
+ return(filp);
+}
+
int map_zero_setup(struct vm_area_struct *vma)
{
+ extern int vm_enough_memory(long pages);
struct shmid_kernel *shp;
+ struct file *filp;
- if (!(shp = newseg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE)))
+ if (!vm_enough_memory((vma->vm_end - vma->vm_start) >> PAGE_SHIFT))
+ return -ENOMEM;
+ if (!(shp = newseg_alloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, 0)))
+ return -ENOMEM;
+ if ((filp = file_setup(vma->vm_file, shp)) == 0) {
+ killseg_core(shp, 0);
return -ENOMEM;
- shp->id = zero_id; /* hack for shm_lock et al */
- vma->vm_private_data = shp;
+ }
+ vma->vm_file = filp;
+ VMA_TO_SHP(vma) = (void *)shp;
+ shp->id = zero_id;
+ init_MUTEX(&shp->zsem);
vma->vm_ops = &shmzero_vm_ops;
shmzero_open(vma);
spin_lock(&zmap_list_lock);
- shp->attaches = (struct vm_area_struct *)zmap_list;
- zmap_list = shp;
+ list_add(&shp->zero_list, &zshmid_kernel.zero_list);
spin_unlock(&zmap_list_lock);
return 0;
}
@@ -1216,53 +1605,66 @@ static void shmzero_open(struct vm_area_struct *shmd)
{
struct shmid_kernel *shp;
- shp = (struct shmid_kernel *) shmd->vm_private_data;
- down(&shp->sem);
+ shp = VMA_TO_SHP(shmd);
+ down(&shp->zsem);
shp->shm_nattch++;
- up(&shp->sem);
+ up(&shp->zsem);
}
static void shmzero_close(struct vm_area_struct *shmd)
{
int done = 0;
- struct shmid_kernel *shp, *prev, *cur;
+ struct shmid_kernel *shp;
- shp = (struct shmid_kernel *) shmd->vm_private_data;
- down(&shp->sem);
+ shp = VMA_TO_SHP(shmd);
+ down(&shp->zsem);
if (--shp->shm_nattch == 0)
done = 1;
- up(&shp->sem);
+ up(&shp->zsem);
if (done) {
spin_lock(&zmap_list_lock);
if (shp == zswap_shp)
- zswap_shp = (struct shmid_kernel *)(shp->attaches);
- if (shp == zmap_list)
- zmap_list = (struct shmid_kernel *)(shp->attaches);
- else {
- prev = zmap_list;
- cur = (struct shmid_kernel *)(prev->attaches);
- while (cur != shp) {
- prev = cur;
- cur = (struct shmid_kernel *)(prev->attaches);
- }
- prev->attaches = (struct vm_area_struct *)(shp->attaches);
- }
+ zswap_shp = list_entry(zswap_shp->zero_list.next,
+ struct shmid_kernel, zero_list);
+ list_del(&shp->zero_list);
spin_unlock(&zmap_list_lock);
killseg_core(shp, 0);
}
}
+static struct page * shmzero_nopage(struct vm_area_struct * shmd, unsigned long address, int no_share)
+{
+ struct page *page;
+ struct shmid_kernel *shp;
+ unsigned int idx;
+ int dummy;
+
+ idx = (address - shmd->vm_start) >> PAGE_SHIFT;
+ idx += shmd->vm_pgoff;
+
+ shp = VMA_TO_SHP(shmd);
+ down(&shp->zsem);
+ shm_lock(zero_id);
+ page = shm_nopage_core(shp, idx, &dummy, &zshm_rss);
+ shm_unlock(zero_id);
+ up(&shp->zsem);
+ return(page);
+}
+
static void zmap_unuse(swp_entry_t entry, struct page *page)
{
struct shmid_kernel *shp;
spin_lock(&zmap_list_lock);
- shp = zmap_list;
- while (shp) {
+ shm_lock(zero_id);
+ for (shp = list_entry(zshmid_kernel.zero_list.next, struct shmid_kernel,
+ zero_list); shp != &zshmid_kernel;
+ shp = list_entry(shp->zero_list.next, struct shmid_kernel,
+ zero_list)) {
if (shm_unuse_core(shp, entry, page))
break;
- shp = (struct shmid_kernel *)shp->attaches;
}
+ shm_unlock(zero_id);
spin_unlock(&zmap_list_lock);
}
@@ -1275,7 +1677,7 @@ static void zshm_swap (int prio, int gfp_mask, zone_t *zone)
int counter;
struct page * page_map;
- counter = 10; /* maybe we should use zshm_rss */
+ counter = zshm_rss >> prio;
if (!counter)
return;
next:
@@ -1283,25 +1685,30 @@ next:
return;
spin_lock(&zmap_list_lock);
- if (zmap_list == 0)
+ shm_lock(zero_id);
+ if (zshmid_kernel.zero_list.next == 0)
goto failed;
next_id:
- if ((shp = zswap_shp) == 0) {
+ if (zswap_shp == &zshmid_kernel) {
if (loop) {
failed:
+ shm_unlock(zero_id);
spin_unlock(&zmap_list_lock);
__swap_free(swap_entry, 2);
return;
}
- zswap_shp = shp = zmap_list;
+ zswap_shp = list_entry(zshmid_kernel.zero_list.next,
+ struct shmid_kernel, zero_list);
zswap_idx = 0;
loop = 1;
}
+ shp = zswap_shp;
check_table:
idx = zswap_idx++;
if (idx >= shp->shm_npages) {
- zswap_shp = (struct shmid_kernel *)(zswap_shp->attaches);
+ zswap_shp = list_entry(zswap_shp->zero_list.next,
+ struct shmid_kernel, zero_list);
zswap_idx = 0;
goto next_id;
}
@@ -1310,6 +1717,7 @@ check_table:
case RETRY: goto check_table;
case FAILED: goto failed;
}
+ shm_unlock(zero_id);
spin_unlock(&zmap_list_lock);
shm_swap_postop(page_map);
@@ -1317,3 +1725,4 @@ check_table:
goto next;
return;
}
+
diff --git a/ipc/util.c b/ipc/util.c
index 1c929256a..580bef8af 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -40,9 +40,6 @@ void __init ipc_init_ids(struct ipc_ids* ids, int size)
if(size > IPCMNI)
size = IPCMNI;
ids->size = size;
- if(size == 0)
- return;
-
ids->in_use = 0;
ids->max_id = -1;
ids->seq = 0;
diff --git a/kernel/acct.c b/kernel/acct.c
index fdadf7a9f..63e66a558 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -88,24 +88,16 @@ void acct_timeout(unsigned long unused)
*/
static int check_free_space(struct file *file)
{
- mm_segment_t fs;
struct statfs sbuf;
- struct super_block *sb;
int res = acct_active;
int act;
if (!file || !acct_needcheck)
return res;
- sb = file->f_dentry->d_inode->i_sb;
- if (!sb->s_op || !sb->s_op->statfs)
- return res;
-
- fs = get_fs();
- set_fs(KERNEL_DS);
/* May block */
- sb->s_op->statfs(sb, &sbuf, sizeof(struct statfs));
- set_fs(fs);
+ if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf))
+ return res;
if (sbuf.f_bavail <= SUSPEND * sbuf.f_blocks / 100)
act = -1;
diff --git a/kernel/exit.c b/kernel/exit.c
index 9dd09f050..333981ab9 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -45,6 +45,18 @@ void release(struct task_struct * p)
current->cmin_flt += p->min_flt + p->cmin_flt;
current->cmaj_flt += p->maj_flt + p->cmaj_flt;
current->cnswap += p->nswap + p->cnswap;
+ /*
+ * Potentially available timeslices are retrieved
+ * here - this way the parent does not get penalized
+ * for creating too many processes.
+ *
+ * (this cannot be used to artificially 'generate'
+ * timeslices, because any timeslice recovered here
+ * was given away by the parent in the first place.)
+ */
+ current->counter += p->counter;
+ if (current->counter > current->priority)
+ current->counter = current->priority;
free_task_struct(p);
} else {
printk("task releasing itself\n");
diff --git a/kernel/fork.c b/kernel/fork.c
index 71989b3f7..f30adb908 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -713,8 +713,10 @@ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
* more scheduling fairness. This is only important in the first
* timeslice, on the long run the scheduling behaviour is unchanged.
*/
+ p->counter = (current->counter + 1) >> 1;
current->counter >>= 1;
- p->counter = current->counter;
+ if (!current->counter)
+ current->need_resched = 1;
/*
* Ok, add it to the run-queues and make it
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 45594e6af..78b40185d 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -131,7 +131,6 @@ EXPORT_SYMBOL(def_blk_fops);
EXPORT_SYMBOL(in_group_p);
EXPORT_SYMBOL(update_atime);
EXPORT_SYMBOL(get_super);
-EXPORT_SYMBOL(get_fs_type);
EXPORT_SYMBOL(get_empty_super);
EXPORT_SYMBOL(remove_vfsmnt);
EXPORT_SYMBOL(getname);
@@ -157,11 +156,6 @@ EXPORT_SYMBOL(d_path);
EXPORT_SYMBOL(mark_buffer_dirty);
EXPORT_SYMBOL(__mark_buffer_dirty);
EXPORT_SYMBOL(__mark_inode_dirty);
-EXPORT_SYMBOL(free_kiovec);
-EXPORT_SYMBOL(brw_kiovec);
-EXPORT_SYMBOL(alloc_kiovec);
-EXPORT_SYMBOL(expand_kiobuf);
-EXPORT_SYMBOL(unmap_kiobuf);
EXPORT_SYMBOL(get_empty_filp);
EXPORT_SYMBOL(init_private_file);
EXPORT_SYMBOL(filp_open);
@@ -358,6 +352,18 @@ EXPORT_SYMBOL(__br_write_lock);
EXPORT_SYMBOL(__br_write_unlock);
#endif
+/* Kiobufs */
+EXPORT_SYMBOL(kiobuf_init);
+
+EXPORT_SYMBOL(alloc_kiovec);
+EXPORT_SYMBOL(free_kiovec);
+EXPORT_SYMBOL(expand_kiobuf);
+
+EXPORT_SYMBOL(map_user_kiobuf);
+EXPORT_SYMBOL(lock_kiovec);
+EXPORT_SYMBOL(unlock_kiovec);
+EXPORT_SYMBOL(brw_kiovec);
+
/* autoirq from drivers/net/auto_irq.c */
EXPORT_SYMBOL(autoirq_setup);
EXPORT_SYMBOL(autoirq_report);
@@ -393,6 +399,7 @@ EXPORT_SYMBOL(schedule_timeout);
EXPORT_SYMBOL(jiffies);
EXPORT_SYMBOL(xtime);
EXPORT_SYMBOL(do_gettimeofday);
+EXPORT_SYMBOL(do_settimeofday);
#ifndef __ia64__
EXPORT_SYMBOL(loops_per_sec);
#endif
diff --git a/kernel/module.c b/kernel/module.c
index fb9d4ef8d..c36964022 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -350,6 +350,21 @@ err0:
return error;
}
+static spinlock_t unload_lock = SPIN_LOCK_UNLOCKED;
+int try_inc_mod_count(struct module *mod)
+{
+ int res = 1;
+ if (mod) {
+ spin_lock(&unload_lock);
+ if (mod->flags & MOD_DELETED)
+ res = 0;
+ else
+ __MOD_INC_USE_COUNT(mod);
+ spin_unlock(&unload_lock);
+ }
+ return res;
+}
+
asmlinkage long
sys_delete_module(const char *name_user)
{
@@ -377,11 +392,18 @@ sys_delete_module(const char *name_user)
}
put_mod_name(name);
error = -EBUSY;
- if (mod->refs != NULL || __MOD_IN_USE(mod))
+ if (mod->refs != NULL)
goto out;
- free_module(mod, 0);
- error = 0;
+ spin_lock(&unload_lock);
+ if (!__MOD_IN_USE(mod)) {
+ mod->flags |= MOD_DELETED;
+ spin_unlock(&unload_lock);
+ free_module(mod, 0);
+ error = 0;
+ } else {
+ spin_unlock(&unload_lock);
+ }
goto out;
}
@@ -390,6 +412,7 @@ restart:
something_changed = 0;
for (mod = module_list; mod != &kernel_module; mod = next) {
next = mod->next;
+ spin_lock(&unload_lock);
if (mod->refs == NULL
&& (mod->flags & MOD_AUTOCLEAN)
&& (mod->flags & MOD_RUNNING)
@@ -398,11 +421,16 @@ restart:
&& !__MOD_IN_USE(mod)) {
if ((mod->flags & MOD_VISITED)
&& !(mod->flags & MOD_JUST_FREED)) {
+ spin_unlock(&unload_lock);
mod->flags &= ~MOD_VISITED;
} else {
+ mod->flags |= MOD_DELETED;
+ spin_unlock(&unload_lock);
free_module(mod, 1);
something_changed = 1;
}
+ } else {
+ spin_unlock(&unload_lock);
}
}
if (something_changed)
@@ -775,7 +803,6 @@ free_module(struct module *mod, int tag_freed)
/* Let the module clean up. */
- mod->flags |= MOD_DELETED;
if (mod->flags & MOD_RUNNING)
{
if(mod->cleanup)
diff --git a/kernel/signal.c b/kernel/signal.c
index dca49b492..55017e2f6 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -40,6 +40,8 @@ void __init signals_init(void)
sizeof(struct signal_queue),
__alignof__(struct signal_queue),
SIG_SLAB_DEBUG, NULL, NULL);
+ if (!signal_queue_cachep)
+ panic("signals_init(): cannot create signal_queue SLAB cache");
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 550df4db9..1748d8afd 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -808,23 +808,39 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist)
return 0;
}
-int in_group_p(gid_t grp)
+static int supplemental_group_member(gid_t grp)
{
- if (grp != current->fsgid) {
- int i = current->ngroups;
- if (i) {
- gid_t *groups = current->groups;
- do {
- if (*groups == grp)
- goto out;
- groups++;
- i--;
- } while (i);
- }
- return 0;
+ int i = current->ngroups;
+
+ if (i) {
+ gid_t *groups = current->groups;
+ do {
+ if (*groups == grp)
+ return 1;
+ groups++;
+ i--;
+ } while (i);
}
-out:
- return 1;
+ return 0;
+}
+
+/*
+ * Check whether we're fsgid/egid or in the supplemental group..
+ */
+int in_group_p(gid_t grp)
+{
+ int retval = 1;
+ if (grp != current->fsgid)
+ retval = supplemental_group_member(grp);
+ return retval;
+}
+
+int in_egroup_p(gid_t grp)
+{
+ int retval = 1;
+ if (grp != current->egid)
+ retval = supplemental_group_member(grp);
+ return retval;
}
DECLARE_RWSEM(uts_sem);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index efcda3de4..0001a1473 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -57,8 +57,7 @@ extern int sg_big_buff;
#endif
#ifdef CONFIG_SYSVIPC
extern size_t shm_ctlmax;
-extern int shm_ctlall;
-extern int shm_ctlmni;
+extern char shm_path[];
extern int msg_ctlmax;
extern int msg_ctlmnb;
extern int msg_ctlmni;
@@ -200,12 +199,10 @@ static ctl_table kern_table[] = {
{KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
0644, NULL, &proc_dointvec},
#ifdef CONFIG_SYSVIPC
+ {KERN_SHMPATH, "shmpath", &shm_path, 256,
+ 0644, NULL, &proc_dostring, &sysctl_string },
{KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t),
0644, NULL, &proc_doulongvec_minmax},
- {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (int),
- 0644, NULL, &proc_dointvec},
- {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int),
- 0644, NULL, &proc_dointvec},
{KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int),
0644, NULL, &proc_dointvec},
{KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int),
@@ -351,25 +348,6 @@ extern asmlinkage long sys_sysctl(struct __sysctl_args *args)
return error;
}
-/* Like in_group_p, but testing against egid, not fsgid */
-int in_egroup_p(gid_t grp)
-{
- if (grp != current->egid) {
- int i = current->ngroups;
- if (i) {
- gid_t *groups = current->groups;
- do {
- if (*groups == grp)
- goto out;
- groups++;
- i--;
- } while (i);
- }
- return 0;
- }
-out:
- return 1;
-}
/* ctl_perm does NOT grant the superuser all rights automatically, because
some sysctl variables are readonly even to root. */
diff --git a/mm/filemap.c b/mm/filemap.c
index 6756c70a0..b5febc2e5 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -954,8 +954,7 @@ static void generic_file_readahead(int reada_ok,
*/
void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor)
{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = filp->f_dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
unsigned long index, offset;
struct page *cached_page;
@@ -1307,8 +1306,7 @@ struct page * filemap_nopage(struct vm_area_struct * area,
{
int error;
struct file *file = area->vm_file;
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file->f_dentry->d_inode;
struct address_space *mapping = inode->i_mapping;
struct page *page, **hash, *old_page;
unsigned long size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
diff --git a/mm/memory.c b/mm/memory.c
index 1232bd928..dbcdd0052 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -398,28 +398,25 @@ static struct page * follow_page(unsigned long address)
return pte_page(*pte);
}
- printk(KERN_ERR "Missing page in follow_page\n");
return NULL;
}
/*
- * Given a physical address, is there a useful struct page pointing to it?
+ * Given a physical address, is there a useful struct page pointing to
+ * it? This may become more complex in the future if we start dealing
+ * with IO-aperture pages in kiobufs.
*/
-struct page * get_page_map(struct page *page, unsigned long vaddr)
+static inline struct page * get_page_map(struct page *page)
{
- if (MAP_NR(vaddr) >= max_mapnr)
- return 0;
- if (page == ZERO_PAGE(vaddr))
- return 0;
- if (PageReserved(page))
+ if (page > (mem_map + max_mapnr))
return 0;
return page;
}
/*
* Force in an entire range of pages from the current process's user VA,
- * and pin and lock the pages for IO.
+ * and pin them in physical memory.
*/
#define dprintk(x...)
@@ -430,8 +427,6 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
struct mm_struct * mm;
struct vm_area_struct * vma = 0;
struct page * map;
- int doublepage = 0;
- int repeat = 0;
int i;
/* Make sure the iobuf is not already mapped somewhere. */
@@ -447,11 +442,10 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
if (err)
return err;
- repeat:
down(&mm->mmap_sem);
err = -EFAULT;
- iobuf->locked = 1;
+ iobuf->locked = 0;
iobuf->offset = va & ~PAGE_MASK;
iobuf->length = len;
@@ -471,16 +465,15 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
spin_lock(&mm->page_table_lock);
map = follow_page(ptr);
if (!map) {
+ spin_unlock(&mm->page_table_lock);
dprintk (KERN_ERR "Missing page in map_user_kiobuf\n");
- goto retry;
+ goto out_unlock;
}
- map = get_page_map(map, ptr);
- if (map) {
- if (TryLockPage(map)) {
- goto retry;
- }
+ map = get_page_map(map);
+ if (map)
atomic_inc(&map->count);
- }
+ else
+ printk (KERN_INFO "Mapped page missing [%d]\n", i);
spin_unlock(&mm->page_table_lock);
iobuf->maplist[i] = map;
iobuf->nr_pages = ++i;
@@ -497,66 +490,133 @@ int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
unmap_kiobuf(iobuf);
dprintk ("map_user_kiobuf: end %d\n", err);
return err;
+}
- retry:
+/*
+ * Unmap all of the pages referenced by a kiobuf. We release the pages,
+ * and unlock them if they were locked.
+ */
+
+void unmap_kiobuf (struct kiobuf *iobuf)
+{
+ int i;
+ struct page *map;
+
+ for (i = 0; i < iobuf->nr_pages; i++) {
+ map = iobuf->maplist[i];
+ if (map) {
+ if (iobuf->locked)
+ UnlockPage(map);
+ __free_page(map);
+ }
+ }
+
+ iobuf->nr_pages = 0;
+ iobuf->locked = 0;
+}
+
+
+/*
+ * Lock down all of the pages of a kiovec for IO.
+ *
+ * If any page is mapped twice in the kiovec, we return the error -EINVAL.
+ *
+ * The optional wait parameter causes the lock call to block until all
+ * pages can be locked if set. If wait==0, the lock operation is
+ * aborted if any locked pages are found and -EAGAIN is returned.
+ */
+
+int lock_kiovec(int nr, struct kiobuf *iovec[], int wait)
+{
+ struct kiobuf *iobuf;
+ int i, j;
+ struct page *page, **ppage;
+ int doublepage = 0;
+ int repeat = 0;
+
+ repeat:
+
+ for (i = 0; i < nr; i++) {
+ iobuf = iovec[i];
+
+ if (iobuf->locked)
+ continue;
+ iobuf->locked = 1;
+
+ ppage = iobuf->maplist;
+ for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
+ page = *ppage;
+ if (!page)
+ continue;
+
+ if (TryLockPage(page))
+ goto retry;
+ }
+ }
+
+ return 0;
+
+ retry:
+
/*
- * Undo the locking so far, wait on the page we got to, and try again.
+ * We couldn't lock one of the pages. Undo the locking so far,
+ * wait on the page we got to, and try again.
*/
- spin_unlock(&mm->page_table_lock);
- unmap_kiobuf(iobuf);
- up(&mm->mmap_sem);
-
+
+ unlock_kiovec(nr, iovec);
+ if (!wait)
+ return -EAGAIN;
+
/*
* Did the release also unlock the page we got stuck on?
*/
- if (map) {
- if (!PageLocked(map)) {
- /* If so, we may well have the page mapped twice
- * in the IO address range. Bad news. Of
- * course, it _might_ * just be a coincidence,
- * but if it happens more than * once, chances
- * are we have a double-mapped page. */
- if (++doublepage >= 3) {
- return -EINVAL;
- }
- }
-
- /*
- * Try again...
+ if (!PageLocked(page)) {
+ /*
+ * If so, we may well have the page mapped twice
+ * in the IO address range. Bad news. Of
+ * course, it _might_ just be a coincidence,
+ * but if it happens more than once, chances
+ * are we have a double-mapped page.
*/
- wait_on_page(map);
+ if (++doublepage >= 3)
+ return -EINVAL;
+
+ /* Try again... */
+ wait_on_page(page);
}
- if (++repeat < 16) {
- ptr = va & PAGE_MASK;
+ if (++repeat < 16)
goto repeat;
- }
return -EAGAIN;
}
-
/*
- * Unmap all of the pages referenced by a kiobuf. We release the pages,
- * and unlock them if they were locked.
+ * Unlock all of the pages of a kiovec after IO.
*/
-void unmap_kiobuf (struct kiobuf *iobuf)
+int unlock_kiovec(int nr, struct kiobuf *iovec[])
{
- int i;
- struct page *map;
+ struct kiobuf *iobuf;
+ int i, j;
+ struct page *page, **ppage;
- for (i = 0; i < iobuf->nr_pages; i++) {
- map = iobuf->maplist[i];
+ for (i = 0; i < nr; i++) {
+ iobuf = iovec[i];
+
+ if (!iobuf->locked)
+ continue;
+ iobuf->locked = 0;
- if (map && iobuf->locked) {
- UnlockPage(map);
- __free_page(map);
+ ppage = iobuf->maplist;
+ for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
+ page = *ppage;
+ if (!page)
+ continue;
+ UnlockPage(page);
}
}
-
- iobuf->nr_pages = 0;
- iobuf->locked = 0;
+ return 0;
}
static inline void zeromap_pte_range(pte_t * pte, unsigned long address,
diff --git a/mm/mmap.c b/mm/mmap.c
index 5a6820972..b650babc8 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -305,14 +305,14 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
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;
- vma->vm_file = file;
- get_file(file);
}
/*
@@ -334,6 +334,8 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned lon
return addr;
unmap_and_free_vma:
+ vma->vm_file = NULL;
+ fput(file);
/* Undo any partial mapping done by a device driver. */
flush_cache_range(mm, vma->vm_start, vma->vm_end);
zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
diff --git a/net/Config.in b/net/Config.in
index 833846406..624885478 100644
--- a/net/Config.in
+++ b/net/Config.in
@@ -54,11 +54,11 @@ if [ "$CONFIG_IPX" != "n" ]; then
source net/ipx/Config.in
fi
tristate 'Appletalk protocol support' CONFIG_ATALK
+tristate 'DECnet Support' CONFIG_DECNET
+if [ "$CONFIG_DECNET" != "n" ]; then
+ source net/decnet/Config.in
+fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'DECnet Support (EXPERIMENTAL)' CONFIG_DECNET
- if [ "$CONFIG_DECNET" != "n" ]; then
- source net/decnet/Config.in
- fi
tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index 6590ff316..37aae3e6c 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -50,6 +50,7 @@
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
+#include <linux/spinlock.h>
#include <net/sock.h>
#include <net/datalink.h>
#include <net/psnap.h>
@@ -67,8 +68,7 @@ int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME;
* Lists of aarp entries
*/
-struct aarp_entry
-{
+struct aarp_entry {
/* These first two are only used for unresolved entries */
unsigned long last_sent; /* Last time we xmitted the aarp request */
struct sk_buff_head packet_queue; /* Queue of frames wait for resolution */
@@ -85,8 +85,13 @@ struct aarp_entry
* Hashed list of resolved, unresolved and proxy entries
*/
-static struct aarp_entry *resolved[AARP_HASH_SIZE], *unresolved[AARP_HASH_SIZE], *proxies[AARP_HASH_SIZE];
-static int unresolved_count=0;
+static struct aarp_entry *resolved[AARP_HASH_SIZE];
+static struct aarp_entry *unresolved[AARP_HASH_SIZE];
+static struct aarp_entry *proxies[AARP_HASH_SIZE];
+static int unresolved_count = 0;
+
+/* One lock protects it all. */
+static spinlock_t aarp_lock = SPIN_LOCK_UNLOCKED;
/*
* Used to walk the list and purge/kick entries.
@@ -96,38 +101,49 @@ static struct timer_list aarp_timer;
/*
* Delete an aarp queue
+ *
+ * Must run under aarp_lock.
*/
-static void aarp_expire(struct aarp_entry *a)
+static void __aarp_expire(struct aarp_entry *a)
{
struct sk_buff *skb;
- while((skb=skb_dequeue(&a->packet_queue))!=NULL)
+ while ((skb=skb_dequeue(&a->packet_queue)) != NULL)
kfree_skb(skb);
- kfree_s(a,sizeof(*a));
+
+ kfree_s(a, sizeof(*a));
}
/*
* Send an aarp queue entry request
+ *
+ * Must run under aarp_lock.
*/
-static void aarp_send_query(struct aarp_entry *a)
+static void __aarp_send_query(struct aarp_entry *a)
{
- static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
- struct net_device *dev=a->dev;
- int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
- struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
+ static char aarp_eth_multicast[ETH_ALEN] =
+ { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+ struct net_device *dev = a->dev;
+ int len = dev->hard_header_len + sizeof(struct elapaarp) + aarp_dl->header_length;
+ struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
struct elapaarp *eah;
- struct at_addr *sat=atalk_find_dev_addr(dev);
+ struct at_addr *sat = atalk_find_dev_addr(dev);
- if(skb==NULL || sat==NULL)
+ if (skb == NULL)
return;
+
+ if (sat == NULL) {
+ kfree_skb(skb);
+ return;
+ }
/*
* Set up the buffer.
*/
- skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length);
- eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp));
+ skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+ eah = (struct elapaarp *)skb_put(skb, sizeof(struct elapaarp));
skb->protocol = htons(ETH_P_ATALK);
skb->nh.raw = skb->h.raw = (void *) eah;
skb->dev = dev;
@@ -173,21 +189,25 @@ static void aarp_send_query(struct aarp_entry *a)
a->xmit_count++;
}
-static void aarp_send_reply(struct net_device *dev, struct at_addr *us, struct at_addr *them, unsigned char *sha)
+/* This runs under aarp_lock and in softint context, so only
+ * atomic memory allocations can be used.
+ */
+static void aarp_send_reply(struct net_device *dev, struct at_addr *us,
+ struct at_addr *them, unsigned char *sha)
{
- int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
- struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
+ int len = dev->hard_header_len + sizeof(struct elapaarp) + aarp_dl->header_length;
+ struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
struct elapaarp *eah;
- if(skb==NULL)
+ if (skb == NULL)
return;
/*
* Set up the buffer.
*/
- skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length);
- eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp));
+ skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+ eah = (struct elapaarp *)skb_put(skb, sizeof(struct elapaarp));
skb->protocol = htons(ETH_P_ATALK);
skb->nh.raw = skb->h.raw = (void *) eah;
skb->dev = dev;
@@ -208,7 +228,7 @@ static void aarp_send_reply(struct net_device *dev, struct at_addr *us, struct a
eah->pa_src_net = us->s_net;
eah->pa_src_node= us->s_node;
- if(sha==NULL)
+ if (sha == NULL)
memset(eah->hw_dst, '\0', ETH_ALEN);
else
memcpy(eah->hw_dst, sha, ETH_ALEN);
@@ -227,110 +247,110 @@ static void aarp_send_reply(struct net_device *dev, struct at_addr *us, struct a
* Send it.
*/
dev_queue_xmit(skb);
-
}
/*
* Send probe frames. Called from aarp_probe_network and aarp_proxy_probe_network.
*/
-
+
void aarp_send_probe(struct net_device *dev, struct at_addr *us)
{
- int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length;
- struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC);
+ int len = dev->hard_header_len + sizeof(struct elapaarp) + aarp_dl->header_length;
+ struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
struct elapaarp *eah;
- static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
-
- if(skb==NULL)
+ static char aarp_eth_multicast[ETH_ALEN] =
+ { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+
+ if (skb == NULL)
return;
-
+
/*
* Set up the buffer.
- */
+ */
- skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length);
- eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp));
+ skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length);
+ eah = (struct elapaarp *)skb_put(skb, sizeof(struct elapaarp));
skb->protocol = htons(ETH_P_ATALK);
skb->nh.raw = skb->h.raw = (void *) eah;
skb->dev = dev;
-
+
/*
* Set up the ARP.
*/
-
+
eah->hw_type = htons(AARP_HW_TYPE_ETHERNET);
eah->pa_type = htons(ETH_P_ATALK);
- eah->hw_len = ETH_ALEN;
+ eah->hw_len = ETH_ALEN;
eah->pa_len = AARP_PA_ALEN;
eah->function = htons(AARP_PROBE);
-
+
memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN);
-
+
eah->pa_src_zero= 0;
eah->pa_src_net = us->s_net;
eah->pa_src_node= us->s_node;
-
+
memset(eah->hw_dst, '\0', ETH_ALEN);
-
+
eah->pa_dst_zero= 0;
eah->pa_dst_net = us->s_net;
eah->pa_dst_node= us->s_node;
-
+
/*
* Add ELAP headers and set target to the AARP multicast.
*/
-
- aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);
+
+ aarp_dl->datalink_header(aarp_dl, skb, aarp_eth_multicast);
/*
* Send it.
- */
+ */
dev_queue_xmit(skb);
-
}
/*
* Handle an aarp timer expire
+ *
+ * Must run under the aarp_lock.
*/
-static void aarp_expire_timer(struct aarp_entry **n)
+static void __aarp_expire_timer(struct aarp_entry **n)
{
struct aarp_entry *t;
- while((*n)!=NULL)
- {
+
+ while ((*n) != NULL) {
/* Expired ? */
- if(time_after(jiffies, (*n)->expires_at))
- {
- t= *n;
- *n=(*n)->next;
- aarp_expire(t);
+ if(time_after(jiffies, (*n)->expires_at)) {
+ t = *n;
+ *n = (*n)->next;
+ __aarp_expire(t);
+ } else {
+ n = &((*n)->next);
}
- else
- n=&((*n)->next);
}
}
/*
* Kick all pending requests 5 times a second.
+ *
+ * Must run under the aarp_lock.
*/
-static void aarp_kick(struct aarp_entry **n)
+static void __aarp_kick(struct aarp_entry **n)
{
struct aarp_entry *t;
- while((*n)!=NULL)
- {
+
+ while ((*n) != NULL) {
/* Expired - if this will be the 11th transmit, we delete
- instead */
- if((*n)->xmit_count>=sysctl_aarp_retransmit_limit)
- {
- t= *n;
- *n=(*n)->next;
- aarp_expire(t);
- }
- else
- {
- aarp_send_query(*n);
- n=&((*n)->next);
+ * instead.
+ */
+ if ((*n)->xmit_count >= sysctl_aarp_retransmit_limit) {
+ t = *n;
+ *n = (*n)->next;
+ __aarp_expire(t);
+ } else {
+ __aarp_send_query(*n);
+ n = &((*n)->next);
}
}
}
@@ -338,21 +358,22 @@ static void aarp_kick(struct aarp_entry **n)
/*
* A device has gone down. Take all entries referring to the device
* and remove them.
+ *
+ * Must run under the aarp_lock.
*/
-static void aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
+static void __aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
{
struct aarp_entry *t;
- while((*n)!=NULL)
- {
- if((*n)->dev==dev)
- {
- t= *n;
- *n=(*n)->next;
- aarp_expire(t);
+
+ while ((*n) != NULL) {
+ if ((*n)->dev == dev) {
+ t = *n;
+ *n = (*n)->next;
+ __aarp_expire(t);
+ } else {
+ n = &((*n)->next);
}
- else
- n=&((*n)->next);
}
}
@@ -362,15 +383,19 @@ static void aarp_expire_device(struct aarp_entry **n, struct net_device *dev)
static void aarp_expire_timeout(unsigned long unused)
{
- int ct=0;
- for(ct=0;ct<AARP_HASH_SIZE;ct++)
- {
- aarp_expire_timer(&resolved[ct]);
- aarp_kick(&unresolved[ct]);
- aarp_expire_timer(&unresolved[ct]);
- aarp_expire_timer(&proxies[ct]);
+ int ct;
+
+ spin_lock_bh(&aarp_lock);
+
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ __aarp_expire_timer(&resolved[ct]);
+ __aarp_kick(&unresolved[ct]);
+ __aarp_expire_timer(&unresolved[ct]);
+ __aarp_expire_timer(&proxies[ct]);
}
+ spin_unlock_bh(&aarp_lock);
+
mod_timer(&aarp_timer, jiffies +
(unresolved_count ? sysctl_aarp_tick_time:
sysctl_aarp_expiry_time));
@@ -382,77 +407,92 @@ static void aarp_expire_timeout(unsigned long unused)
static int aarp_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{
- int ct=0;
- if(event==NETDEV_DOWN)
- {
- for(ct=0;ct<AARP_HASH_SIZE;ct++)
- {
- aarp_expire_device(&resolved[ct],ptr);
- aarp_expire_device(&unresolved[ct],ptr);
- aarp_expire_device(&proxies[ct],ptr);
+ int ct;
+
+ if (event == NETDEV_DOWN) {
+ spin_lock_bh(&aarp_lock);
+
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ __aarp_expire_device(&resolved[ct], ptr);
+ __aarp_expire_device(&unresolved[ct], ptr);
+ __aarp_expire_device(&proxies[ct], ptr);
}
+
+ spin_unlock_bh(&aarp_lock);
}
return NOTIFY_DONE;
}
/*
- * Create a new aarp entry.
+ * Create a new aarp entry. This must use GFP_ATOMIC because it
+ * runs while holding spinlocks.
*/
static struct aarp_entry *aarp_alloc(void)
{
- struct aarp_entry *a=kmalloc(sizeof(struct aarp_entry), GFP_ATOMIC);
- if(a==NULL)
+ struct aarp_entry *a = kmalloc(sizeof(struct aarp_entry), GFP_ATOMIC);
+
+ if (a == NULL)
return NULL;
+
skb_queue_head_init(&a->packet_queue);
+
return a;
}
/*
* Find an entry. We might return an expired but not yet purged entry. We
* don't care as it will do no harm.
+ *
+ * This must run under the aarp_lock.
*/
-static struct aarp_entry *aarp_find_entry(struct aarp_entry *list, struct net_device *dev, struct at_addr *sat)
+static struct aarp_entry *__aarp_find_entry(struct aarp_entry *list,
+ struct net_device *dev,
+ struct at_addr *sat)
{
- unsigned long flags;
- save_flags(flags);
- cli();
- while(list)
- {
- if(list->target_addr.s_net==sat->s_net &&
- list->target_addr.s_node==sat->s_node && list->dev==dev)
+ while (list) {
+ if (list->target_addr.s_net == sat->s_net &&
+ list->target_addr.s_node == sat->s_node &&
+ list->dev == dev)
break;
- list=list->next;
+ list = list->next;
}
- restore_flags(flags);
+
return list;
}
+/* Called from the DDP code, and thus must be exported. */
void aarp_proxy_remove(struct net_device *dev, struct at_addr *sa)
{
struct aarp_entry *a;
int hash;
hash = sa->s_node % (AARP_HASH_SIZE-1);
- a = aarp_find_entry(proxies[hash], dev, sa);
+
+ spin_lock_bh(&aarp_lock);
+
+ a = __aarp_find_entry(proxies[hash], dev, sa);
if (a)
- {
- a->expires_at = 0;
-
- }
+ a->expires_at = jiffies - 1;
+
+ spin_unlock_bh(&aarp_lock);
}
-struct at_addr* aarp_proxy_find(struct net_device *dev, struct at_addr *sa)
+/* This must run under aarp_lock. */
+static struct at_addr *__aarp_proxy_find(struct net_device *dev, struct at_addr *sa)
{
+ struct at_addr *retval;
struct aarp_entry *a;
int hash;
hash = sa->s_node % (AARP_HASH_SIZE-1);
- a = aarp_find_entry(proxies[hash], dev, sa);
+
+ retval = NULL;
+ a = __aarp_find_entry(proxies[hash], dev, sa);
if (a != NULL)
- return sa;
-
- return NULL;
+ retval = sa;
+
+ return retval;
}
@@ -468,31 +508,27 @@ void aarp_send_probe_phase1(struct atalk_iface *iface)
sa->sat_addr.s_node = iface->address.s_node;
sa->sat_addr.s_net = ntohs(iface->address.s_net);
- /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
- if(!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR)))
- {
- (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
- if((iface->address.s_net != htons(sa->sat_addr.s_net))
- || (iface->address.s_node != sa->sat_addr.s_node))
- iface->status |= ATIF_PROBE_FAIL;
-
- iface->address.s_net = htons(sa->sat_addr.s_net);
- iface->address.s_node = sa->sat_addr.s_node;
- }
+ /* We pass the Net:Node to the drivers/cards by a Device ioctl. */
+ if (!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR))) {
+ (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR);
+ if ((iface->address.s_net != htons(sa->sat_addr.s_net)) ||
+ (iface->address.s_node != sa->sat_addr.s_node))
+ iface->status |= ATIF_PROBE_FAIL;
- return;
+ iface->address.s_net = htons(sa->sat_addr.s_net);
+ iface->address.s_node = sa->sat_addr.s_node;
+ }
}
void aarp_probe_network(struct atalk_iface *atif)
{
- if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
+ if(atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP) {
aarp_send_probe_phase1(atif);
- else
- {
+ } else {
unsigned int count;
- for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
- {
+
+ for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
aarp_send_probe(atif->dev, &atif->address);
/*
@@ -511,17 +547,17 @@ int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
{
struct aarp_entry *entry;
unsigned int count;
- int hash;
+ int hash, retval;
/*
* we don't currently support LocalTalk or PPP for proxy AARP;
* if someone wants to try and add it, have fun
*/
if (atif->dev->type == ARPHRD_LOCALTLK)
- return (-EPROTONOSUPPORT);
+ return -EPROTONOSUPPORT;
if (atif->dev->type == ARPHRD_PPP)
- return (-EPROTONOSUPPORT);
+ return -EPROTONOSUPPORT;
/*
* create a new AARP entry with the flags set to be published --
@@ -529,7 +565,7 @@ int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
*/
entry = aarp_alloc();
if (entry == NULL)
- return (-ENOMEM);
+ return -ENOMEM;
entry->expires_at = -1;
entry->status = ATIF_PROBE;
@@ -537,44 +573,46 @@ int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
entry->target_addr.s_net = sa->s_net;
entry->dev = atif->dev;
- hash = sa->s_node % (AARP_HASH_SIZE-1);
+ spin_lock_bh(&aarp_lock);
+
+ hash = sa->s_node % (AARP_HASH_SIZE - 1);
entry->next = proxies[hash];
proxies[hash] = entry;
- for(count = 0; count < AARP_RETRANSMIT_LIMIT; count++)
- {
+ for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) {
aarp_send_probe(atif->dev, sa);
/*
* Defer 1/10th
*/
current->state = TASK_INTERRUPTIBLE;
+
+ spin_unlock_bh(&aarp_lock);
+
schedule_timeout(HZ/10);
+ spin_lock_bh(&aarp_lock);
+
if (entry->status & ATIF_PROBE_FAIL)
break;
}
- /*
- * FIX ME: I think we need exclusive access to the status flags,
- * in case some one fails the probe while we're removing
- * the probe flag.
- */
- if (entry->status & ATIF_PROBE_FAIL)
- {
+ retval = 1;
+
+ if (entry->status & ATIF_PROBE_FAIL) {
/* free the entry */
- entry->expires_at = 0;
+ entry->expires_at = jiffies - 1;
/* return network full */
- return (-EADDRINUSE);
- }
- else
- {
+ retval = -EADDRINUSE;
+ } else {
/* clear the probing flag */
entry->status &= ~ATIF_PROBE;
}
- return 1;
+ spin_unlock_bh(&aarp_lock);
+
+ return retval;
}
@@ -583,23 +621,21 @@ int aarp_proxy_probe_network(struct atalk_iface *atif, struct at_addr *sa)
*/
int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr)
{
- static char ddp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
+ static char ddp_eth_multicast[ETH_ALEN] = { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF };
int hash;
struct aarp_entry *a;
- unsigned long flags;
- skb->nh.raw=skb->data;
+ skb->nh.raw = skb->data;
/*
* Check for LocalTalk first
*/
- if(dev->type==ARPHRD_LOCALTLK)
- {
- struct at_addr *at=atalk_find_dev_addr(dev);
- struct ddpehdr *ddp=(struct ddpehdr *)skb->data;
- int ft=2;
+ if (dev->type == ARPHRD_LOCALTLK) {
+ struct at_addr *at = atalk_find_dev_addr(dev);
+ struct ddpehdr *ddp = (struct ddpehdr *)skb->data;
+ int ft = 2;
/*
* Compressible ?
@@ -608,29 +644,29 @@ int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa
* (zero matches anything)
*/
- if( ( ddp->deh_snet==0 || at->s_net==ddp->deh_snet)
- &&( ddp->deh_dnet==0 || at->s_net==ddp->deh_dnet) )
- {
- skb_pull(skb,sizeof(struct ddpehdr)-4);
+ if( ( ddp->deh_snet==0 || at->s_net==ddp->deh_snet) &&
+ ( ddp->deh_dnet==0 || at->s_net==ddp->deh_dnet) ) {
+ skb_pull(skb, sizeof(struct ddpehdr) - 4);
+
/*
* The upper two remaining bytes are the port
* numbers we just happen to need. Now put the
* length in the lower two.
*/
- *((__u16 *)skb->data)=htons(skb->len);
- ft=1;
+ *((__u16 *)skb->data) = htons(skb->len);
+ ft = 1;
}
/*
* Nice and easy. No AARP type protocols occur here
* so we can just shovel it out with a 3 byte LLAP header
*/
- skb_push(skb,3);
- skb->data[0]=sa->s_node;
- skb->data[1]=at->s_node;
- skb->data[2]=ft;
+ skb_push(skb, 3);
+ skb->data[0] = sa->s_node;
+ skb->data[1] = at->s_node;
+ skb->data[2] = ft;
- if(skb->sk)
+ if (skb->sk)
skb->priority = skb->sk->priority;
skb->dev = dev;
dev_queue_xmit(skb);
@@ -640,10 +676,9 @@ int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa
/*
* On a PPP link we neither compress nor aarp.
*/
- if(dev->type==ARPHRD_PPP)
- {
+ if (dev->type == ARPHRD_PPP) {
skb->protocol = htons(ETH_P_PPPTALK);
- if(skb->sk)
+ if (skb->sk)
skb->priority = skb->sk->priority;
skb->dev = dev;
dev_queue_xmit(skb);
@@ -654,44 +689,43 @@ int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa
* Non ELAP we cannot do.
*/
- if(dev->type!=ARPHRD_ETHER)
- {
+ if (dev->type != ARPHRD_ETHER)
return -1;
- }
skb->dev = dev;
skb->protocol = htons(ETH_P_ATALK);
- hash=sa->s_node%(AARP_HASH_SIZE-1);
- save_flags(flags);
- cli();
+ hash = sa->s_node % (AARP_HASH_SIZE - 1);
/*
* Do we have a resolved entry ?
*/
- if(sa->s_node==ATADDR_BCAST)
- {
+ if (sa->s_node == ATADDR_BCAST) {
ddp_dl->datalink_header(ddp_dl, skb, ddp_eth_multicast);
- if(skb->sk)
+
+ if (skb->sk)
skb->priority = skb->sk->priority;
dev_queue_xmit(skb);
- restore_flags(flags);
return 1;
}
- a=aarp_find_entry(resolved[hash],dev,sa);
- if(a!=NULL)
- {
+
+ spin_lock_bh(&aarp_lock);
+
+ a = __aarp_find_entry(resolved[hash], dev, sa);
+
+ if (a != NULL) {
/*
* Return 1 and fill in the address
*/
- a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
+ a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10);
ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
if(skb->sk)
skb->priority = skb->sk->priority;
dev_queue_xmit(skb);
- restore_flags(flags);
+
+ spin_unlock_bh(&aarp_lock);
return 1;
}
@@ -699,15 +733,15 @@ int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa
* Do we have an unresolved entry: This is the less common path
*/
- a=aarp_find_entry(unresolved[hash],dev,sa);
- if(a!=NULL)
- {
+ a = __aarp_find_entry(unresolved[hash], dev, sa);
+ if (a != NULL) {
/*
* Queue onto the unresolved queue
*/
skb_queue_tail(&a->packet_queue, skb);
- restore_flags(flags);
+
+ spin_unlock_bh(&aarp_lock);
return 0;
}
@@ -715,14 +749,13 @@ int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa
* Allocate a new entry
*/
- a=aarp_alloc();
- if(a==NULL)
- {
+ a = aarp_alloc();
+ if (a == NULL) {
/*
* Whoops slipped... good job it's an unreliable
* protocol 8)
*/
- restore_flags(flags);
+ spin_unlock_bh(&aarp_lock);
return -1;
}
@@ -731,30 +764,34 @@ int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa
*/
skb_queue_tail(&a->packet_queue, skb);
- a->expires_at=jiffies+sysctl_aarp_resolve_time;
- a->dev=dev;
- a->next=unresolved[hash];
- a->target_addr= *sa;
- a->xmit_count=0;
- unresolved[hash]=a;
+ a->expires_at = jiffies + sysctl_aarp_resolve_time;
+ a->dev = dev;
+ a->next = unresolved[hash];
+ a->target_addr = *sa;
+ a->xmit_count = 0;
+ unresolved[hash] = a;
unresolved_count++;
- restore_flags(flags);
/*
* Send an initial request for the address
*/
- aarp_send_query(a);
+ __aarp_send_query(a);
/*
* Switch to fast timer if needed (That is if this is the
* first unresolved entry to get added)
*/
- if(unresolved_count==1)
- {
+ if (unresolved_count == 1)
mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time);
- }
+
+
+ /*
+ * Now finally, it is safe to drop the lock.
+ */
+
+ spin_unlock_bh(&aarp_lock);
/*
* Tell the ddp layer we have taken over for this frame.
@@ -766,39 +803,40 @@ int aarp_send_ddp(struct net_device *dev,struct sk_buff *skb, struct at_addr *sa
/*
* An entry in the aarp unresolved queue has become resolved. Send
* all the frames queued under it.
+ *
+ * Must run under aarp_lock.
*/
-static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int hash)
+static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int hash)
{
struct sk_buff *skb;
- while(*list!=NULL)
- {
- if(*list==a)
- {
+
+ while (*list != NULL) {
+ if (*list == a) {
unresolved_count--;
- *list=a->next;
-
+
+ *list = a->next;
+
/*
* Move into the resolved list
*/
-
- a->next=resolved[hash];
- resolved[hash]=a;
-
+
+ a->next = resolved[hash];
+ resolved[hash] = a;
+
/*
* Kick frames off
*/
-
- while((skb=skb_dequeue(&a->packet_queue))!=NULL)
- {
- a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
- ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr);
- if(skb->sk)
+
+ while ((skb = skb_dequeue(&a->packet_queue)) != NULL) {
+ a->expires_at = jiffies + (sysctl_aarp_expiry_time*10);
+ ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
+ if (skb->sk)
skb->priority = skb->sk->priority;
dev_queue_xmit(skb);
}
+ } else {
+ list = &((*list)->next);
}
- else
- list=&((*list)->next);
}
}
@@ -811,138 +849,129 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
struct elapaarp *ea=(struct elapaarp *)skb->h.raw;
struct aarp_entry *a;
struct at_addr sa, *ma, da;
- unsigned long flags;
int hash;
struct atalk_iface *ifa;
-
-
+
/*
- * We only do Ethernet SNAP AARP
+ * We only do Ethernet SNAP AARP.
*/
-
- if(dev->type!=ARPHRD_ETHER)
- {
+
+ if (dev->type != ARPHRD_ETHER) {
kfree_skb(skb);
return 0;
}
-
+
/*
* Frame size ok ?
*/
-
- if(!skb_pull(skb,sizeof(*ea)))
- {
+
+ if (!skb_pull(skb, sizeof(*ea))) {
kfree_skb(skb);
return 0;
}
- ea->function=ntohs(ea->function);
-
+ ea->function = ntohs(ea->function);
+
/*
* Sanity check fields.
*/
-
- if(ea->function<AARP_REQUEST || ea->function > AARP_PROBE || ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN ||
- ea->pa_src_zero != 0 || ea->pa_dst_zero != 0)
- {
+
+ if (ea->function < AARP_REQUEST ||
+ ea->function > AARP_PROBE ||
+ ea->hw_len != ETH_ALEN ||
+ ea->pa_len != AARP_PA_ALEN ||
+ ea->pa_src_zero != 0 ||
+ ea->pa_dst_zero != 0) {
kfree_skb(skb);
return 0;
}
-
- /*
- * Looks good
- */
-
- hash=ea->pa_src_node%(AARP_HASH_SIZE-1);
/*
- * Build an address
+ * Looks good.
*/
-
- sa.s_node=ea->pa_src_node;
- sa.s_net=ea->pa_src_net;
-
+
+ hash = ea->pa_src_node % (AARP_HASH_SIZE - 1);
+
/*
- * Process the packet
+ * Build an address.
*/
-
- save_flags(flags);
+
+ sa.s_node = ea->pa_src_node;
+ sa.s_net = ea->pa_src_net;
/*
- * Check for replies of me
+ * Process the packet.
+ * Check for replies of me.
*/
-
- ifa=atalk_find_dev(dev);
- if(ifa==NULL)
- {
- restore_flags(flags);
+
+ ifa = atalk_find_dev(dev);
+ if (ifa == NULL) {
kfree_skb(skb);
- return 1;
+ return 1;
}
- if(ifa->status&ATIF_PROBE)
- {
- if(ifa->address.s_node==ea->pa_dst_node && ifa->address.s_net==ea->pa_dst_net)
- {
+
+ if (ifa->status & ATIF_PROBE) {
+ if (ifa->address.s_node == ea->pa_dst_node &&
+ ifa->address.s_net == ea->pa_dst_net) {
/*
* Fail the probe (in use)
*/
-
- ifa->status|=ATIF_PROBE_FAIL;
- restore_flags(flags);
+
+ ifa->status |= ATIF_PROBE_FAIL;
kfree_skb(skb);
- return 1;
+ return 1;
}
}
-
+
/*
* Check for replies of proxy AARP entries
*/
- /*
- * FIX ME: do we need a cli() here?
- * aarp_find_entry does one on its own, between saving and restoring flags, so
- * I don't think it is necessary, but I could be wrong -- it's happened before
- */
da.s_node = ea->pa_dst_node;
da.s_net = ea->pa_dst_net;
- a = aarp_find_entry(proxies[hash], dev, &da);
- if (a != NULL)
- if (a->status & ATIF_PROBE)
- {
+
+ spin_lock_bh(&aarp_lock);
+
+ a = __aarp_find_entry(proxies[hash], dev, &da);
+
+ if (a != NULL) {
+ if (a->status & ATIF_PROBE) {
a->status |= ATIF_PROBE_FAIL;
-
+
+ spin_unlock_bh(&aarp_lock);
+
/*
- * we do not respond to probe or request packets for
+ * we do not respond to probe or request packets for
* this address while we are probing this address
*/
- restore_flags(flags);
kfree_skb(skb);
+
return 1;
}
+ }
- switch(ea->function)
- {
+ switch (ea->function) {
case AARP_REPLY:
- if(unresolved_count==0) /* Speed up */
+ if (unresolved_count == 0) /* Speed up */
break;
+
/*
- * Find the entry
+ * Find the entry.
*/
- cli(); /* FIX ME: is this cli() necessary? aarp_find_entry does one on its own... */
- if((a=aarp_find_entry(unresolved[hash],dev,&sa))==NULL || dev != a->dev)
+ if ((a = __aarp_find_entry(unresolved[hash],dev,&sa)) == NULL ||
+ (dev != a->dev))
break;
+
/*
- * We can fill one in - this is good
+ * We can fill one in - this is good.
*/
memcpy(a->hwaddr,ea->hw_src,ETH_ALEN);
- aarp_resolved(&unresolved[hash],a,hash);
- if(unresolved_count==0)
- {
- mod_timer(&aarp_timer, jiffies +
- sysctl_aarp_expiry_time);
- }
+ __aarp_resolved(&unresolved[hash],a,hash);
+ if (unresolved_count == 0)
+ mod_timer(&aarp_timer,
+ jiffies + sysctl_aarp_expiry_time);
break;
case AARP_REQUEST:
@@ -956,100 +985,101 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_t
* of our proxies before we toss the packet out.
*/
- sa.s_node=ea->pa_dst_node;
- sa.s_net=ea->pa_dst_net;
+ sa.s_node = ea->pa_dst_node;
+ sa.s_net = ea->pa_dst_net;
/*
- * see if we have a matching proxy
+ * See if we have a matching proxy.
*/
- ma = aarp_proxy_find(dev, &sa);
- if (!ma)
- {
- ma=&ifa->address;
- }
- else
- {
+ ma = __aarp_proxy_find(dev, &sa);
+ if (!ma) {
+ ma = &ifa->address;
+ } else {
/*
- * we need to make a copy of the entry
+ * We need to make a copy of the entry.
*/
da.s_node = sa.s_node;
da.s_net = da.s_net;
ma = &da;
}
- if(ea->function==AARP_PROBE)
- {
+ if (ea->function == AARP_PROBE) {
/* A probe implies someone trying to get an
- address. So as a precaution flush any
- entries we have for this address */
- struct aarp_entry *a=aarp_find_entry(
+ * address. So as a precaution flush any
+ * entries we have for this address.
+ */
+ struct aarp_entry *a = __aarp_find_entry(
resolved[sa.s_node%(AARP_HASH_SIZE-1)],
skb->dev,
&sa);
/* Make it expire next tick - that avoids us
- getting into a probe/flush/learn/probe/flush/learn
- cycle during probing of a slow to respond host addr */
- if(a!=NULL)
- a->expires_at=jiffies-1;
+ * getting into a probe/flush/learn/probe/flush/learn
+ * cycle during probing of a slow to respond host addr.
+ */
+ if (a != NULL)
+ a->expires_at = jiffies - 1;
}
- if(sa.s_node!=ma->s_node)
+
+ if (sa.s_node != ma->s_node)
break;
- if(sa.s_net && ma->s_net && sa.s_net!=ma->s_net)
+
+ if (sa.s_net && ma->s_net && sa.s_net != ma->s_net)
break;
- sa.s_node=ea->pa_src_node;
- sa.s_net=ea->pa_src_net;
+ sa.s_node = ea->pa_src_node;
+ sa.s_net = ea->pa_src_net;
/*
* aarp_my_address has found the address to use for us.
*/
- aarp_send_reply(dev,ma,&sa,ea->hw_src);
+ aarp_send_reply(dev, ma, &sa, ea->hw_src);
break;
- }
- restore_flags(flags);
+ };
+
+ spin_unlock_bh(&aarp_lock);
+
kfree_skb(skb);
- return 1;
+ return 1;
}
-static struct notifier_block aarp_notifier={
+static struct notifier_block aarp_notifier = {
aarp_device_event,
NULL,
0
};
-static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3};
+static char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 };
void __init aarp_proto_init(void)
{
- if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL)
+ if ((aarp_dl = register_snap_client(aarp_snap_id, aarp_rcv)) == NULL)
printk(KERN_CRIT "Unable to register AARP with SNAP.\n");
init_timer(&aarp_timer);
- aarp_timer.function=aarp_expire_timeout;
- aarp_timer.data=0;
- aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
+ aarp_timer.function = aarp_expire_timeout;
+ aarp_timer.data = 0;
+ aarp_timer.expires = jiffies + sysctl_aarp_expiry_time;
add_timer(&aarp_timer);
register_netdevice_notifier(&aarp_notifier);
}
-
-
/*
* Remove the AARP entries associated with a device.
*/
void aarp_device_down(struct net_device *dev)
{
- int ct = 0;
+ int ct;
+
+ spin_lock_bh(&aarp_lock);
- for(ct = 0; ct < AARP_HASH_SIZE; ct++)
- {
- aarp_expire_device(&resolved[ct], dev);
- aarp_expire_device(&unresolved[ct], dev);
- aarp_expire_device(&proxies[ct], dev);
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ __aarp_expire_device(&resolved[ct], dev);
+ __aarp_expire_device(&unresolved[ct], dev);
+ __aarp_expire_device(&proxies[ct], dev);
}
- return;
+ spin_unlock_bh(&aarp_lock);
}
/*
@@ -1064,10 +1094,11 @@ static int aarp_get_info(char *buffer, char **start, off_t offset, int length)
len = sprintf(buffer,
"%-10.10s ""%-10.10s""%-18.18s""%12.12s""%12.12s"" xmit_count status\n",
"address","device","hw addr","last_sent", "expires");
- for (ct = 0; ct < AARP_HASH_SIZE; ct++)
- {
- for (entry = resolved[ct]; entry; entry = entry->next)
- {
+
+ spin_lock_bh(&aarp_lock);
+
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ for (entry = resolved[ct]; entry; entry = entry->next) {
len+= sprintf(buffer+len,"%6u:%-3u ",
(unsigned int)ntohs(entry->target_addr.s_net),
(unsigned int)(entry->target_addr.s_node));
@@ -1090,10 +1121,8 @@ static int aarp_get_info(char *buffer, char **start, off_t offset, int length)
}
}
- for (ct = 0; ct < AARP_HASH_SIZE; ct++)
- {
- for (entry = unresolved[ct]; entry; entry = entry->next)
- {
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ for (entry = unresolved[ct]; entry; entry = entry->next) {
len+= sprintf(buffer+len,"%6u:%-3u ",
(unsigned int)ntohs(entry->target_addr.s_net),
(unsigned int)(entry->target_addr.s_node));
@@ -1115,10 +1144,8 @@ static int aarp_get_info(char *buffer, char **start, off_t offset, int length)
}
}
- for (ct = 0; ct < AARP_HASH_SIZE; ct++)
- {
- for (entry = proxies[ct]; entry; entry = entry->next)
- {
+ for (ct = 0; ct < AARP_HASH_SIZE; ct++) {
+ for (entry = proxies[ct]; entry; entry = entry->next) {
len+= sprintf(buffer+len,"%6u:%-3u ",
(unsigned int)ntohs(entry->target_addr.s_net),
(unsigned int)(entry->target_addr.s_node));
@@ -1140,6 +1167,7 @@ static int aarp_get_info(char *buffer, char **start, off_t offset, int length)
}
}
+ spin_unlock_bh(&aarp_lock);
return len;
}
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 2c576f462..80fc635f2 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -71,6 +71,7 @@
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
+#include <linux/spinlock.h>
#include <linux/termios.h> /* For TIOCOUTQ/INQ */
#include <net/datalink.h>
#include <net/p8022.h>
@@ -118,49 +119,50 @@ static struct proto_ops atalk_dgram_ops;
* *
\**************************************************************************/
-static struct sock *atalk_socket_list = NULL;
+static struct sock *atalk_sockets = NULL;
+static spinlock_t atalk_sockets_lock = SPIN_LOCK_UNLOCKED;
-/*
- * Note: Sockets may not be removed _during_ an interrupt or inet_bh
- * handler using this technique. They can be added although we do not
- * use this facility.
- */
-
-extern inline void atalk_remove_socket(struct sock *sk)
+extern inline void atalk_insert_socket(struct sock *sk)
{
- sklist_remove_socket(&atalk_socket_list,sk);
+ spin_lock_bh(&atalk_sockets_lock);
+ if ((sk->next = atalk_sockets) != NULL)
+ atalk_sockets->pprev = &sk->next;
+ atalk_sockets = sk;
+ sk->pprev = &atalk_sockets;
+ spin_unlock_bh(&atalk_sockets_lock);
}
-extern inline void atalk_insert_socket(struct sock *sk)
+extern inline void atalk_remove_socket(struct sock *sk)
{
- sklist_insert_socket(&atalk_socket_list,sk);
+ spin_lock_bh(&atalk_sockets_lock);
+ if (sk->pprev != NULL) {
+ if (sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ }
+ spin_unlock_bh(&atalk_sockets_lock);
}
static struct sock *atalk_search_socket(struct sockaddr_at *to, struct atalk_iface *atif)
{
struct sock *s;
- for(s = atalk_socket_list; s != NULL; s = s->next)
- {
- if(to->sat_port != s->protinfo.af_at.src_port)
- {
+ spin_lock_bh(&atalk_sockets_lock);
+ for (s = atalk_sockets; s != NULL; s = s->next) {
+ if (to->sat_port != s->protinfo.af_at.src_port)
continue;
- }
- if(to->sat_addr.s_net == ATADDR_ANYNET
- && to->sat_addr.s_node == ATADDR_BCAST
- && s->protinfo.af_at.src_net == atif->address.s_net)
- {
+ if (to->sat_addr.s_net == ATADDR_ANYNET &&
+ to->sat_addr.s_node == ATADDR_BCAST &&
+ s->protinfo.af_at.src_net == atif->address.s_net)
break;
- }
- if(to->sat_addr.s_net == s->protinfo.af_at.src_net
- && (to->sat_addr.s_node == s->protinfo.af_at.src_node
- || to->sat_addr.s_node == ATADDR_BCAST
- || to->sat_addr.s_node == ATADDR_ANYNODE))
- {
+ if (to->sat_addr.s_net == s->protinfo.af_at.src_net &&
+ (to->sat_addr.s_node == s->protinfo.af_at.src_node ||
+ to->sat_addr.s_node == ATADDR_BCAST ||
+ to->sat_addr.s_node == ATADDR_ANYNODE))
break;
- }
/* XXXX.0 -- we got a request for this router. make sure
* that the node is appropriately set. */
@@ -171,44 +173,80 @@ static struct sock *atalk_search_socket(struct sockaddr_at *to, struct atalk_ifa
break;
}
}
+ spin_unlock_bh(&atalk_sockets_lock);
- return (s);
+ return s;
}
/*
- * Find a socket in the list.
+ * Try to find a socket matching ADDR in the socket list,
+ * if found then return it. If not, insert SK into the
+ * socket list.
+ *
+ * This entire operation must execute atomically.
*/
-static struct sock *atalk_find_socket(struct sockaddr_at *sat)
+static struct sock *atalk_find_or_insert_socket(struct sock *sk, struct sockaddr_at *sat)
{
struct sock *s;
- for(s = atalk_socket_list; s != NULL; s = s->next)
- {
- if(s->protinfo.af_at.src_net != sat->sat_addr.s_net)
- {
- continue;
- }
-
- if(s->protinfo.af_at.src_node != sat->sat_addr.s_node)
- {
- continue;
- }
+ spin_lock_bh(&atalk_sockets_lock);
- if(s->protinfo.af_at.src_port != sat->sat_port)
- {
- continue;
- }
+ for (s = atalk_sockets; s != NULL; s = s->next) {
+ if (s->protinfo.af_at.src_net == sat->sat_addr.s_net &&
+ s->protinfo.af_at.src_node == sat->sat_addr.s_node &&
+ s->protinfo.af_at.src_port == sat->sat_port)
+ break;
+ }
- break;
+ if (!s) {
+ /* Wheee, it's free, assign and insert. */
+ if ((sk->next = atalk_sockets) != NULL)
+ atalk_sockets->pprev = &sk->next;
+ atalk_sockets = sk;
+ sk->pprev = &atalk_sockets;
}
- return (s);
+ spin_unlock_bh(&atalk_sockets_lock);
+
+ return s;
+}
+
+static void atalk_destroy_timer(unsigned long data)
+{
+ struct sock *sk = (struct sock *) data;
+
+ if (atomic_read(&sk->wmem_alloc) == 0 &&
+ atomic_read(&sk->rmem_alloc) == 0 &&
+ sk->dead) {
+ sock_put(sk);
+ MOD_DEC_USE_COUNT;
+ } else {
+ sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
+ add_timer(&sk->timer);
+ }
}
extern inline void atalk_destroy_socket(struct sock *sk)
{
- sklist_destroy_socket(&atalk_socket_list, sk);
- MOD_DEC_USE_COUNT;
+ struct sk_buff *skb;
+
+ atalk_remove_socket(sk);
+
+ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL)
+ kfree_skb(skb);
+
+ if (atomic_read(&sk->wmem_alloc) == 0 &&
+ atomic_read(&sk->rmem_alloc) == 0 &&
+ sk->dead) {
+ sock_put(sk);
+ MOD_DEC_USE_COUNT;
+ } else {
+ init_timer(&sk->timer);
+ sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
+ sk->timer.function = atalk_destroy_timer;
+ sk->timer.data = (unsigned long) sk;
+ add_timer(&sk->timer);
+ }
}
/*
@@ -217,51 +255,52 @@ extern inline void atalk_destroy_socket(struct sock *sk)
static int atalk_get_info(char *buffer, char **start, off_t offset, int length)
{
struct sock *s;
- int len=0;
- off_t pos=0;
- off_t begin=0;
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
/*
* Output the AppleTalk data for the /proc filesystem.
*/
len += sprintf(buffer,"Type local_addr remote_addr tx_queue rx_queue st uid\n");
- for(s = atalk_socket_list; s != NULL; s = s->next)
- {
+
+ spin_lock_bh(&atalk_sockets_lock);
+ for (s = atalk_sockets; s != NULL; s = s->next) {
len += sprintf(buffer+len,"%02X ", s->type);
len += sprintf(buffer+len,"%04X:%02X:%02X ",
- ntohs(s->protinfo.af_at.src_net),
- s->protinfo.af_at.src_node,
- s->protinfo.af_at.src_port);
+ ntohs(s->protinfo.af_at.src_net),
+ s->protinfo.af_at.src_node,
+ s->protinfo.af_at.src_port);
len += sprintf(buffer+len,"%04X:%02X:%02X ",
- ntohs(s->protinfo.af_at.dest_net),
- s->protinfo.af_at.dest_node,
- s->protinfo.af_at.dest_port);
+ ntohs(s->protinfo.af_at.dest_net),
+ s->protinfo.af_at.dest_node,
+ s->protinfo.af_at.dest_port);
len += sprintf(buffer+len,"%08X:%08X ",
- atomic_read(&s->wmem_alloc),
- atomic_read(&s->rmem_alloc));
+ atomic_read(&s->wmem_alloc),
+ atomic_read(&s->rmem_alloc));
len += sprintf(buffer+len,"%02X %d\n", s->state,
- SOCK_INODE(s->socket)->i_uid);
+ SOCK_INODE(s->socket)->i_uid);
/* Are we still dumping unwanted data then discard the record */
pos = begin + len;
- if(pos < offset)
- {
+ if (pos < offset) {
len = 0; /* Keep dumping into the buffer start */
begin = pos;
}
- if(pos > offset + length) /* We have dumped enough */
+ if (pos > offset + length) /* We have dumped enough */
break;
}
+ spin_lock_bh(&atalk_sockets_lock);
/* The data in question runs from begin to begin+len */
*start = buffer + (offset - begin); /* Start of wanted data */
len -= (offset - begin); /* Remove unwanted header data from length */
- if(len > length)
+ if (len > length)
len = length; /* Remove unwanted tail data from length */
- return (len);
+ return len;
}
/**************************************************************************\
@@ -270,8 +309,13 @@ static int atalk_get_info(char *buffer, char **start, off_t offset, int length)
* *
\**************************************************************************/
+/* Anti-deadlock ordering is router_lock --> iface_lock -DaveM */
static struct atalk_route *atalk_router_list = NULL;
+static rwlock_t atalk_router_lock = RW_LOCK_UNLOCKED;
+
static struct atalk_iface *atalk_iface_list = NULL;
+static spinlock_t atalk_iface_lock = SPIN_LOCK_UNLOCKED;
+
static struct atalk_route atrtr_default; /* For probing devices or in a routerless network */
/*
@@ -287,43 +331,40 @@ static void atif_drop_device(struct net_device *dev)
struct atalk_iface **iface = &atalk_iface_list;
struct atalk_iface *tmp;
- while((tmp = *iface) != NULL)
- {
- if(tmp->dev == dev)
- {
+ spin_lock_bh(&atalk_iface_lock);
+ while ((tmp = *iface) != NULL) {
+ if (tmp->dev == dev) {
*iface = tmp->next;
kfree_s(tmp, sizeof(struct atalk_iface));
- dev->atalk_ptr=NULL;
+ dev->atalk_ptr = NULL;
MOD_DEC_USE_COUNT;
- }
- else
+ } else
iface = &tmp->next;
}
-
+ spin_unlock_bh(&atalk_iface_lock);
}
static struct atalk_iface *atif_add_device(struct net_device *dev, struct at_addr *sa)
{
struct atalk_iface *iface = (struct atalk_iface *)
kmalloc(sizeof(*iface), GFP_KERNEL);
- unsigned long flags;
- if(iface==NULL)
- return (NULL);
+ if (iface == NULL)
+ return NULL;
+
+ iface->dev = dev;
+ dev->atalk_ptr = iface;
+ iface->address = *sa;
+ iface->status = 0;
- iface->dev=dev;
- dev->atalk_ptr=iface;
- iface->address= *sa;
- iface->status=0;
- save_flags(flags);
- cli();
- iface->next=atalk_iface_list;
- atalk_iface_list=iface;
- restore_flags(flags);
+ spin_lock_bh(&atalk_iface_lock);
+ iface->next = atalk_iface_list;
+ atalk_iface_list = iface;
+ spin_unlock_bh(&atalk_iface_lock);
MOD_INC_USE_COUNT;
- return (iface);
+ return iface;
}
@@ -332,60 +373,57 @@ static struct atalk_iface *atif_add_device(struct net_device *dev, struct at_add
*/
static int atif_probe_device(struct atalk_iface *atif)
{
- int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
- int probe_net=ntohs(atif->address.s_net);
- int probe_node=atif->address.s_node;
+ int netrange = ntohs(atif->nets.nr_lastnet) - ntohs(atif->nets.nr_firstnet) + 1;
+ int probe_net = ntohs(atif->address.s_net);
+ int probe_node = atif->address.s_node;
int netct, nodect;
/*
* Offset the network we start probing with.
*/
- if(probe_net == ATADDR_ANYNET)
- {
- if(!netrange)
+ if (probe_net == ATADDR_ANYNET) {
+ if (!netrange)
probe_net = ntohs(atif->nets.nr_firstnet);
else
- probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+ probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies % netrange);
}
- if(probe_node == ATADDR_ANYNODE)
- probe_node = jiffies&0xFF;
+ if (probe_node == ATADDR_ANYNODE)
+ probe_node = jiffies & 0xFF;
/*
* Scan the networks.
*/
atif->status |= ATIF_PROBE;
- for(netct = 0; netct <= netrange; netct++)
- {
+ for (netct = 0; netct <= netrange; netct++) {
/*
* Sweep the available nodes from a given start.
*/
atif->address.s_net = htons(probe_net);
- for(nodect = 0; nodect < 256; nodect++)
- {
+ for (nodect = 0; nodect < 256; nodect++) {
atif->address.s_node = ((nodect+probe_node) & 0xFF);
- if(atif->address.s_node > 0 && atif->address.s_node<254)
- {
+ if (atif->address.s_node > 0 && atif->address.s_node < 254) {
/*
* Probe a proposed address.
*/
aarp_probe_network(atif);
- if(!(atif->status & ATIF_PROBE_FAIL)) {
+ if (!(atif->status & ATIF_PROBE_FAIL)) {
atif->status &= ~ATIF_PROBE;
- return (0);
+ return 0;
}
}
atif->status &= ~ATIF_PROBE_FAIL;
}
probe_net++;
- if(probe_net > ntohs(atif->nets.nr_lastnet))
+ if (probe_net > ntohs(atif->nets.nr_lastnet))
probe_net = ntohs(atif->nets.nr_firstnet);
}
atif->status &= ~ATIF_PROBE;
- return (-EADDRINUSE); /* Network is full... */
+
+ return -EADDRINUSE; /* Network is full... */
}
@@ -394,46 +432,43 @@ static int atif_probe_device(struct atalk_iface *atif)
*/
static int atif_proxy_probe_device(struct atalk_iface *atif, struct at_addr* proxy_addr)
{
- int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1;
- int probe_net=ntohs(atif->address.s_net); // we probe the interface's network
- int probe_node=ATADDR_ANYNODE; // we'll take anything
+ int netrange = ntohs(atif->nets.nr_lastnet) - ntohs(atif->nets.nr_firstnet) + 1;
+ int probe_net = ntohs(atif->address.s_net); /* we probe the interface's network */
+ int probe_node = ATADDR_ANYNODE; /* we'll take anything */
int netct, nodect;
/*
* Offset the network we start probing with.
*/
- if(probe_net == ATADDR_ANYNET)
- {
- if(!netrange)
+ if (probe_net == ATADDR_ANYNET) {
+ if (!netrange)
probe_net = ntohs(atif->nets.nr_firstnet);
else
- probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
+ probe_net = ntohs(atif->nets.nr_firstnet) + (jiffies % netrange);
}
- if(probe_node == ATADDR_ANYNODE)
- probe_node = jiffies&0xFF;
+ if (probe_node == ATADDR_ANYNODE)
+ probe_node = jiffies & 0xFF;
/*
* Scan the networks.
*/
- for(netct = 0; netct <= netrange; netct++)
- {
+ for (netct = 0; netct <= netrange; netct++) {
/*
* Sweep the available nodes from a given start.
*/
proxy_addr->s_net = htons(probe_net);
- for(nodect = 0; nodect < 256; nodect++)
- {
- proxy_addr->s_node = ((nodect+probe_node) & 0xFF);
- if((proxy_addr->s_node>0) && (proxy_addr->s_node<254))
- {
+ for (nodect = 0; nodect < 256; nodect++) {
+ proxy_addr->s_node = ((nodect + probe_node) & 0xFF);
+ if ((proxy_addr->s_node > 0) && (proxy_addr->s_node < 254)) {
/*
* Tell AARP to probe a proposed address.
*/
- int probe_result = aarp_proxy_probe_network(atif, proxy_addr);
+ int probe_result = aarp_proxy_probe_network(atif,
+ proxy_addr);
if (probe_result == 0)
return 0;
@@ -447,22 +482,23 @@ static int atif_proxy_probe_device(struct atalk_iface *atif, struct at_addr* pro
probe_net = ntohs(atif->nets.nr_firstnet);
}
- return (-EADDRINUSE); /* Network is full... */
+ return -EADDRINUSE; /* Network is full... */
}
struct at_addr *atalk_find_dev_addr(struct net_device *dev)
{
- struct atalk_iface *iface=dev->atalk_ptr;
+ struct atalk_iface *iface = dev->atalk_ptr;
if(iface)
- return (&iface->address);
+ return &iface->address;
- return (NULL);
+ return NULL;
}
static struct at_addr *atalk_find_primary(void)
{
+ struct at_addr *retval;
struct atalk_iface *iface;
struct atalk_iface *fiface = NULL;
@@ -470,20 +506,27 @@ static struct at_addr *atalk_find_primary(void)
* Return a point-to-point interface only if
* there is no non-ptp interface available.
*/
- for(iface=atalk_iface_list; iface != NULL; iface=iface->next)
- {
- if(!fiface && !(iface->dev->flags & IFF_LOOPBACK))
- fiface=iface;
- if(!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)))
- return (&iface->address);
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {
+ if (!fiface && !(iface->dev->flags & IFF_LOOPBACK))
+ fiface = iface;
+ if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
+ retval = &iface->address;
+ goto out;
+ }
}
- if(fiface)
- return (&fiface->address);
- if(atalk_iface_list != NULL)
- return (&atalk_iface_list->address);
- else
- return (NULL);
+ if (fiface) {
+ retval = &fiface->address;
+ } else if (atalk_iface_list != NULL) {
+ retval = &atalk_iface_list->address;
+ } else {
+ retval = NULL;
+ }
+out:
+ spin_unlock_bh(&atalk_iface_lock);
+
+ return retval;
}
/*
@@ -494,13 +537,15 @@ static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev)
{
struct atalk_iface *iface=dev->atalk_ptr;
- if(iface==NULL || (iface->status & ATIF_PROBE))
- return (NULL);
- if(node == ATADDR_BCAST || iface->address.s_node == node
- || node == ATADDR_ANYNODE)
- return (iface);
+ if (iface==NULL || (iface->status & ATIF_PROBE))
+ return NULL;
+
+ if (node == ATADDR_BCAST ||
+ iface->address.s_node == node ||
+ node == ATADDR_ANYNODE)
+ return iface;
- return (NULL);
+ return NULL;
}
/*
@@ -510,22 +555,24 @@ static struct atalk_iface *atalk_find_interface(int net, int node)
{
struct atalk_iface *iface;
- for(iface=atalk_iface_list; iface != NULL; iface=iface->next)
- {
- if((node==ATADDR_BCAST || node==ATADDR_ANYNODE
- || iface->address.s_node==node)
- && iface->address.s_net==net
- && !(iface->status & ATIF_PROBE))
- return (iface);
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {
+ if ((node == ATADDR_BCAST ||
+ node == ATADDR_ANYNODE ||
+ iface->address.s_node == node) &&
+ iface->address.s_net == net &&
+ !(iface->status & ATIF_PROBE))
+ break;
/* XXXX.0 -- net.0 returns the iface associated with net */
- if ((node==ATADDR_ANYNODE) && (net != ATADDR_ANYNET) &&
+ if ((node == ATADDR_ANYNODE) && (net != ATADDR_ANYNET) &&
(ntohs(iface->nets.nr_firstnet) <= ntohs(net)) &&
(ntohs(net) <= ntohs(iface->nets.nr_lastnet)))
- return (iface);
+ break;
}
+ spin_unlock_bh(&atalk_iface_lock);
- return (NULL);
+ return iface;
}
@@ -544,23 +591,20 @@ static struct atalk_route *atrtr_find(struct at_addr *target)
struct atalk_route *r;
struct atalk_route *net_route = NULL;
- for(r=atalk_router_list; r != NULL; r=r->next)
- {
- if(!(r->flags & RTF_UP))
+ read_lock_bh(&atalk_router_lock);
+ for (r = atalk_router_list; r != NULL; r = r->next) {
+ if (!(r->flags & RTF_UP))
continue;
- if(r->target.s_net == target->s_net)
- {
- if (r->flags & RTF_HOST)
- {
+
+ if (r->target.s_net == target->s_net) {
+ if (r->flags & RTF_HOST) {
/*
* if this host route is for the target,
* the we're done
*/
if (r->target.s_node == target->s_node)
- return (r);
- }
- else
- {
+ goto out;
+ } else {
/*
* this route will work if there isn't a
* direct host route, so cache it
@@ -574,13 +618,20 @@ static struct atalk_route *atrtr_find(struct at_addr *target)
* if we found a network route but not a direct host
* route, then return it
*/
- if (net_route != NULL)
- return (net_route);
-
- if(atrtr_default.dev)
- return (&atrtr_default);
+ if (net_route != NULL) {
+ r = net_route;
+ } else if (atrtr_default.dev) {
+ r = &atrtr_default;
+ } else {
+ /*
+ * No route can be found.
+ */
+ r = NULL;
+ }
- return (NULL);
+out:
+ read_unlock_bh(&atalk_router_lock);
+ return r;
}
@@ -590,12 +641,12 @@ static struct atalk_route *atrtr_find(struct at_addr *target)
*/
struct net_device *atrtr_get_dev(struct at_addr *sa)
{
- struct atalk_route *atr=atrtr_find(sa);
+ struct atalk_route *atr = atrtr_find(sa);
- if(atr == NULL)
- return (NULL);
+ if (atr == NULL)
+ return NULL;
else
- return (atr->dev);
+ return atr->dev;
}
/*
@@ -616,13 +667,11 @@ static void atrtr_set_default(struct net_device *dev)
*/
static int atrtr_create(struct rtentry *r, struct net_device *devhint)
{
- struct sockaddr_at *ta=(struct sockaddr_at *)&r->rt_dst;
- struct sockaddr_at *ga=(struct sockaddr_at *)&r->rt_gateway;
+ struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst;
+ struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway;
struct atalk_route *rt;
struct atalk_iface *iface, *riface;
- unsigned long flags;
-
- save_flags(flags);
+ int retval;
/*
* Fixme: Raise/Lower a routing change semaphore for these
@@ -632,53 +681,59 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint)
/*
* Validate the request
*/
- if(ta->sat_family != AF_APPLETALK)
- return (-EINVAL);
- if(devhint == NULL && ga->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (ta->sat_family != AF_APPLETALK)
+ return -EINVAL;
+
+ if (devhint == NULL && ga->sat_family != AF_APPLETALK)
+ return -EINVAL;
/*
* Now walk the routing table and make our decisions.
*/
- for(rt=atalk_router_list; rt!=NULL; rt=rt->next)
- {
- if(r->rt_flags != rt->flags)
+ write_lock_bh(&atalk_router_lock);
+ for (rt = atalk_router_list; rt != NULL; rt = rt->next) {
+ if (r->rt_flags != rt->flags)
continue;
- if(ta->sat_addr.s_net == rt->target.s_net)
- {
- if(!(rt->flags & RTF_HOST))
+ if (ta->sat_addr.s_net == rt->target.s_net) {
+ if (!(rt->flags & RTF_HOST))
break;
- if(ta->sat_addr.s_node == rt->target.s_node)
+ if (ta->sat_addr.s_node == rt->target.s_node)
break;
}
}
- if(devhint == NULL)
- {
- for(riface = NULL, iface = atalk_iface_list; iface; iface = iface->next)
- {
- if(riface == NULL && ntohs(ga->sat_addr.s_net) >= ntohs(iface->nets.nr_firstnet) &&
- ntohs(ga->sat_addr.s_net) <= ntohs(iface->nets.nr_lastnet))
- {
+ if(devhint == NULL) {
+ riface = NULL;
+
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface; iface = iface->next) {
+ if (riface == NULL &&
+ ntohs(ga->sat_addr.s_net) >= ntohs(iface->nets.nr_firstnet) &&
+ ntohs(ga->sat_addr.s_net) <= ntohs(iface->nets.nr_lastnet))
riface = iface;
- }
- if(ga->sat_addr.s_net == iface->address.s_net
- && ga->sat_addr.s_node == iface->address.s_node)
+
+ if (ga->sat_addr.s_net == iface->address.s_net &&
+ ga->sat_addr.s_node == iface->address.s_node)
riface = iface;
- }
+ }
+ spin_unlock_bh(&atalk_iface_lock);
+
+ retval = -ENETUNREACH;
+ if (riface == NULL)
+ goto out;
- if(riface == NULL)
- return (-ENETUNREACH);
devhint = riface->dev;
}
- if(rt == NULL)
- {
- rt = (struct atalk_route *)kmalloc(sizeof(struct atalk_route), GFP_KERNEL);
- if(rt == NULL)
- return (-ENOBUFS);
- cli();
+ if (rt == NULL) {
+ rt = (struct atalk_route *)
+ kmalloc(sizeof(struct atalk_route), GFP_ATOMIC);
+
+ retval = -ENOBUFS;
+ if (rt == NULL)
+ goto out;
+
rt->next = atalk_router_list;
atalk_router_list = rt;
}
@@ -691,33 +746,38 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint)
rt->flags = r->rt_flags;
rt->gateway = ga->sat_addr;
- restore_flags(flags);
+ retval = 0;
- return (0);
+out:
+ write_unlock_bh(&atalk_router_lock);
+
+ return retval;
}
/*
* Delete a route. Find it and discard it.
*/
-static int atrtr_delete( struct at_addr *addr )
+static int atrtr_delete(struct at_addr * addr)
{
struct atalk_route **r = &atalk_router_list;
struct atalk_route *tmp;
+ int retval = 0;
- while((tmp = *r) != NULL)
- {
- if(tmp->target.s_net == addr->s_net
- && (!(tmp->flags&RTF_GATEWAY)
- || tmp->target.s_node == addr->s_node))
- {
+ write_lock_bh(&atalk_router_lock);
+ while ((tmp = *r) != NULL) {
+ if (tmp->target.s_net == addr->s_net &&
+ (!(tmp->flags&RTF_GATEWAY) ||
+ tmp->target.s_node == addr->s_node)) {
*r = tmp->next;
kfree_s(tmp, sizeof(struct atalk_route));
- return (0);
+ goto out;
}
r = &tmp->next;
}
-
- return (-ENOENT);
+ retval = -ENOENT;
+out:
+ write_unlock_bh(&atalk_router_lock);
+ return retval;
}
/*
@@ -729,18 +789,18 @@ void atrtr_device_down(struct net_device *dev)
struct atalk_route **r = &atalk_router_list;
struct atalk_route *tmp;
- while((tmp = *r) != NULL)
- {
- if(tmp->dev == dev)
- {
+ write_lock_bh(&atalk_router_lock);
+ while ((tmp = *r) != NULL) {
+ if (tmp->dev == dev) {
*r = tmp->next;
kfree_s(tmp, sizeof(struct atalk_route));
- }
- else
+ } else {
r = &tmp->next;
+ }
}
+ write_unlock_bh(&atalk_router_lock);
- if(atrtr_default.dev == dev)
+ if (atrtr_default.dev == dev)
atrtr_set_default(NULL);
}
@@ -760,13 +820,12 @@ static inline void atalk_dev_down(struct net_device *dev)
*/
static int ddp_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{
- if(event == NETDEV_DOWN)
- {
+ if (event == NETDEV_DOWN) {
/* Discard any use of this */
atalk_dev_down((struct net_device *) ptr);
}
- return (NOTIFY_DONE);
+ return NOTIFY_DONE;
}
/*
@@ -789,29 +848,28 @@ int atif_ioctl(int cmd, void *arg)
struct rtentry rtdef;
int add_route;
- if(copy_from_user(&atreq,arg,sizeof(atreq)))
- return (-EFAULT);
+ if (copy_from_user(&atreq, arg, sizeof(atreq)))
+ return -EFAULT;
- if((dev = __dev_get_by_name(atreq.ifr_name)) == NULL)
- return (-ENODEV);
+ if ((dev = __dev_get_by_name(atreq.ifr_name)) == NULL)
+ return -ENODEV;
- sa=(struct sockaddr_at*)&atreq.ifr_addr;
- atif=atalk_find_dev(dev);
+ sa = (struct sockaddr_at*) &atreq.ifr_addr;
+ atif = atalk_find_dev(dev);
- switch(cmd)
- {
+ switch (cmd) {
case SIOCSIFADDR:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
- if(dev->type != ARPHRD_ETHER
- && dev->type != ARPHRD_LOOPBACK
- && dev->type != ARPHRD_LOCALTLK
- && dev->type != ARPHRD_PPP)
- return (-EPROTONOSUPPORT);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
+ if (dev->type != ARPHRD_ETHER &&
+ dev->type != ARPHRD_LOOPBACK &&
+ dev->type != ARPHRD_LOCALTLK &&
+ dev->type != ARPHRD_PPP)
+ return -EPROTONOSUPPORT;
- nr=(struct netrange *)&sa->sat_zero[0];
+ nr = (struct netrange *) &sa->sat_zero[0];
add_route = 1;
@@ -819,8 +877,8 @@ int atif_ioctl(int cmd, void *arg)
* if this is a point-to-point iface, and we already have an
* iface for this AppleTalk address, then we should not add a route
*/
- if (dev->flags & IFF_POINTOPOINT && atalk_find_interface(sa->sat_addr.s_net, sa->sat_addr.s_node))
- {
+ if ((dev->flags & IFF_POINTOPOINT) &&
+ atalk_find_interface(sa->sat_addr.s_net, sa->sat_addr.s_node)) {
printk(KERN_DEBUG "AppleTalk: point-to-point interface added with existing address\n");
add_route = 0;
}
@@ -829,123 +887,123 @@ int atif_ioctl(int cmd, void *arg)
* Phase 1 is fine on LocalTalk but we don't do
* EtherTalk phase 1. Anyone wanting to add it go ahead.
*/
- if(dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
- return (-EPROTONOSUPPORT);
- if(sa->sat_addr.s_node == ATADDR_BCAST
- || sa->sat_addr.s_node == 254)
- return (-EINVAL);
- if(atif)
- {
+ if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+ return -EPROTONOSUPPORT;
+ if (sa->sat_addr.s_node == ATADDR_BCAST ||
+ sa->sat_addr.s_node == 254)
+ return -EINVAL;
+ if (atif) {
/*
* Already setting address.
*/
- if(atif->status&ATIF_PROBE)
- return (-EBUSY);
+ if (atif->status & ATIF_PROBE)
+ return -EBUSY;
atif->address.s_net = sa->sat_addr.s_net;
atif->address.s_node = sa->sat_addr.s_node;
atrtr_device_down(dev); /* Flush old routes */
- }
- else
- {
- atif=atif_add_device(dev, &sa->sat_addr);
+ } else {
+ atif = atif_add_device(dev, &sa->sat_addr);
if (atif == NULL)
- return (-ENOMEM);
+ return -ENOMEM;
}
- atif->nets= *nr;
+ atif->nets = *nr;
/*
* Check if the chosen address is used. If so we
* error and atalkd will try another.
*/
- if(!(dev->flags & IFF_LOOPBACK) && !(dev->flags & IFF_POINTOPOINT) && atif_probe_device(atif) < 0)
- {
+ if (!(dev->flags & IFF_LOOPBACK) &&
+ !(dev->flags & IFF_POINTOPOINT) &&
+ atif_probe_device(atif) < 0) {
atif_drop_device(dev);
- return (-EADDRINUSE);
+ return -EADDRINUSE;
}
/*
* Hey it worked - add the direct routes.
*/
- sa = (struct sockaddr_at *)&rtdef.rt_gateway;
+ sa = (struct sockaddr_at *) &rtdef.rt_gateway;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_net = atif->address.s_net;
sa->sat_addr.s_node = atif->address.s_node;
- sa = (struct sockaddr_at *)&rtdef.rt_dst;
+ sa = (struct sockaddr_at *) &rtdef.rt_dst;
rtdef.rt_flags = RTF_UP;
sa->sat_family = AF_APPLETALK;
sa->sat_addr.s_node = ATADDR_ANYNODE;
- if((dev->flags & IFF_LOOPBACK) || (dev->flags & IFF_POINTOPOINT))
+ if ((dev->flags & IFF_LOOPBACK) ||
+ (dev->flags & IFF_POINTOPOINT))
rtdef.rt_flags |= RTF_HOST;
/*
* Routerless initial state.
*/
- if(nr->nr_firstnet == htons(0)
- && nr->nr_lastnet == htons(0xFFFE))
- {
+ if (nr->nr_firstnet == htons(0) &&
+ nr->nr_lastnet == htons(0xFFFE)) {
sa->sat_addr.s_net = atif->address.s_net;
atrtr_create(&rtdef, dev);
atrtr_set_default(dev);
- }
- else
- {
+ } else {
limit = ntohs(nr->nr_lastnet);
- if(limit - ntohs(nr->nr_firstnet) > 4096)
- {
+ if (limit - ntohs(nr->nr_firstnet) > 4096) {
printk(KERN_WARNING "Too many routes/iface.\n");
- return (-EINVAL);
+ return -EINVAL;
}
- if (add_route)
- for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++)
- {
+ if (add_route) {
+ for(ct = ntohs(nr->nr_firstnet);ct <= limit; ct++) {
sa->sat_addr.s_net = htons(ct);
atrtr_create(&rtdef, dev);
}
+ }
}
dev_mc_add(dev, aarp_mcast, 6, 1);
- return (0);
+ return 0;
case SIOCGIFADDR:
- if(atif == NULL)
- return (-EADDRNOTAVAIL);
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family=AF_APPLETALK;
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr=atif->address;
+ if (atif == NULL)
+ return -EADDRNOTAVAIL;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family =
+ AF_APPLETALK;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr =
+ atif->address;
break;
case SIOCGIFBRDADDR:
- if(atif == NULL)
- return (-EADDRNOTAVAIL);
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family=AF_APPLETALK;
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net=atif->address.s_net;
- ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST;
+ if (atif == NULL)
+ return -EADDRNOTAVAIL;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family =
+ AF_APPLETALK;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net =
+ atif->address.s_net;
+ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node =
+ ATADDR_BCAST;
break;
case SIOCATALKDIFADDR:
case SIOCDIFADDR:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
atalk_dev_down(dev);
break;
case SIOCSARP:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
if (atif == NULL)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
/*
* for now, we only support proxy AARP on ELAP;
* we should be able to do it for LocalTalk, too.
*/
- if(dev->type != ARPHRD_ETHER)
- return (-EPROTONOSUPPORT);
+ if (dev->type != ARPHRD_ETHER)
+ return -EPROTONOSUPPORT;
/*
* atif points to the current interface on this network;
@@ -954,28 +1012,28 @@ int atif_ioctl(int cmd, void *arg)
* to probe. consequently, it must exist.
*/
if (!atif)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
- nr=(struct netrange *)&(atif->nets);
+ nr = (struct netrange *) &(atif->nets);
/*
* Phase 1 is fine on Localtalk but we don't do
* Ethertalk phase 1. Anyone wanting to add it go ahead.
*/
- if(dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
- return (-EPROTONOSUPPORT);
+ if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+ return -EPROTONOSUPPORT;
- if(sa->sat_addr.s_node == ATADDR_BCAST
- || sa->sat_addr.s_node == 254)
- return (-EINVAL);
+ if (sa->sat_addr.s_node == ATADDR_BCAST ||
+ sa->sat_addr.s_node == 254)
+ return -EINVAL;
/*
* Check if the chosen address is used. If so we
* error and ATCP will try another.
*/
if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
- return (-EADDRINUSE);
+ return -EADDRINUSE;
- /*
+ /*
* We now have an address on the local network, and the AARP
* code will defend it for us until we take it down.
* We don't set up any routes right now, because ATCP will
@@ -984,25 +1042,25 @@ int atif_ioctl(int cmd, void *arg)
break;
case SIOCDARP:
- if(!capable(CAP_NET_ADMIN))
- return (-EPERM);
- if(sa->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
if (atif == NULL)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
/*
* give to aarp module to remove proxy entry
*/
aarp_proxy_remove(atif->dev, &(sa->sat_addr));
- return (0);
- }
+ return 0;
+ };
- if(copy_to_user(arg, &atreq, sizeof(atreq)))
- return (-EFAULT);
+ if (copy_to_user(arg, &atreq, sizeof(atreq)))
+ return -EFAULT;
- return (0);
+ return 0;
}
/*
@@ -1013,27 +1071,26 @@ static int atrtr_ioctl(unsigned int cmd, void *arg)
struct rtentry rt;
struct net_device *dev = NULL;
- if(copy_from_user(&rt, arg, sizeof(rt)))
- return (-EFAULT);
+ if (copy_from_user(&rt, arg, sizeof(rt)))
+ return -EFAULT;
- switch(cmd)
- {
+ switch (cmd) {
case SIOCDELRT:
- if(rt.rt_dst.sa_family != AF_APPLETALK)
- return (-EINVAL);
- return (atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr));
+ if (rt.rt_dst.sa_family != AF_APPLETALK)
+ return -EINVAL;
+ return atrtr_delete(&((struct sockaddr_at *)&rt.rt_dst)->sat_addr);
case SIOCADDRT:
/* FIX ME: the name of the device is still in user space, isn't it? */
- if (rt.rt_dev != NULL)
+ if (rt.rt_dev != NULL) {
if ((dev = __dev_get_by_name(rt.rt_dev)) == NULL)
- return -(ENODEV);
-
- return (atrtr_create(&rt, dev));
+ return -ENODEV;
+ }
+ return atrtr_create(&rt, dev);
default:
- return (-EINVAL);
- }
+ return -EINVAL;
+ };
}
/* Called from proc fs - just make it print the ifaces neatly */
@@ -1041,29 +1098,31 @@ static int atrtr_ioctl(unsigned int cmd, void *arg)
static int atalk_if_get_info(char *buffer, char **start, off_t offset, int length)
{
struct atalk_iface *iface;
- int len=0;
- off_t pos=0;
- off_t begin=0;
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
len += sprintf(buffer,"Interface Address Networks Status\n");
- for(iface = atalk_iface_list; iface != NULL; iface = iface->next)
- {
+
+ spin_lock_bh(&atalk_iface_lock);
+ for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {
len += sprintf(buffer+len,"%-16s %04X:%02X %04X-%04X %d\n",
- iface->dev->name, ntohs(iface->address.s_net),
- iface->address.s_node, ntohs(iface->nets.nr_firstnet),
- ntohs(iface->nets.nr_lastnet), iface->status);
+ iface->dev->name, ntohs(iface->address.s_net),
+ iface->address.s_node, ntohs(iface->nets.nr_firstnet),
+ ntohs(iface->nets.nr_lastnet), iface->status);
pos = begin + len;
- if(pos < offset)
- {
+ if (pos < offset) {
len = 0;
begin = pos;
}
- if(pos > offset + length)
+ if (pos > offset + length)
break;
}
+ spin_unlock_bh(&atalk_iface_lock);
+
*start = buffer + (offset - begin);
len -= (offset - begin);
- if(len > length)
+ if (len > length)
len = length;
return (len);
@@ -1074,41 +1133,40 @@ static int atalk_if_get_info(char *buffer, char **start, off_t offset, int lengt
static int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length)
{
struct atalk_route *rt;
- int len=0;
- off_t pos=0;
- off_t begin=0;
+ int len = 0;
+ off_t pos = 0;
+ off_t begin = 0;
len += sprintf(buffer,"Target Router Flags Dev\n");
- if(atrtr_default.dev)
- {
+ if (atrtr_default.dev) {
rt = &atrtr_default;
len += sprintf(buffer+len,"Default %04X:%02X %-4d %s\n",
- ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags,
- rt->dev->name);
+ ntohs(rt->gateway.s_net), rt->gateway.s_node,
+ rt->flags, rt->dev->name);
}
- for(rt = atalk_router_list; rt != NULL; rt = rt->next)
- {
+ read_lock_bh(&atalk_router_lock);
+ for (rt = atalk_router_list; rt != NULL; rt = rt->next) {
len += sprintf(buffer+len,"%04X:%02X %04X:%02X %-4d %s\n",
- ntohs(rt->target.s_net),rt->target.s_node,
- ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags,
- rt->dev->name);
+ ntohs(rt->target.s_net), rt->target.s_node,
+ ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags,
+ rt->dev->name);
pos = begin + len;
- if(pos < offset)
- {
+ if (pos < offset) {
len = 0;
begin = pos;
}
- if(pos > offset + length)
+ if (pos > offset + length)
break;
}
+ read_unlock_bh(&atalk_router_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
- if(len > length)
+ if (len > length)
len = length;
- return (len);
+ return len;
}
/**************************************************************************\
@@ -1124,27 +1182,25 @@ static int atalk_rt_get_info(char *buffer, char **start, off_t offset, int lengt
*/
unsigned short atalk_checksum(struct ddpehdr *ddp, int len)
{
- unsigned long sum=0; /* Assume unsigned long is >16 bits */
- unsigned char *data=(unsigned char *)ddp;
+ unsigned long sum = 0; /* Assume unsigned long is >16 bits */
+ unsigned char *data = (unsigned char *) ddp;
len -= 4; /* skip header 4 bytes */
data += 4;
/* This ought to be unwrapped neatly. I'll trust gcc for now */
- while(len--)
- {
+ while (len--) {
sum += *data;
sum <<= 1;
- if(sum & 0x10000)
- {
+ if (sum & 0x10000) {
sum++;
sum &= 0xFFFF;
}
data++;
}
- if(sum)
- return htons((unsigned short)sum);
+ if (sum)
+ return htons((unsigned short) sum);
return 0xFFFF; /* Use 0xFFFF for 0. 0 itself means none */
}
@@ -1158,11 +1214,10 @@ static int atalk_create(struct socket *sock, int protocol)
struct sock *sk;
sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, 1);
- if(sk == NULL)
- return (-ENOMEM);
+ if (sk == NULL)
+ return -ENOMEM;
- switch(sock->type)
- {
+ switch (sock->type) {
/*
* We permit SOCK_DGRAM and RAW is an extension. It is
* trivial to do and gives you the full ELAP frame.
@@ -1182,19 +1237,19 @@ static int atalk_create(struct socket *sock, int protocol)
break;
*/
default:
- sk_free((void *)sk);
- return (-ESOCKTNOSUPPORT);
- }
+ sk_free((void *) sk);
+ return -ESOCKTNOSUPPORT;
+ };
MOD_INC_USE_COUNT;
- sock_init_data(sock,sk);
+ sock_init_data(sock, sk);
sk->destruct = NULL;
/* Checksums on by default */
sk->zapped = 1;
- return (0);
+ return 0;
}
/*
@@ -1204,32 +1259,63 @@ static int atalk_release(struct socket *sock)
{
struct sock *sk=sock->sk;
- if(sk == NULL)
- return (0);
+ if (sk == NULL)
+ return 0;
- if(!sk->dead)
+ if (!sk->dead)
sk->state_change(sk);
sk->dead = 1;
sock->sk = NULL;
atalk_destroy_socket(sk);
- return (0);
+ return 0;
}
/*
- * Pick a source address if one is not given. Just return
- * an error if not supportable.
+ * Pick a source port when one is not given. If we can
+ * find a suitable free one, we insert the socket into
+ * the tables using it.
+ *
+ * This whole operation must be atomic.
*/
-static int atalk_pick_port(struct sockaddr_at *sat)
+static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat)
{
- for(sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++)
- {
- if(atalk_find_socket(sat) == NULL)
- return sat->sat_port;
+ struct sock *s;
+ int retval;
+
+ spin_lock_bh(&atalk_sockets_lock);
+
+ for (sat->sat_port = ATPORT_RESERVED;
+ sat->sat_port < ATPORT_LAST;
+ sat->sat_port++) {
+ for (s = atalk_sockets; s != NULL; s = s->next) {
+ if (s->protinfo.af_at.src_net == sat->sat_addr.s_net &&
+ s->protinfo.af_at.src_node == sat->sat_addr.s_node &&
+ s->protinfo.af_at.src_port == sat->sat_port)
+ goto try_next_port;
+ }
+
+ /* Wheee, it's free, assign and insert. */
+ if ((sk->next = atalk_sockets) != NULL)
+ atalk_sockets->pprev = &sk->next;
+ atalk_sockets = sk;
+ sk->pprev = &atalk_sockets;
+
+ sk->protinfo.af_at.src_port = sat->sat_port;
+
+ retval = 0;
+ goto out;
+
+ try_next_port:
+ ;
}
- return (-EBUSY);
+ retval = -EBUSY;
+out:
+ spin_unlock_bh(&atalk_sockets_lock);
+
+ return retval;
}
static int atalk_autobind(struct sock *sk)
@@ -1238,20 +1324,18 @@ static int atalk_autobind(struct sock *sk)
struct sockaddr_at sat;
int n;
- if(ap == NULL || ap->s_net == htons(ATADDR_ANYNET))
- return (-EADDRNOTAVAIL);
+ if (ap == NULL || ap->s_net == htons(ATADDR_ANYNET))
+ return -EADDRNOTAVAIL;
sk->protinfo.af_at.src_net = sat.sat_addr.s_net = ap->s_net;
sk->protinfo.af_at.src_node = sat.sat_addr.s_node = ap->s_node;
- if((n = atalk_pick_port(&sat)) < 0)
- return (n);
+ if ((n = atalk_pick_and_bind_port(sk, &sat)) < 0)
+ return n;
- sk->protinfo.af_at.src_port = n;
- atalk_insert_socket(sk);
sk->zapped = 0;
- return (0);
+ return 0;
}
/*
@@ -1260,95 +1344,87 @@ static int atalk_autobind(struct sock *sk)
static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk;
- struct sockaddr_at *addr=(struct sockaddr_at *)uaddr;
+ struct sockaddr_at *addr = (struct sockaddr_at *)uaddr;
sk = sock->sk;
if(sk->zapped == 0)
- return (-EINVAL);
+ return -EINVAL;
if(addr_len != sizeof(struct sockaddr_at))
- return (-EINVAL);
+ return -EINVAL;
if(addr->sat_family != AF_APPLETALK)
- return (-EAFNOSUPPORT);
+ return -EAFNOSUPPORT;
- if(addr->sat_addr.s_net == htons(ATADDR_ANYNET))
- {
- struct at_addr *ap=atalk_find_primary();
+ if(addr->sat_addr.s_net == htons(ATADDR_ANYNET)) {
+ struct at_addr *ap = atalk_find_primary();
if(ap == NULL)
- return (-EADDRNOTAVAIL);
+ return -EADDRNOTAVAIL;
sk->protinfo.af_at.src_net = addr->sat_addr.s_net = ap->s_net;
sk->protinfo.af_at.src_node = addr->sat_addr.s_node= ap->s_node;
- }
- else
- {
- if(atalk_find_interface(addr->sat_addr.s_net, addr->sat_addr.s_node) == NULL)
- return (-EADDRNOTAVAIL);
+ } else {
+ if (atalk_find_interface(addr->sat_addr.s_net, addr->sat_addr.s_node) == NULL)
+ return -EADDRNOTAVAIL;
sk->protinfo.af_at.src_net = addr->sat_addr.s_net;
sk->protinfo.af_at.src_node = addr->sat_addr.s_node;
}
- if(addr->sat_port == ATADDR_ANYPORT)
- {
- int n = atalk_pick_port(addr);
- if(n < 0)
- return (n);
+ if (addr->sat_port == ATADDR_ANYPORT) {
+ int n = atalk_pick_and_bind_port(sk, addr);
- sk->protinfo.af_at.src_port = addr->sat_port = n;
- }
- else
+ if (n < 0)
+ return n;
+ } else
sk->protinfo.af_at.src_port = addr->sat_port;
- if(atalk_find_socket(addr) != NULL)
- return (-EADDRINUSE);
+ if (atalk_find_or_insert_socket(sk, addr) != NULL)
+ return -EADDRINUSE;
- atalk_insert_socket(sk);
sk->zapped = 0;
- return (0);
+ return 0;
}
/*
* Set the address we talk to.
*/
static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
- int addr_len, int flags)
+ int addr_len, int flags)
{
- struct sock *sk=sock->sk;
+ struct sock *sk = sock->sk;
struct sockaddr_at *addr;
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
- if(addr_len != sizeof(*addr))
- return (-EINVAL);
+ if (addr_len != sizeof(*addr))
+ return -EINVAL;
+
addr = (struct sockaddr_at *)uaddr;
- if(addr->sat_family != AF_APPLETALK)
- return (-EAFNOSUPPORT);
+ if (addr->sat_family != AF_APPLETALK)
+ return -EAFNOSUPPORT;
- if(addr->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast)
- {
+ if (addr->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) {
#if 1
printk(KERN_WARNING "%s is broken and did not set SO_BROADCAST. It will break when 2.2 is released.\n",
current->comm);
#else
- return (-EACCES);
+ return -EACCES;
#endif
}
- if(sk->zapped)
- {
- if(atalk_autobind(sk) < 0)
- return (-EBUSY);
+ if (sk->zapped) {
+ if (atalk_autobind(sk) < 0)
+ return -EBUSY;
}
- if(atrtr_get_dev(&addr->sat_addr) == NULL)
- return (-ENETUNREACH);
+ if (atrtr_get_dev(&addr->sat_addr) == NULL)
+ return -ENETUNREACH;
sk->protinfo.af_at.dest_port = addr->sat_port;
sk->protinfo.af_at.dest_net = addr->sat_addr.s_net;
@@ -1357,7 +1433,7 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
sock->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
- return (0);
+ return 0;
}
@@ -1366,30 +1442,27 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
* fields into the sockaddr.
*/
static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
+ int *uaddr_len, int peer)
{
struct sockaddr_at sat;
struct sock *sk;
sk = sock->sk;
- if(sk->zapped)
- {
- if(atalk_autobind(sk) < 0)
- return (-ENOBUFS);
+ if (sk->zapped) {
+ if (atalk_autobind(sk) < 0)
+ return -ENOBUFS;
}
*uaddr_len = sizeof(struct sockaddr_at);
- if(peer)
- {
- if(sk->state != TCP_ESTABLISHED)
- return (-ENOTCONN);
+ if (peer) {
+ if (sk->state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+
sat.sat_addr.s_net = sk->protinfo.af_at.dest_net;
sat.sat_addr.s_node = sk->protinfo.af_at.dest_node;
sat.sat_port = sk->protinfo.af_at.dest_port;
- }
- else
- {
+ } else {
sat.sat_addr.s_net = sk->protinfo.af_at.src_net;
sat.sat_addr.s_node = sk->protinfo.af_at.src_node;
sat.sat_port = sk->protinfo.af_at.src_port;
@@ -1398,7 +1471,7 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
sat.sat_family = AF_APPLETALK;
memcpy(uaddr, &sat, sizeof(sat));
- return (0);
+ return 0;
}
/*
@@ -1411,17 +1484,16 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct sock *sock;
- struct ddpehdr *ddp=(void *)skb->h.raw;
+ struct ddpehdr *ddp = (void *) skb->h.raw;
struct atalk_iface *atif;
struct sockaddr_at tosat;
int origlen;
struct ddpebits ddphv;
/* Size check */
- if(skb->len < sizeof(*ddp))
- {
+ if (skb->len < sizeof(*ddp)) {
kfree_skb(skb);
- return (0);
+ return 0;
}
/*
@@ -1449,26 +1521,24 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
* (Otherwise we'll detonate most spectacularly
* in the middle of recvmsg()).
*/
- if(skb->len < sizeof(*ddp))
- {
+ if (skb->len < sizeof(*ddp)) {
kfree_skb(skb);
- return (0);
+ return 0;
}
/*
* Any checksums. Note we don't do htons() on this == is assumed to be
* valid for net byte orders all over the networking code...
*/
- if(ddp->deh_sum && atalk_checksum(ddp, ddphv.deh_len) != ddp->deh_sum)
- {
+ if (ddp->deh_sum && atalk_checksum(ddp, ddphv.deh_len) != ddp->deh_sum) {
/* Not a valid AppleTalk frame - dustbin time */
kfree_skb(skb);
- return (0);
+ return 0;
}
/* Check the packet is aimed at us */
- if(ddp->deh_dnet == 0) /* Net 0 is 'this network' */
+ if (ddp->deh_dnet == 0) /* Net 0 is 'this network' */
atif = atalk_find_anynet(ddp->deh_dnode, dev);
else
atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);
@@ -1476,8 +1546,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
/*
* Not ours, so we route the packet via the correct AppleTalk interface.
*/
- if(atif == NULL)
- {
+ if (atif == NULL) {
struct atalk_route *rt;
struct at_addr ta;
@@ -1485,8 +1554,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
* Don't route multicast, etc., packets, or packets
* sent to "this network"
*/
- if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0)
- {
+ if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0) {
/*
* FIX ME:
* Can it ever happen that a packet is from a PPP iface and needs to be broadcast onto the default network?
@@ -1495,7 +1563,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
printk(KERN_DEBUG "AppleTalk: didn't forward broadcast packet received from PPP iface\n");
kfree_skb(skb);
- return (0);
+ return 0;
}
ta.s_net = ddp->deh_dnet;
@@ -1503,10 +1571,9 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
/* Route the packet */
rt = atrtr_find(&ta);
- if(rt == NULL || ddphv.deh_hops == DDP_MAXHOPS)
- {
+ if (rt == NULL || ddphv.deh_hops == DDP_MAXHOPS) {
kfree_skb(skb);
- return (0);
+ return 0;
}
ddphv.deh_hops++;
@@ -1514,8 +1581,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
* Route goes through another gateway, so
* set the target to the gateway instead.
*/
- if(rt->flags & RTF_GATEWAY)
- {
+ if (rt->flags & RTF_GATEWAY) {
ta.s_net = rt->gateway.s_net;
ta.s_node = rt->gateway.s_node;
}
@@ -1539,7 +1605,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
*
* Note. ddp-> becomes invalid at the realloc.
*/
- if(skb_headroom(skb) < 22)
+ if (skb_headroom(skb) < 22)
/* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */
skb = skb_realloc_headroom(skb, 32);
else
@@ -1549,26 +1615,24 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
* If the buffer didn't vanish into the lack of
* space bitbucket we can send it.
*/
- if(skb)
- {
- if(aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1)
+ if (skb) {
+ if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1)
kfree_skb(skb);
}
- return (0);
+ return 0;
}
#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)
/*
* Check if IP-over-DDP
*/
- if(skb->data[12] == 22)
- {
+ if (skb->data[12] == 22) {
struct net_device *dev;
/* This needs to be able to handle ipddp"N" devices */
- if((dev = __dev_get_by_name("ipddp0")) == NULL)
- return (-ENODEV);
+ if ((dev = __dev_get_by_name("ipddp0")) == NULL)
+ return -ENODEV;
skb->protocol = htons(ETH_P_IP);
skb_pull(skb, 13);
@@ -1576,10 +1640,10 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
skb->h.raw = skb->data;
((struct net_device_stats *)dev->priv)->rx_packets++;
- ((struct net_device_stats *)dev->priv)->rx_bytes += skb->len+13;
+ ((struct net_device_stats *)dev->priv)->rx_bytes += skb->len + 13;
netif_rx(skb); /* Send the SKB up to a higher place. */
- return (0);
+ return 0;
}
#endif
@@ -1593,10 +1657,10 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
sock = atalk_search_socket(&tosat, atif);
- if(sock == NULL) /* But not one of our sockets */
- {
+ if (sock == NULL) {
+ /* But not one of our sockets */
kfree_skb(skb);
- return (0);
+ return 0;
}
/*
@@ -1605,10 +1669,10 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
skb->sk = sock;
- if(sock_queue_rcv_skb(sock, skb) < 0)
+ if (sock_queue_rcv_skb(sock, skb) < 0)
kfree_skb(skb);
- return (0);
+ return 0;
}
/*
@@ -1624,17 +1688,15 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
/*
* Expand any short form frames.
*/
- if(skb->mac.raw[2] == 1)
- {
+ if (skb->mac.raw[2] == 1) {
/*
* Find our address.
*/
ap = atalk_find_dev_addr(dev);
- if(ap == NULL || skb->len < sizeof(struct ddpshdr))
- {
+ if (ap == NULL || skb->len < sizeof(struct ddpshdr)) {
kfree_skb(skb);
- return (0);
+ return 0;
}
/*
@@ -1673,57 +1735,51 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_
}
skb->h.raw = skb->data;
- return (atalk_rcv(skb, dev, pt));
+ return atalk_rcv(skb, dev, pt);
}
-static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
- struct scm_cookie *scm)
+static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
{
- struct sock *sk=sock->sk;
- struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name;
+ struct sock *sk = sock->sk;
+ struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name;
struct sockaddr_at local_satalk, gsat;
struct sk_buff *skb;
struct net_device *dev;
struct ddpehdr *ddp;
int size;
struct atalk_route *rt;
- int loopback=0;
+ int loopback = 0;
int err;
int flags = msg->msg_flags;
- if(flags & ~MSG_DONTWAIT)
- return (-EINVAL);
+ if (flags & ~MSG_DONTWAIT)
+ return -EINVAL;
- if(len > DDP_MAXSZ)
- return (-EMSGSIZE);
+ if (len > DDP_MAXSZ)
+ return -EMSGSIZE;
- if(usat)
- {
- if(sk->zapped)
- {
- if(atalk_autobind(sk) < 0)
- return (-EBUSY);
+ if (usat) {
+ if(sk->zapped) {
+ if (atalk_autobind(sk) < 0)
+ return -EBUSY;
}
- if(msg->msg_namelen < sizeof(*usat))
- return (-EINVAL);
- if(usat->sat_family != AF_APPLETALK)
- return (-EINVAL);
+ if (msg->msg_namelen < sizeof(*usat))
+ return -EINVAL;
+ if (usat->sat_family != AF_APPLETALK)
+ return -EINVAL;
/* netatalk doesn't implement this check */
- if(usat->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast)
- {
+ if (usat->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) {
printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as it will break before 2.2\n");
#if 0
- return (-EPERM);
+ return -EPERM;
#endif
}
- }
- else
- {
- if(sk->state != TCP_ESTABLISHED)
- return (-ENOTCONN);
- usat =& local_satalk;
+ } else {
+ if (sk->state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+ usat = &local_satalk;
usat->sat_family = AF_APPLETALK;
usat->sat_port = sk->protinfo.af_at.dest_port;
usat->sat_addr.s_node = sk->protinfo.af_at.dest_node;
@@ -1732,26 +1788,27 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
/* Build a packet */
- SOCK_DEBUG(sk, "SK %p: Got address.\n",sk);
+ SOCK_DEBUG(sk, "SK %p: Got address.\n", sk);
/* For headers */
size = sizeof(struct ddpehdr) + len + ddp_dl->header_length;
- if(usat->sat_addr.s_net != 0 || usat->sat_addr.s_node == ATADDR_ANYNODE)
- {
+ if (usat->sat_addr.s_net != 0 || usat->sat_addr.s_node == ATADDR_ANYNODE) {
rt = atrtr_find(&usat->sat_addr);
- if(rt == NULL)
- return (-ENETUNREACH);
+ if (rt == NULL)
+ return -ENETUNREACH;
+
dev = rt->dev;
- }
- else
- {
+ } else {
struct at_addr at_hint;
+
at_hint.s_node = 0;
at_hint.s_net = sk->protinfo.af_at.src_net;
+
rt = atrtr_find(&at_hint);
- if(rt == NULL)
- return (-ENETUNREACH);
+ if (rt == NULL)
+ return -ENETUNREACH;
+
dev = rt->dev;
}
@@ -1759,9 +1816,9 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
size += dev->hard_header_len;
- skb = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
- if(skb == NULL)
- return (err);
+ skb = sock_alloc_send_skb(sk, size, 0, (flags & MSG_DONTWAIT), &err);
+ if (skb == NULL)
+ return err;
skb->sk = sk;
skb_reserve(skb, ddp_dl->header_length);
@@ -1771,7 +1828,7 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
- ddp = (struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr));
+ ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));
ddp->deh_pad = 0;
ddp->deh_hops = 0;
ddp->deh_len = len + sizeof(*ddp);
@@ -1791,14 +1848,13 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
SOCK_DEBUG(sk, "SK %p: Copy user data (%d bytes).\n", sk, len);
- err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
- if(err)
- {
+ err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+ if (err) {
kfree_skb(skb);
- return (-EFAULT);
+ return -EFAULT;
}
- if(sk->no_check == 1)
+ if (sk->no_check == 1)
ddp->deh_sum = 0;
else
ddp->deh_sum = atalk_checksum(ddp, len + sizeof(*ddp));
@@ -1807,24 +1863,20 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
* Loopback broadcast packets to non gateway targets (ie routes
* to group we are in)
*/
- if(ddp->deh_dnode == ATADDR_BCAST)
- {
- if((!(rt->flags&RTF_GATEWAY)) && (!(dev->flags&IFF_LOOPBACK)))
- {
+ if (ddp->deh_dnode == ATADDR_BCAST) {
+ if ((!(rt->flags&RTF_GATEWAY)) && (!(dev->flags&IFF_LOOPBACK))) {
struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL);
- if(skb2)
- {
+ if (skb2) {
loopback = 1;
SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk);
- if(aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL) == -1)
+ if (aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL) == -1)
kfree_skb(skb2);
/* else queued/sent above in the aarp queue */
}
}
}
- if((dev->flags & IFF_LOOPBACK) || loopback)
- {
+ if ((dev->flags & IFF_LOOPBACK) || loopback) {
SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
/* loop back */
skb_orphan(skb);
@@ -1834,70 +1886,60 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
skb_pull(skb,dev->hard_header_len);
skb_pull(skb,ddp_dl->header_length);
atalk_rcv(skb, dev, NULL);
- }
- else
- {
+ } else {
SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
- if (rt->flags & RTF_GATEWAY)
- {
+ if (rt->flags & RTF_GATEWAY) {
gsat.sat_addr = rt->gateway;
usat = &gsat;
}
- if(aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1)
+ if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1)
kfree_skb(skb);
/* else queued/sent above in the aarp queue */
}
SOCK_DEBUG(sk, "SK %p: Done write (%d).\n", sk, len);
- return (len);
+ return len;
}
static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size,
- int flags, struct scm_cookie *scm)
+ int flags, struct scm_cookie *scm)
{
- struct sock *sk=sock->sk;
- struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name;
+ struct sock *sk = sock->sk;
+ struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
struct ddpehdr *ddp = NULL;
struct ddpebits ddphv;
int copied = 0;
struct sk_buff *skb;
int err = 0;
-
- skb = skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&err);
- if(skb == NULL)
- return (err);
+ skb = skb_recv_datagram(sk, (flags & ~MSG_DONTWAIT),
+ (flags & MSG_DONTWAIT), &err);
+ if (skb == NULL)
+ return err;
ddp = (struct ddpehdr *)(skb->h.raw);
*((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
- if(sk->type == SOCK_RAW)
- {
+ if (sk->type == SOCK_RAW) {
copied = ddphv.deh_len;
- if(copied > size)
- {
+ if (copied > size) {
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
- }
- else
- {
+ } else {
copied = ddphv.deh_len - sizeof(*ddp);
- if(copied > size)
- {
+ if (copied > size) {
copied = size;
msg->msg_flags |= MSG_TRUNC;
}
- err = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied);
+ err = skb_copy_datagram_iovec(skb, sizeof(*ddp), msg->msg_iov, copied);
}
- if(!err)
- {
- if(sat)
- {
+ if (!err) {
+ if (sat) {
sat->sat_family = AF_APPLETALK;
sat->sat_port = ddp->deh_sport;
sat->sat_addr.s_node = ddp->deh_snode;
@@ -1908,7 +1950,7 @@ static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size,
skb_free_datagram(sk, skb); /* Free the datagram. */
- return (err ? err : (copied));
+ return err ? err : copied;
}
diff --git a/net/decnet/Config.in b/net/decnet/Config.in
index b11cdfa22..c019d3f59 100644
--- a/net/decnet/Config.in
+++ b/net/decnet/Config.in
@@ -5,7 +5,6 @@ bool ' DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' DECnet: router support (EXPERIMENTAL)' CONFIG_DECNET_ROUTER
if [ "$CONFIG_DECNET_ROUTER" = "y" ]; then
- bool ' DECnet: use FWMARK value as routing key' CONFIG_DECNET_ROUTE_FWMARK
+ bool ' DECnet: use FWMARK value as routing key (EXPERIMENTAL)' CONFIG_DECNET_ROUTE_FWMARK
fi
fi
-bool ' DECnet: raw socket support' CONFIG_DECNET_RAW
diff --git a/net/decnet/Makefile b/net/decnet/Makefile
index 1eeef6b40..03d35cc9c 100644
--- a/net/decnet/Makefile
+++ b/net/decnet/Makefile
@@ -8,10 +8,6 @@ ifeq ($(CONFIG_DECNET_ROUTER),y)
O_OBJS += dn_fib.o dn_rules.o dn_table.o
endif
-ifeq ($(CONFIG_DECNET_RAW),y)
-O_OBJS += dn_raw.o
-endif
-
ifeq ($(CONFIG_DECNET_FW),y)
O_OBJS += dn_fw.o
endif
diff --git a/net/decnet/TODO b/net/decnet/TODO
index 0f5c3a649..72ab936a2 100644
--- a/net/decnet/TODO
+++ b/net/decnet/TODO
@@ -4,8 +4,6 @@ Steve's quick list of things that need finishing off:
o Proper timeouts on each neighbour (in routing mode) rather than
just the 60 second On-Ethernet cache value.
- o Misc. get/set_sockopt() functions [done for the time being, more later]
-
o Support for X.25 linklayer
o Support for DDCMP link layer
@@ -14,10 +12,6 @@ Steve's quick list of things that need finishing off:
o PPP support (rfc1762)
- o sendmsg() in the raw socket layer (yes, its for sending routing messages)
-
- o Fix /proc for raw sockets
-
o Lots of testing with real applications
o Verify errors etc. against POSIX 1003.1g (draft)
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 7860597ab..a2453c06a 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -123,7 +123,6 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
#include <net/dn_dev.h>
#include <net/dn_route.h>
#include <net/dn_fib.h>
-#include <net/dn_raw.h>
#include <net/dn_neigh.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
@@ -401,11 +400,6 @@ struct sock *dn_alloc_sock(struct socket *sock, int flags)
goto no_sock;
if (sock) {
-#ifdef CONFIG_DECNET_RAW
- if (sock->type == SOCK_RAW)
- sock->ops = &dn_raw_proto_ops;
- else
-#endif /* CONFIG_DECNET_RAW */
sock->ops = &dn_proto_ops;
}
sock_init_data(sock,sk);
@@ -647,13 +641,6 @@ static int dn_create(struct socket *sock, int protocol)
break;
case SOCK_STREAM:
break;
-#ifdef CONFIG_DECNET_RAW
- case SOCK_RAW:
- if ((protocol != DNPROTO_NSP) &&
- (protocol != DNPROTO_ROU))
- return -EPROTONOSUPPORT;
- break;
-#endif /* CONFIG_DECNET_RAW */
default:
return -ESOCKTNOSUPPORT;
}
@@ -1095,6 +1082,7 @@ static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table
static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
+ struct dn_scp *scp = &sk->protinfo.dn;
int err = -EOPNOTSUPP;
unsigned long amount = 0;
struct sk_buff *skb;
@@ -1221,8 +1209,17 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case TIOCINQ:
lock_sock(sk);
- if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+ if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) {
amount = skb->len;
+ } else {
+ struct sk_buff *skb = sk->receive_queue.next;
+ for(;;) {
+ if (skb == (struct sk_buff *)&sk->receive_queue)
+ break;
+ amount += skb->len;
+ skb = skb->next;
+ }
+ }
release_sock(sk);
err = put_user(amount, (int *)arg);
break;
@@ -2028,11 +2025,7 @@ static int dn_get_info(char *buffer, char **start, off_t offset, int length)
return len;
}
-#ifdef CONFIG_DECNET_RAW
-
-extern int dn_raw_get_info(char *, char **, off_t, int);
-#endif /* CONFIG_DECNET_RAW */
static struct net_proto_family dn_family_ops = {
AF_DECnet,
dn_create
@@ -2066,16 +2059,14 @@ void dn_unregister_sysctl(void);
void __init decnet_proto_init(struct net_proto *pro)
{
- printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.38s (C) 1995-1999 Linux DECnet Project Team\n");
+ printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.49s (C) 1995-2000 Linux DECnet Project Team\n");
sock_register(&dn_family_ops);
dev_add_pack(&dn_dix_packet_type);
register_netdevice_notifier(&dn_dev_notifier);
proc_net_create("decnet", 0, dn_get_info);
-#ifdef CONFIG_DECNET_RAW
- proc_net_create("decnet_raw", 0, dn_raw_get_info);
-#endif
+
dn_neigh_init();
dn_dev_init();
dn_route_init();
@@ -2153,9 +2144,6 @@ void __exit cleanup_module(void)
#endif /* CONFIG_DECNET_ROUTER */
proc_net_remove("decnet");
-#ifdef CONFIG_DECNET_RAW
- proc_net_remove("decnet_raw");
-#endif
dev_remove_pack(&dn_dix_packet_type);
sock_unregister(AF_DECnet);
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 66c72b4bd..854ed0e92 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -70,7 +70,6 @@
#include <net/dn_nsp.h>
#include <net/dn_dev.h>
#include <net/dn_route.h>
-#include <net/dn_raw.h>
/*
@@ -320,7 +319,7 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
struct dn_scp *scp = &sk->protinfo.dn;
unsigned short reason;
- if (skb->len < 2)
+ if (skb->len != 2)
goto out;
reason = dn_ntohs(*(__u16 *)skb->data);
@@ -552,10 +551,6 @@ static int dn_nsp_rx_packet(struct sk_buff *skb)
if (decnet_debug_level & 2)
printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
-#ifdef CONFIG_DECNET_RAW
- dn_raw_rx_nsp(skb);
-#endif /* CONFIG_DECNET_RAW */
-
if (skb->len < 2)
goto free_out;
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index e4d0adad3..ebbf4163f 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -511,7 +511,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
int ddl, unsigned char *dd, __u16 rem, __u16 loc)
{
struct sk_buff *skb = NULL;
- int size = 8 + ddl;
+ int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0);
unsigned char *msg;
if ((dst == NULL) || (rem == 0)) {
@@ -531,7 +531,8 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
msg += 2;
*(__u16 *)msg = dn_htons(reason);
msg += 2;
- *msg++ = ddl;
+ if (msgflg == NSP_DISCINIT)
+ *msg++ = ddl;
if (ddl) {
memcpy(msg, dd, ddl);
diff --git a/net/decnet/dn_raw.c b/net/decnet/dn_raw.c
deleted file mode 100644
index 90e9b2bad..000000000
--- a/net/decnet/dn_raw.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * DECnet An implementation of the DECnet protocol suite for the LINUX
- * operating system. DECnet is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * DECnet Raw Sockets Interface
- *
- * Author: Steve Whitehouse <SteveW@ACM.org>
- *
- *
- * Changes:
- * Steve Whitehouse - connect() function.
- * Steve Whitehouse - SMP changes, removed MOP stubs. MOP will
- * be userland only.
- */
-
-#include <linux/config.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <net/sock.h>
-#include <net/dst.h>
-#include <net/dn.h>
-#include <net/dn_raw.h>
-#include <net/dn_route.h>
-
-static rwlock_t dn_raw_hash_lock = RW_LOCK_UNLOCKED;
-static struct sock *dn_raw_nsp_sklist = NULL;
-static struct sock *dn_raw_routing_sklist = NULL;
-
-static void dn_raw_hash(struct sock *sk)
-{
- struct sock **skp;
-
- switch(sk->protocol) {
- case DNPROTO_NSP:
- skp = &dn_raw_nsp_sklist;
- break;
- case DNPROTO_ROU:
- skp = &dn_raw_routing_sklist;
- break;
- default:
- printk(KERN_DEBUG "dn_raw_hash: Unknown protocol\n");
- return;
- }
-
- write_lock_bh(&dn_raw_hash_lock);
- sk->next = *skp;
- sk->pprev = skp;
- *skp = sk;
- write_unlock_bh(&dn_raw_hash_lock);
-}
-
-static void dn_raw_unhash(struct sock *sk)
-{
- struct sock **skp = sk->pprev;
-
- if (skp == NULL)
- return;
-
- write_lock_bh(&dn_raw_hash_lock);
- while(*skp != sk)
- skp = &((*skp)->next);
- *skp = sk->next;
- write_unlock_bh(&dn_raw_hash_lock);
-
- sk->next = NULL;
- sk->pprev = NULL;
-}
-
-static void dn_raw_autobind(struct sock *sk)
-{
- dn_raw_hash(sk);
- sk->zapped = 0;
-}
-
-static int dn_raw_release(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- if (sk == NULL)
- return 0;
-
- if (!sk->dead) sk->state_change(sk);
-
- sk->dead = 1;
- sk->socket = NULL;
- sock->sk = NULL;
-
- dn_raw_unhash(sk);
- sock_put(sk);
-
- return 0;
-}
-
-/*
- * Bind does odd things with raw sockets. Its basically used to filter
- * the incoming packets, but this differs with the different layers
- * at which you extract packets.
- *
- * For Routing layer sockets, the object name is a host ordered unsigned
- * short which is a mask for the 16 different types of possible routing
- * packet. I'd like to also select by destination address of the packets
- * but alas, this is rather too difficult to do at the moment.
- */
-static int dn_raw_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
-{
- struct sock *sk = sock->sk;
- struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr;
-
- if (addr_len != sizeof(struct sockaddr_dn))
- return -EINVAL;
-
- if (sk->zapped == 0)
- return -EINVAL;
-
- switch(sk->protocol) {
- case DNPROTO_ROU:
- if (dn_ntohs(addr->sdn_objnamel) && (dn_ntohs(addr->sdn_objnamel) != 2))
- return -EINVAL;
- /* Fall through here */
- case DNPROTO_NSP:
- if (dn_ntohs(addr->sdn_add.a_len) && (dn_ntohs(addr->sdn_add.a_len) != 2))
- return -EINVAL;
- break;
- default:
- return -EPROTONOSUPPORT;
- }
-
- if (dn_ntohs(addr->sdn_objnamel) > (DN_MAXOBJL-1))
- return -EINVAL;
-
- if (dn_ntohs(addr->sdn_add.a_len) > DN_MAXADDL)
- return -EINVAL;
-
- memcpy(&sk->protinfo.dn.addr, addr, sizeof(struct sockaddr_dn));
-
- dn_raw_autobind(sk);
-
- return 0;
-}
-
-/*
- * This is to allow send() and write() to work. You set the destination address
- * with this function.
- */
-static int dn_raw_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
-{
- struct sock *sk = sock->sk;
- struct dn_scp *scp = &sk->protinfo.dn;
- struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
- int err;
-
- lock_sock(sk);
-
- err = -EINVAL;
- if (addr_len != sizeof(struct sockaddr_dn))
- goto out;
-
- if (saddr->sdn_family != AF_DECnet)
- goto out;
-
- if (dn_ntohs(saddr->sdn_objnamel) > (DN_MAXOBJL-1))
- goto out;
-
- if (dn_ntohs(saddr->sdn_add.a_len) > DN_MAXADDL)
- goto out;
-
- if (sk->zapped)
- dn_raw_autobind(sk);
-
- if ((err = dn_route_output(&sk->dst_cache, dn_saddr2dn(saddr), dn_saddr2dn(&scp->addr), 0)) < 0)
- goto out;
-
- memcpy(&scp->peer, saddr, sizeof(struct sockaddr_dn));
-out:
- release_sock(sk);
-
- return err;
-}
-
-/*
- * TBD.
- */
-static int dn_raw_sendmsg(struct socket *sock, struct msghdr *hdr, int size,
- struct scm_cookie *scm)
-{
- struct sock *sk = sock->sk;
-
- if (sk->zapped)
- dn_raw_autobind(sk);
-
- if (sk->protocol != DNPROTO_NSP)
- return -EOPNOTSUPP;
-
- return 0;
-}
-
-/*
- * This works fine, execpt that it doesn't report the originating address
- * or anything at the moment.
- */
-static int dn_raw_recvmsg(struct socket *sock, struct msghdr *msg, int size,
- int flags, struct scm_cookie *scm)
-{
- struct sock *sk = sock->sk;
- struct sk_buff *skb;
- int err = 0;
- int copied = 0;
-
- lock_sock(sk);
-
- if (sk->zapped)
- dn_raw_autobind(sk);
-
- if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err)) == NULL)
- goto out;
-
- copied = skb->len;
-
- if (copied > size) {
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
-
- if ((err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied)) != 0) {
- if (flags & MSG_PEEK)
- atomic_dec(&skb->users);
- else
- skb_queue_head(&sk->receive_queue, skb);
-
- goto out;
- }
-
- skb_free_datagram(sk, skb);
-
-out:
- release_sock(sk);
-
- return copied ? copied : err;
-}
-
-struct proto_ops dn_raw_proto_ops = {
- AF_DECnet,
-
- dn_raw_release,
- dn_raw_bind,
- dn_raw_connect,
- sock_no_socketpair,
- sock_no_accept,
- sock_no_getname,
- datagram_poll,
- sock_no_ioctl,
- sock_no_listen,
- sock_no_shutdown,
- sock_no_setsockopt,
- sock_no_getsockopt,
- sock_no_fcntl,
- dn_raw_sendmsg,
- dn_raw_recvmsg,
- sock_no_mmap
-};
-
-#ifdef CONFIG_PROC_FS
-int dn_raw_get_info(char *buffer, char **start, off_t offset, int length)
-{
- int len = 0;
- off_t pos = 0;
- off_t begin = 0;
- struct sock *sk;
-
- read_lock_bh(&dn_raw_hash_lock);
- for(sk = dn_raw_nsp_sklist; sk; sk = sk->next) {
- len += sprintf(buffer+len, "NSP\n");
-
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
-
- if (pos > offset + length)
- goto all_done;
-
- }
-
- for(sk = dn_raw_routing_sklist; sk; sk = sk->next) {
- len += sprintf(buffer+len, "ROU\n");
-
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
-
- if (pos > offset + length)
- goto all_done;
- }
-
-all_done:
- read_unlock_bh(&dn_raw_hash_lock);
-
- *start = buffer + (offset - begin);
- len -= (offset - begin);
-
- if (len > length) len = length;
-
- return(len);
-}
-#endif /* CONFIG_PROC_FS */
-
-void dn_raw_rx_nsp(struct sk_buff *skb)
-{
- struct sock *sk;
- struct sk_buff *skb2;
-
- read_lock(&dn_raw_hash_lock);
- for(sk = dn_raw_nsp_sklist; sk != NULL; sk = sk->next) {
- if (skb->len > sock_rspace(sk))
- continue;
- if (sk->dead)
- continue;
- if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
- skb_set_owner_r(skb2, sk);
- skb_queue_tail(&sk->receive_queue, skb2);
- sk->data_ready(sk, skb->len);
- }
- }
- read_unlock(&dn_raw_hash_lock);
-}
-
-void dn_raw_rx_routing(struct sk_buff *skb)
-{
- struct sock *sk;
- struct sk_buff *skb2;
- struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
- unsigned short rt_flagmask;
- unsigned short objnamel;
- struct dn_scp *scp;
-
- read_lock(&dn_raw_hash_lock);
- for(sk = dn_raw_routing_sklist; sk != NULL; sk = sk->next) {
- if (skb->len > sock_rspace(sk))
- continue;
- if (sk->dead)
- continue;
- scp = &sk->protinfo.dn;
-
- rt_flagmask = dn_ntohs(*(unsigned short *)scp->addr.sdn_objname);
- objnamel = dn_ntohs(scp->addr.sdn_objnamel);
-
- if ((objnamel == 2) && (!((1 << (cb->rt_flags & 0x0f)) & rt_flagmask)))
- continue;
-
- if ((skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
- skb_set_owner_r(skb2, sk);
- skb_queue_tail(&sk->receive_queue, skb2);
- sk->data_ready(sk, skb->len);
- }
- }
- read_unlock(&dn_raw_hash_lock);
-}
-
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 27ff3a10f..5e54a6fa8 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -77,7 +77,6 @@
#include <net/dn_route.h>
#include <net/dn_neigh.h>
#include <net/dn_fib.h>
-#include <net/dn_raw.h>
struct dn_rt_hash_bucket
{
@@ -427,10 +426,6 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
(int)flags, (dev) ? dev->name : "???", len, skb->len,
padlen);
-#ifdef CONFIG_DECNET_RAW
- dn_raw_rx_routing(skb);
-#endif /* CONFIG_DECNET_RAW */
-
if (flags & DN_RT_PKT_CNTL) {
switch(flags & DN_RT_CNTL_MSK) {
case DN_RT_PKT_INIT:
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index f80e5afc1..ff65e9ae6 100644
--- a/net/decnet/sysctl_net_decnet.c
+++ b/net/decnet/sysctl_net_decnet.c
@@ -29,9 +29,9 @@
int decnet_debug_level = 0;
int decnet_time_wait = 30;
-int decnet_dn_count = 3;
-int decnet_di_count = 5;
-int decnet_dr_count = 5;
+int decnet_dn_count = 1;
+int decnet_di_count = 3;
+int decnet_dr_count = 3;
#ifdef CONFIG_SYSCTL
extern int decnet_dst_gc_interval;
diff --git a/net/econet/Makefile b/net/econet/Makefile
index 367584873..8da31b692 100644
--- a/net/econet/Makefile
+++ b/net/econet/Makefile
@@ -7,17 +7,10 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
+O_TARGET := econet.o
MOD_LIST_NAME := NET_MISC_MODULES
-O_OBJS :=
-M_OBJS :=
-
-ifeq ($(CONFIG_ECONET),y)
- O_OBJS += econet.o
-else
- ifeq ($(CONFIG_ECONET), m)
- M_OBJS += econet.o
- endif
-endif
+O_OBJS := af_econet.o sysctl_net_ec.o
+M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/net/econet/econet.c b/net/econet/af_econet.c
index 6e7523eed..091155076 100644
--- a/net/econet/econet.c
+++ b/net/econet/af_econet.c
@@ -2,8 +2,6 @@
* An implementation of the Acorn Econet and AUN protocols.
* Philip Blundell <philb@gnu.org>
*
- * Fixes:
- *
* 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
@@ -14,9 +12,6 @@
#include <linux/config.h>
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -45,15 +40,24 @@
#include <net/ip.h>
#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
static struct proto_ops econet_ops;
static struct sock *econet_sklist;
-static spinlock_t aun_queue_lock;
+/* Since there are only 256 possible network numbers (or fewer, depends
+ how you count) it makes sense to use a simple lookup table. */
+static struct net_device *net2dev_map[256];
#ifdef CONFIG_ECONET_AUNUDP
+static spinlock_t aun_queue_lock;
static struct socket *udpsock;
#define AUN_PORT 0x8000
+#define EC_PORT_IP 0xd2
+
struct aunhdr
{
unsigned char code; /* AUN magic protocol byte */
@@ -87,48 +91,6 @@ struct ec_cb
#endif
};
-struct ec_device
-{
- struct net_device *dev; /* Real device structure */
- unsigned char station, net; /* Econet protocol address */
- struct ec_device *prev, *next; /* Linked list */
-};
-
-static struct ec_device *edevlist = NULL;
-
-static spinlock_t edevlist_lock;
-
-/*
- * Faster version of edev_get - call with IRQs off
- */
-
-static __inline__ struct ec_device *__edev_get(struct net_device *dev)
-{
- struct ec_device *edev;
- for (edev = edevlist; edev; edev = edev->next)
- {
- if (edev->dev == dev)
- break;
- }
- return edev;
-}
-
-/*
- * Find an Econet device given its `dev' pointer. This is IRQ safe.
- *
- * Against what is it safe? --ANK
- */
-
-static struct ec_device *edev_get(struct net_device *dev)
-{
- struct ec_device *edev;
- unsigned long flags;
- spin_lock_irqsave(&edevlist_lock, flags);
- edev = __edev_get(dev);
- spin_unlock_irqrestore(&edevlist_lock, flags);
- return edev;
-}
-
/*
* Pull a packet from our receive queue and hand it to the user.
* If necessary we block.
@@ -274,7 +236,6 @@ static int econet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name;
struct net_device *dev;
struct ec_addr addr;
- struct ec_device *edev;
int err;
unsigned char port, cb;
struct sk_buff *skb;
@@ -318,14 +279,16 @@ static int econet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
}
/* Look for a device with the right network number. */
- for (edev = edevlist; edev && (edev->net != addr.net);
- edev = edev->next);
+ dev = net2dev_map[addr.net];
- /* Bridge? What's that? */
- if (edev == NULL)
- return -ENETUNREACH;
-
- dev = edev->dev;
+ /* If not directly reachable, use some default */
+ if (dev == NULL)
+ {
+ dev = net2dev_map[0];
+ /* No interfaces at all? */
+ if (dev == NULL)
+ return -ENETDOWN;
+ }
if (dev->type == ARPHRD_ECONET)
{
@@ -349,8 +312,15 @@ static int econet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (dev->hard_header) {
int res;
+ struct ec_framehdr *fh;
err = -EINVAL;
- res = dev->hard_header(skb, dev, ntohs(proto), &addr, NULL, len);
+ res = dev->hard_header(skb, dev, ntohs(proto),
+ &addr, NULL, len);
+ /* Poke in our control byte and
+ port number. Hack, hack. */
+ fh = (struct ec_framehdr *)(skb->data);
+ fh->cb = cb;
+ fh->port = port;
if (sock->type != SOCK_DGRAM) {
skb->tail = skb->data;
skb->len = 0;
@@ -602,7 +572,6 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void *arg)
struct ifreq ifr;
struct ec_device *edev;
struct net_device *dev;
- unsigned long flags;
struct sockaddr_ec *sec;
/*
@@ -620,43 +589,33 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void *arg)
switch (cmd)
{
case SIOCSIFADDR:
- spin_lock_irqsave(&edevlist_lock, flags);
- edev = __edev_get(dev);
+ edev = dev->ec_ptr;
if (edev == NULL)
{
/* Magic up a new one. */
- printk("Get fascist grenade!!!\n");
- *(int*)0 = 0;
- /* Note to author: please, remove this spinlock.
- You do not change edevlist from interrupts,
- so that such aggressive protection is redundant.
-
- BTW not all scans of edev_list are protected.
- */
edev = kmalloc(GFP_KERNEL, sizeof(struct ec_device));
if (edev == NULL) {
printk("af_ec: memory squeeze.\n");
- spin_unlock_irqrestore(&edevlist_lock, flags);
dev_put(dev);
return -ENOMEM;
}
memset(edev, 0, sizeof(struct ec_device));
- edev->dev = dev;
- edev->next = edevlist;
- edevlist = edev;
+ dev->ec_ptr = edev;
}
+ else
+ net2dev_map[edev->net] = NULL;
edev->station = sec->addr.station;
edev->net = sec->addr.net;
- spin_unlock_irqrestore(&edevlist_lock, flags);
+ net2dev_map[sec->addr.net] = dev;
+ if (!net2dev_map[0])
+ net2dev_map[0] = dev;
dev_put(dev);
return 0;
case SIOCGIFADDR:
- spin_lock_irqsave(&edevlist_lock, flags);
- edev = __edev_get(dev);
+ edev = dev->ec_ptr;
if (edev == NULL)
{
- spin_unlock_irqrestore(&edevlist_lock, flags);
dev_put(dev);
return -ENODEV;
}
@@ -664,7 +623,6 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void *arg)
sec->addr.station = edev->station;
sec->addr.net = edev->net;
sec->sec_family = AF_ECONET;
- spin_unlock_irqrestore(&edevlist_lock, flags);
dev_put(dev);
if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
@@ -773,8 +731,8 @@ SOCKOPS_WRAP(econet, PF_ECONET);
* Find the listening socket, if any, for the given data.
*/
-static struct sock *ec_listening_socket(unsigned char port, unsigned char
- station, unsigned char net)
+struct sock *ec_listening_socket(unsigned char port, unsigned char
+ station, unsigned char net)
{
struct sock *sk = econet_sklist;
@@ -835,23 +793,43 @@ static void aun_send_response(__u32 addr, unsigned long seq, int code, int cb)
}
/*
+ * Queue a received packet for a socket.
+ */
+
+static int ec_queue_packet(struct sock *sk, struct sk_buff *skb,
+ unsigned char stn, unsigned char net,
+ unsigned char cb, unsigned char port)
+{
+ struct ec_cb *eb = (struct ec_cb *)&skb->cb;
+ struct sockaddr_ec *sec = (struct sockaddr_ec *)&eb->sec;
+
+ memset(sec, 0, sizeof(struct sockaddr_ec));
+ sec->sec_family = AF_ECONET;
+ sec->type = ECTYPE_PACKET_RECEIVED;
+ sec->port = port;
+ sec->cb = cb;
+ sec->addr.net = net;
+ sec->addr.station = stn;
+
+ return sock_queue_rcv_skb(sk, skb);
+}
+
+/*
* Handle incoming AUN packets. Work out if anybody wants them,
* and send positive or negative acknowledgements as appropriate.
*/
static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
{
- struct ec_device *edev = edev_get(skb->dev);
struct iphdr *ip = skb->nh.iph;
unsigned char stn = ntohl(ip->saddr) & 0xff;
struct sock *sk;
struct sk_buff *newskb;
- struct ec_cb *eb;
- struct sockaddr_ec *sec;
+ struct ec_device *edev = skb->dev->ec_ptr;
+
+ if (! edev)
+ goto bad;
- if (edev == NULL)
- return; /* Device not configured for AUN */
-
if ((sk = ec_listening_socket(ah->port, stn, edev->net)) == NULL)
goto bad; /* Nobody wants it */
@@ -864,20 +842,10 @@ static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
goto bad;
}
- eb = (struct ec_cb *)&newskb->cb;
- sec = (struct sockaddr_ec *)&eb->sec;
- memset(sec, 0, sizeof(struct sockaddr_ec));
- sec->sec_family = AF_ECONET;
- sec->type = ECTYPE_PACKET_RECEIVED;
- sec->port = ah->port;
- sec->cb = ah->cb;
- sec->addr.net = edev->net;
- sec->addr.station = stn;
-
memcpy(skb_put(newskb, len - sizeof(struct aunhdr)), (void *)(ah+1),
len - sizeof(struct aunhdr));
- if (sock_queue_rcv_skb(sk, newskb) < 0)
+ if (ec_queue_packet(sk, newskb, stn, edev->net, ah->cb, ah->port))
{
/* Socket is bankrupt. */
kfree_skb(newskb);
@@ -923,6 +891,7 @@ foundit:
tx_result(skb->sk, eb->cookie, result);
skb_unlink(skb);
spin_unlock_irqrestore(&aun_queue_lock, flags);
+ kfree_skb(skb);
}
/*
@@ -983,7 +952,6 @@ static void aun_data_available(struct sock *sk, int slen)
* drop the packet.
*/
-
static void ab_cleanup(unsigned long h)
{
struct sk_buff *skb;
@@ -1000,6 +968,7 @@ static void ab_cleanup(unsigned long h)
tx_result(skb->sk, eb->cookie,
ECTYPE_TRANSMIT_NOT_PRESENT);
skb_unlink(skb);
+ kfree_skb(skb);
}
skb = newskb;
}
@@ -1054,31 +1023,85 @@ release:
}
#endif
+#ifdef CONFIG_ECONET_NATIVE
+
+/*
+ * Receive an Econet frame from a device.
+ */
+
+static int econet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+ struct ec_framehdr *hdr = (struct ec_framehdr *)skb->data;
+ struct sock *sk;
+ struct ec_device *edev = dev->ec_ptr;
+
+ if (! edev)
+ {
+ kfree_skb(skb);
+ return 0;
+ }
+
+ if (skb->len < sizeof(struct ec_framehdr))
+ {
+ /* Frame is too small to be any use */
+ kfree_skb(skb);
+ return 0;
+ }
+
+ /* First check for encapsulated IP */
+ if (hdr->port == EC_PORT_IP)
+ {
+ skb->protocol = htons(ETH_P_IP);
+ skb_pull(skb, sizeof(struct ec_framehdr));
+ netif_rx(skb);
+ return 0;
+ }
+
+ sk = ec_listening_socket(hdr->port, hdr->src_stn, hdr->src_net);
+ if (!sk)
+ {
+ kfree_skb(skb);
+ return 0;
+ }
+
+ return ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb,
+ hdr->port);
+}
+
+struct packet_type econet_packet_type=
+{
+ 0,
+ NULL,
+ econet_rcv,
+ NULL,
+ NULL
+};
+
+static void econet_hw_initialise(void)
+{
+ econet_packet_type.type = htons(ETH_P_ECONET);
+ dev_add_pack(&econet_packet_type);
+}
+
+#endif
+
static int econet_notifier(struct notifier_block *this, unsigned long msg, void *data)
{
struct net_device *dev = (struct net_device *)data;
struct ec_device *edev;
- unsigned long flags;
switch (msg) {
case NETDEV_UNREGISTER:
/* A device has gone down - kill any data we hold for it. */
- spin_lock_irqsave(&edevlist_lock, flags);
- for (edev = edevlist; edev; edev = edev->next)
+ edev = dev->ec_ptr;
+ if (edev)
{
- if (edev->dev == dev)
- {
- if (edev->prev)
- edev->prev->next = edev->next;
- else
- edevlist = edev->next;
- if (edev->next)
- edev->next->prev = edev->prev;
- kfree(edev);
- break;
- }
+ if (net2dev_map[0] == dev)
+ net2dev_map[0] = 0;
+ net2dev_map[edev->net] = NULL;
+ kfree(edev);
+ dev->ec_ptr = NULL;
}
- spin_unlock_irqrestore(&edevlist_lock, flags);
break;
}
@@ -1091,9 +1114,9 @@ struct notifier_block econet_netdev_notifier={
0
};
-#ifdef MODULE
-void cleanup_module(void)
+void __exit econet_proto_exit(void)
{
+ extern void econet_sysctl_unregister(void);
#ifdef CONFIG_ECONET_AUNUDP
del_timer(&ab_cleanup_timer);
if (udpsock)
@@ -1101,25 +1124,30 @@ void cleanup_module(void)
#endif
unregister_netdevice_notifier(&econet_netdev_notifier);
sock_unregister(econet_family_ops.family);
- return;
+#ifdef CONFIG_SYSCTL
+ econet_sysctl_unregister();
+#endif
}
-int init_module(void)
-#else
-void __init econet_proto_init(struct net_proto *pro)
-#endif
+int __init econet_proto_init(struct net_proto *pro)
{
- spin_lock_init(&edevlist_lock);
+ extern void econet_sysctl_register(void);
spin_lock_init(&aun_queue_lock);
- /* Stop warnings from happening on UP systems. */
- (void)edevlist_lock;
- (void)aun_queue_lock;
sock_register(&econet_family_ops);
#ifdef CONFIG_ECONET_AUNUDP
aun_udp_initialise();
#endif
+#ifdef CONFIG_ECONET_NATIVE
+ econet_hw_initialise();
+#endif
register_netdevice_notifier(&econet_netdev_notifier);
-#ifdef MODULE
- return 0;
+#ifdef CONFIG_SYSCTL
+ econet_sysctl_register();
#endif
+ return 0;
}
+
+#ifdef MODULE
+module_init(econet_proto_init);
+module_exit(econet_proto_exit);
+#endif
diff --git a/net/econet/sysctl_net_ec.c b/net/econet/sysctl_net_ec.c
new file mode 100644
index 000000000..9790a3a9b
--- /dev/null
+++ b/net/econet/sysctl_net_ec.c
@@ -0,0 +1,43 @@
+/*
+ * An implementation of the Acorn Econet and AUN protocols.
+ * Philip Blundell <philb@gnu.org>
+ *
+ * Fixes:
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+
+ctl_table econet_table[] = {
+ {0}
+};
+
+static struct ctl_table_header *econet_sysctl_header;
+
+static ctl_table econet_net_table[] = {
+ {NET_ECONET, "econet", NULL, 0, 0555, econet_table},
+ {0}
+};
+
+static ctl_table econet_root_table[] = {
+ {CTL_NET, "net", NULL, 0, 0555, econet_net_table},
+ {0}
+};
+
+void econet_sysctl_register(void)
+{
+ econet_sysctl_header = register_sysctl_table(econet_root_table, 0);
+}
+
+#ifdef MODULE
+void econet_sysctl_unregister(void)
+{
+ unregister_sysctl_table(econet_sysctl_header);
+}
+#endif /* MODULE */
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 9f7ad441e..7d3e49bed 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.163 2000/02/08 21:27:13 davem Exp $
+ * Version: $Id: tcp.c,v 1.164 2000/03/08 19:36:40 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -624,28 +624,29 @@ int tcp_listen_start(struct sock *sk)
tp->listen_opt = lopt;
write_unlock_bh(&tp->syn_wait_lock);
+ /* There is race window here: we announce ourselves listening,
+ * but this transition is still not validated by get_port().
+ * It is OK, because this socket enters to hash table only
+ * after validation is complete.
+ */
sk->state = TCP_LISTEN;
- if (sk->num == 0) {
- if (sk->prot->get_port(sk, 0) != 0) {
- sk->state = TCP_CLOSE;
- write_lock_bh(&tp->syn_wait_lock);
- tp->listen_opt = NULL;
- write_unlock_bh(&tp->syn_wait_lock);
- kfree(lopt);
- return -EAGAIN;
- }
+ if (sk->prot->get_port(sk, sk->num) == 0) {
sk->sport = htons(sk->num);
- } else {
- if (sk->prev)
- ((struct tcp_bind_bucket*)sk->prev)->fastreuse = 0;
- }
- sk_dst_reset(sk);
- sk->prot->hash(sk);
- sk->socket->flags |= SO_ACCEPTCON;
- sk->write_space = tcp_listen_write_space;
+ sk->write_space = tcp_listen_write_space;
+ sk_dst_reset(sk);
+ sk->prot->hash(sk);
+ sk->socket->flags |= SO_ACCEPTCON;
- return 0;
+ return 0;
+ }
+
+ sk->state = TCP_CLOSE;
+ write_lock_bh(&tp->syn_wait_lock);
+ tp->listen_opt = NULL;
+ write_unlock_bh(&tp->syn_wait_lock);
+ kfree(lopt);
+ return -EADDRINUSE;
}
/*
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 25a71d5f0..204f25574 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.200 2000/02/11 22:27:26 davem Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.201 2000/03/08 19:36:42 davem Exp $
*
* IPv4 specific functions
*
@@ -231,14 +231,15 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
break;
}
if (tb != NULL && tb->owners != NULL) {
- if (tb->fastreuse != 0 && sk->reuse != 0) {
+ if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
goto success;
} else {
struct sock *sk2 = tb->owners;
int sk_reuse = sk->reuse;
for( ; sk2 != NULL; sk2 = sk2->bind_next) {
- if (sk->bound_dev_if == sk2->bound_dev_if) {
+ if (sk != sk2 &&
+ sk->bound_dev_if == sk2->bound_dev_if) {
if (!sk_reuse ||
!sk2->reuse ||
sk2->state == TCP_LISTEN) {
@@ -269,11 +270,15 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)
tb->fastreuse = 0;
success:
sk->num = snum;
- if ((sk->bind_next = tb->owners) != NULL)
- tb->owners->bind_pprev = &sk->bind_next;
- tb->owners = sk;
- sk->bind_pprev = &tb->owners;
- sk->prev = (struct sock *) tb;
+ if (sk->prev == NULL) {
+ if ((sk->bind_next = tb->owners) != NULL)
+ tb->owners->bind_pprev = &sk->bind_next;
+ tb->owners = sk;
+ sk->bind_pprev = &tb->owners;
+ sk->prev = (struct sock *) tb;
+ } else {
+ BUG_TRAP(sk->prev == (struct sock *) tb);
+ }
ret = 0;
fail_unlock:
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f47b4a103..b0e8ee714 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.120 2000/02/27 19:51:49 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.121 2000/03/08 19:36:47 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -132,7 +132,7 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
break;
}
if (tb != NULL && tb->owners != NULL) {
- if (tb->fastreuse != 0 && sk->reuse != 0) {
+ if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
goto success;
} else {
struct sock *sk2 = tb->owners;
@@ -141,7 +141,8 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
/* We must walk the whole port owner list in this case. -DaveM */
for( ; sk2 != NULL; sk2 = sk2->bind_next) {
- if (sk->bound_dev_if == sk2->bound_dev_if) {
+ if (sk != sk2 &&
+ sk->bound_dev_if == sk2->bound_dev_if) {
if (!sk_reuse ||
!sk2->reuse ||
sk2->state == TCP_LISTEN) {
@@ -177,11 +178,15 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)
success:
sk->num = snum;
- if ((sk->bind_next = tb->owners) != NULL)
- tb->owners->bind_pprev = &sk->bind_next;
- tb->owners = sk;
- sk->bind_pprev = &tb->owners;
- sk->prev = (struct sock *) tb;
+ if (sk->prev == NULL) {
+ if ((sk->bind_next = tb->owners) != NULL)
+ tb->owners->bind_pprev = &sk->bind_next;
+ tb->owners = sk;
+ sk->bind_pprev = &tb->owners;
+ sk->prev = (struct sock *) tb;
+ } else {
+ BUG_TRAP(sk->prev == (struct sock *) tb);
+ }
ret = 0;
fail_unlock:
diff --git a/net/netsyms.c b/net/netsyms.c
index d99e53957..48cd5b503 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -216,8 +216,10 @@ EXPORT_SYMBOL(scm_detach_fds);
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
EXPORT_SYMBOL(br_handle_frame_hook);
+#ifdef CONFIG_INET
EXPORT_SYMBOL(br_ioctl_hook);
#endif
+#endif
#ifdef CONFIG_INET
/* Internet layer registration */
@@ -534,8 +536,10 @@ EXPORT_SYMBOL(unregister_hipdev);
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(sysctl_wmem_max);
EXPORT_SYMBOL(sysctl_rmem_max);
+#ifdef CONFIG_INET
EXPORT_SYMBOL(sysctl_ip_default_ttl);
#endif
+#endif
#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
#include<linux/if_ltalk.h>
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index e539693fe..bda8d54d8 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -42,6 +42,10 @@ extern ctl_table ipv6_table[];
extern ctl_table tr_table[];
#endif
+#ifdef CONFIG_ECONET
+extern ctl_table econet_table[];
+#endif
+
ctl_table net_table[] = {
{NET_CORE, "core", NULL, 0, 0555, core_table},
#ifdef CONFIG_UNIX
@@ -63,5 +67,8 @@ ctl_table net_table[] = {
#ifdef CONFIG_TR
{NET_TR, "token-ring", NULL, 0, 0555, tr_table},
#endif
+#ifdef CONFIG_ECONET
+ {NET_ECONET, "econet", NULL, 0, 0555, econet_table},
+#endif
{0}
};