From 9ace672ec6cd978d4f15794a7be5a28c2fdd49fa Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:28:08 -0500 Subject: [PATCH] Import 2.3.25pre1 --- CREDITS | 10 +- Documentation/Configure.help | 33 +- Documentation/filesystems/00-INDEX | 2 + Documentation/filesystems/bfs.txt | 54 ++ Documentation/kernel-parameters.txt | 4 +- MAINTAINERS | 17 +- Makefile | 7 +- arch/arm/Makefile | 38 +- arch/arm/boot/compressed/Makefile | 2 +- arch/arm/boot/compressed/head.S | 31 +- arch/arm/config.in | 17 +- arch/arm/kernel/armksyms.c | 8 +- arch/arm/kernel/bios32.c | 437 +++++----- arch/arm/kernel/dec21285.c | 161 +--- arch/arm/kernel/ecard.c | 12 +- arch/arm/kernel/setup.c | 301 ++++--- arch/arm/kernel/sys_arm.c | 2 - arch/arm/kernel/traps.c | 41 +- arch/arm/mm/fault-armv.c | 12 +- arch/arm/mm/fault-common.c | 18 - arch/arm/mm/init.c | 292 ++++--- arch/arm/mm/map.h | 12 +- arch/arm/mm/mm-armo.c | 116 ++- arch/arm/mm/mm-armv.c | 249 +++--- arch/arm/mm/mm-ebsa110.c | 6 - arch/arm/mm/mm-footbridge.c | 6 - arch/arm/mm/mm-nexuspci.c | 6 - arch/arm/mm/mm-rpc.c | 22 - arch/arm/mm/mm-tbox.c | 6 - arch/arm/mm/proc-arm2,3.S | 2 +- arch/arm/mm/proc-arm6,7.S | 2 +- arch/arm/mm/proc-sa110.S | 4 +- arch/arm/mm/small_page.c | 314 ++++---- arch/arm/vmlinux-armo.lds.in | 22 +- arch/i386/kernel/apm.c | 12 +- arch/i386/kernel/mca.c | 6 +- arch/i386/kernel/mtrr.c | 2 +- arch/i386/kernel/smpboot.c | 6 +- arch/i386/lib/mmx.c | 12 +- arch/m68k/mac/iop.c | 23 +- arch/mips/config.in | 15 +- arch/ppc/config.in | 17 +- drivers/acorn/net/Config.in | 6 +- drivers/block/DAC960.c | 29 +- drivers/block/cpqarray.c | 37 +- drivers/block/ide-geometry.c | 6 +- drivers/block/ide-proc.c | 26 +- drivers/block/md.c | 130 +-- drivers/char/h8.c | 22 +- drivers/char/mem.c | 5 +- drivers/char/misc.c | 10 +- drivers/char/nvram.c | 35 +- drivers/char/radio-cadet.c | 52 +- drivers/char/radio-rtrack2.c | 24 +- drivers/char/radio-sf16fmi.c | 25 +- drivers/char/radio-terratec.c | 25 +- drivers/char/radio-trust.c | 4 - drivers/char/radio-typhoon.c | 99 +-- drivers/char/radio-zoltrix.c | 23 +- drivers/char/riscom8.c | 2 + drivers/char/serial.c | 4 +- drivers/char/specialix.c | 3 +- drivers/char/sx.c | 2 + drivers/char/videodev.c | 30 - drivers/net/3c503.c | 10 +- drivers/net/bmac.c | 13 +- drivers/net/hamradio/bpqether.c | 13 +- drivers/net/hamradio/scc.c | 11 +- drivers/net/hamradio/yam.c | 19 +- drivers/net/strip.c | 32 +- drivers/net/wd.c | 14 +- drivers/nubus/nubus.c | 46 +- drivers/nubus/proc.c | 10 +- drivers/pci/pcisyms.c | 1 + drivers/pci/proc.c | 52 +- drivers/sound/es1370.c | 131 ++- drivers/sound/es1371.c | 526 ++++++++----- drivers/sound/esssolo1.c | 102 ++- drivers/sound/sonicvibes.c | 112 ++- drivers/sound/soundcard.c | 17 +- drivers/usb/acm.c | 53 +- drivers/usb/audio.c | 104 ++- drivers/usb/cpia.c | 41 +- drivers/usb/ezusb.c | 31 +- drivers/usb/hp_scanner.c | 24 +- drivers/usb/hub.c | 56 +- drivers/usb/inits.h | 1 + drivers/usb/keyboard.c | 29 +- drivers/usb/mouse.c | 39 +- drivers/usb/ohci-hcd.c | 4 +- drivers/usb/printer.c | 41 +- drivers/usb/proc_usb.c | 42 +- drivers/usb/usb-core.c | 1 + drivers/usb/usb-serial.c | 27 +- drivers/usb/usb.c | 274 +++++-- drivers/usb/usb.h | 30 +- drivers/usb/usb_scsi.c | 59 +- drivers/usb/uss720.c | 55 +- drivers/video/acornfb.c | 658 ++++------------ drivers/video/acornfb.h | 200 +++++ drivers/video/cyber2000fb.c | 1008 ++++++++++++++---------- drivers/video/cyber2000fb.h | 54 +- drivers/video/fbmem.c | 6 +- drivers/zorro/proc.c | 9 +- fs/Config.in | 6 + fs/Makefile | 10 +- fs/bfs/Makefile | 14 + fs/bfs/bfs_defs.h | 15 + fs/bfs/dir.c | 382 +++++++++ fs/bfs/file.c | 76 ++ fs/bfs/inode.c | 372 +++++++++ fs/buffer.c | 38 +- fs/coda/sysctl.c | 62 +- fs/dcache.c | 2 +- fs/exec.c | 2 +- fs/ext2/acl.c | 10 +- fs/ext2/balloc.c | 16 +- fs/ext2/bitmap.c | 4 +- fs/ext2/dir.c | 9 +- fs/ext2/file.c | 14 +- fs/ext2/fsync.c | 13 +- fs/ext2/ialloc.c | 16 +- fs/ext2/inode.c | 13 +- fs/ext2/ioctl.c | 9 +- fs/ext2/namei.c | 10 +- fs/ext2/super.c | 21 +- fs/ext2/symlink.c | 9 +- fs/ext2/truncate.c | 14 +- fs/filesystems.c | 5 + fs/nfs/nfs3xdr.c | 2 +- fs/nfs/read.c | 8 +- fs/nfs/write.c | 12 +- fs/nfsd/nfsctl.c | 8 +- fs/proc/Makefile | 2 +- fs/proc/array.c | 381 +-------- fs/proc/generic.c | 27 - fs/proc/mem.c | 9 +- fs/proc/proc_misc.c | 607 ++++++++++++++ fs/proc/procfs_syms.c | 3 +- fs/proc/root.c | 242 +----- fs/smbfs/cache.c | 33 +- fs/smbfs/file.c | 6 +- include/asm-alpha/termios.h | 1 + include/asm-arm/arch-arc/memory.h | 1 + include/asm-arm/arch-ebsa110/memory.h | 1 + include/asm-arm/arch-ebsa285/memory.h | 2 + include/asm-arm/arch-nexuspci/memory.h | 5 +- include/asm-arm/arch-rpc/memory.h | 5 +- include/asm-arm/arch-rpc/system.h | 4 +- include/asm-arm/arch-sa1100/memory.h | 5 +- include/asm-arm/io.h | 17 +- include/asm-arm/page.h | 18 +- include/asm-arm/pgtable.h | 287 +++++-- include/asm-arm/proc-armo/cache.h | 8 +- include/asm-arm/proc-armo/pgtable.h | 259 +----- include/asm-arm/proc-armv/cache.h | 7 +- include/asm-arm/proc-armv/pgtable.h | 285 +------ include/asm-arm/setup.h | 18 + include/asm-arm/termios.h | 1 + include/asm-i386/io.h | 4 +- include/asm-i386/page.h | 3 - include/asm-i386/pgtable-2level.h | 2 - include/asm-i386/pgtable-3level.h | 7 - include/asm-i386/pgtable.h | 8 +- include/asm-i386/string.h | 1 + include/asm-m68k/termios.h | 1 + include/asm-mips/termios.h | 1 + include/asm-ppc/termios.h | 1 + include/asm-sh/termios.h | 1 + include/asm-sparc/termios.h | 1 + include/asm-sparc64/termios.h | 1 + include/linux/apm_bios.h | 2 +- include/linux/bfs_fs.h | 91 +++ include/linux/bfs_fs_i.h | 18 + include/linux/bfs_fs_sb.h | 26 + include/linux/fs.h | 4 + include/linux/ipc.h | 2 +- include/linux/mm.h | 25 +- include/linux/pagemap.h | 12 +- include/linux/pci.h | 1 - include/linux/pci_ids.h | 1 + include/linux/proc_fs.h | 261 ++---- include/linux/sem.h | 15 +- include/linux/serial.h | 14 + include/linux/serialP.h | 12 - include/linux/shm.h | 2 +- include/linux/swap.h | 18 +- include/linux/wrapper.h | 2 +- ipc/msg.c | 6 +- ipc/sem.c | 830 +++++++++++-------- ipc/shm.c | 41 +- kernel/sysctl.c | 20 +- mm/filemap.c | 138 ++-- mm/highmem.c | 4 +- mm/memory.c | 28 +- mm/mlock.c | 9 +- mm/mmap.c | 18 +- mm/mprotect.c | 8 +- mm/mremap.c | 3 +- mm/page_io.c | 10 +- mm/slab.c | 2 +- mm/swap_state.c | 40 +- mm/swapfile.c | 35 +- mm/vmscan.c | 11 +- net/802/tr.c | 17 +- net/appletalk/aarp.c | 12 +- net/appletalk/ddp.c | 38 +- net/ax25/af_ax25.c | 34 +- net/bridge/br.c | 12 +- net/core/dev.c | 34 +- net/core/dev_mcast.c | 5 +- net/core/profile.c | 5 +- net/decnet/af_decnet.c | 25 +- net/decnet/dn_dev.c | 11 +- net/decnet/dn_fib.c | 11 +- net/decnet/dn_neigh.c | 11 +- net/decnet/dn_route.c | 11 +- net/ipv4/af_inet.c | 52 +- net/ipv4/arp.c | 21 +- net/ipv4/fib_frontend.c | 7 +- net/ipv4/ip_output.c | 16 +- net/ipv4/ipmr.c | 16 +- net/ipv4/route.c | 22 +- net/ipv6/addrconf.c | 11 +- net/ipv6/af_inet6.c | 53 +- net/ipv6/ip6_flowlabel.c | 7 +- net/ipv6/mcast.c | 6 +- net/ipv6/ndisc.c | 12 +- net/ipv6/route.c | 21 +- net/ipx/af_ipx.c | 29 +- net/irda/irlan/irlan_common.c | 2 +- net/irda/irproc.c | 2 +- net/netlink/af_netlink.c | 6 +- net/netrom/af_netrom.c | 33 +- net/rose/af_rose.c | 43 +- net/sched/sch_api.c | 6 +- net/sunrpc/stats.c | 10 +- net/unix/af_unix.c | 4 +- net/wanrouter/wanproc.c | 10 - net/x25/af_x25.c | 23 +- scripts/Configure | 6 +- 241 files changed, 6743 insertions(+), 5960 deletions(-) create mode 100644 Documentation/filesystems/bfs.txt create mode 100644 drivers/video/acornfb.h create mode 100644 fs/bfs/Makefile create mode 100644 fs/bfs/bfs_defs.h create mode 100644 fs/bfs/dir.c create mode 100644 fs/bfs/file.c create mode 100644 fs/bfs/inode.c create mode 100644 fs/proc/proc_misc.c create mode 100644 include/linux/bfs_fs.h create mode 100644 include/linux/bfs_fs_i.h create mode 100644 include/linux/bfs_fs_sb.h diff --git a/CREDITS b/CREDITS index 56427bd90212..ca6a4c41eb0e 100644 --- a/CREDITS +++ b/CREDITS @@ -31,6 +31,12 @@ D: NFS over TCP patches S: University of Limerick S: Ireland +N: Tigran A. Aivazian +E: tigran@ocston.org +W: http://www.ocston.org/~tigran +D: BFS filesystem +S: United Kingdom + N: Werner Almesberger E: werner.almesberger@lrc.di.epfl.ch D: dosfs, LILO, some fd features, various other hacks here and there @@ -1772,8 +1778,8 @@ S: 7000 Stuttgart 50 S: Germany N: Stephen Rothwell -E: Stephen.Rothwell@canb.auug.org.au -W: http://www.canb.auug.org.au/~sfr +E: sfr@linuxcare.com +W: http://linuxcare.com.au/sfr P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B 91 88 FA D9 C8 40 AA 02 D: Boot/setup/build work for setup > 2K D: Author, APM driver diff --git a/Documentation/Configure.help b/Documentation/Configure.help index b14a53b0e0e1..375c4c5d477b 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -7970,6 +7970,21 @@ CONFIG_EXT2_FS compiled as a module, and so this could be dangerous. Most everyone wants to say Y here. +SCO UnixWare BFS Support +CONFIG_BFS_FS + Boot Filesystem (BFS) is a filesystem used under SCO UnixWare to + allow bootloader access the kernel image and other important files + during the boot process. It is usually mounted under /stand and + corresponds to the slice marked as "STAND" in the UnixWare + partition. This is useful if you want to access files on your /stand + slice from Linux. If you don't know what it is, say N. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called bfs.o. Note that the filesystem of your root partition (the + one containing the directory /) cannot be compiled as a module. + ISO 9660 CDROM filesystem support CONFIG_ISO9660_FS This is the standard filesystem used on CDROMs. It was previously @@ -9881,7 +9896,7 @@ CONFIG_MTRR lead to all sorts of problems. You can safely say Y even if your machine doesn't have MTRRs, you'll - just add about 3k to your kernel. + just add about 9K to your kernel. See Documentation/mtrr.txt for more information. @@ -9938,9 +9953,15 @@ CONFIG_APM APM is a BIOS specification for saving power using several different techniques. This is mostly useful for battery powered laptops with APM compliant BIOSes. If you say Y here, the system time will be - reset after a USER RESUME operation, the /proc/apm device will - provide battery status information, and user-space programs will - receive notification of APM "events" (e.g., battery status change). + reset after a RESUME operation, the /proc/apm device will provide + battery status information, and user-space programs will receive + notification of APM "events" (e.g. battery status change). + + If you select "Y" here, you can disable actual use of the APM + BIOS by passing the "apm=off" option to the kernel at boot time. + + Note that the APM support is almost completely disabled for + machines with more than one CPU. Supporting software is available; for more information, read the Battery Powered Linux mini-HOWTO, available from @@ -9953,9 +9974,7 @@ CONFIG_APM This driver does not support the TI 4000M TravelMate and the ACER 486/DX4/75 because they don't have compliant BIOSes. Many "green" desktop machines also don't have compliant BIOSes, and this driver - will cause those machines to panic during the boot phase (typically, - these machines are using a data segment of 0040, which is reserved - for the Linux kernel). + may cause those machines to panic during the boot phase. If you are running Linux on a laptop, you may also want to read the Linux Laptop home page on the WWW at diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index b481c8a673eb..b4ffac0228b8 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -4,6 +4,8 @@ adfs.txt - info and mount options for the Acorn Advanced Disc Filing System. affs.txt - info and mount options for the Amiga Fast File System. +bfs.txt + - info for the SCO UnixWare Boot Filesystem (BFS). coda.txt - description of the CODA filesystem. fat_cvf.txt diff --git a/Documentation/filesystems/bfs.txt b/Documentation/filesystems/bfs.txt new file mode 100644 index 000000000000..bd672888a465 --- /dev/null +++ b/Documentation/filesystems/bfs.txt @@ -0,0 +1,54 @@ +The BFS filesystem is used on SCO UnixWare machines for /stand slice. +There are no special mount options supported by bfs at this time. +You can mount it only read-only at this stage. Even if you attempt to +mount it read-write it will be automatically mounted read-only, unless +you have enabled "BFS write support" when configuring the kernel. + +In order to access /stand partition under Linux you obviously need to +know the partition number and the kernel must support UnixWare disk slices +(CONFIG_UNIXWARE_DISKLABEL config option). However BFS support does not +depend on having UnixWare disklabel support because one can also mount +BFS filesystem via loopback: + +# losetup /dev/loop0 stand.img +# mount -t bfs /dev/loop0 /mnt/stand + +where stand.img is a file containing the image of BFS filesystem. +When you have finished using it and umounted you need to also deallocate +/dev/loop0 device by: + +# losetup -d /dev/loop0 + +You can simplify mounting by just typing: + +# mount -t bfs -o loop stand.img /mnt/stand + +this will allocate the first available loopback device (and load loop.o +kernel module if necessary) automatically. Beware that umount will not +deallocate /dev/loopN device if /etc/mtab file on your system is a +symbolic link to /proc/mounts. You will need to do it manually using +"-d" switch of losetup(8). Read losetup(8) manpage for more info. + +To create the BFS image under UnixWare you need to find out first which +slice contains it. The command prtvtoc(1M) is your friend: + +# prtvtoc /dev/rdsk/c0b0t0d0s0 + +(assuming your root disk is on target=0, lun=0, bus=0, controller=0). Then you +look for the slice with tag "STAND", which is usually slice 10. With this +information you can use dd(1) to create the BFS image: + +# umount /stand +# dd if=/dev/rdsk/c0b0t0d0sa of=stand.img bs=512 + +Just in case, you can verify that you have done the right thing by checking +the magic number: + +# od -Ad -tx4 stand.img | more + +The first 4 bytes should be 0x1BADFACE. + +If you have any questions or suggestions regarding this BFS implementation +please contact me: + +Tigran A. Aivazian . diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dc57ee65150c..1eade18a4405 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -11,7 +11,7 @@ restrictions on the kernel for the said kernel parameter to be valid. The restrictions referred to are that the relevant option is valid if: APIC APIC support is enabled. - APM Automatic Power Management support is enabled. + APM Advanced Power Management support is enabled. AX25 Appropriate AX.25 support is enabled. CD Appropriate CD support is enabled. EIDE EIDE/ATAPI support is enabled. @@ -65,7 +65,7 @@ running once the system is up. AM53C974= [HW,SCSI] - apm= [APM] Automatic Power Management. + apm= [APM] Advanced Power Management. arcrimi= [HW,NET] diff --git a/MAINTAINERS b/MAINTAINERS index eed47b34db83..455721957eb6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -128,9 +128,10 @@ S: Maintained APM DRIVER P: Stephen Rothwell -M: Stephen.Rothwell@canb.auug.org.au +M: sfr@linuxcare.com L: linux-laptop@vger.rutgers.edu -S: Maintained +W: http://linuxcare.com.au/apm/ +S: Supported APPLETALK NETWORK LAYER P: Jay Schulist @@ -145,10 +146,9 @@ S: Maintained ARM PORT P: Russell King -M: linux@arm.uk.linux.org +M: linux@arm.linux.org.uk L: linux-arm@vger.rutgers.edu -L: arm-linux@tardis.ed.ac.uk -W: http://www.arm.uk.linux.org/~rmk/armlinux.html +W: http://www.arm.linux.org.uk/~rmk/armlinux.html S: Maintained ARPD SUPPORT @@ -176,6 +176,13 @@ M: kenji@bitgate.com W: http://ftp.bitgate.com/pcwd/ S: Maintained +BFS FILE SYSTEM +P: Tigran A. Aivazian +M: tigran@ocston.org +L: linux-kernel@vger.rutgers.edu +W: http://www.ocston.org/~tigran/patches/bfs +S: Maintained + BUSLOGIC SCSI DRIVER P: Leonard N. Zubkoff M: Leonard N. Zubkoff diff --git a/Makefile b/Makefile index 427f1eae20de..5dfefbe30ec5 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 24 +SUBLEVEL = 25 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -392,10 +392,8 @@ clean: archclean rm -f drivers/sound/bin2hex drivers/sound/hex2hex rm -f net/khttpd/make_times_h rm -f net/khttpd/times.h - if [ -d modules ]; then \ - rm -f core `find modules/ -type f -print`; \ - fi rm -f submenu* + rm -rf modules mrproper: clean archmrproper rm -f include/linux/autoconf.h include/linux/version.h @@ -416,7 +414,6 @@ mrproper: clean archmrproper rm -f .hdepend scripts/mkdep scripts/split-include rm -f $(TOPDIR)/include/linux/modversions.h rm -rf $(TOPDIR)/include/linux/modules - rm -rf modules distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 0895fc0ba1e7..f8c91aca3f24 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -16,10 +16,10 @@ LD := $(CROSS_COMPILE)ld OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S CPP := $(CC) -E PERL := perl -LINKFLAGS := -X -T arch/arm/vmlinux.lds +LINKFLAGS := -p -X -T arch/arm/vmlinux.lds ARCHCC := $(word 1,$(CC)) - +AFLAGS += -mno-fpu CFLAGS_PIPE := -pipe CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) @@ -31,6 +31,15 @@ ifdef CONFIG_DEBUG_INFO CFLAGS += -g endif +# Ensure this is ld "2.9.4" or later +NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) + +ifneq ($(NEW_LINKER),y) +dummy:; @echo '*** 2.3 kernels no longer build correctly with old versions of binutils.' + @echo '*** Please upgrade your binutils to 2.9.5.' + @false +endif + # GCC 2.7 uses different options to later compilers; sort out which we have NEW_GCC := $(shell if $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; then echo n; else echo y; fi) @@ -55,21 +64,6 @@ CFLAGS_ARM7 := -m6 CFLAGS_SA110 := -m6 endif -# See if this is ld "2.9.4" or later -NEW_LINKER := $(shell if $(LD) --gc-sections --version >/dev/null 2>&1; then echo y; else echo n; fi) - -ifeq ($(NEW_LINKER),y) -AFLAGS += -mno-fpu -AFLAGS_PROC_CPU_26 := -mapcs-26 -AFLAGS_PROC_CPU_32v3 := -mapcs-32 -marmv3m -AFLAGS_PROC_CPU_32v4 := -mapcs-32 -marmv4t -LINKFLAGS := -p $(LINKFLAGS) -else -AFLAGS_PROC_CPU_26 := -m3 -AFLAGS_PROC_CPU_32v3 := -m6 -AFLAGS_PROC_CPU_32v4 := -m6 -endif - # # Select CPU dependent flags # @@ -77,7 +71,7 @@ ifeq ($(CONFIG_CPU_26),y) PROCESSOR = armo TEXTADDR = 0x02080000 CFLAGS += $(CFLAGS_PROC_CPU_26) - AFLAGS += $(AFLAGS_PROC_CPU_26) + AFLAGS += -mapcs-26 endif ifeq ($(CONFIG_CPU_32),y) @@ -85,10 +79,10 @@ ifeq ($(CONFIG_CPU_32),y) TEXTADDR = 0xC0008000 ifeq ($(CONFIG_CPU_32v4),y) CFLAGS += $(CFLAGS_PROC_CPU_32v4) - AFLAGS += $(AFLAGS_PROC_CPU_32v4) + AFLAGS += -mapcs-32 -marmv4 else CFLAGS += $(CFLAGS_PROC_CPU_32v3) - AFLAGS += $(AFLAGS_PROC_CPU_32v3) + AFLAGS += -mapcs-32 -marmv3m endif # # Exactly one of the following must be selected @@ -156,7 +150,7 @@ LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB) DRIVERS += arch/arm/special/special.a ifeq ($(CONFIG_NWFPE),y) -CORE_FILES += arch/arm/nwfpe/math-emu.o +LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) endif ifeq ($(CONFIG_ARCH_ACORN),y) @@ -173,7 +167,7 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot # to date before starting compilation CONSTANTS := constants -constants: dummy +constants: $(TOPDIR)/include/asm-arm/proc-fns.h dummy @$(MAKE) -C arch/arm/lib constants.h symlinks: archsymlinks diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 3c0478ab389c..a9d71cb7b81d 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -8,7 +8,7 @@ OBJS = misc.o SYSTEM = $(TOPDIR)/vmlinux CFLAGS = -O2 -DSTDC_HEADERS $(CFLAGS_PROC) FONTC = $(TOPDIR)/drivers/video/font_acorn_8x8.c -ZLDFLAGS = -X -T vmlinux.lds +ZLDFLAGS = -p -X -T vmlinux.lds # # Architecture dependencies diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 721967e4b7ec..e87c0a72e969 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -96,6 +96,8 @@ start: */ reloc_start: add r8, r5, r0 #if 0 + mov r0, #'\n' + bl putc mov r0, r6 mov r1, #8 bl phex @@ -139,8 +141,8 @@ reloc_start: add r8, r5, r0 bl phex mov r0, #'\n' bl putc - mov r0, r4 - bl memdump + mov r0, r4 + bl memdump #endif eor r0, r6, #0x44 << 24 @ SA-110? eor r0, r0, #0x01 << 16 @@ -155,6 +157,25 @@ call_kernel: mov r0, #0 phexbuf: .space 12 +#if 0 + .macro loadsp, rb + mov \rb, #0x7c000000 + .endm + + .macro writeb, rb + strb \rb, [r3, #0x3f8] + .endm +#else + .macro loadsp, rb + mov \rb, #0x03000000 + orr \rb, \rb, #0x00010000 + .endm + + .macro writeb, rb + strb \rb, [r3, #0x3f8 << 2] + .endm +#endif + phex: adr r3, phexbuf mov r2, #0 strb r2, [r3, r1] @@ -169,11 +190,11 @@ phex: adr r3, phexbuf strb r2, [r3, r1] b 1b -puts: mov r3, #0x7c000000 +puts: loadsp r3 1: ldrb r2, [r0], #1 teq r2, #0 moveq pc, lr -2: strb r2, [r3, #0x3f8] +2: writeb r2 mov r1, #0x00020000 3: subs r1, r1, #1 bne 3b @@ -186,7 +207,7 @@ puts: mov r3, #0x7c000000 putc: mov r2, r0 mov r0, #0 - mov r3, #0x7c000000 + loadsp r3 b 2b memdump: mov r12, r0 diff --git a/arch/arm/config.in b/arch/arm/config.in index 3e0bcd0f3532..81c95f6be806 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -21,6 +21,7 @@ choice 'ARM system type' \ EBSA-110 CONFIG_ARCH_EBSA110 \ FootBridge-based CONFIG_FOOTBRIDGE" RiscPC # SA1100-based CONFIG_ARCH_SA1100 + if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then bool 'FootBridge in HOST mode' CONFIG_HOST_FOOTBRIDGE if [ "$CONFIG_HOST_FOOTBRIDGE" = "y" ]; then @@ -45,13 +46,13 @@ fi if [ "$CONFIG_ARCH_SA1100" = "y" ]; then define_bool CONFIG_CPU_SA1100 y choice 'SA1100 implementation' \ - "Brutus CONFIG_SA1100_BRUTUS \ - empeg CONFIG_SA1100_EMPEG \ - Itsy CONFIG_SA1100_ITSY \ - LART CONFIG_SA1100_LART \ - PLEB CONFIG_SA1100_PLEB \ - Victor CONFIG_SA1100_VICTOR \ - Tifon CONFIG_SA1100_TIFON" Brutus + "Brutus CONFIG_SA1100_BRUTUS \ + Empeg CONFIG_SA1100_EMPEG \ + Itsy CONFIG_SA1100_ITSY \ + LART CONFIG_SA1100_LART \ + PLEB CONFIG_SA1100_PLEB \ + Victor CONFIG_SA1100_VICTOR \ + Tifon CONFIG_SA1100_TIFON" Brutus fi # @@ -121,8 +122,6 @@ else define_bool CONFIG_ISA_DMA n fi -endmenu - if [ "$CONFIG_CPU_32" = "y" -a "$CONFIG_ARCH_EBSA110" != "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'Enable kernel-mode alignment trap handler (EXPERIMENTAL)' CONFIG_ALIGNMENT_TRAP fi diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index ebb2f150dea1..8d9bac1a74c3 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -98,7 +99,8 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(system_rev); EXPORT_SYMBOL(system_serial_low); EXPORT_SYMBOL(system_serial_high); - +EXPORT_SYMBOL(__bug); +EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -152,8 +154,8 @@ EXPORT_SYMBOL(__bus_to_virt); #ifndef CONFIG_NO_PGT_CACHE EXPORT_SYMBOL(quicklists); #endif -EXPORT_SYMBOL(__bad_pmd); -EXPORT_SYMBOL(__bad_pmd_kernel); +EXPORT_SYMBOL(__handle_bad_pmd); +EXPORT_SYMBOL(__handle_bad_pmd_kernel); /* string / mem functions */ EXPORT_SYMBOL_NOVERS(strcpy); diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 3bd7a73585b1..28c12d3e8a0e 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -13,16 +13,14 @@ #include #include -int have_isa_bridge; +#include "bios32.h" -int (*pci_irq_fixup)(struct pci_dev *dev); +static int debug_pci; +int have_isa_bridge; -extern struct pci_ops *dc21285_init(int pass); -extern void pcibios_fixup_ebsa285(struct pci_dev *dev); extern void hw_init(void); -void -pcibios_report_device_errors(void) +void pcibios_report_device_errors(void) { struct pci_dev *dev; @@ -31,16 +29,17 @@ pcibios_report_device_errors(void) pci_read_config_word(dev, PCI_STATUS, &status); - if (status & 0xf900) { - pci_write_config_word(dev, PCI_STATUS, status & 0xf900); - printk(KERN_DEBUG "PCI: %02x:%02x status = %X\n", - dev->bus->number, dev->devfn, status); - } + if ((status & 0xf900) == 0) + continue; + + pci_write_config_word(dev, PCI_STATUS, status & 0xf900); + printk(KERN_DEBUG "PCI: status %04X on %s\n", + status, dev->name); } } /* - * We don't use this to fix the device, but more our initialisation. + * We don't use this to fix the device, but initialisation of it. * It's not the correct use for this, but it works. The actions we * take are: * - enable only IO @@ -68,196 +67,108 @@ static void __init pci_fixup_83c553(struct pci_dev *dev) pci_write_config_byte(dev, 0x81, 0x01); } -struct pci_fixup pcibios_fixups[] = { - { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553 }, - { 0 } -}; - -/* - * Assign new address to PCI resource. We hope our resource information - * is complete. On the PC, we don't re-assign resources unless we are - * forced to do so. - * - * Expects start=0, end=size-1, flags=resource type. - */ - -int __init pcibios_assign_resource(struct pci_dev *dev, int i) +static void __init pci_fixup_unassign(struct pci_dev *dev) { - struct resource *r = &dev->resource[i]; - struct resource *pr = pci_find_parent_resource(dev, r); - unsigned long size = r->end + 1; - unsigned long flags = 0; - - if (!pr) - return -EINVAL; - if (r->flags & IORESOURCE_IO) { - if (size > 0x100) - return -EFBIG; - if (allocate_resource(pr, r, size, 0x9000, ~0, 1024)) - return -EBUSY; - flags = PCI_BASE_ADDRESS_SPACE_IO; - } else { - if (allocate_resource(pr, r, size, 0x00100000, 0x7fffffff, size)) - return -EBUSY; - } - if (i < 6) - pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start | flags); - return 0; + dev->resource[0].end -= dev->resource[0].start; + dev->resource[0].start = 0; } /* - * Assign an address to an I/O range. + * PCI IDE controllers use non-standard I/O port + * decoding, respect it. */ -static void __init pcibios_fixup_io_addr(struct pci_dev *dev, struct resource *r, int idx) +static void __init pci_fixup_ide_bases(struct pci_dev *dev) { - unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2); - unsigned int size = r->end - r->start + 1; - u32 try; + struct resource *r; + int i; - /* - * We need to avoid collisions with `mirrored' VGA ports and other strange - * ISA hardware, so we always want the addresses kilobyte aligned. - */ - if (!size || size > 256) { - printk(KERN_ERR "PCI: Cannot assign I/O space to %s, " - "%d bytes are too much.\n", dev->name, size); + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) return; - } - - if (allocate_resource(&ioport_resource, r, size, 0x9000, ~0, 1024)) { - printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O " - "space for %s.\n", size, dev->name); - return; - } - printk("PCI: Assigning I/O space %04lx-%04lx to %s\n", - r->start, r->end, dev->name); - - pci_write_config_dword(dev, reg, r->start | PCI_BASE_ADDRESS_SPACE_IO); - pci_read_config_dword(dev, reg, &try); - - if ((try & PCI_BASE_ADDRESS_IO_MASK) != r->start) { - r->start = 0; - pci_write_config_dword(dev, reg, 0); - printk(KERN_ERR "PCI: I/O address setup failed, got %04x\n", try); + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + r = dev->resource + i; + if ((r->start & ~0x80) == 0x374) { + r->start |= 2; + r->end = r->start; + } } } +struct pci_fixup pcibios_fixups[] = { + { + PCI_FIXUP_HEADER, + PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, + pci_fixup_83c553 + }, { + PCI_FIXUP_HEADER, + PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F, + pci_fixup_unassign + }, { + PCI_FIXUP_HEADER, + PCI_ANY_ID, PCI_ANY_ID, + pci_fixup_ide_bases + }, { 0 } +}; + /* - * Assign an address to an memory range. + * Allocate resources for all PCI devices that have been enabled. + * We need to do that before we try to fix up anything. */ -static void __init pcibios_fixup_mem_addr(struct pci_dev *dev, struct resource *r, int idx) +static void __init pcibios_claim_resources(void) { - unsigned int reg = PCI_BASE_ADDRESS_0 + (idx << 2); - unsigned int size = r->end - r->start + 1; - u32 try; - - if (!size) { - printk(KERN_ERR "PCI: Cannot assign memory space to %s, " - "%d bytes are too much.\n", dev->name, size); - return; - } - - if (allocate_resource(&iomem_resource, r, size, - 0x00100000, 0x0fffffff, 1024)) { - printk(KERN_ERR "PCI: Unable to find free %d bytes of memory " - "space for %s.\n", size, dev->name); - return; - } - - printk("PCI: Assigning memory space %08lx-%08lx to %s\n", - r->start, r->end, dev->name); - - pci_write_config_dword(dev, reg, r->start); - pci_read_config_dword(dev, reg, &try); + struct pci_dev *dev; + int idx; - if (try != r->start) { - r->start = 0; - pci_write_config_dword(dev, reg, 0); - printk(KERN_ERR "PCI: memory address setup failed, " - "got %08x\n", try); - } + for (dev = pci_devices; dev; dev = dev->next) + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) + if (dev->resource[idx].flags && + dev->resource[idx].start) + pci_claim_resource(dev, idx); } -#define _PCI_REGION_IO 1 -#define _PCI_REGION_MEM 2 - -/* - * Fix up one PCI devices regions, enables and interrupt lines - */ -static void __init pcibios_fixup_device(struct pci_dev *dev, u16 *cmd) +void __init +pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) { - int i, has_regions = 0; - - /* - * Fix up the regions. Any regions which aren't allocated - * are given a free region. - */ - for (i = 0; i < 6; i++) { - struct resource *r = dev->resource + i; + unsigned long where, size; + u32 reg; - if (r->flags & IORESOURCE_IO) { - has_regions |= _PCI_REGION_IO; + if (debug_pci) + printk("PCI: Assigning %3s %08lx to %s\n", + res->flags & IORESOURCE_IO ? "IO" : "MEM", + res->start, dev->name); - if (!r->start || r->end == 0xffffffff) - pcibios_fixup_io_addr(dev, r, i); - } else if (r->end) { - has_regions |= _PCI_REGION_MEM; + where = PCI_BASE_ADDRESS_0 + resource * 4; + size = res->end - res->start; - if (!r->start) - pcibios_fixup_mem_addr(dev, r, i); - } - } - - switch (dev->class >> 8) { - case PCI_CLASS_BRIDGE_ISA: - case PCI_CLASS_BRIDGE_EISA: - /* - * If this device is an ISA bridge, set the have_isa_bridge - * flag. We will then go looking for things like keyboard, - * etc - */ - have_isa_bridge = !0; - /* FALL THROUGH */ - - default: - /* - * Don't enable VGA-compatible cards since they have - * fixed I/O and memory space. - * - * Don't enabled disabled IDE interfaces either because - * some BIOSes may reallocate the same address when they - * find that no devices are attached. - */ - if (has_regions & _PCI_REGION_IO && - !((*cmd) & PCI_COMMAND_IO)) { - printk("PCI: Enabling I/O for %s\n", dev->name); - *cmd |= PCI_COMMAND_IO; - } + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); +} - if (has_regions & _PCI_REGION_MEM && - !((*cmd) & PCI_COMMAND_MEMORY)) { - printk("PCI: Enabling memory for %s\n", dev->name); - *cmd |= PCI_COMMAND_MEMORY; - } - } +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + if (debug_pci) + printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); } /* - * Fix base addresses, I/O and memory enables and IRQ's + * Called after each bus is probed, but before its children + * are examined. */ -static void __init pcibios_fixup_devices(void) +void __init pcibios_fixup_bus(struct pci_bus *bus) { struct pci_dev *dev; - for (dev = pci_devices; dev; dev = dev->next) { + for (dev = bus->devices; dev; dev = dev->sibling) { u16 cmd; /* - * architecture specific hacks. - * I don't really want this here, - * but I don't see any other place - * for it to live. + * architecture specific hacks. I don't really want + * this here, but I don't see any other place for it + * to live. Shame the device doesn't support + * capabilities */ if (machine_is_netwinder() && dev->vendor == PCI_VENDOR_ID_DEC && @@ -265,6 +176,15 @@ static void __init pcibios_fixup_devices(void) /* Put the chip to sleep in case the driver isn't loaded */ pci_write_config_dword(dev, 0x40, 0x80000000); + /* + * If this device is an ISA bridge, set the have_isa_bridge + * flag. We will then go looking for things like keyboard, + * etc + */ + if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA || + dev->class >> 8 == PCI_CLASS_BRIDGE_EISA) + have_isa_bridge = !0; + /* * Set latency timer to 32, and a cache line size to 32 bytes. * Also, set system error enable, parity error enable, and @@ -272,113 +192,150 @@ static void __init pcibios_fixup_devices(void) */ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 32); pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8); - pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); pci_read_config_word(dev, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_FAST_BACK | PCI_COMMAND_SERR | PCI_COMMAND_PARITY; - pcibios_fixup_device(dev, &cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0); + } +} - /* - * now fixup the IRQs, if required - */ - if (pci_irq_fixup) - dev->irq = pci_irq_fixup(dev); +static u8 __init no_swizzle(struct pci_dev *dev, u8 *pin) +{ + return 0; +} - /* - * If any remaining IRQs are weird, fix it now. - */ - if (dev->irq >= NR_IRQS) - dev->irq = 0; +/* ebsa285 host-specific stuff */ +static int irqmap_ebsa285[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; - /* - * catch any drivers still reading this from the - * device itself. This can be removed once - * all drivers are fixed. (are there any?) - */ - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } +static u8 __init ebsa285_swizzle(struct pci_dev *dev, u8 *pin) +{ + return PCI_SLOT(dev->devfn); } -/* - * Allocate resources for all PCI devices that have been enabled. - * We need to do that before we try to fix up anything. - */ -static void __init pcibios_claim_resources(void) +static int __init ebsa285_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { - struct pci_dev *dev; - int idx; + return irqmap_ebsa285[(slot + pin) & 3]; +} - for (dev = pci_devices; dev; dev = dev->next) - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { - struct resource *a, *r = &dev->resource[idx]; - - /* - * Ignore regions that start at 0 or - * end at 0xffffffff - */ - if (!r->start || r->end == 0xffffffff) - continue; - - if (r->flags & IORESOURCE_IO) - a = &ioport_resource; - else - a = &iomem_resource; - - if (request_resource(a, r) < 0) - printk(KERN_ERR "PCI: Address space collision " - "on region %d of %s\n", - idx, dev->name); - /* We probably should disable the region, - * shouldn't we? - */ - } +static struct hw_pci ebsa285_pci __initdata = { + dc21285_init, + 0x9000, + 0x00100000, + ebsa285_swizzle, + ebsa285_map_irq +}; + +/* cats host-specific stuff */ +static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; + +static int __init cats_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (dev->irq >= 128) + return 16 + (dev->irq & 0x1f); + + if (dev->irq >= 1 && dev->irq <= 4) + return irqmap_cats[dev->irq - 1]; + + if (dev->irq != 0) + printk("PCI: device %02x:%02x has unknown irq line %x\n", + dev->bus->number, dev->devfn, dev->irq); + + return -1; } -/* - * Called after each bus is probed, but before its children - * are examined. - * - * No fixup of bus required - */ -void __init pcibios_fixup_bus(struct pci_bus *bus) +static struct hw_pci cats_pci __initdata = { + dc21285_init, + 0x9000, + 0x00100000, + no_swizzle, + cats_map_irq +}; + +/* netwinder host-specific stuff */ +static int __init netwinder_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { +#define DEV(v,d) ((v)<<16|(d)) + switch (DEV(dev->vendor, dev->device)) { + case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): + return IRQ_NETWINDER_ETHER100; + + case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): + return IRQ_NETWINDER_ETHER10; + + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553): + return 0; + + case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105): + return IRQ_ISA_HARDDISK1; + + case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): + return IRQ_NETWINDER_VGA; + + default: + printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n", + dev->bus->number, dev->devfn, + dev->vendor, dev->device); + return 0; + } } +static struct hw_pci netwinder_pci __initdata = { + dc21285_init, + 0x9000, + 0x00100000, + no_swizzle, + netwinder_map_irq +}; + void __init pcibios_init(void) { - struct pci_ops *ops; + struct hw_pci *hw_pci = NULL; + + if (machine_is_ebsa285()) + hw_pci = &ebsa285_pci; + else if (machine_is_cats()) + hw_pci = &cats_pci; + else if (machine_is_netwinder()) + hw_pci = &netwinder_pci; + + if (hw_pci == NULL) + return; /* - * Pre-initialisation. Set up the host bridge. + * Set up the host bridge, and scan the bus. */ - ops = dc21285_init(0); + hw_pci->init(); - printk("PCI: Probing PCI hardware\n"); - - pci_scan_bus(0, ops, NULL); + /* + * Other architectures don't seem to do this... should we? + */ pcibios_claim_resources(); - pcibios_fixup_devices(); /* - * Now clear down any PCI error IRQs and - * register the error handler + * Assign any unassigned resources. Note that we really ought to + * have min/max stuff here - max mem address is 0x0fffffff */ - dc21285_init(1); + pci_assign_unassigned_resources(hw_pci->io_start, hw_pci->mem_start); + pci_fixup_irqs(hw_pci->swizzle, hw_pci->map_irq); + pci_set_bus_ranges(); /* - * Initialise any other hardware after we've - * got the PCI bus initialised. We may need - * the PCI bus to talk to this other hardware. + * Initialise any other hardware after we've got the PCI bus + * initialised. We may need the PCI bus to talk to this other + * hardware. */ hw_init(); } char * __init pcibios_setup(char *str) { + if (!strcmp(str, "debug")) { + debug_pci = 1; + return NULL; + } return str; } diff --git a/arch/arm/kernel/dec21285.c b/arch/arm/kernel/dec21285.c index 42a9a616fe5b..2622dec25401 100644 --- a/arch/arm/kernel/dec21285.c +++ b/arch/arm/kernel/dec21285.c @@ -18,11 +18,12 @@ #include #include +#include "bios32.h" + #define MAX_SLOTS 21 extern int setup_arm_irq(int, struct irqaction *); extern void pcibios_report_device_errors(void); -extern int (*pci_irq_fixup)(struct pci_dev *dev); static unsigned long dc21285_base_address(struct pci_dev *dev, int where) @@ -202,129 +203,53 @@ static struct irqaction dc21285_error_action = { dc21285_error, SA_INTERRUPT, 0, "PCI error", NULL, NULL }; -static int irqmap_ebsa[] __initdata = { IRQ_IN1, IRQ_IN0, IRQ_PCI, IRQ_IN3 }; - -static int __init ebsa_irqval(struct pci_dev *dev) -{ - u8 pin; - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); - - return irqmap_ebsa[(PCI_SLOT(dev->devfn) + pin) & 3]; -} - -static int irqmap_cats[] __initdata = { IRQ_PCI, IRQ_IN0, IRQ_IN1, IRQ_IN3 }; - -static int __init cats_irqval(struct pci_dev *dev) -{ - if (dev->irq >= 128) - return 16 + (dev->irq & 0x1f); - - switch (dev->irq) { - case 1 ... 4: - return irqmap_cats[dev->irq - 1]; - - default: - printk("PCI: device %02x:%02x has unknown irq line %x\n", - dev->bus->number, dev->devfn, dev->irq); - case 0: - break; - } - return 0; -} - -static int __init netwinder_irqval(struct pci_dev *dev) -{ -#define DEV(v,d) ((v)<<16|(d)) - switch (DEV(dev->vendor, dev->device)) { - case DEV(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142): - return IRQ_NETWINDER_ETHER100; - - case DEV(PCI_VENDOR_ID_WINBOND2, 0x5a5a): - return IRQ_NETWINDER_ETHER10; - - case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553): - return 0; - - case DEV(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105): - return IRQ_ISA_HARDDISK1; - - case DEV(PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000): - return IRQ_NETWINDER_VGA; - - default: - printk(KERN_ERR "PCI: %02X:%02X [%04X:%04X] unknown device\n", - dev->bus->number, dev->devfn, - dev->vendor, dev->device); - return 0; - } -} - -struct pci_ops * __init dc21285_init(int pass) +void __init dc21285_init(void) { unsigned int mem_size; unsigned long cntl; - if (pass == 0) { - mem_size = (unsigned int)high_memory - PAGE_OFFSET; - *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; - *CSR_SDRAMBASEOFFSET = 0; - *CSR_ROMBASEMASK = 0x80000000; - *CSR_CSRBASEMASK = 0; - *CSR_CSRBASEOFFSET = 0; - *CSR_PCIADDR_EXTN = 0; + mem_size = (unsigned int)high_memory - PAGE_OFFSET; + *CSR_SDRAMBASEMASK = (mem_size - 1) & 0x0ffc0000; + *CSR_SDRAMBASEOFFSET = 0; + *CSR_ROMBASEMASK = 0x80000000; + *CSR_CSRBASEMASK = 0; + *CSR_CSRBASEOFFSET = 0; + *CSR_PCIADDR_EXTN = 0; #ifdef CONFIG_HOST_FOOTBRIDGE - /* - * Map our SDRAM at a known address in PCI space, just in case - * the firmware had other ideas. Using a nonzero base is - * necessary, since some VGA cards forcefully use PCI addresses - * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). - */ - *CSR_PCICACHELINESIZE = 0x00002008; - *CSR_PCICSRBASE = 0; - *CSR_PCICSRIOBASE = 0; - *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); - *CSR_PCIROMBASE = 0; - *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | - PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | - PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | - (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); + /* + * Map our SDRAM at a known address in PCI space, just in case + * the firmware had other ideas. Using a nonzero base is + * necessary, since some VGA cards forcefully use PCI addresses + * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). + */ + *CSR_PCICACHELINESIZE = 0x00002008; + *CSR_PCICSRBASE = 0; + *CSR_PCICSRIOBASE = 0; + *CSR_PCISDRAMBASE = virt_to_bus((void *)PAGE_OFFSET); + *CSR_PCIROMBASE = 0; + *CSR_PCICMD = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK | + PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | + (1 << 31) | (1 << 29) | (1 << 28) | (1 << 24); #endif - printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n", - *CSR_CLASSREV & 0xff); - - switch (machine_arch_type) { - case MACH_TYPE_EBSA285: - pci_irq_fixup = ebsa_irqval; - break; - - case MACH_TYPE_CATS: - pci_irq_fixup = cats_irqval; - break; - - case MACH_TYPE_NETWINDER: - pci_irq_fixup = netwinder_irqval; - break; - } - - return &dc21285_ops; - } else { - /* - * Clear any existing errors - we aren't - * interested in historical data... - */ - cntl = *CSR_SA110_CNTL & 0xffffde07; - *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; - cntl = *CSR_PCICMD & 0x0000ffff; - *CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; - - /* - * Initialise PCI error IRQ after we've finished probing - */ - setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action); - - return NULL; - } + printk(KERN_DEBUG"PCI: DC21285 footbridge, revision %02lX\n", + *CSR_CLASSREV & 0xff); + + pci_scan_bus(0, &dc21285_ops, NULL); + + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + cntl = *CSR_SA110_CNTL & 0xffffde07; + *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; + cntl = *CSR_PCICMD & 0x0000ffff; + *CSR_PCICMD = cntl | 1 << 31 | 1 << 29 | 1 << 28 | 1 << 24; + + /* + * Initialise PCI error IRQ after we've finished probing + */ + setup_arm_irq(IRQ_PCI_ERR, &dc21285_error_action); } diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 99b2b2b1d507..c777db9939d3 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -888,19 +888,13 @@ int get_ecard_dev_info(char *buf, char **start, off_t pos, int count, int wr) return (count > cnt) ? cnt : count; } -static struct proc_dir_entry proc_ecard_devices = { - PROC_BUS_ECARD_DEVICES, 7, "devices", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations, - get_ecard_dev_info -}; - -static struct proc_dir_entry *proc_bus_ecard_dir; +static struct proc_dir_entry *proc_bus_ecard_dir = NULL; static void ecard_proc_init(void) { proc_bus_ecard_dir = create_proc_entry("ecard", S_IFDIR, proc_bus); - proc_register(proc_bus_ecard_dir, &proc_ecard_devices); + create_proc_info_entry("devices", 0, proc_bus_ecard_dir, + get_ecard_dev_info); } /* diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index b09b3798b6c2..340700dbe7f1 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -42,50 +43,74 @@ extern void reboot_setup(char *str, int *ints); extern void disable_hlt(void); - -struct drive_info_struct { char dummy[32]; } drive_info; -struct screen_info screen_info = { - orig_video_lines: 30, - orig_video_cols: 80, - orig_video_mode: 0, - orig_video_ega_bx: 0, - orig_video_isVGA: 1, - orig_video_points: 8 -}; - extern int root_mountflags; -extern int _text, _etext, _edata, _end; - -unsigned char aux_device_present; - char elf_platform[ELF_PLATFORM_SIZE]; -unsigned int elf_hwcap; +extern int _stext, _text, _etext, _edata, _end; -/* - * From head-armv.S - */ unsigned int processor_id; unsigned int __machine_arch_type; unsigned int vram_size; unsigned int system_rev; unsigned int system_serial_low; unsigned int system_serial_high; -#ifdef MULTI_CPU -struct processor processor; -#endif +unsigned int elf_hwcap; + #ifdef CONFIG_ARCH_ACORN unsigned int memc_ctrl_reg; unsigned int number_mfm_drives; #endif +struct meminfo meminfo; + +#ifdef MULTI_CPU +struct processor processor; +#endif + +struct drive_info_struct { char dummy[32]; } drive_info; + +struct screen_info screen_info = { + orig_video_lines: 30, + orig_video_cols: 80, + orig_video_mode: 0, + orig_video_ega_bx: 0, + orig_video_isVGA: 1, + orig_video_points: 8 +}; + +unsigned char aux_device_present; +char elf_platform[ELF_PLATFORM_SIZE]; +char saved_command_line[COMMAND_LINE_SIZE]; + static struct proc_info_item proc_info; +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + +static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '?', '?', 'b' } }; #define ENDIANNESS ((char)endian_test.l) -/*------------------------------------------------------------------------- - * Early initialisation routines for various configurable items in the - * kernel. Each one either supplies a setup_ function, or defines this - * symbol to be empty if not configured. +/* + * Standard memory resources */ +static struct resource mem_res[] = { + { "System RAM", 0, 0, IORESOURCE_MEM | IORESOURCE_BUSY }, + { "Video RAM", 0, 0, IORESOURCE_MEM }, + { "Kernel code", 0, 0, IORESOURCE_MEM }, + { "Kernel data", 0, 0, IORESOURCE_MEM } +}; + +#define system_ram mem_res[0] +#define video_ram mem_res[1] +#define kernel_code mem_res[2] +#define kernel_data mem_res[3] + +static struct resource io_res[] = { + { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY }, + { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY }, + { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY } +}; + +#define lp0 io_res[0] +#define lp1 io_res[1] +#define lp2 io_res[2] static void __init setup_processor(void) { @@ -124,55 +149,69 @@ static void __init setup_processor(void) cpu_proc_init(); } -static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; -static char command_line[COMMAND_LINE_SIZE] = { 0, }; - char saved_command_line[COMMAND_LINE_SIZE]; +static unsigned long __init memparse(char *ptr, char **retptr) +{ + unsigned long ret = simple_strtoul(ptr, retptr, 0); + + switch (**retptr) { + case 'M': + case 'm': + ret <<= 10; + case 'K': + case 'k': + ret <<= 10; + (*retptr)++; + default: + break; + } + return ret; +} +/* + * Initial parsing of the command line. We need to pick out the + * memory size. We look for mem=size@start, where start and size + * are "size[KkMm]" + */ static void __init -setup_mem(char *cmd_line, unsigned long *mem_sz) +parse_cmdline(char **cmdline_p, char *from) { char c = ' ', *to = command_line; - int len = 0; - - if (!*mem_sz) - *mem_sz = MEM_SIZE; + int usermem = 0, len = 0; for (;;) { - if (c == ' ') { - if (cmd_line[0] == 'm' && - cmd_line[1] == 'e' && - cmd_line[2] == 'm' && - cmd_line[3] == '=') { - *mem_sz = simple_strtoul(cmd_line+4, &cmd_line, 0); - switch(*cmd_line) { - case 'M': - case 'm': - *mem_sz <<= 10; - case 'K': - case 'k': - *mem_sz <<= 10; - cmd_line++; - } - } - /* if there are two spaces, remove one */ - if (*cmd_line == ' ') { - cmd_line++; - continue; + if (c == ' ' && !memcmp(from, "mem=", 4)) { + unsigned long size, start; + + if (to != command_line) + to -= 1; + + /* If the user specifies memory size, we + * blow away any automatically generated + * size. + */ + if (usermem == 0) { + usermem = 1; + meminfo.nr_banks = 0; } + + start = 0; + size = memparse(from + 4, &from); + if (*from == '@') + start = memparse(from + 1, &from); + + meminfo.bank[meminfo.nr_banks].start = start; + meminfo.bank[meminfo.nr_banks].size = size; + meminfo.nr_banks += 1; } - c = *cmd_line++; + c = *from++; if (!c) break; if (COMMAND_LINE_SIZE <= ++len) break; *to++ = c; } - *to = '\0'; - - /* remove trailing spaces */ - while (*--to == ' ' && to != command_line) - *to = '\0'; + *cmdline_p = command_line; } static void __init @@ -199,51 +238,90 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) static void __init setup_initrd(unsigned int start, unsigned int size) { #ifdef CONFIG_BLK_DEV_INITRD - if (start) { - initrd_start = start; - initrd_end = start + size; - } else { - initrd_start = 0; - initrd_end = 0; - } + if (start == 0) + size = 0; + initrd_start = start; + initrd_end = start + size; #endif } -static void __init check_initrd(unsigned long mem_end) +/* + * Work out our memory regions. Note that "pfn" is the physical page number + * relative to the first physical page, not the physical address itself. + */ +static void __init setup_bootmem(void) { + unsigned int end_pfn, bootmem_end; + int bank; + + /* + * Calculate the end of memory. + */ + for (bank = 0; bank < meminfo.nr_banks; bank++) { + if (meminfo.bank[bank].size) { + unsigned long end; + + end = meminfo.bank[bank].start + + meminfo.bank[bank].size; + if (meminfo.end < end) + meminfo.end = end; + } + } + + bootmem_end = __pa(PAGE_ALIGN((unsigned long)&_end)); + end_pfn = meminfo.end >> PAGE_SHIFT; + + /* + * Initialise the boot-time allocator + */ + bootmem_end += init_bootmem(bootmem_end >> PAGE_SHIFT, end_pfn); + + /* + * Register all available RAM with the bootmem allocator. + * The address is relative to the start of physical memory. + */ + for (bank = 0; bank < meminfo.nr_banks; bank ++) + free_bootmem(meminfo.bank[bank].start, meminfo.bank[bank].size); + + /* + * reserve the following regions: + * physical page 0 - it contains the exception vectors + * kernel and the bootmem structure + * swapper page directory (if any) + * initrd (if any) + */ + reserve_bootmem(0, PAGE_SIZE); +#ifdef CONFIG_CPU_32 + reserve_bootmem(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(void *)); +#endif + reserve_bootmem(__pa(&_stext), bootmem_end - __pa(&_stext)); #ifdef CONFIG_BLK_DEV_INITRD - if (initrd_end > mem_end) { + if (__pa(initrd_end) > (end_pfn << PAGE_SHIFT)) { printk ("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx) - disabling initrd\n", - initrd_end, mem_end); + "(0x%08lx > 0x%08x) - disabling initrd\n", + __pa(initrd_end), end_pfn << PAGE_SHIFT); initrd_start = 0; } + + if (initrd_start) + reserve_bootmem(__pa(initrd_start), + initrd_end - initrd_start); #endif } -/* - * Standard memory resources - */ -static struct resource system_ram = { "System RAM", 0, 0, IORESOURCE_MEM | IORESOURCE_BUSY }; -static struct resource video_ram = { "Video RAM", 0, 0, IORESOURCE_MEM }; -static struct resource kernel_code = { "Kernel code", 0, 0, IORESOURCE_MEM }; -static struct resource kernel_data = { "Kernel data", 0, 0, IORESOURCE_MEM }; -static struct resource lpt1 = { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY }; -static struct resource lpt2 = { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY }; -static struct resource lpt3 = { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }; - -static void __init request_standard_resources(unsigned long end) +static void __init request_standard_resources(void) { kernel_code.start = __virt_to_bus((unsigned long) &_text); kernel_code.end = __virt_to_bus((unsigned long) &_etext - 1); kernel_data.start = __virt_to_bus((unsigned long) &_etext); kernel_data.end = __virt_to_bus((unsigned long) &_edata - 1); system_ram.start = __virt_to_bus(PAGE_OFFSET); - system_ram.end = __virt_to_bus(end - 1); + system_ram.end = __virt_to_bus(meminfo.end + PAGE_OFFSET - 1); request_resource(&iomem_resource, &system_ram); request_resource(&system_ram, &kernel_code); request_resource(&system_ram, &kernel_data); + if (video_ram.start != video_ram.end) request_resource(&iomem_resource, &video_ram); @@ -253,17 +331,16 @@ static void __init request_standard_resources(unsigned long end) */ if (machine_is_ebsa110() || machine_is_riscpc() || machine_is_netwinder()) - request_resource(&ioport_resource, &lpt1); + request_resource(&ioport_resource, &lp0); if (machine_is_riscpc()) - request_resource(&ioport_resource, &lpt2); + request_resource(&ioport_resource, &lp1); if (machine_is_ebsa110() || machine_is_netwinder()) - request_resource(&ioport_resource, &lpt3); + request_resource(&ioport_resource, &lp2); } -void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) +void __init setup_arch(char **cmdline_p) { struct param_struct *params = (struct param_struct *)PARAMS_BASE; - unsigned long memory_end = 0; char *from = default_command_line; #if defined(CONFIG_ARCH_ARC) @@ -296,10 +373,6 @@ void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigne case MACH_TYPE_RISCPC: /* RiscPC can't handle half-word loads and stores */ elf_hwcap &= ~HWCAP_HALF; - { - extern void init_dram_banks(struct param_struct *); - init_dram_banks(params); - } switch (params->u1.s.pages_in_vram) { case 512: @@ -309,6 +382,17 @@ void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigne default: break; } + { + int i; + + for (i = 0; i < 4; i++) { + meminfo.bank[i].start = i << 26; + meminfo.bank[i].size = + params->u1.s.pages_in_bank[i] * + params->u1.s.page_size; + } + meminfo.nr_banks = 4; + } #endif case MACH_TYPE_ARCHIMEDES: case MACH_TYPE_A5K: @@ -347,7 +431,7 @@ void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigne */ reboot_setup("s", NULL); params = NULL; - ORIG_VIDEO_LINES = 25; + ORIG_VIDEO_LINES = 25; ORIG_VIDEO_POINTS = 16; ORIG_Y = 24; video_ram.start = 0x0a0000; @@ -393,7 +477,11 @@ void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigne } if (params) { - memory_end = PAGE_SIZE * params->u1.s.nr_pages; + if (meminfo.nr_banks == 0) { + meminfo.nr_banks = 1; + meminfo.bank[0].start = 0; + meminfo.bank[0].size = params->u1.s.nr_pages << PAGE_SHIFT; + } ROOT_DEV = to_kdev_t(params->u1.s.rootdev); system_rev = params->u1.s.system_rev; system_serial_low = params->u1.s.system_serial_low; @@ -413,24 +501,23 @@ void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigne from = params->commandline; } - /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, from, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - - setup_mem(from, &memory_end); - - memory_end += PAGE_OFFSET; + if (meminfo.nr_banks == 0) { + meminfo.nr_banks = 1; + meminfo.bank[0].start = 0; + meminfo.bank[0].size = MEM_SIZE; + } - *cmdline_p = command_line; init_mm.start_code = (unsigned long) &_text; init_mm.end_code = (unsigned long) &_etext; init_mm.end_data = (unsigned long) &_edata; init_mm.brk = (unsigned long) &_end; - *memory_start_p = (unsigned long) &_end; - *memory_end_p = memory_end; - request_standard_resources(memory_end); - check_initrd(memory_end); + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, from, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + parse_cmdline(cmdline_p, from); + setup_bootmem(); + request_standard_resources(); #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c index 3d39c8d39580..f25544c144bb 100644 --- a/arch/arm/kernel/sys_arm.c +++ b/arch/arm/kernel/sys_arm.c @@ -29,8 +29,6 @@ /* * Constant strings used in inlined functions in header files */ -/* proc/system.h */ -const char xchg_str[] = "xchg"; /* * sys_pipe() is the normal C calling standard for creating diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index da0d464f6cd1..038946e9c1ce 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -34,7 +34,10 @@ char *processor_modes[]= "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" }; -static char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; +/* proc/system.h */ +const char xchg_str[] = "xchg"; + +static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; static inline void console_verbose(void) { @@ -335,10 +338,11 @@ asmlinkage void deferred(int n, struct pt_regs *regs) } #ifdef CONFIG_DEBUG_USER - printk(KERN_ERR "[%d] %s: old system call.\n", current->pid, - current->comm); + printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", current->pid, + current->comm, n); #endif force_sig(SIGILL, current); + die_if_kernel("Oops", regs, n); } asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr) @@ -385,8 +389,37 @@ asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs } #endif +void __bug(const char *file, int line, void *data) +{ + printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line); + if (data) + printk(KERN_CRIT"extra data = %p\n", data); + *(int *)0 = 0; +} + +void __readwrite_bug(const char *fn) +{ + printk("%s called, but not implemented", fn); + *(int *)0 = 0; +} + +void __pte_error(const char *file, int line, unsigned long val) +{ + printk("%s:%d: bad pte %08lx.\n", file, line, val); +} + +void __pmd_error(const char *file, int line, unsigned long val) +{ + printk("%s:%d: bad pmd %08lx.\n", file, line, val); +} + +void __pgd_error(const char *file, int line, unsigned long val) +{ + printk("%s:%d: bad pgd %08lx.\n", file, line, val); +} + asmlinkage void __div0(void) { - printk("Awooga, division by zero in kernel.\n"); + printk("Division by zero in kernel.\n"); __backtrace(); } diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 8c2df7f5e97a..8715ea271a95 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -90,6 +90,7 @@ static unsigned long ai_half; static unsigned long ai_word; static unsigned long ai_multi; +#ifdef CONFIG_SYSCTL static int proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -113,23 +114,18 @@ static int proc_alignment_read(char *page, char **start, off_t off, return len; } -#ifdef CONFIG_SYSCTL /* * This needs to be done after sysctl_init, otherwise sys/ * will be overwritten. */ void __init alignment_init(void) { - struct proc_dir_entry *e; - - e = create_proc_entry("sys/debug/alignment", S_IFREG | S_IRUGO, NULL); - - if (e) - e->read_proc = proc_alignment_read; + create_proc_read_entry("sys/debug/alignment", 0, NULL, + proc_alignment_read); } __initcall(alignment_init); -#endif +#endif /* CONFIG_SYSCTL */ static int do_alignment_exception(struct pt_regs *regs) diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c index c87fa760e048..e516261ed64f 100644 --- a/arch/arm/mm/fault-common.c +++ b/arch/arm/mm/fault-common.c @@ -8,24 +8,6 @@ extern void die(char *msg, struct pt_regs *regs, unsigned int err); -void __bad_pmd(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); -} - -void __bad_pmd_kernel(pmd_t *pmd) -{ - printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); -#ifdef CONFIG_DEBUG_ERRORS - __backtrace(); -#endif - set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); -} - /* * This is useful to dump out the page tables associated with * 'addr' in mm 'mm'. diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 115cec885d82..229b4dcd790e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -1,7 +1,7 @@ /* * linux/arch/arm/mm/init.c * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-1999 Russell King */ #include @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include #endif @@ -27,73 +28,94 @@ #include #include #include +#include #include "map.h" +static unsigned long totalram_pages; pgd_t swapper_pg_dir[PTRS_PER_PGD]; -#ifndef CONFIG_NO_PGT_CACHE -struct pgtable_cache_struct quicklists; -#endif -extern unsigned long free_area_init(unsigned long, unsigned long); extern void show_net_buffers(void); -extern char _etext, _text, _edata, __bss_start, _end; -extern char __init_begin, __init_end; - -int do_check_pgt_cache(int low, int high) -{ - int freed = 0; -#ifndef CONFIG_NO_PGT_CACHE - if(pgtable_cache_size > high) { - do { - if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; - if(pmd_quicklist) - free_pmd_slow(get_pmd_fast()), freed++; - if(pte_quicklist) - free_pte_slow(get_pte_fast()), freed++; - } while(pgtable_cache_size > low); - } -#endif - return freed; -} - /* - * BAD_PAGE is the page that is used for page faults when linux - * is out-of-memory. Older versions of linux just did a + * empty_bad_page is the page that is used for page faults when + * linux is out-of-memory. Older versions of linux just did a * do_exit(), but using this instead means there is less risk * for a process dying in kernel mode, possibly leaving a inode * unused etc.. * - * BAD_PAGETABLE is the accompanying page-table: it is initialized - * to point to BAD_PAGE entries. + * empty_bad_pte_table is the accompanying page-table: it is + * initialized to point to BAD_PAGE entries. * - * ZERO_PAGE is a special page that is used for zero-initialized - * data and COW. + * empty_zero_page is a special page that is used for + * zero-initialized data and COW. */ -pte_t *empty_bad_page_table; +struct page *empty_zero_page; +struct page *empty_bad_page; +pte_t *empty_bad_pte_table; -pte_t *__bad_pagetable(void) +pte_t *get_bad_pte_table(void) { - pte_t bad_page; + pte_t v; int i; - bad_page = BAD_PAGE; + v = pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED)); + for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(empty_bad_page_table + i, bad_page); + set_pte(empty_bad_pte_table + i, v); + + return empty_bad_pte_table; +} + +void __handle_bad_pmd(pmd_t *pmd) +{ + pmd_ERROR(*pmd); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); +} - return empty_bad_page_table; +void __handle_bad_pmd_kernel(pmd_t *pmd) +{ + pmd_ERROR(*pmd); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table())); } -unsigned long *empty_zero_page; -unsigned long *empty_bad_page; +#ifndef CONFIG_NO_PGT_CACHE +struct pgtable_cache_struct quicklists; + +int do_check_pgt_cache(int low, int high) +{ + int freed = 0; -pte_t __bad_page(void) + if(pgtable_cache_size > high) { + do { + if(pgd_quicklist) { + free_pgd_slow(get_pgd_fast()); + freed++; + } + if(pmd_quicklist) { + free_pmd_slow(get_pmd_fast()); + freed++; + } + if(pte_quicklist) { + free_pte_slow(get_pte_fast()); + freed++; + } + } while(pgtable_cache_size > low); + } + return freed; +} +#else +int do_check_pgt_cache(int low, int high) { - memzero (empty_bad_page, PAGE_SIZE); - return pte_nocache(pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED))); + return 0; } +#endif void show_mem(void) { @@ -104,23 +126,28 @@ void show_mem(void) printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - for (page = mem_map, end = mem_map + max_mapnr; - page < end; page++) { + + page = mem_map; + end = mem_map + max_mapnr; + + do { if (PageSkip(page)) { - if (page->next_hash < page) - break; page = page->next_hash; + if (page == NULL) + break; } total++; if (PageReserved(page)) reserved++; else if (PageSwapCache(page)) cached++; - else if (!atomic_read(&page->count)) + else if (!page_count(page)) free++; else shared += atomic_read(&page->count) - 1; - } + page++; + } while (page < end); + printk("%d pages of RAM\n", total); printk("%d free pages\n", free); printk("%d reserved pages\n", reserved); @@ -138,31 +165,42 @@ void show_mem(void) /* * paging_init() sets up the page tables... */ -unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) +void __init paging_init(void) { - start_mem = PAGE_ALIGN(start_mem); - - empty_zero_page = (unsigned long *)start_mem; - memzero(empty_zero_page, PAGE_SIZE); - start_mem += PAGE_SIZE; - - empty_bad_page = (unsigned long *)start_mem; - start_mem += PAGE_SIZE; + void *zero_page, *bad_page, *bad_table; #ifdef CONFIG_CPU_32 - start_mem += PTRS_PER_PTE * BYTES_PER_PTR; +#define TABLE_OFFSET (PTRS_PER_PTE) +#else +#define TABLE_OFFSET 0 #endif - empty_bad_page_table = (pte_t *)start_mem; - start_mem += PTRS_PER_PTE * BYTES_PER_PTR; - - start_mem = setup_page_tables(start_mem, end_mem); - +#define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *)) + + /* + * allocate what we need for the bad pages + */ + zero_page = alloc_bootmem_low_pages(PAGE_SIZE); + bad_page = alloc_bootmem_low_pages(PAGE_SIZE); + bad_table = alloc_bootmem_low_pages(TABLE_SIZE); + + /* + * initialise the page tables + */ + pagetable_init(); flush_tlb_all(); - end_mem &= PAGE_MASK; - high_memory = (void *)end_mem; + free_area_init(max_low_pfn); + + /* + * finish off the bad pages once + * the mem_map is initialised + */ + memzero(zero_page, PAGE_SIZE); + memzero(bad_page, PAGE_SIZE); - return free_area_init(start_mem, end_mem); + empty_zero_page = mem_map + MAP_NR(zero_page); + empty_bad_page = mem_map + MAP_NR(bad_page); + empty_bad_pte_table = ((pte_t *)bad_table) + TABLE_OFFSET; } static inline void free_unused_mem_map(void) @@ -184,7 +222,7 @@ static inline void free_unused_mem_map(void) high = ((unsigned long)page->next_hash) & PAGE_MASK; while (low < high) { - clear_bit(PG_reserved, &mem_map[MAP_NR(low)].flags); + ClearPageReserved(mem_map + MAP_NR(low)); low += PAGE_SIZE; } } @@ -195,67 +233,35 @@ static inline void free_unused_mem_map(void) * memory is free. This is done after various parts of the system have * claimed their memory after the kernel image. */ -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +void __init mem_init(void) { int codepages = 0; int reservedpages = 0; int datapages = 0; int initpages = 0, i, min_nr; - unsigned long tmp; - end_mem &= PAGE_MASK; - high_memory = (void *)end_mem; - max_mapnr = MAP_NR(end_mem); - num_physpages = 0; - - /* setup address validity bitmap */ - start_mem = create_mem_holes(start_mem, end_mem); - - start_mem = PAGE_ALIGN(start_mem); - - /* mark usable pages in the mem_map[] */ - mark_usable_memory_areas(start_mem, end_mem); - - /* free unused mem_map[] entries */ - free_unused_mem_map(); + max_mapnr = max_low_pfn; + high_memory = (void *)__va(max_low_pfn * PAGE_SIZE); -#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \ - (w) < (unsigned long)(max)) - - for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) { - if (PageSkip(mem_map+MAP_NR(tmp))) { - unsigned long next; - - next = mem_map[MAP_NR(tmp)].next_hash - mem_map; - - next = (next << PAGE_SHIFT) + PAGE_OFFSET; - - if (next < tmp || next >= end_mem) - break; - tmp = next; - } - num_physpages++; - if (PageReserved(mem_map+MAP_NR(tmp))) { - if (BETWEEN(tmp, &__init_begin, &__init_end)) - initpages++; - else if (BETWEEN(tmp, &_text, &_etext)) - codepages++; - else if (BETWEEN(tmp, &_etext, &_edata)) - datapages++; - else if (BETWEEN(tmp, &__bss_start, start_mem)) - datapages++; - else - reservedpages++; - continue; - } - atomic_set(&mem_map[MAP_NR(tmp)].count, 1); -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end)) +#ifdef CONFIG_CPU_32 + /* + * We may have non-contiguous memory. Setup the PageSkip stuff, + * and mark the areas of mem_map which can be freed + */ + if (meminfo.nr_banks != 1) + create_memmap_holes(); #endif - free_page(tmp); - } -#undef BETWEEN + /* this will put all unused low memory onto the freelists */ + totalram_pages += free_all_bootmem(); + + /* + * Since our memory may not be contiguous, calculate the + * real number of pages we have in this system + */ + num_physpages = 0; + for (i = 0; i < meminfo.nr_banks; i++) + num_physpages += meminfo.bank[i].size >> PAGE_SHIFT; printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n", (unsigned long) nr_free_pages << (PAGE_SHIFT-10), @@ -265,6 +271,9 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem) datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10)); + /* + * Correct freepages watermarks + */ i = nr_free_pages >> 7; if (PAGE_SIZE < 32768) min_nr = 10; @@ -288,22 +297,26 @@ void __init mem_init(unsigned long start_mem, unsigned long end_mem) #endif } -static void free_area(unsigned long addr, unsigned long end, char *s) +static inline void free_area(unsigned long addr, unsigned long end, char *s) { unsigned int size = (end - addr) >> 10; + struct page *page = mem_map + MAP_NR(addr); - for (; addr < end; addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(addr)].count, 1); + for (; addr < end; addr += PAGE_SIZE, page ++) { + ClearPageReserved(page); + set_page_count(page, 1); free_page(addr); + totalram_pages++; } if (size) printk(" %dk %s", size, s); } -void free_initmem (void) +void free_initmem(void) { + extern char __init_begin, __init_end; + printk("Freeing unused kernel memory:"); free_area((unsigned long)(&__init_begin), @@ -333,28 +346,11 @@ void free_initmem (void) void si_meminfo(struct sysinfo *val) { - struct page *page, *end; - - val->totalram = 0; + val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); - for (page = mem_map, end = mem_map + max_mapnr; - page < end; page++) { - if (PageSkip(page)) { - if (page->next_hash < page) - break; - page = page->next_hash; - } - if (PageReserved(page)) - continue; - val->totalram++; - if (!atomic_read(&page->count)) - continue; - val->sharedram += atomic_read(&page->count) - 1; - } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; - val->totalbig = 0; - val->freebig = 0; + val->freeram = nr_free_pages; + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = 0; + val->mem_unit = PAGE_SIZE; } diff --git a/arch/arm/mm/map.h b/arch/arm/mm/map.h index a1fc92b2c728..0a3ee8b4d085 100644 --- a/arch/arm/mm/map.h +++ b/arch/arm/mm/map.h @@ -16,17 +16,9 @@ struct map_desc { bufferable:1; }; -struct mem_desc { - unsigned long virt_start; - unsigned long virt_end; -}; - extern struct map_desc io_desc[]; extern unsigned int io_desc_size; -extern struct mem_desc mem_desc[]; -extern unsigned int mem_desc_size; -extern void mark_usable_memory_areas(unsigned long start, unsigned long end); -extern unsigned long create_mem_holes(unsigned long start, unsigned long end); -extern unsigned long setup_page_tables(unsigned long start, unsigned long end); +extern void create_memmap_holes(void); +extern void pagetable_init(void); diff --git a/arch/arm/mm/mm-armo.c b/arch/arm/mm/mm-armo.c index 55245f4e8dc5..5ee95ea4520c 100644 --- a/arch/arm/mm/mm-armo.c +++ b/arch/arm/mm/mm-armo.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -18,40 +19,54 @@ #define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) #define PGD_TABLE_SIZE (PTRS_PER_PGD * BYTES_PER_PTR) -/* - * FIXME: the following over-allocates by 6400% - */ -static inline void *alloc_table(int size, int prio) -{ - if (size != 128) - printk("invalid table size\n"); - return (void *)get_page_8k(prio); -} +int page_nr; + +extern unsigned long get_page_2k(int prio); +extern void free_page_2k(unsigned long); +extern pte_t *get_bad_pte_table(void); /* * Allocate a page table. Note that we place the MEMC * table before the page directory. This means we can * easily get to both tightly-associated data structures - * with a single pointer. This function is slightly - * better - it over-allocates by only 711% + * with a single pointer. + * + * We actually only need 1152 bytes, 896 bytes is wasted. + * We could try to fit 7 PTEs into that slot somehow. */ static inline void *alloc_pgd_table(int priority) { - unsigned long pg8k; + unsigned long pg2k; - pg8k = get_page_8k(priority); - if (pg8k) - pg8k += MEMC_TABLE_SIZE; + pg2k = get_page_2k(priority); + if (pg2k) + pg2k += MEMC_TABLE_SIZE; - return (void *)pg8k; + return (void *)pg2k; } -void free_table(void *table) +void free_pgd_slow(pgd_t *pgd) { - unsigned long tbl = (unsigned long)table; + unsigned long tbl = (unsigned long)pgd; + + tbl -= MEMC_TABLE_SIZE; + free_page_2k(tbl); +} - tbl &= ~8191; - free_page_8k(tbl); +/* + * FIXME: the following over-allocates by 1600% + */ +static inline void *alloc_pte_table(int size, int prio) +{ + if (size != 128) + printk("invalid table size\n"); + return (void *)get_page_2k(prio); +} + +void free_pte_slow(pte_t *pte) +{ + unsigned long tbl = (unsigned long)pte; + free_page_2k(tbl); } pgd_t *get_pgd_slow(void) @@ -62,9 +77,9 @@ pgd_t *get_pgd_slow(void) if (pgd) { pgd_t *init = pgd_offset(&init_mm, 0); - memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t)); memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); /* * On ARM, first page must always be allocated @@ -92,7 +107,7 @@ pgd_t *get_pgd_slow(void) nomem_pmd: pmd_free(new_pmd); nomem: - free_table(pgd); + free_pgd_slow(pgd); return NULL; } @@ -100,19 +115,19 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) { pte_t *pte; - pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); + pte = (pte_t *)alloc_pte_table(PTRS_PER_PTE * sizeof(pte_t), GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR); - set_pmd(pmd, mk_pmd(pte)); + memzero(pte, PTRS_PER_PTE * sizeof(pte_t)); + set_pmd(pmd, mk_user_pmd(pte)); return pte + offset; } - set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); return NULL; } - free_table((void *)pte); + free_pte_slow(pte); if (pmd_bad(*pmd)) { - __bad_pmd(pmd); + __handle_bad_pmd(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + offset; @@ -124,47 +139,22 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) * some more work to get it to fit into our separate processor and * architecture structure. */ -int page_nr; - -#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR) - -static inline void setup_swapper_dir (int index, pte_t *ptep) +void __init pagetable_init(void) { - set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep)); -} - -unsigned long __init -setup_page_tables(unsigned long start_mem, unsigned long end_mem) -{ - unsigned int i; - union { unsigned long l; pte_t *pte; } u; + pte_t *pte; + int i; - page_nr = MAP_NR(end_mem); + page_nr = max_low_pfn; - /* map in pages for (0x0000 - 0x8000) */ - u.l = ((start_mem + (PTE_SIZE-1)) & ~(PTE_SIZE-1)); - start_mem = u.l + PTE_SIZE; - memzero (u.pte, PTE_SIZE); - u.pte[0] = mk_pte(PAGE_OFFSET + 491520, PAGE_READONLY); - setup_swapper_dir (0, u.pte); + pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); + memzero(pte, PTRS_PER_PTE * sizeof(pte_t)); + pte[0] = mk_pte_phys(PAGE_OFFSET + 491520, PAGE_READONLY); + set_pmd(pmd_offset(swapper_pg_dir, 0), mk_kernel_pmd(pte)); for (i = 1; i < PTRS_PER_PGD; i++) pgd_val(swapper_pg_dir[i]) = 0; - - return start_mem; } -unsigned long __init -create_mem_holes(unsigned long start, unsigned long end) +void __init create_memmap_holes(void) { - return start; -} - -void __init -mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem) -{ - while (start_mem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; - } } diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index d52c21cc4130..3df6c13b53d8 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -1,22 +1,28 @@ /* - * arch/arm/mm/mm-armv.c + * linux/arch/arm/mm/mm-armv.c * - * Page table sludge for ARM v3 and v4 processor architectures. + * Page table sludge for ARM v3 and v4 processor architectures. * - * Copyright (C) 1998-1999 Russell King + * Copyright (C) 1998-1999 Russell King */ #include #include #include +#include #include #include #include +#include #include "map.h" unsigned long *valid_addr_bitmap; +extern unsigned long get_page_2k(int priority); +extern void free_page_2k(unsigned long page); +extern pte_t *get_bad_pte_table(void); + /* * need to get a 16k page for level 1 */ @@ -26,12 +32,12 @@ pgd_t *get_pgd_slow(void) pmd_t *new_pmd; if (pgd) { - pgd_t *init = pgd_offset(&init_mm, 0); + pgd_t *init = pgd_offset_k(0); - memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memzero(pgd, USER_PTRS_PER_PGD * sizeof(pgd_t)); memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); - clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR); + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + clean_cache_area(pgd, PTRS_PER_PGD * sizeof(pgd_t)); /* * On ARM, first page must always be allocated @@ -48,7 +54,7 @@ pgd_t *get_pgd_slow(void) pte_t *new_pte = pte_offset(new_pmd, 0); pte_t *old_pte = pte_offset(old_pmd, 0); - set_pte (new_pte, *old_pte); + set_pte(new_pte, *old_pte); } } } @@ -61,6 +67,31 @@ nomem: return NULL; } +void free_pgd_slow(pgd_t *pgd) +{ + if (pgd) { /* can pgd be NULL? */ + pmd_t *pmd; + pte_t *pte; + + /* pgd is always present and good */ + pmd = (pmd_t *)pgd; + if (pmd_none(*pmd)) + goto free; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + goto free; + } + + pte = pte_offset(pmd, 0); + pmd_clear(pmd); + pte_free(pte); + pmd_free(pmd); + } +free: + free_pages((unsigned long) pgd, 2); +} + pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) { pte_t *pte; @@ -68,18 +99,18 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) pte = (pte_t *)get_page_2k(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); - clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); + clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); pte += PTRS_PER_PTE; set_pmd(pmd, mk_user_pmd(pte)); return pte + offset; } - set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); + set_pmd(pmd, mk_user_pmd(get_bad_pte_table())); return NULL; } free_page_2k((unsigned long)pte); if (pmd_bad(*pmd)) { - __bad_pmd(pmd); + __handle_bad_pmd(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + offset; @@ -92,23 +123,28 @@ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) pte = (pte_t *)get_page_2k(GFP_KERNEL); if (pmd_none(*pmd)) { if (pte) { - memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR); - clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR); + memzero(pte, 2 * PTRS_PER_PTE * sizeof(pte_t)); + clean_cache_area(pte, PTRS_PER_PTE * sizeof(pte_t)); pte += PTRS_PER_PTE; set_pmd(pmd, mk_kernel_pmd(pte)); return pte + offset; } - set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); + set_pmd(pmd, mk_kernel_pmd(get_bad_pte_table())); return NULL; } free_page_2k((unsigned long)pte); if (pmd_bad(*pmd)) { - __bad_pmd_kernel(pmd); + __handle_bad_pmd_kernel(pmd); return NULL; } return (pte_t *) pmd_page(*pmd) + offset; } +void free_pte_slow(pte_t *pte) +{ + free_page_2k((unsigned long)(pte - PTRS_PER_PTE)); +} + /* * Create a SECTION PGD between VIRT and PHYS in domain * DOMAIN with protection PROT @@ -131,34 +167,22 @@ alloc_init_section(unsigned long virt, unsigned long phys, int prot) * the hardware pte table. */ static inline void -alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot) +alloc_init_page(unsigned long virt, unsigned long phys, int domain, int prot) { pmd_t *pmdp; pte_t *ptep; pmdp = pmd_offset(pgd_offset_k(virt), virt); -#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR) - if (pmd_none(*pmdp)) { - unsigned long memory = *mem; - - memory = (memory + PTE_SIZE - 1) & ~(PTE_SIZE - 1); + pte_t *ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * + sizeof(pte_t)); - ptep = (pte_t *)memory; - memzero(ptep, PTE_SIZE); - memory += PTE_SIZE; - - ptep = (pte_t *)memory; - memzero(ptep, PTE_SIZE); + memzero(ptep, 2 * PTRS_PER_PTE * sizeof(pte_t)); + ptep += PTRS_PER_PTE; set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain))); - - *mem = memory + PTE_SIZE; } - -#undef PTE_SIZE - ptep = pte_offset(pmdp, virt); set_pte(ptep, mk_pte_phys(phys, __pgprot(prot))); @@ -169,8 +193,7 @@ alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int * the clearance is done by the middle-level functions (pmd) * rather than the top-level (pgd) functions. */ -static inline void -free_init_section(unsigned long virt) +static inline void free_init_section(unsigned long virt) { pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); } @@ -181,8 +204,7 @@ free_init_section(unsigned long virt) * are able to cope here with varying sizes and address * offsets, and we take full advantage of sections. */ -static void __init -create_mapping(unsigned long *mem_ptr, struct map_desc *md) +static void __init create_mapping(struct map_desc *md) { unsigned long virt, length; int prot_sect, prot_pte; @@ -205,7 +227,7 @@ create_mapping(unsigned long *mem_ptr, struct map_desc *md) length = md->length; while ((virt & 1048575 || (virt + off) & 1048575) && length >= PAGE_SIZE) { - alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte); + alloc_init_page(virt, virt + off, md->domain, prot_pte); virt += PAGE_SIZE; length -= PAGE_SIZE; @@ -219,7 +241,7 @@ create_mapping(unsigned long *mem_ptr, struct map_desc *md) } while (length >= PAGE_SIZE) { - alloc_init_page(mem_ptr, virt, virt + off, md->domain, prot_pte); + alloc_init_page(virt, virt + off, md->domain, prot_pte); virt += PAGE_SIZE; length -= PAGE_SIZE; @@ -227,17 +249,15 @@ create_mapping(unsigned long *mem_ptr, struct map_desc *md) } /* - * Initial boot-time mapping. This covers just the - * zero page, kernel and the flush area. NB: it - * must be sorted by virtual address, and no + * Initial boot-time mapping. This covers just the zero page, kernel and + * the flush area. NB: it must be sorted by virtual address, and no * virtual address overlaps. - * init_map[2..4] are for architectures with small - * amounts of banked memory. + * init_map[2..4] are for architectures with banked memory. */ static struct map_desc init_map[] __initdata = { { 0, 0, PAGE_SIZE, DOMAIN_USER, 0, 0, 1, 0 }, /* zero page */ { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, /* kernel memory */ - { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, + { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, /* (4 banks) */ { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, { 0, 0, 0, DOMAIN_KERNEL, 0, 1, 1, 1 }, { 0, 0, PGDIR_SIZE, DOMAIN_KERNEL, 1, 0, 1, 1 }, /* cache flush 1 */ @@ -246,19 +266,15 @@ static struct map_desc init_map[] __initdata = { #define NR_INIT_MAPS (sizeof(init_map) / sizeof(init_map[0])) -unsigned long __init -setup_page_tables(unsigned long start_mem, unsigned long end_mem) +void __init pagetable_init(void) { unsigned long address = 0; - int idx = 0; + int i; /* - * Correct the above mappings + * Setup the above mappings */ - init_map[0].physical = - init_map[1].physical = __virt_to_phys(PAGE_OFFSET); - init_map[1].virtual = PAGE_OFFSET; - init_map[1].length = end_mem - PAGE_OFFSET; + init_map[0].physical = PHYS_OFFSET; init_map[5].physical = FLUSH_BASE_PHYS; init_map[5].virtual = FLUSH_BASE; #ifdef FLUSH_BASE_MINICACHE @@ -267,109 +283,108 @@ setup_page_tables(unsigned long start_mem, unsigned long end_mem) init_map[6].length = PGDIR_SIZE; #endif + for (i = 0; i < meminfo.nr_banks; i++) { + init_map[i+1].physical = PHYS_OFFSET + meminfo.bank[i].start; + init_map[i+1].virtual = PAGE_OFFSET + meminfo.bank[i].start; + init_map[i+1].length = meminfo.bank[i].size; + } + /* - * Firstly, go through the initial mappings, - * but clear out any pgdir entries that are - * not in the description. + * Go through the initial mappings, but clear out any + * pgdir entries that are not in the description. */ + i = 0; do { - if (address < init_map[idx].virtual || idx == NR_INIT_MAPS) { + if (address < init_map[i].virtual || i == NR_INIT_MAPS) { free_init_section(address); address += PGDIR_SIZE; } else { - create_mapping(&start_mem, init_map + idx); + create_mapping(init_map + i); - address = init_map[idx].virtual + init_map[idx].length; + address = init_map[i].virtual + init_map[i].length; address = (address + PGDIR_SIZE - 1) & PGDIR_MASK; do { - idx += 1; - } while (init_map[idx].length == 0 && idx < NR_INIT_MAPS); + i += 1; + } while (init_map[i].length == 0 && i < NR_INIT_MAPS); } } while (address != 0); /* - * Now, create the architecture specific mappings + * Create the architecture specific mappings */ - for (idx = 0; idx < io_desc_size; idx++) - create_mapping(&start_mem, io_desc + idx); + for (i = 0; i < io_desc_size; i++) + create_mapping(io_desc + i); flush_cache_all(); - - return start_mem; } /* - * The mem_map array can get very big. Mark the end of the - * valid mem_map banks with PG_skip, and setup the address - * validity bitmap. + * The mem_map array can get very big. Mark the end of the valid mem_map + * banks with PG_skip, and setup the address validity bitmap. */ -unsigned long __init -create_mem_holes(unsigned long start_mem, unsigned long end_mem) +void __init create_memmap_holes(void) { + unsigned int start_pfn, end_pfn = -1; struct page *pg = NULL; unsigned int sz, i; - if (!machine_is_riscpc()) - return start_mem; + for (i = 0; i < meminfo.nr_banks; i++) { + if (meminfo.bank[i].size == 0) + continue; - sz = (end_mem - PAGE_OFFSET) >> 20; - sz = (sz + 31) >> 3; - - valid_addr_bitmap = (unsigned long *)start_mem; - start_mem += sz; + start_pfn = meminfo.bank[i].start >> PAGE_SHIFT; - memset(valid_addr_bitmap, 0, sz); + /* + * subtle here - if we have a full bank, then + * start_pfn == end_pfn, and we don't want to + * set PG_skip, or next_hash + */ + if (pg && start_pfn != end_pfn) { + set_bit(PG_skip, &pg->flags); + pg->next_hash = mem_map + start_pfn; - if (start_mem > mem_desc[0].virt_end) - printk(KERN_CRIT "*** Error: RAM bank 0 too small\n"); + start_pfn = PAGE_ALIGN(__pa(pg + 1)); + end_pfn = __pa(pg->next_hash) & PAGE_MASK; - for (i = 0; i < mem_desc_size; i++) { - unsigned int idx, end; + if (end_pfn != start_pfn) + free_bootmem(start_pfn, end_pfn - start_pfn); - if (pg) { - pg->next_hash = mem_map + - MAP_NR(mem_desc[i].virt_start); pg = NULL; } - idx = __kern_valid_idx(mem_desc[i].virt_start); - end = __kern_valid_idx(mem_desc[i].virt_end); - - do - set_bit(idx, valid_addr_bitmap); - while (++idx < end); - - if (mem_desc[i].virt_end < end_mem) { - pg = mem_map + MAP_NR(mem_desc[i].virt_end); + end_pfn = (meminfo.bank[i].start + + meminfo.bank[i].size) >> PAGE_SHIFT; - set_bit(PG_skip, &pg->flags); - } + if (end_pfn != meminfo.end >> PAGE_SHIFT) + pg = mem_map + end_pfn; } - if (pg) + if (pg) { + set_bit(PG_skip, &pg->flags); pg->next_hash = NULL; - - return start_mem; -} - -void __init -mark_usable_memory_areas(unsigned long start_mem, unsigned long end_mem) -{ - /* - * Mark all of memory from the end of kernel to end of memory - */ - while (start_mem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; } +#if 0 /* - * Mark memory from page 1 to start of the swapper page directory + * setup address validity map + * - don't think this is used anymore? */ - start_mem = PAGE_OFFSET + PAGE_SIZE; - while (start_mem < (unsigned long)&swapper_pg_dir) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; + sz = meminfo.end >> (PAGE_SHIFT + 8); /* in MB */ + sz = (sz + 31) >> 3; + + valid_addr_bitmap = alloc_bootmem(sz); + memzero(valid_addr_bitmap, sz); + + for (i = 0; i < meminfo.nr_banks; i++) { + int idx, end; + + idx = meminfo.bank[i].start >> 20; + end = (meminfo.bank[i].start + + meminfo.bank[i].size) >> 20; + do + set_bit(idx, valid_addr_bitmap); + while (++idx < end); } -} +#endif +} diff --git a/arch/arm/mm/mm-ebsa110.c b/arch/arm/mm/mm-ebsa110.c index 8086bbc08d60..5e31deb59a74 100644 --- a/arch/arm/mm/mm-ebsa110.c +++ b/arch/arm/mm/mm-ebsa110.c @@ -13,12 +13,6 @@ #include "map.h" -struct mem_desc mem_desc[] __initdata = { - 0, 0 -}; - -unsigned int __initdata mem_desc_size = 0; - const struct map_desc io_desc[] __initdata = { { IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 } diff --git a/arch/arm/mm/mm-footbridge.c b/arch/arm/mm/mm-footbridge.c index 74bac27ea8cb..304ee68c2791 100644 --- a/arch/arm/mm/mm-footbridge.c +++ b/arch/arm/mm/mm-footbridge.c @@ -89,12 +89,6 @@ unsigned long __bus_to_virt(unsigned long res) #endif -struct mem_desc mem_desc[] __initdata = { - 0, 0 -}; - -unsigned int __initdata mem_desc_size = 0; - struct map_desc io_desc[] __initdata = { MAPPING }; diff --git a/arch/arm/mm/mm-nexuspci.c b/arch/arm/mm/mm-nexuspci.c index a4ee48f8da29..3bec2581d2d6 100644 --- a/arch/arm/mm/mm-nexuspci.c +++ b/arch/arm/mm/mm-nexuspci.c @@ -18,12 +18,6 @@ #include "map.h" -struct mem_desc mem_desc[] __initdata = { - 0, 0 -}; - -unsigned int __initdata mem_desc_size = 0; - const struct map_desc io_desc[] __initdata = { { 0xfff00000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, { 0xffe00000, 0x20000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, diff --git a/arch/arm/mm/mm-rpc.c b/arch/arm/mm/mm-rpc.c index 634bb3c8f430..0490cbdd039c 100644 --- a/arch/arm/mm/mm-rpc.c +++ b/arch/arm/mm/mm-rpc.c @@ -16,28 +16,6 @@ #define SIZE(x) (sizeof(x) / sizeof(x[0])) -struct mem_desc mem_desc[] __initdata = { - { 0xc0000000, 0xc0000000 }, - { 0xc4000000, 0xc4000000 }, - { 0xc8000000, 0xc8000000 }, - { 0xcc000000, 0xcc000000 } -}; - -unsigned int __initdata mem_desc_size = SIZE(mem_desc); - -void __init -init_dram_banks(struct param_struct *params) -{ - unsigned int bank; - - for (bank = 0; bank < mem_desc_size; bank++) - mem_desc[bank].virt_end += PAGE_SIZE * - params->u1.s.pages_in_bank[bank]; - - params->u1.s.nr_pages = mem_desc[3].virt_end - PAGE_OFFSET; - params->u1.s.nr_pages /= PAGE_SIZE; -} - struct map_desc io_desc[] __initdata = { /* VRAM */ { SCREEN2_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, diff --git a/arch/arm/mm/mm-tbox.c b/arch/arm/mm/mm-tbox.c index a6dd2a28feeb..095509b3ddd9 100644 --- a/arch/arm/mm/mm-tbox.c +++ b/arch/arm/mm/mm-tbox.c @@ -18,12 +18,6 @@ #include "map.h" -struct mem_desc mem_desc[] __initdata = { - 0, 0 -}; - -unsigned int __initdata mem_desc_size = 0; - /* Logical Physical * 0xffff1000 0x00100000 DMA registers * 0xffff2000 0x00200000 MPEG diff --git a/arch/arm/mm/proc-arm2,3.S b/arch/arm/mm/proc-arm2,3.S index df2e13357967..dcb5c10dcd19 100644 --- a/arch/arm/mm/proc-arm2,3.S +++ b/arch/arm/mm/proc-arm2,3.S @@ -327,7 +327,7 @@ arm2_elf_name: .asciz "v1" arm3_elf_name: .asciz "v2" .align - .section ".proc.info", #alloc + .section ".proc.info", #alloc, #execinstr .long 0x41560200 .long 0xfffffff0 diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S index f3819fa01d6d..b085c3c4e703 100644 --- a/arch/arm/mm/proc-arm6,7.S +++ b/arch/arm/mm/proc-arm6,7.S @@ -532,7 +532,7 @@ cpu_elf_name: .asciz "v3" .size cpu_elf_name, . - cpu_elf_name .align - .section ".proc.info", #alloc + .section ".proc.info", #alloc, #execinstr .type __arm6_proc_info, #object __arm6_proc_info: diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index 73c0f83df975..266d960b5567 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -446,7 +446,8 @@ ENTRY(cpu_sa1100_reset) bl cpu_sa110_flush_tlb_all mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches mrc p15, 0, r0, c1, c0, 0 @ ctrl register - bic r0, r0, #1 @ ...............m + bic r0, r0, #0x000f @ ............wcam + bic r0, r0, #0x1100 @ ...i...s........ ldmfd sp!, {r1, pc} /* * Purpose : Function pointers used to access above functions - all calls @@ -546,6 +547,7 @@ cpu_elf_name: .asciz "v4" .align .section ".proc.info", #alloc, #execinstr + .type __sa110_proc_info,#object __sa110_proc_info: .long 0x4401a100 diff --git a/arch/arm/mm/small_page.c b/arch/arm/mm/small_page.c index 6bdc6cfc7cb5..f82089800334 100644 --- a/arch/arm/mm/small_page.c +++ b/arch/arm/mm/small_page.c @@ -21,205 +21,201 @@ #include #include -#if PAGE_SIZE == 4096 -/* 2K blocks */ -#define SMALL_ALLOC_SHIFT (11) -#define NAME(x) x##_2k -#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384 -/* 8K blocks */ -#define SMALL_ALLOC_SHIFT (13) -#define NAME(x) x##_8k -#endif +#include +#include -#define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT) -#define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE) -#define BLOCK_MASK ((1 << NR_BLOCKS) - 1) +#define PEDANTIC -#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK) -#define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off) -#define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off)) -#define ALL_USED BLOCK_MASK -#define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off))) -#define SM_PAGE_PTR(page,block) ((struct free_small_page *)((page) + \ - ((block) << SMALL_ALLOC_SHIFT))) - -#if NR_BLOCKS != 2 && NR_BLOCKS != 4 -#error I only support 2 or 4 blocks per page -#endif +/* + * Requirement: + * We need to be able to allocate naturally aligned memory of finer + * granularity than the page size. This is typically used for the + * second level page tables on 32-bit ARMs. + * + * Theory: + * We "misuse" the Linux memory management system. We use __get_pages + * to allocate a page and then mark it as reserved. The Linux memory + * management system will then ignore the "offset", "next_hash" and + * "pprev_hash" entries in the mem_map for this page. + * + * We then use a bitstring in the "offset" field to mark which segments + * of the page are in use, and manipulate this as required during the + * allocation and freeing of these small pages. + * + * We also maintain a queue of pages being used for this purpose using + * the "next_hash" and "pprev_hash" entries of mem_map; + */ -struct free_small_page { - unsigned long next; - unsigned long prev; +struct order { + struct page *queue; + unsigned int mask; /* (1 << shift) - 1 */ + unsigned int shift; /* (1 << shift) size of page */ + unsigned int block_mask; /* nr_blocks - 1 */ + unsigned int all_used; /* (1 << nr_blocks) - 1 */ }; -/* - * To handle allocating small pages, we use the main get_free_page routine, - * and split the page up into 4. The page is marked in mem_map as reserved, - * so it can't be free'd by free_page. The count field is used to keep track - * of which sections of this page are allocated. - */ -static unsigned long small_page_ptr; - -static unsigned char offsets[1<offset) +#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &(pg)->offset)) +#define SET_USED(pg,off) (set_bit(off, &(pg)->offset)) - for (i = 0; i < NR_BLOCKS; i++) { - fsp = SM_PAGE_PTR(page, i); - fsp->next = fsp->prev = 0; - } -} - -static inline void set_page_links_prev(unsigned long page, unsigned long prev) +static void add_page_to_queue(struct page *page, struct page **p) { - struct free_small_page *fsp; - unsigned int mask; - int i; - - if (!page) - return; - - mask = USED(&mem_map[MAP_NR(page)]); - for (i = 0; i < NR_BLOCKS; i++) { - if (mask & (1 << i)) - continue; - fsp = SM_PAGE_PTR(page, i); - fsp->prev = prev; - } +#ifdef PEDANTIC + if (page->pprev_hash) + PAGE_BUG(page); +#endif + page->next_hash = *p; + if (*p) + (*p)->pprev_hash = &page->next_hash; + *p = page; + page->pprev_hash = p; } -static inline void set_page_links_next(unsigned long page, unsigned long next) +static void remove_page_from_queue(struct page *page) { - struct free_small_page *fsp; - unsigned int mask; - int i; - - if (!page) - return; - - mask = USED(&mem_map[MAP_NR(page)]); - for (i = 0; i < NR_BLOCKS; i++) { - if (mask & (1 << i)) - continue; - fsp = SM_PAGE_PTR(page, i); - fsp->next = next; + if (page->pprev_hash) { + if (page->next_hash) + page->next_hash->pprev_hash = page->pprev_hash; + *page->pprev_hash = page->next_hash; + page->pprev_hash = NULL; } } -unsigned long NAME(get_page)(int priority) +static unsigned long __get_small_page(int priority, struct order *order) { - struct free_small_page *fsp; - unsigned long new_page; unsigned long flags; struct page *page; int offset; save_flags(flags); - if (!small_page_ptr) + if (!order->queue) goto need_new_page; + cli(); + page = order->queue; again: - page = mem_map + MAP_NR(small_page_ptr); - offset = offsets[USED(page)]; +#ifdef PEDANTIC + if (USED_MAP(page) & ~order->all_used) + PAGE_BUG(page); +#endif + offset = ffz(USED_MAP(page)); SET_USED(page, offset); - new_page = (unsigned long)SM_PAGE_PTR(small_page_ptr, offset); - if (USED(page) == ALL_USED) { - fsp = (struct free_small_page *)new_page; - set_page_links_prev (fsp->next, 0); - small_page_ptr = fsp->next; - } + if (USED_MAP(page) == order->all_used) + remove_page_from_queue(page); restore_flags(flags); - return new_page; + + return page_address(page) + (offset << order->shift); need_new_page: - new_page = __get_free_page(priority); - if (!small_page_ptr) { - if (new_page) { - set_bit (PG_reserved, &mem_map[MAP_NR(new_page)].flags); - clear_page_links (new_page); - cli(); - small_page_ptr = new_page; - goto again; - } - restore_flags(flags); - return 0; + page = __get_pages(priority, 0); + if (!order->queue) { + if (!page) + goto no_page; + SetPageReserved(page); + USED_MAP(page) = 0; + cli(); + add_page_to_queue(page, &order->queue); + } else { + __free_page(page); + cli(); + page = order->queue; } - free_page(new_page); - cli(); goto again; + +no_page: + restore_flags(flags); + return 0; } -void NAME(free_page)(unsigned long spage) +static void __free_small_page(unsigned long spage, struct order *order) { - struct free_small_page *ofsp, *cfsp; unsigned long flags; + unsigned long nr; struct page *page; - int offset, oldoffset; - - if (!spage) - goto none; - - offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1); - spage -= offset << SMALL_ALLOC_SHIFT; - - page = mem_map + MAP_NR(spage); - if (!PageReserved(page) || !USED(page)) - goto non_small; - - if (IS_FREE(page, offset)) - goto free; - - save_flags_cli (flags); - oldoffset = offsets[USED(page)]; - CLEAR_USED(page, offset); - ofsp = SM_PAGE_PTR(spage, oldoffset); - cfsp = SM_PAGE_PTR(spage, offset); - - if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */ - cfsp->prev = 0; - cfsp->next = small_page_ptr; - set_page_links_prev (small_page_ptr, spage); - small_page_ptr = spage; - } else if (!USED(page)) { - set_page_links_prev (ofsp->next, ofsp->prev); - set_page_links_next (ofsp->prev, ofsp->next); - if (spage == small_page_ptr) - small_page_ptr = ofsp->next; - clear_bit (PG_reserved, &page->flags); + + nr = MAP_NR(spage); + if (nr < max_mapnr) { + page = mem_map + nr; + + /* + * The container-page must be marked Reserved + */ + if (!PageReserved(page) || spage & order->mask) + goto non_small; + +#ifdef PEDANTIC + if (USED_MAP(page) & ~order->all_used) + PAGE_BUG(page); +#endif + + spage = spage >> order->shift; + spage &= order->block_mask; + + /* + * the following must be atomic wrt get_page + */ + save_flags_cli(flags); + + if (USED_MAP(page) == order->all_used) + add_page_to_queue(page, &order->queue); + + if (!TEST_AND_CLEAR_USED(page, spage)) + goto already_free; + + if (USED_MAP(page) == 0) + goto free_page; + restore_flags(flags); - free_page (spage); - } else - *cfsp = *ofsp; + } + return; + +free_page: + /* + * unlink the page from the small page queue and free it + */ + remove_page_from_queue(page); restore_flags(flags); + ClearPageReserved(page); + __free_page(page); return; non_small: - printk ("Trying to free non-small page from %p\n", __builtin_return_address(0)); - return; -free: - printk ("Trying to free free small page from %p\n", __builtin_return_address(0)); -none: + printk("Trying to free non-small page from %p\n", __builtin_return_address(0)); return; +already_free: + printk("Trying to free free small page from %p\n", __builtin_return_address(0)); } + +unsigned long get_page_2k(int priority) +{ + return __get_small_page(priority, orders+0); +} + +void free_page_2k(unsigned long spage) +{ + __free_small_page(spage, orders+0); +} + +#if PAGE_SIZE > 8192 +unsigned long get_page_8k(int priority) +{ + return __get_small_page(priority, orders+1); +} + +void free_page_8k(unsigned long spage) +{ + __free_small_page(spage, orders+1); +} +#endif diff --git a/arch/arm/vmlinux-armo.lds.in b/arch/arm/vmlinux-armo.lds.in index 446f49924b6f..5fbafe77a188 100644 --- a/arch/arm/vmlinux-armo.lds.in +++ b/arch/arm/vmlinux-armo.lds.in @@ -7,7 +7,8 @@ ENTRY(stext) SECTIONS { . = TEXTADDR; - __init_begin = .; + + __init_begin = .; /* Init code and data */ .text.init : { *(.text.init) } __proc_info_begin = .; .proc.info : { *(.proc.info) } @@ -27,43 +28,44 @@ SECTIONS *(.init.task) } - _text = .; /* Text and read-only data */ + _text = .; /* Text and read-only data */ .text : { *(.text) *(.fixup) *(.gnu.warning) } + .text.lock : { *(.text.lock) } /* out-of-line lock text */ .rodata : { *(.rodata) } .kstrtab : { *(.kstrtab) } - . = ALIGN(16); /* Exception table */ + . = ALIGN(16); /* Exception table */ __start___ex_table = .; __ex_table : { *(__ex_table) } __stop___ex_table = .; - __start___ksymtab = .; /* Kernel symbol table */ + __start___ksymtab = .; /* Kernel symbol table */ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; - .got : { *(.got) } /* Global offset table */ + .got : { *(.got) } /* Global offset table */ - _etext = .; /* End of text section */ + _etext = .; /* End of text section */ - .data : { /* Data */ + .data : { /* Data */ *(.data) CONSTRUCTORS } - _edata = .; /* End of data section */ + _edata = .; /* End of data section */ - __bss_start = .; /* BSS */ + __bss_start = .; /* BSS */ .bss : { *(.bss) } _end = . ; - /* Stabs debugging sections. */ + /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index a549946674ea..de8a3cd84a39 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -1,8 +1,8 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-1998 Stephen Rothwell - * (Stephen.Rothwell@canb.auug.org.au) - * Development of this driver was funded by NEC Australia P/L + * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com) + * + * Initial development of this driver was funded by NEC Australia P/L * and NEC Corporation * * This program is free software; you can redistribute it and/or modify it @@ -1441,8 +1441,6 @@ __setup("apm=", apm_setup); */ static int __init apm_init(void) { - static struct proc_dir_entry *ent; - if (apm_bios_info.version == 0) { printk(KERN_INFO "apm: BIOS not found.\n"); return -1; @@ -1536,9 +1534,7 @@ static int __init apm_init(void) } #endif - ent = create_proc_entry("apm", 0, 0); - if (ent != NULL) - ent->get_info = apm_get_info; + create_proc_info_entry("apm", 0, 0, apm_get_info); misc_register(&apm_device); diff --git a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c index 792cc8c0d4c5..0a46cd017e4e 100644 --- a/arch/i386/kernel/mca.c +++ b/arch/i386/kernel/mca.c @@ -705,11 +705,11 @@ void __init mca_do_proc_init(void) if(mca_info == NULL) return; /* Should never happen */ - proc_register(&proc_mca, &(struct proc_dir_entry) { + proc_register(proc_mca, &(struct proc_dir_entry) { PROC_MCA_REGISTERS, 3, "pos", S_IFREG|S_IRUGO, 1, 0, 0, 0, &proc_mca_inode_operations,}); - proc_register(&proc_mca, &(struct proc_dir_entry) { + proc_register(proc_mca, &(struct proc_dir_entry) { PROC_MCA_MACHINE, 7, "machine", S_IFREG|S_IRUGO, 1, 0, 0, 0, &proc_mca_inode_operations,}); @@ -745,7 +745,7 @@ void __init mca_do_proc_init(void) node->name = mca_info->slot[i].procname; node->mode = S_IFREG | S_IRUGO; node->ops = &proc_mca_inode_operations; - proc_register(&proc_mca, node); + proc_register(proc_mca, node); } } /* mca_do_proc_init() */ diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index f55e86b61c9c..a5a4b447f58e 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -1516,7 +1516,7 @@ static struct inode_operations proc_mtrr_inode_operations = { }; static struct proc_dir_entry proc_root_mtrr = { - PROC_MTRR, 4, "mtrr", + 0, 4, "mtrr", S_IFREG | S_IWUSR | S_IRUGO, 1, 0, 0, 0, &proc_mtrr_inode_operations }; diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 4386e8dd0d10..85f4399789a0 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -821,8 +821,9 @@ void __init init_smp_mappings(void) * could use the real zero-page, but it's safer * this way if some buggy code writes to this page ... */ - apic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE)); + apic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); memset((void *)apic_phys, 0, PAGE_SIZE); + apic_phys = __pa(apic_phys); } set_fixmap(FIX_APIC_BASE, apic_phys); dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); @@ -836,8 +837,9 @@ void __init init_smp_mappings(void) if (smp_found_config) { ioapic_phys = mp_ioapics[i].mpc_apicaddr; } else { - ioapic_phys = __pa(alloc_bootmem_pages(PAGE_SIZE)); + ioapic_phys = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); memset((void *)ioapic_phys, 0, PAGE_SIZE); + ioapic_phys = __pa(ioapic_phys); } set_fixmap(idx,ioapic_phys); dprintk("mapped IOAPIC to %08lx (%08lx)\n", diff --git a/arch/i386/lib/mmx.c b/arch/i386/lib/mmx.c index 5257aeba6d8f..0314041f93f6 100644 --- a/arch/i386/lib/mmx.c +++ b/arch/i386/lib/mmx.c @@ -89,7 +89,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len) return p; } -static void fast_clear_page(long page) +static void fast_clear_page(void *page) { int i; if (!(current->flags & PF_USEDFPU)) @@ -129,7 +129,7 @@ static void fast_clear_page(long page) stts(); } -static void fast_copy_page(long to, long from) +static void fast_copy_page(void *to, void *from) { int i; if (!(current->flags & PF_USEDFPU)) @@ -196,7 +196,7 @@ static void fast_copy_page(long to, long from) * Favour MMX for page clear and copy. */ -static void slow_zero_page(long page) +static void slow_zero_page(void * page) { int d0, d1; __asm__ __volatile__( \ @@ -207,7 +207,7 @@ static void slow_zero_page(long page) :"memory"); } -void mmx_clear_page(long page) +void mmx_clear_page(void * page) { if(in_interrupt()) slow_zero_page(page); @@ -215,7 +215,7 @@ void mmx_clear_page(long page) fast_clear_page(page); } -static void slow_copy_page(long to, long from) +static void slow_copy_page(void *to, void *from) { int d0, d1, d2; __asm__ __volatile__( \ @@ -227,7 +227,7 @@ static void slow_copy_page(long to, long from) } -void mmx_copy_page(long to, long from) +void mmx_copy_page(void *to, void *from) { if(in_interrupt()) slow_copy_page(to, from); diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c index ab07e3d48ff0..26a0518db0fc 100644 --- a/arch/m68k/mac/iop.c +++ b/arch/m68k/mac/iop.c @@ -125,21 +125,9 @@ int iop_scc_present,iop_ism_present; #ifdef CONFIG_PROC_FS - -/* - * sneaky reuse of the PROC_MAC_VIA inode. It's not needed by via.c - * anymore so we'll use it to debut the IOPs. - */ - -int iop_get_proc_info(char *, char **, off_t, int, int); - -static struct proc_dir_entry proc_mac_iop = { - PROC_MAC_VIA, 7, "mac_iop", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations, - &iop_get_proc_info -}; - +static int iop_get_proc_info(char *, char **, off_t, int, int); +#else +static int iop_get_proc_info(char *, char **, off_t, int, int) {} #endif /* CONFIG_PROC_FS */ /* structure for tracking channel listeners */ @@ -315,9 +303,7 @@ void __init iop_init(void) iop_listeners[IOP_NUM_ISM][i].handler = NULL; } -#ifdef CONFIG_PROC_FS - proc_register(&proc_root, &proc_mac_iop); -#endif + create_proc_info_entry("mac_iop",0,0,iop_get_proc_info); } /* @@ -722,4 +708,5 @@ int iop_get_proc_info(char *buf, char **start, off_t pos, int count, int wr) } return (count > cnt) ? cnt : count; } + #endif /* CONFIG_PROC_FS */ diff --git a/arch/mips/config.in b/arch/mips/config.in index 2375108f4c7d..26356e86f82e 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -177,13 +177,12 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_SGI" = "y" ]; then bool ' SGI Seeq ethernet controller support' CONFIG_SGISEEQ fi - if [ "$CONFIG_DECSTATION" = "y" ]; then - bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE - fi - if [ "$CONFIG_BAGET_MIPS" = "y" ]; then - tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE - tristate ' Baget Backplane Shared Memory support' CONFIG_BAGETBSM - fi + if [ "$CONFIG_DECSTATION" = "y" ]; then + bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE + fi + if [ "$CONFIG_BAGET_MIPS" = "y" ]; then + tristate ' Baget AMD LANCE support' CONFIG_BAGETLANCE + tristate ' Baget Backplane Shared Memory support' CONFIG_BAGETBSM fi fi endmenu @@ -206,7 +205,7 @@ if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" mainmenu_option next_comment - comment comment 'Old CD-ROM drivers (not SCSI, not IDE)' + comment 'Old CD-ROM drivers (not SCSI, not IDE)' bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 46908b644966..c26497adf021 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -4,6 +4,11 @@ # mainmenu_name "Linux/PowerPC Kernel Configuration" +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + mainmenu_option next_comment comment 'Platform support' define_bool CONFIG_PPC y @@ -53,14 +58,16 @@ fi endmenu mainmenu_option next_comment -comment 'General setup' - -bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then - bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel module loader' CONFIG_KMOD + bool ' Set version information on all module symbols' CONFIG_MODVERSIONS + bool ' Kernel module loader' CONFIG_KMOD fi +endmenu + +mainmenu_option next_comment +comment 'General setup' if [ "$CONFIG_APUS" = "y" ]; then define_bool CONFIG_PCI n diff --git a/drivers/acorn/net/Config.in b/drivers/acorn/net/Config.in index aaea7f9949a2..707ae92f7604 100644 --- a/drivers/acorn/net/Config.in +++ b/drivers/acorn/net/Config.in @@ -2,6 +2,6 @@ # Acorn Network device configuration # These are for Acorn's Expansion card network interfaces # -tristate 'Acorn Ether1 (82586) support' CONFIG_ARM_ETHER1 -tristate 'Acorn/ANT Ether3 (NQ8005) support' CONFIG_ARM_ETHER3 -tristate 'I-cubed EtherH (NS8390) support' CONFIG_ARM_ETHERH +tristate ' Acorn Ether1 (82586) support' CONFIG_ARM_ETHER1 +tristate ' Acorn/ANT Ether3 (NQ8005) support' CONFIG_ARM_ETHER3 +tristate ' I-cubed EtherH (NS8390) support' CONFIG_ARM_ETHERH diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 9f26a4b5e992..b2f24a633a34 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -95,11 +95,11 @@ static FileOperations_T /* - DAC960_ProcDirectoryEntry is the DAC960 /proc/rd directory entry. + DAC960_ProcDirectoryEntry is the DAC960 /proc/driver/rd directory entry. */ -static PROC_DirectoryEntry_T - DAC960_ProcDirectoryEntry; +static PROC_DirectoryEntry_T * + DAC960_ProcDirectoryEntry = NULL; /* @@ -3466,23 +3466,18 @@ static int DAC960_ProcWriteUserCommand(File_T *File, const char *Buffer, /* - DAC960_CreateProcEntries creates the /proc/rd/... entries for the DAC960 - Driver. + DAC960_CreateProcEntries creates the /proc/driver/rd/... entries + for the DAC960 Driver. */ static void DAC960_CreateProcEntries(void) { - static PROC_DirectoryEntry_T StatusProcEntry; + static PROC_DirectoryEntry_T *StatusProcEntry; int ControllerNumber; - DAC960_ProcDirectoryEntry.name = "rd"; - DAC960_ProcDirectoryEntry.namelen = strlen(DAC960_ProcDirectoryEntry.name); - DAC960_ProcDirectoryEntry.mode = S_IFDIR | S_IRUGO | S_IXUGO; - proc_register(&proc_root, &DAC960_ProcDirectoryEntry); - StatusProcEntry.name = "status"; - StatusProcEntry.namelen = strlen(StatusProcEntry.name); - StatusProcEntry.mode = S_IFREG | S_IRUGO; - StatusProcEntry.read_proc = DAC960_ProcReadStatus; - proc_register(&DAC960_ProcDirectoryEntry, &StatusProcEntry); + DAC960_ProcDirectoryEntry = create_proc_entry("driver/rd", S_IFDIR, NULL); + StatusProcEntry = create_proc_read_entry("status", 0, + DAC960_ProcDirectoryEntry, + DAC960_ProcReadStatus, NULL); for (ControllerNumber = 0; ControllerNumber < DAC960_ControllerCount; ControllerNumber++) @@ -3495,7 +3490,7 @@ static void DAC960_CreateProcEntries(void) ControllerProcEntry->name = Controller->ControllerName; ControllerProcEntry->namelen = strlen(ControllerProcEntry->name); ControllerProcEntry->mode = S_IFDIR | S_IRUGO | S_IXUGO; - proc_register(&DAC960_ProcDirectoryEntry, ControllerProcEntry); + proc_register(DAC960_ProcDirectoryEntry, ControllerProcEntry); InitialStatusProcEntry = &Controller->InitialStatusProcEntry; InitialStatusProcEntry->name = "initial_status"; InitialStatusProcEntry->namelen = strlen(InitialStatusProcEntry->name); @@ -3529,7 +3524,7 @@ static void DAC960_CreateProcEntries(void) static void DAC960_DestroyProcEntries(void) { - proc_unregister(&proc_root, DAC960_ProcDirectoryEntry.low_ino); + remove_proc_entry("driver/rd", NULL); } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 92b1c7d4df92..45146311185a 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -161,8 +161,14 @@ static int frevalidate_logvol(kdev_t dev); static int revalidate_logvol(kdev_t dev, int maxusage); static int revalidate_allvol(kdev_t dev); +#ifdef CONFIG_PROC_FS static void ida_procinit(int i); static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data); +#else +static void ida_procinit(int i) {} +static int ida_proc_get_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) {} +#endif static void ida_geninit(struct gendisk *g) { @@ -207,26 +213,21 @@ struct file_operations ida_fops = { }; +#ifdef CONFIG_PROC_FS + /* * Get us a file in /proc/array that says something about each controller. * Create /proc/array if it doesn't exist yet. */ -static void ida_procinit(int i) +static void __init ida_procinit(int i) { -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *pd; - if (proc_array == NULL) { - proc_array = create_proc_entry("array", S_IFDIR|S_IRUGO|S_IXUGO, - &proc_root); + proc_array = create_proc_entry("driver/array", S_IFDIR, NULL); if (!proc_array) return; } - pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_array); - if (!pd) return; - pd->read_proc = ida_proc_get_info; - pd->data = hba[i]; -#endif + create_proc_read_entry(hba[i]->devname, 0, proc_array, + ida_proc_get_info, hba[i]); } /* @@ -311,6 +312,7 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int lengt len = length; return len; } +#endif /* CONFIG_PROC_FS */ #ifdef MODULE @@ -318,7 +320,7 @@ MODULE_PARM(eisa, "1-8i"); EXPORT_NO_SYMBOLS; /* This is a bit of a hack... */ -int init_module(void) +int __init init_module(void) { int i, j; cpqarray_init(); @@ -333,11 +335,14 @@ int init_module(void) } return 0; } + void cleanup_module(void) { int i; struct gendisk *g; + remove_proc_entry("driver/array", NULL); + for(i=0; iaccess.set_intr_mask(hba[i], 0); free_irq(hba[i]->intr, hba[i]); @@ -359,15 +364,11 @@ void cleanup_module(void) } } } -#ifdef CONFIG_PROC_FS - remove_proc_entry("array", &proc_root); -#endif + kfree(ida); kfree(ida_sizes); kfree(ida_hardsizes); kfree(ida_blocksizes); - - } #endif /* MODULE */ @@ -375,7 +376,7 @@ void cleanup_module(void) * This is it. Find all the controllers and register them. I really hate * stealing all these major device numbers. */ -void cpqarray_init(void) +void __init cpqarray_init(void) { void (*request_fns[MAX_CTLR])(void) = { do_ida_request0, do_ida_request1, diff --git a/drivers/block/ide-geometry.c b/drivers/block/ide-geometry.c index 44aa1844df4d..8370d35a6df5 100644 --- a/drivers/block/ide-geometry.c +++ b/drivers/block/ide-geometry.c @@ -81,7 +81,6 @@ void probe_cmos_for_drives (ide_hwif_t *hwif) */ static void ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) { - struct hd_driveid *id = drive->id; static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}; const byte *headp = dm_head_vals; unsigned long total, tracks; @@ -92,10 +91,7 @@ ontrack(ide_drive_t *drive, int heads, int *c, int *h, int *s) { * 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. */ - if (id) - total = id->cyls * id->heads * id->sectors; - else - total = drive->cyl * drive->head * drive->sect; + total = DRIVER(drive)->capacity(drive); *s = 63; diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c index 48d77c1607f8..b68072428540 100644 --- a/drivers/block/ide-proc.c +++ b/drivers/block/ide-proc.c @@ -769,31 +769,25 @@ static void destroy_proc_ide_interfaces(void) void proc_ide_create(void) { - struct proc_dir_entry *ent; proc_ide_root = create_proc_entry("ide", S_IFDIR, 0); if (!proc_ide_root) return; + create_proc_ide_interfaces(); - ent = create_proc_entry("drivers", 0, proc_ide_root); - if (!ent) return; - ent->read_proc = proc_ide_read_drivers; + create_proc_read_entry("drivers",0,proc_ide_root, + proc_ide_read_drivers, NULL); + #ifdef CONFIG_BLK_DEV_ALI15X3 - if ((ali_display_info) && (ali_proc)) { - ent = create_proc_entry("ali", 0, proc_ide_root); - ent->get_info = ali_display_info; - } + if ((ali_display_info) && (ali_proc)) + create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info); #endif /* CONFIG_BLK_DEV_ALI15X3 */ #ifdef CONFIG_BLK_DEV_SIS5513 - if ((sis_display_info) && (sis_proc)) { - ent = create_proc_entry("sis", 0, proc_ide_root); - ent->get_info = sis_display_info; - } + if ((sis_display_info) && (sis_proc)) + create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info); #endif /* CONFIG_BLK_DEV_SIS5513 */ #ifdef CONFIG_BLK_DEV_VIA82CXXX - if ((via_display_info) && (via_proc)) { - ent = create_proc_entry("via", 0, proc_ide_root); - ent->get_info = via_display_info; - } + if ((via_display_info) && (via_proc)) + create_proc_info_entry("via", 0, proc_ide_root, via_display_info); #endif /* CONFIG_BLK_DEV_VIA82CXXX */ } diff --git a/drivers/block/md.c b/drivers/block/md.c index 684b47c1b65d..4dedb867188f 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -872,11 +872,74 @@ EXPORT_SYMBOL(md_wakeup_thread); EXPORT_SYMBOL(md_do_sync); #ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_md = { - PROC_MD, 6, "mdstat", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations, -}; +static int md_status_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int sz = 0, i, j, size; + int begin = 0; + + sz=sprintf( page, "Personalities : "); + for (i=0; iname); + page[sz-1]='\n'; + + sz+=sprintf (page+sz, "read_ahead "); + if (read_ahead[MD_MAJOR]==INT_MAX) + sz+=sprintf (page+sz, "not set\n"); + else + sz+=sprintf (page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); + + for (i=0; i= off+count) { + *eof = 1; + break; + } + sz+=sprintf (page+sz, "md%d : %sactive", + i, md_dev[i].pers ? "" : "in"); + + if (md_dev[i].pers) + sz+=sprintf (page+sz, " %s", md_dev[i].pers->name); + + for (j=0, size=0; jmax_invalid_dev) + sz+=sprintf (page+sz, " maxfault=%ld", + MAX_FAULT(md_dev+i)); + + sz+=md_dev[i].pers->status (page+sz, i, md_dev+i); + sz+=sprintf (page+sz, "\n"); + } + + sz -= off; + *start = page + off; + if (sz>count) + sz = count; + if (sz<0) + sz = 0; + return sz; +} #endif static void md_geninit (struct gendisk *gdisk) @@ -896,7 +959,7 @@ static void md_geninit (struct gendisk *gdisk) max_readahead[MD_MAJOR] = md_maxreadahead; #ifdef CONFIG_PROC_FS - proc_register(&proc_root, &proc_md); + create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL); #endif } @@ -919,61 +982,6 @@ int md_error (kdev_t mddev, kdev_t rdev) return 0; } -int get_md_status (char *page) -{ - int sz=0, i, j, size; - - sz+=sprintf( page+sz, "Personalities : "); - for (i=0; iname); - - page[sz-1]='\n'; - - sz+=sprintf (page+sz, "read_ahead "); - if (read_ahead[MD_MAJOR]==INT_MAX) - sz+=sprintf (page+sz, "not set\n"); - else - sz+=sprintf (page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); - - for (i=0; iname); - - size=0; - for (j=0; jmax_invalid_dev) - sz+=sprintf (page+sz, " maxfault=%ld", MAX_FAULT(md_dev+i)); - - sz+=md_dev[i].pers->status (page+sz, i, md_dev+i); - sz+=sprintf (page+sz, "\n"); - } - - return (sz); -} - int register_md_personality (int p_num, struct md_personality *p) { int i=(p_num >> PERSONALITY_SHIFT); diff --git a/drivers/char/h8.c b/drivers/char/h8.c index d146a808f27c..0a6a63fff0eb 100644 --- a/drivers/char/h8.c +++ b/drivers/char/h8.c @@ -3,6 +3,9 @@ * * The H8 is used to deal with the power and thermal environment * of a system. + * + * Fixes: + * June 1999, AV added releasing /proc/driver/h8 */ #include @@ -18,10 +21,8 @@ #include #include #include -#ifdef CONFIG_PROC_FS #include #include -#endif #include #include #include @@ -58,6 +59,8 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); #ifdef CONFIG_PROC_FS static int h8_get_info(char *, char **, off_t, int, int); +#else +static int h8_get_info(char *, char **, off_t, int, int) {} #endif /* @@ -125,12 +128,6 @@ static struct miscdevice h8_device = { &h8_fops }; -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry h8_proc_entry = { - 0, 3, "h8", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, h8_get_info -}; -#endif - union intr_buf intrbuf; int intr_buf_ptr; union intr_buf xx; @@ -321,9 +318,7 @@ int init_module(void) misc_register(&h8_device); request_region(h8_base, 8, "h8"); -#ifdef CONFIG_PROC_FS - proc_register(&proc_root, &h8_proc_entry); -#endif + create_proc_info_entry("driver/h8", 0, NULL, h8_get_info); QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *); QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *); @@ -339,6 +334,7 @@ int init_module(void) void cleanup_module(void) { + remove_proc_entry("driver/h8", NULL); misc_deregister(&h8_device); release_region(h8_base, 8); free_irq(h8_irq, NULL); @@ -355,9 +351,7 @@ int h8_init(void) } printk("H8 at 0x%x IRQ %d\n", h8_base, h8_irq); -#ifdef CONFIG_PROC_FS - proc_register(&proc_root, &h8_proc_entry); -#endif + create_proc_info_entry("driver/h8", 0, NULL, h8_get_info); misc_register(&h8_device); request_region(h8_base, 8, "h8"); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 7d5e5f11ea97..dd53a44b504c 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -190,10 +190,7 @@ static inline int noncached_address(unsigned long addr) static int mmap_mem(struct file * file, struct vm_area_struct * vma) { - unsigned long offset = vma->vm_offset; - - if (offset & ~PAGE_MASK) - return -ENXIO; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; /* * Accessing memory above the top the kernel knows about or diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 18ab3f269083..8fa32916e5e1 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -76,7 +76,6 @@ extern int rtc_sun_init(void); /* Combines MK48T02 and MK48T08 */ extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); extern int dsp56k_init(void); -extern int nvram_init(void); extern int radio_init(void); extern int pc110pad_init(void); extern int pmu_device_init(void); @@ -180,13 +179,9 @@ int misc_deregister(struct miscdevice * misc) EXPORT_SYMBOL(misc_register); EXPORT_SYMBOL(misc_deregister); -static struct proc_dir_entry *proc_misc; - int __init misc_init(void) { - proc_misc = create_proc_entry("misc", 0, 0); - if (proc_misc) - proc_misc->read_proc = misc_read_proc; + create_proc_read_entry("misc", 0, 0, misc_read_proc, NULL); #ifdef CONFIG_BUSMOUSE bus_mouse_init(); #endif @@ -235,9 +230,6 @@ int __init misc_init(void) #ifdef CONFIG_ATARI_DSP56K dsp56k_init(); #endif -#ifdef CONFIG_NVRAM - nvram_init(); -#endif #ifdef CONFIG_MISC_RADIO radio_init(); #endif diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index dde61fe778bd..9ac9908723f4 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -95,9 +95,7 @@ #include #include #include -#ifdef CONFIG_PROC_FS #include -#endif #include #include @@ -352,8 +350,10 @@ static int nvram_release( struct inode *inode, struct file *file ) #ifdef CONFIG_PROC_FS - -struct proc_dir_entry *proc_nvram; +static int nvram_read_proc( char *buffer, char **start, off_t offset, + int size, int *eof, + void *data) {} +#else static int nvram_read_proc( char *buffer, char **start, off_t offset, int size, int *eof, void *data ) @@ -391,7 +391,7 @@ static int nvram_read_proc( char *buffer, char **start, off_t offset, } \ } while(0) -#endif +#endif /* CONFIG_PROC_FS */ static struct file_operations nvram_fops = { nvram_llseek, @@ -413,7 +413,7 @@ static struct miscdevice nvram_dev = { }; -int __init nvram_init(void) +static int __init nvram_init(void) { /* First test whether the driver should init at all */ if (!CHECK_DRIVER_INIT()) @@ -421,29 +421,18 @@ int __init nvram_init(void) printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION ); misc_register( &nvram_dev ); -#ifdef CONFIG_PROC_FS - if ((proc_nvram = create_proc_entry( "nvram", 0, 0 ))) - proc_nvram->read_proc = nvram_read_proc; -#endif - + create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL); return( 0 ); } -#ifdef MODULE -int init_module (void) -{ - return( nvram_init() ); -} - -void cleanup_module (void) +static void __exit nvram_cleanup_module (void) { -#ifdef CONFIG_PROC_FS - if (proc_nvram) - remove_proc_entry( "nvram", 0 ); -#endif + remove_proc_entry( "driver/nvram", 0 ); misc_deregister( &nvram_dev ); } -#endif + +module_init(nvram_init); +module_exit(nvram_cleanup_module); /* diff --git a/drivers/char/radio-cadet.c b/drivers/char/radio-cadet.c index 98b66f0c28b1..a979e7424b0b 100644 --- a/drivers/char/radio-cadet.c +++ b/drivers/char/radio-cadet.c @@ -39,7 +39,6 @@ struct timer_list tunertimer,rdstimer,readtimer; static __u8 rdsin=0,rdsout=0,rdsstat=0; static unsigned char rdsbuf[RDS_BUFFER]; static int cadet_lock=0; -static int cadet_probe(void); /* * Signal Strength Threshold Values @@ -543,22 +542,6 @@ static struct video_device cadet_radio= NULL }; -int __init cadet_init(struct video_init *v) -{ -#ifndef MODULE - if(cadet_probe()<0) { - return EINVAL; - } -#endif - if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) - return -EINVAL; - - request_region(io,2,"cadet"); - printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io); - return 0; -} - - #ifndef MODULE static int cadet_probe(void) { @@ -578,9 +561,27 @@ static int cadet_probe(void) } #endif +int __init cadet_init(void) +{ +#ifndef MODULE + io = cadet_probe (); +#endif + + if(io < 0) { +#ifdef MODULE + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); +#endif + return EINVAL; + } + if(video_register_device(&cadet_radio,VFL_TYPE_RADIO)==-1) + return -EINVAL; + + request_region(io,2,"cadet"); + printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io); + return 0; +} -#ifdef MODULE MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); @@ -589,21 +590,12 @@ MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0 EXPORT_NO_SYMBOLS; -int init_module(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - return cadet_init(NULL); -} - -void cleanup_module(void) +static void __exit cadet_cleanup_module(void) { video_unregister_device(&cadet_radio); release_region(io,2); } -#endif +module_init(cadet_init); +module_exit(cadet_cleanup_module); diff --git a/drivers/char/radio-rtrack2.c b/drivers/char/radio-rtrack2.c index 8876d789d7be..c060ded4a148 100644 --- a/drivers/char/radio-rtrack2.c +++ b/drivers/char/radio-rtrack2.c @@ -228,8 +228,13 @@ static struct video_device rtrack2_radio= NULL }; -int __init rtrack2_init(struct video_init *v) +static int __init rtrack2_init(void) { + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n"); + return -EINVAL; + } if (check_region(io, 4)) { printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io); @@ -252,8 +257,6 @@ int __init rtrack2_init(struct video_init *v) return 0; } -#ifdef MODULE - MODULE_AUTHOR("Ben Pfaff"); MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); MODULE_PARM(io, "i"); @@ -261,23 +264,14 @@ MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); EXPORT_NO_SYMBOLS; -int init_module(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n"); - return -EINVAL; - } - return rtrack2_init(NULL); -} - -void cleanup_module(void) +static void __exit rtrack2_cleanup_module(void) { video_unregister_device(&rtrack2_radio); release_region(io,4); } -#endif +module_init(rtrack2_init); +module_exit(rtrack2_cleanup_module); /* Local variables: diff --git a/drivers/char/radio-sf16fmi.c b/drivers/char/radio-sf16fmi.c index ef73f2d77c97..55328a96f296 100644 --- a/drivers/char/radio-sf16fmi.c +++ b/drivers/char/radio-sf16fmi.c @@ -289,8 +289,13 @@ static struct video_device fmi_radio= NULL }; -int __init fmi_init(struct video_init *v) +static int __init fmi_init(void) { + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } if (check_region(io, 2)) { printk(KERN_ERR "fmi: port 0x%x already in use\n", io); @@ -316,8 +321,6 @@ int __init fmi_init(struct video_init *v) return 0; } -#ifdef MODULE - MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); MODULE_DESCRIPTION("A driver for the SF16MI radio."); MODULE_PARM(io, "i"); @@ -325,20 +328,12 @@ MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); EXPORT_NO_SYMBOLS; -int init_module(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - return fmi_init(NULL); -} - -void cleanup_module(void) +static void __exit fmi_cleanup_module(void) { video_unregister_device(&fmi_radio); release_region(io,2); } -#endif +module_init(fmi_init); +module_exit(fmi_cleanup_module); + diff --git a/drivers/char/radio-terratec.c b/drivers/char/radio-terratec.c index 9fb119c30642..1dda1618e098 100644 --- a/drivers/char/radio-terratec.c +++ b/drivers/char/radio-terratec.c @@ -307,8 +307,13 @@ static struct video_device terratec_radio= NULL }; -int __init terratec_init(struct video_init *v) +static int __init terratec_init(void) { + if(io==-1) + { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } if (check_region(io, 2)) { printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io); @@ -334,8 +339,6 @@ int __init terratec_init(struct video_init *v) return 0; } -#ifdef MODULE - MODULE_AUTHOR("R.OFFERMANNS & others"); MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); MODULE_PARM(io, "i"); @@ -343,21 +346,13 @@ MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x5 EXPORT_NO_SYMBOLS; -int init_module(void) -{ - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - return terratec_init(NULL); -} - -void cleanup_module(void) +static void __exit terratec_cleanup_module(void) { video_unregister_device(&terratec_radio); release_region(io,2); printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n"); } -#endif +module_init(terratec_init); +module_exit(terratec_cleanup_module); + diff --git a/drivers/char/radio-trust.c b/drivers/char/radio-trust.c index 15dee607ae79..4e86bda903a1 100644 --- a/drivers/char/radio-trust.c +++ b/drivers/char/radio-trust.c @@ -333,8 +333,6 @@ static int __init trust_init(void) return 0; } -#ifdef MODULE - MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); MODULE_PARM(io, "i"); @@ -342,8 +340,6 @@ MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); EXPORT_NO_SYMBOLS; -#endif /* MODULE */ - static void __exit cleanup_trust_module(void) { video_unregister_device(&trust_radio); diff --git a/drivers/char/radio-typhoon.c b/drivers/char/radio-typhoon.c index 698f113e8041..4e5993add4e2 100644 --- a/drivers/char/radio-typhoon.c +++ b/drivers/char/radio-typhoon.c @@ -75,13 +75,6 @@ static void typhoon_close(struct video_device *dev); static int typhoon_read_proc(char *buf, char **start, off_t offset, int len, int unused); #endif -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -int typhoon_init(struct video_init *v); -#else -int typhoon_init(struct video_init *v) __init; -#endif static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) { @@ -337,53 +330,8 @@ static int typhoon_read_proc(char *buf, char **start, off_t offset, int len, return len; } -static struct proc_dir_entry typhoon_proc_entry = { - 0, /* low_ino: inode is dynamic */ - 13, "radio-typhoon", /* length of name and name */ - S_IFREG | S_IRUGO, /* mode */ - 1, 0, 0, /* nlinks, owner, group */ - 0, /* size -- not used */ - NULL, /* operations -- use default */ - &typhoon_read_proc, /* function used to read data */ - /* nothing more */ -}; - #endif /* CONFIG_RADIO_TYPHOON_PROC_FS */ -int typhoon_init(struct video_init *v) -{ - printk(KERN_INFO BANNER); - if (check_region(typhoon_unit.iobase, 8)) { - printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", - typhoon_unit.iobase); - return -EBUSY; - } - - typhoon_radio.priv = &typhoon_unit; - if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1) - return -EINVAL; - - request_region(typhoon_unit.iobase, 8, "typhoon"); - printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); - printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", - typhoon_unit.mutefreq); - typhoon_unit.mutefreq <<= 4; - - /* mute card - prevents noisy bootups */ - typhoon_mute(&typhoon_unit); - -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS - - if (proc_register(&proc_root, &typhoon_proc_entry)) - printk(KERN_ERR "radio-typhoon: registering /proc/radio-typhoon failed\n"); - -#endif - - return 0; -} - -#ifdef MODULE - MODULE_AUTHOR("Dr. Henrik Seidel"); MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); MODULE_PARM(io, "i"); @@ -394,10 +342,14 @@ MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); EXPORT_NO_SYMBOLS; static int io = -1; + +#ifdef MODULE static unsigned long mutefreq = 0; +#endif -int init_module(void) +static int __init typhoon_init(void) { +#ifdef MODULE if (io == -1) { printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n"); return -EINVAL; @@ -410,24 +362,49 @@ int init_module(void) return -EINVAL; } typhoon_unit.mutefreq = mutefreq; +#endif /* MODULE */ - return typhoon_init(NULL); -} + printk(KERN_INFO BANNER); + io = typhoon_unit.iobase; + if (check_region(io, 8)) { + printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", + typhoon_unit.iobase); + return -EBUSY; + } -void cleanup_module(void) -{ + typhoon_radio.priv = &typhoon_unit; + if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO) == -1) + return -EINVAL; + + request_region(typhoon_unit.iobase, 8, "typhoon"); + printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); + printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", + typhoon_unit.mutefreq); + typhoon_unit.mutefreq <<= 4; + + /* mute card - prevents noisy bootups */ + typhoon_mute(&typhoon_unit); #ifdef CONFIG_RADIO_TYPHOON_PROC_FS + if (!create_proc_read_entry("driver/radio-typhoon", 0, NULL, + typhoon_read_proc, NULL)) + printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n"); +#endif + + return 0; +} - if (proc_unregister(&proc_root, typhoon_proc_entry.low_ino)) - printk(KERN_ERR "radio-typhoon: unregistering /proc/radio-typhoon failed\n"); +static void __exit typhoon_cleanup_module(void) +{ +#ifdef CONFIG_RADIO_TYPHOON_PROC_FS + remove_proc_entry("driver/radio-typhoon"); #endif video_unregister_device(&typhoon_radio); release_region(io, 8); } -#endif - +module_init(typhoon_init); +module_exit(typhoon_cleanup_module); diff --git a/drivers/char/radio-zoltrix.c b/drivers/char/radio-zoltrix.c index a11de7ba8951..dd688935ab57 100644 --- a/drivers/char/radio-zoltrix.c +++ b/drivers/char/radio-zoltrix.c @@ -354,8 +354,12 @@ static struct video_device zoltrix_radio = NULL }; -int __init zoltrix_init(struct video_init *v) +static int __init zoltrix_init(void) { + if (io == -1) { + printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + return -EINVAL; + } if (check_region(io, 2)) { printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io); return -EBUSY; @@ -390,8 +394,6 @@ int __init zoltrix_init(struct video_init *v) return 0; } -#ifdef MODULE - MODULE_AUTHOR("C.van Schaik"); MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); MODULE_PARM(io, "i"); @@ -399,19 +401,12 @@ MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); EXPORT_NO_SYMBOLS; -int init_module(void) -{ - if (io == -1) { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); - return -EINVAL; - } - return zoltrix_init(NULL); -} - -void cleanup_module(void) +static void __exit zoltrix_cleanup_module(void) { video_unregister_device(&zoltrix_radio); release_region(io, 2); } -#endif +module_init(zoltrix_init); +module_exit(zoltrix_cleanup_module); + diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index d53aa4e52d84..34e1dd51ce06 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -75,6 +75,8 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +#define RS_EVENT_WRITE_WAKEUP 0 + DECLARE_TASK_QUEUE(tq_riscom); #define RISCOM_TYPE_NORMAL 1 diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 3a84af7f691e..0511c78f40ec 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -152,12 +152,12 @@ #endif #endif /* NEW_MODULES */ #include - +#include #ifdef LOCAL_HEADERS #include "serial_local.h" #else -#include #include +#include #include #include static char *serial_version = "4.30"; diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 22014dacfe1e..d04f90964ba4 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -171,7 +171,8 @@ DECLARE_TASK_QUEUE(tq_specialix); - +#undef RS_EVENT_WRITE_WAKEUP +#define RS_EVENT_WRITE_WAKEUP 0 #define SPECIALIX_TYPE_NORMAL 1 #define SPECIALIX_TYPE_CALLOUT 2 diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 7e5ff946523f..6ff32878393f 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -340,6 +340,8 @@ static inline void *ioremap(unsigned long base, long length) #endif +#undef RS_EVENT_WRITE_WAKEUP +#define RS_EVENT_WRITE_WAKEUP 0 #include "generic_serial.h" diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index eb76d446ddd9..2f7cb8be17b3 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -57,21 +57,6 @@ extern int init_bw_qcams(struct video_init *); #ifdef CONFIG_VIDEO_PLANB extern int init_planbs(struct video_init *); #endif -#ifdef CONFIG_RADIO_RTRACK2 -extern int rtrack2_init(struct video_init *); -#endif -#ifdef CONFIG_RADIO_SF16FMI -extern int fmi_init(struct video_init *); -#endif -#ifdef CONFIG_RADIO_TYPHOON -extern int typhoon_init(struct video_init *); -#endif -#ifdef CONFIG_RADIO_CADET -extern int cadet_init(struct video_init *); -#endif -#ifdef CONFIG_RADIO_TERRATEC -extern int terratec_init(struct video_init *); -#endif #ifdef CONFIG_VIDEO_ZORAN extern int init_zoran_cards(struct video_init *); #endif @@ -93,21 +78,6 @@ static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_PLANB {"planb", init_planbs}, #endif -#ifdef CONFIG_RADIO_RTRACK2 - {"RTrack2", rtrack2_init}, -#endif -#ifdef CONFIG_RADIO_SF16FMI - {"SF16FMI", fmi_init}, -#endif -#ifdef CONFIG_RADIO_CADET - {"Cadet", cadet_init}, -#endif -#ifdef CONFIG_RADIO_TYPHOON - {"radio-typhoon", typhoon_init}, -#endif -#ifdef CONFIG_RADIO_TERRATEC - {"radio-terratec", terratec_init}, -#endif #ifdef CONFIG_VIDEO_ZORAN {"zoran", init_zoran_cards}, #endif diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 56769686bcdb..d9b268a55ea5 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -449,7 +449,7 @@ el2_block_output(struct net_device *dev, int count, if (dev->mem_start) { /* Shared memory transfer */ unsigned long dest_addr = dev->mem_start + ((start_page - ei_status.tx_start_page) << 8); - memcpy_toio(dest_addr, buf, count); + isa_memcpy_toio(dest_addr, buf, count); outb(EGACFR_NORM, E33G_GACFR); /* Back to bank1 in case on bank0 */ return; } @@ -514,7 +514,7 @@ el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_pag unsigned short word; if (dev->mem_start) { /* Use the shared memory. */ - memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); return; } @@ -560,12 +560,12 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring if (dev->mem_start + ring_offset + count > end_of_ring) { /* We must wrap the input move. */ int semi_count = end_of_ring - (dev->mem_start + ring_offset); - memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count); + isa_memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count); count -= semi_count; - memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); + isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0); + isa_eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0); } return; } diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index f3d3bcc01a50..cd7573400a5a 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -3,6 +3,9 @@ * Apple Powermacs. Assumes it's under a DBDMA controller. * * Copyright (C) 1998 Randy Gobbel. + * + * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to + * dynamic procfs inode. */ #include #include @@ -1378,14 +1381,7 @@ bmac_probe(struct net_device *dev) if (!bmac_reset_and_enable(dev, 0)) return -ENOMEM; -#ifdef CONFIG_PROC_FS - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_BMAC, 4, "bmac", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - bmac_proc_info - }); -#endif + proc_net_create ("bmac", 0, bmac_proc_info); return 0; } @@ -1627,6 +1623,7 @@ void cleanup_module(void) bp = (struct bmac_data *) bmac_devs->priv; unregister_netdev(bmac_devs); + proc_net_remove("bmac"); free_irq(bmac_devs->irq, bmac_misc_intr); free_irq(bp->tx_dma_intr, bmac_txdma_intr); diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 088eaa68e8cf..421803aae3d3 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -632,14 +632,7 @@ int __init bpq_init(void) printk(KERN_INFO "AX.25 ethernet driver version 0.01\n"); -#ifdef CONFIG_PROC_FS - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_AX25_BPQETHER, 8, "bpqether", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - bpq_get_info - }); -#endif + proc_net_create ("bpqether", 0, bpq_get_info); read_lock_bh(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { @@ -673,9 +666,7 @@ void cleanup_module(void) unregister_netdevice_notifier(&bpq_dev_notifier); -#ifdef CONFIG_PROC_FS - proc_net_unregister(PROC_NET_AX25_BPQETHER); -#endif + proc_net_remove ("bpqether"); for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) unregister_netdev(&bpq->axdev); diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index f93f3d26196a..a46cff85f485 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -2174,15 +2174,8 @@ done: } #ifdef CONFIG_PROC_FS - -struct proc_dir_entry scc_proc_dir_entry = -{ - PROC_NET_Z8530, 8, "z8530drv", S_IFREG | S_IRUGO, 1, 0, 0, 0, - &proc_net_inode_operations, scc_net_get_info -}; - -#define scc_net_procfs_init() proc_net_register(&scc_proc_dir_entry); -#define scc_net_procfs_remove() proc_net_unregister(PROC_NET_Z8530); +#define scc_net_procfs_init() proc_net_create("z8530drv",0,scc_net_get_info) +#define scc_net_procfs_remove() proc_net_remove("z8530drv") #else #define scc_net_procfs_init() #define scc_net_procfs_remove() diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 2c468c8c1480..ef3e7d1620cd 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -893,28 +893,17 @@ static int yam_net_get_info(char *buffer, char **start, off_t offset, int length } #ifdef CONFIG_INET - -#ifndef PROC_NET_YAM -#define PROC_NET_YAM (PROC_NET_LAST+10) /* Sorry again... */ -#endif - #ifdef CONFIG_PROC_FS -struct proc_dir_entry yam_proc_dir_entry = -{ - PROC_NET_YAM, 3, "yam", S_IFREG | S_IRUGO, 1, 0, 0, 0, - &proc_net_inode_operations, yam_net_get_info -}; - -#define yam_net_procfs_init() proc_net_register(&yam_proc_dir_entry); -#define yam_net_procfs_remove() proc_net_unregister(PROC_NET_YAM); +#define yam_net_procfs_init() proc_net_create("yam",0,yam_net_get_info) +#define yam_net_procfs_remove() proc_net_remove("yam") #else #define yam_net_procfs_init() #define yam_net_procfs_remove() -#endif +#endif /* CONFIG_PROC_FS */ #else #define yam_net_procfs_init() #define yam_net_procfs_remove() -#endif +#endif /* CONFIG_INET */ /* --------------------------------------------------------------------- */ diff --git a/drivers/net/strip.c b/drivers/net/strip.c index b9131cb738f0..c5756bb11fab 100644 --- a/drivers/net/strip.c +++ b/drivers/net/strip.c @@ -118,8 +118,8 @@ static const char StripVersion[] = "1.3-STUART.CHESHIRE"; #include #include #include -#include #include +#include #include #include @@ -1270,25 +1270,6 @@ static int get_status_info(char *buffer, char **start, off_t req_offset, int req return(calc_start_len(buffer, start, req_offset, req_len, total, buf)); } -static const char proc_strip_status_name[] = "strip"; - -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_strip_get_status_info = -{ - PROC_NET_STRIP_STATUS, /* unsigned short low_ino */ - sizeof(proc_strip_status_name)-1, /* unsigned short namelen */ - proc_strip_status_name, /* const char *name */ - S_IFREG | S_IRUGO, /* mode_t mode */ - 1, /* nlink_t nlink */ - 0, 0, 0, /* uid_t uid, gid_t gid, unsigned long size */ - &proc_net_inode_operations, /* struct inode_operations * ops */ - &get_status_info, /* int (*get_info)(...) */ - NULL, /* void (*fill_inode)(struct inode *); */ - NULL, NULL, NULL, /* struct proc_dir_entry *next, *parent, *subdir; */ - NULL /* void *data; */ -}; -#endif /* CONFIG_PROC_FS */ - /************************************************************************/ /* Sending routines */ @@ -2885,12 +2866,7 @@ int strip_init_ctrl_dev(struct net_device *dummy) /* * Register the status file with /proc */ -#ifdef CONFIG_PROC_FS - if (proc_net_register(&proc_strip_get_status_info) != 0) - { - printk(KERN_ERR "strip: status proc_net_register() failed.\n"); - } -#endif + proc_net_create ("strip", S_IFREG | S_IRUGO, get_status_info); #ifdef MODULE return status; @@ -2921,9 +2897,7 @@ void cleanup_module(void) strip_free(struct_strip_list); /* Unregister with the /proc/net file here. */ -#ifdef CONFIG_PROC_FS - proc_net_unregister(PROC_NET_STRIP_STATUS); -#endif + proc_net_remove ("strip"); if ((i = tty_register_ldisc(N_STRIP, NULL))) printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); diff --git a/drivers/net/wd.c b/drivers/net/wd.c index 8a850ca6f06b..9b442d5f32b4 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -367,9 +367,9 @@ wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page #ifdef notdef /* Officially this is what we are doing, but the readl() is faster */ - memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); #else - ((unsigned int*)hdr)[0] = readl(hdr_start); + ((unsigned int*)hdr)[0] = isa_readl(hdr_start); #endif } @@ -387,12 +387,12 @@ wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_ if (xfer_start + count > dev->rmem_end) { /* We must wrap the input move. */ int semi_count = dev->rmem_end - xfer_start; - memcpy_fromio(skb->data, xfer_start, semi_count); + isa_memcpy_fromio(skb->data, xfer_start, semi_count); count -= semi_count; - memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); + isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); } else { /* Packet is in one chunk -- we can copy + cksum. */ - eth_io_copy_and_sum(skb, xfer_start, count, 0); + isa_eth_io_copy_and_csum(skb, xfer_start, count, 0); } /* Turn off 16 bit access so that reboot works. ISA brain-damage */ @@ -411,10 +411,10 @@ wd_block_output(struct net_device *dev, int count, const unsigned char *buf, if (ei_status.word16) { /* Turn on and off 16 bit access so that reboot works. */ outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5); - memcpy_toio(shmem, buf, count); + isa_memcpy_toio(shmem, buf, count); outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5); } else - memcpy_toio(shmem, buf, count); + isa_memcpy_toio(shmem, buf, count); } diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index 63aadb6106c0..47b3d88fefcf 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c @@ -963,37 +963,39 @@ static int sprint_nubus_board(struct nubus_board* board, char* ptr, int len) return strlen(ptr); } -/* We're going to have to be a bit more sophisticated about this, I - think, because it doesn't really seem to work right when you do a - full listing of boards and devices */ -int get_nubus_list(char *buf) +static int nubus_read_proc(char *buf, char **start, off_t off, + int count, int *eof, void *data) { - int nprinted, len, size; - struct nubus_board* board; -#define MSG "\nwarning: page-size limit reached!\n" - - /* reserve same for truncation warning message: */ - size = PAGE_SIZE - (strlen(MSG) + 1); - len = sprintf(buf, "Nubus boards found:\n"); + int nprinted, len, begin = 0; + int slot; + len = sprintf(buf, "Nubus devices found:\n"); /* Walk the list of NuBus boards */ for (board = nubus_boards; board != NULL; board = board->next) { nprinted = sprint_nubus_board(board, buf + len, size - len); - if (nprinted < 0) { - return len + sprintf(buf + len, MSG); - } + if (nprinted < 0) + break; len += nprinted; + if (len+begin < off) { + begin += len; + len = 0; + } + if (len+begin >= off+count) + break; } + if (slot==16 || len+begin < off) + *eof = 1; + off -= begin; + *strat = buf + off; + len -= off; + if (len>count) + len = count; + if (len<0) + len = 0; return len; } - -static struct proc_dir_entry proc_old_nubus = { - PROC_NUBUS, 5, "nubus", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations -}; -#endif /* CONFIG_PROC_FS */ +#endif void __init nubus_scan_bus(void) { @@ -1034,7 +1036,7 @@ void __init nubus_init(void) nubus_scan_bus(); #ifdef CONFIG_PROC_FS - proc_register(&proc_root, &proc_old_nubus); + create_proc_read_entry("nubus", 0, NULL, nubus_read_proc, NULL); nubus_proc_init(); #endif } diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c index 1e5754b169de..d21b6f995fc6 100644 --- a/drivers/nubus/proc.c +++ b/drivers/nubus/proc.c @@ -60,13 +60,6 @@ get_nubus_dev_info(char *buf, char **start, off_t pos, int count, int wr) return (count > cnt) ? cnt : count; } -static struct proc_dir_entry proc_nubus_devices = { - PROC_BUS_NUBUS_DEVICES, 7, "devices", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations, - get_nubus_dev_info -}; - static struct proc_dir_entry *proc_bus_nubus_dir; static void nubus_proc_subdir(struct nubus_dev* dev, @@ -178,6 +171,7 @@ void __init nubus_proc_init(void) if (!MACH_IS_MAC) return; proc_bus_nubus_dir = create_proc_entry("nubus", S_IFDIR, proc_bus); - proc_register(proc_bus_nubus_dir, &proc_nubus_devices); + create_proc_info_entry("devices", 0, proc_bus_nubus_dir, + get_nubus_dev_info); proc_bus_nubus_add_devices(); } diff --git a/drivers/pci/pcisyms.c b/drivers/pci/pcisyms.c index 44d272776529..101728b72032 100644 --- a/drivers/pci/pcisyms.c +++ b/drivers/pci/pcisyms.c @@ -24,6 +24,7 @@ EXPORT_SYMBOL(pci_find_class); EXPORT_SYMBOL(pci_find_device); EXPORT_SYMBOL(pci_find_slot); EXPORT_SYMBOL(pci_set_master); +EXPORT_SYMBOL(pci_simple_probe); #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(pci_proc_attach_device); EXPORT_SYMBOL(pci_proc_detach_device); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 2e92f80dc9f9..4688e82fb225 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -271,13 +271,6 @@ get_pci_dev_info(char *buf, char **start, off_t pos, int count, int wr) return (count > cnt) ? cnt : count; } -static struct proc_dir_entry proc_pci_devices = { - PROC_BUS_PCI_DEVICES, 7, "devices", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations, - get_pci_dev_info -}; - static struct proc_dir_entry *proc_bus_pci_dir; int pci_proc_attach_device(struct pci_dev *dev) @@ -498,37 +491,39 @@ static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) return len; } - -static struct proc_dir_entry proc_old_pci = { - PROC_PCI, 3, "pci", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_array_inode_operations -}; - /* * Return list of PCI devices as a character string for /proc/pci. * BUF is a buffer that is PAGE_SIZE bytes long. */ -int get_pci_list(char *buf) +static int pci_read_proc(char *buf, char **start, off_t off, + int count, int *eof, void *data) { - int nprinted, len, size; + int nprinted, len, begin = 0; struct pci_dev *dev; -# define MSG "\nwarning: page-size limit reached!\n" - /* reserve same for truncation warning message: */ - size = PAGE_SIZE - (strlen(MSG) + 1); len = sprintf(buf, "PCI devices found:\n"); for (dev = pci_devices; dev; dev = dev->next) { - nprinted = sprint_dev_config(dev, buf + len, size - len); - if (nprinted < 0) { - len += sprintf(buf + len, MSG); - proc_old_pci.size = len; - return len; - } + nprinted = sprint_dev_config(dev, buf + len, count - len); + if (nprinted < 0) + break; len += nprinted; + if (len+begin < off) { + begin += len; + len = 0; + } + if (len+begin >= off+count) + break; } - proc_old_pci.size = len; + if (!dev || len+begin < off) + *eof = 1; + off -= begin; + *start = buf + off; + len -= off; + if (len>count) + len = count; + if (len<0) + len = 0; return len; } @@ -536,9 +531,10 @@ static int __init pci_proc_init(void) { if (pci_present()) { proc_bus_pci_dir = create_proc_entry("pci", S_IFDIR, proc_bus); - proc_register(proc_bus_pci_dir, &proc_pci_devices); + create_proc_info_entry("devices",0, proc_bus_pci_dir, + get_pci_dev_info); proc_bus_pci_add(pci_root); - proc_register(&proc_root, &proc_old_pci); + create_proc_read_entry("pci", 0, NULL, pci_read_proc, NULL); } return 0; } diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 08e819dced1e..e37648d81706 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -113,6 +113,7 @@ * replaced current->state = x with set_current_state(x) * 03.09.99 0.30 change read semantics for MIDI to match * OSS more closely; remove possible wakeup race + * 28.10.99 0.31 More waitqueue races fixed * * some important things missing in Ensoniq documentation: * @@ -1064,9 +1065,9 @@ static int drain_dac1(struct es1370_state *s, int nonblock) if (s->dma_dac1.mapped || !s->dma_dac1.ready) return 0; - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac1.wait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac1.count; spin_unlock_irqrestore(&s->lock, flags); @@ -1100,9 +1101,9 @@ static int drain_dac2(struct es1370_state *s, int nonblock) if (s->dma_dac2.mapped || !s->dma_dac2.ready) return 0; - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac2.wait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac2.count; spin_unlock_irqrestore(&s->lock, flags); @@ -1133,6 +1134,7 @@ static int drain_dac2(struct es1370_state *s, int nonblock) static ssize_t es1370_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct es1370_state *s = (struct es1370_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -1148,26 +1150,38 @@ static ssize_t es1370_read(struct file *file, char *buffer, size_t count, loff_t if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; + add_wait_queue(&s->dma_adc.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); swptr = s->dma_adc.swptr; cnt = s->dma_adc.dmasize-swptr; if (s->dma_adc.count < cnt) cnt = s->dma_adc.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_adc(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_adc.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_adc.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; @@ -1178,12 +1192,15 @@ static ssize_t es1370_read(struct file *file, char *buffer, size_t count, loff_t ret += cnt; start_adc(s); } + remove_wait_queue(&s->dma_adc.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } static ssize_t es1370_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct es1370_state *s = (struct es1370_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -1199,6 +1216,7 @@ static ssize_t es1370_write(struct file *file, const char *buffer, size_t count, if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; + add_wait_queue(&s->dma_dac2.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac2.count < 0) { @@ -1209,20 +1227,31 @@ static ssize_t es1370_write(struct file *file, const char *buffer, size_t count, cnt = s->dma_dac2.dmasize-swptr; if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize) cnt = s->dma_dac2.dmasize - s->dma_dac2.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac2(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_dac2.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_dac2.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac2.swptr = swptr; @@ -1234,6 +1263,8 @@ static ssize_t es1370_write(struct file *file, const char *buffer, size_t count, ret += cnt; start_dac2(s); } + remove_wait_queue(&s->dma_dac2.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } @@ -1608,6 +1639,7 @@ static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd static int es1370_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct es1370_state *s = devs; unsigned long flags; @@ -1624,8 +1656,12 @@ static int es1370_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -1676,8 +1712,8 @@ static int es1370_release(struct inode *inode, struct file *file) dealloc_dmabuf(&s->dma_adc); } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -1705,6 +1741,7 @@ static /*const*/ struct file_operations es1370_audio_fops = { static ssize_t es1370_write_dac(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct es1370_state *s = (struct es1370_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret = 0; unsigned long flags; unsigned swptr; @@ -1719,6 +1756,7 @@ static ssize_t es1370_write_dac(struct file *file, const char *buffer, size_t co return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + add_wait_queue(&s->dma_dac1.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac1.count < 0) { @@ -1729,20 +1767,31 @@ static ssize_t es1370_write_dac(struct file *file, const char *buffer, size_t co cnt = s->dma_dac1.dmasize-swptr; if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize) cnt = s->dma_dac1.dmasize - s->dma_dac1.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac1(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_dac1.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_dac1.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac1.swptr = swptr; @@ -1754,6 +1803,8 @@ static ssize_t es1370_write_dac(struct file *file, const char *buffer, size_t co ret += cnt; start_dac1(s); } + remove_wait_queue(&s->dma_dac1.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } @@ -1991,6 +2042,7 @@ static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int static int es1370_open_dac(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct es1370_state *s = devs; unsigned long flags; @@ -2014,8 +2066,12 @@ static int es1370_open_dac(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2047,8 +2103,8 @@ static int es1370_release_dac(struct inode *inode, struct file *file) stop_dac1(s); dealloc_dmabuf(&s->dma_dac1); s->open_mode &= ~FMODE_DAC; - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -2097,6 +2153,8 @@ static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, l cnt = MIDIINBUF - ptr; if (s->midi.icnt < cnt) cnt = s->midi.icnt; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -2106,7 +2164,6 @@ static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, l ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -2159,8 +2216,10 @@ static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t c cnt = MIDIOUTBUF - ptr; if (s->midi.ocnt + cnt > MIDIOUTBUF) cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) + if (cnt <= 0) { + __set_current_state(TASK_INTERRUPTIBLE); es1370_handle_midi(s); + } spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -2170,7 +2229,6 @@ static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t c ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -2228,6 +2286,7 @@ static unsigned int es1370_midi_poll(struct file *file, struct poll_table_struct static int es1370_midi_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct es1370_state *s = devs; unsigned long flags; @@ -2244,8 +2303,12 @@ static int es1370_midi_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2284,9 +2347,9 @@ static int es1370_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->midi.ocnt; spin_unlock_irqrestore(&s->lock, flags); @@ -2314,8 +2377,8 @@ static int es1370_midi_release(struct inode *inode, struct file *file) outl(s->ctrl, s->io+ES1370_REG_CONTROL); } spin_unlock_irqrestore(&s->lock, flags); - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -2389,7 +2452,7 @@ static int __init init_es1370(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.29 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.31 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (!RSRCISIOREGION(pcidev, 0)) diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index bf5048fe297b..3fc188402b84 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -86,7 +86,14 @@ * replaced current->state = x with set_current_state(x) * 03.09.99 0.18 change read semantics for MIDI to match * OSS more closely; remove possible wakeup race - * + * 21.10.99 0.19 Round sampling rates, requested by + * Kasamatsu Kenichi + * 27.10.99 0.20 Added SigmaTel 3D enhancement string + * Codec ID printing changes + * 28.10.99 0.21 More waitqueue races fixed + * Joe Cotellese + * Changed PCI detection routine so we can more easily + * detect ES137x chip and derivatives. */ /*****************************************************************************/ @@ -116,16 +123,31 @@ #undef OSS_DOCUMENTED_MIXER_SEMANTICS #define ES1371_DEBUG +#define DBG(x) {} +/*#define DBG(x) {x}*/ /* --------------------------------------------------------------------- */ #ifndef PCI_VENDOR_ID_ENSONIQ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #endif + +#ifndef PCI_VENDOR_ID_ECTIVA +#define PCI_VENDOR_ID_ECTIVA 0x1102 +#endif + #ifndef PCI_DEVICE_ID_ENSONIQ_ES1371 #define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 #endif +#ifndef PCI_DEVICE_ID_ENSONIQ_CT5880 +#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 +#endif + +#ifndef PCI_DEVICE_ID_ECTIVA_EV1938 +#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 +#endif + /* ES1371 chip ID */ /* This is a little confusing because all ES1371 compatible chips have the same DEVICE_ID, the only thing differentiating them is the REV_ID field. @@ -135,8 +157,9 @@ #define ES1371REV_ES1373_A 0x04 #define ES1371REV_ES1373_B 0x06 #define ES1371REV_CT5880_A 0x07 +#define CT5880REV_CT5880_C 0x02 #define ES1371REV_ES1371_B 0x09 - +#define EV1938REV_EV1938_A 0x00 #define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371) @@ -144,7 +167,7 @@ #define JOY_EXTENT 8 #define ES1371_REG_CONTROL 0x00 -#define ES1371_REG_STATUS 0x04 +#define ES1371_REG_STATUS 0x04 /* on the 5880 it is control/status */ #define ES1371_REG_UART_DATA 0x08 #define ES1371_REG_UART_STATUS 0x09 #define ES1371_REG_UART_CONTROL 0x09 @@ -212,6 +235,7 @@ static const unsigned sample_shift[] = { 0, 1, 1, 2 }; #define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ +#define CSTAT_5880_AC97_RST 0x20000000 /* CT5880 Reset bit */ #define STAT_EN_SPDIF 0x00040000 /* enable S/PDIF circuitry */ #define STAT_TS_SPDIF 0x00020000 /* test S/PDIF circuitry */ #define STAT_TESTMODE 0x00010000 /* test ASIC */ @@ -370,7 +394,13 @@ static const char *stereo_enhancement[] __initdata = "NVidea 3D Stereo Enhancement", "Philips Incredible Sound", "Texas Instruments 3D Stereo Enhancement", - "VLSI Technology 3D Stereo Enhancement" + "VLSI Technology 3D Stereo Enhancement", + NULL, + NULL, + NULL, + NULL, + NULL, + "SigmaTel SS3D" }; /* --------------------------------------------------------------------- */ @@ -391,8 +421,12 @@ struct es1371_state { /* hardware resources */ unsigned long io; /* long for SPARC */ unsigned int irq; + + /* PCI ID's */ + u16 vendor; + u16 device; u8 rev; /* the chip revision */ - + #ifdef ES1371_DEBUG /* debug /proc entry */ struct proc_dir_entry *ps; @@ -591,8 +625,8 @@ static void set_dac1_rate(struct es1371_state *s, unsigned rate) rate = 48000; if (rate < 4000) rate = 4000; - freq = (rate << 15) / 3000; - s->dac1rate = (freq * 3000) >> 15; + freq = ((rate << 15) + 1500) / 3000; + s->dac1rate = (freq * 3000 + 16384) >> 15; spin_lock_irqsave(&s->lock, flags); r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1; outl(r, s->io + ES1371_REG_SRCONV); @@ -614,9 +648,8 @@ static void set_dac2_rate(struct es1371_state *s, unsigned rate) rate = 48000; if (rate < 4000) rate = 4000; - freq = (rate << 15) / 3000; - s->dac2rate = (freq * 3000) >> 15; - printk (KERN_DEBUG "dac2 freq: %d\n", freq); + freq = ((rate << 15) + 1500) / 3000; + s->dac2rate = (freq * 3000 + 16384) >> 15; spin_lock_irqsave(&s->lock, flags); r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2; outl(r, s->io + ES1371_REG_SRCONV); @@ -1612,10 +1645,9 @@ static int drain_dac1(struct es1371_state *s, int nonblock) if (s->dma_dac1.mapped || !s->dma_dac1.ready) return 0; - - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac1.wait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac1.count; spin_unlock_irqrestore(&s->lock, flags); @@ -1631,7 +1663,7 @@ static int drain_dac1(struct es1371_state *s, int nonblock) tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "es1371: dac1 dma timed out??\n"); + DBG(printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");) } remove_wait_queue(&s->dma_dac1.wait, &wait); set_current_state(TASK_RUNNING); @@ -1648,10 +1680,9 @@ static int drain_dac2(struct es1371_state *s, int nonblock) if (s->dma_dac2.mapped || !s->dma_dac2.ready) return 0; - - __set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&s->dma_dac2.wait, &wait); for (;;) { + __set_current_state(TASK_UNINTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac2.count; spin_unlock_irqrestore(&s->lock, flags); @@ -1667,7 +1698,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock) tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "es1371: dac2 dma timed out??\n"); + DBG(printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");) } remove_wait_queue(&s->dma_dac2.wait, &wait); set_current_state(TASK_RUNNING); @@ -1681,6 +1712,7 @@ static int drain_dac2(struct es1371_state *s, int nonblock) static ssize_t es1371_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct es1371_state *s = (struct es1371_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -1696,26 +1728,38 @@ static ssize_t es1371_read(struct file *file, char *buffer, size_t count, loff_t if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; + add_wait_queue(&s->dma_adc.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); swptr = s->dma_adc.swptr; cnt = s->dma_adc.dmasize-swptr; if (s->dma_adc.count < cnt) cnt = s->dma_adc.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_adc(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_adc.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_adc.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; @@ -1726,12 +1770,15 @@ static ssize_t es1371_read(struct file *file, char *buffer, size_t count, loff_t ret += cnt; start_adc(s); } + remove_wait_queue(&s->dma_adc.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } static ssize_t es1371_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct es1371_state *s = (struct es1371_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -1747,6 +1794,7 @@ static ssize_t es1371_write(struct file *file, const char *buffer, size_t count, if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; + add_wait_queue(&s->dma_dac2.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac2.count < 0) { @@ -1757,20 +1805,31 @@ static ssize_t es1371_write(struct file *file, const char *buffer, size_t count, cnt = s->dma_dac2.dmasize-swptr; if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize) cnt = s->dma_dac2.dmasize - s->dma_dac2.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac2(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_dac2.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_dac2.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac2.swptr = swptr; @@ -1782,6 +1841,8 @@ static ssize_t es1371_write(struct file *file, const char *buffer, size_t count, ret += cnt; start_dac2(s); } + remove_wait_queue(&s->dma_dac2.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } @@ -1894,7 +1955,6 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd if (file->f_mode & FMODE_WRITE) { stop_dac2(s); s->dma_dac2.ready = 0; - printk (KERN_DEBUG "es137x: setting DAC2 rate: %d\n", val); set_dac2_rate(s, val); } } @@ -2152,6 +2212,7 @@ static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd static int es1371_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct es1371_state *s = devs; unsigned long flags; @@ -2168,8 +2229,12 @@ static int es1371_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2251,6 +2316,7 @@ static /*const*/ struct file_operations es1371_audio_fops = { static ssize_t es1371_write_dac(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct es1371_state *s = (struct es1371_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret = 0; unsigned long flags; unsigned swptr; @@ -2265,6 +2331,7 @@ static ssize_t es1371_write_dac(struct file *file, const char *buffer, size_t co return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + add_wait_queue(&s->dma_dac1.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac1.count < 0) { @@ -2275,20 +2342,31 @@ static ssize_t es1371_write_dac(struct file *file, const char *buffer, size_t co cnt = s->dma_dac1.dmasize-swptr; if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize) cnt = s->dma_dac1.dmasize - s->dma_dac1.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac1(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_dac1.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_dac1.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac1.swptr = swptr; @@ -2300,6 +2378,8 @@ static ssize_t es1371_write_dac(struct file *file, const char *buffer, size_t co ret += cnt; start_dac1(s); } + remove_wait_queue(&s->dma_dac1.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } @@ -2528,6 +2608,7 @@ static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int static int es1371_open_dac(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct es1371_state *s = devs; unsigned long flags; @@ -2551,8 +2632,12 @@ static int es1371_open_dac(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2633,6 +2718,8 @@ static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, l cnt = MIDIINBUF - ptr; if (s->midi.icnt < cnt) cnt = s->midi.icnt; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -2642,7 +2729,6 @@ static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, l ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -2695,8 +2781,10 @@ static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t c cnt = MIDIOUTBUF - ptr; if (s->midi.ocnt + cnt > MIDIOUTBUF) cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) + if (cnt <= 0) { + __set_current_state(TASK_INTERRUPTIBLE); es1371_handle_midi(s); + } spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -2706,7 +2794,6 @@ static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t c ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -2764,6 +2851,7 @@ static unsigned int es1371_midi_poll(struct file *file, struct poll_table_struct static int es1371_midi_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct es1371_state *s = devs; unsigned long flags; @@ -2780,8 +2868,12 @@ static int es1371_midi_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2819,9 +2911,9 @@ static int es1371_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->midi.ocnt; spin_unlock_irqrestore(&s->lock, flags); @@ -2952,162 +3044,212 @@ static struct initvol { ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) #define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) - -static int __init init_es1371(void) +static int __init probe_chip(struct pci_dev *pcidev, int index) { struct es1371_state *s; - struct pci_dev *pcidev = NULL; mm_segment_t fs; - int i, val, val2, index = 0; - unsigned cssr; - - if (!pci_present()) /* No PCI bus in this machine! */ - return -ENODEV; - printk(KERN_INFO "es1371: version v0.17 time " __TIME__ " " __DATE__ "\n"); - while (index < NR_DEVICE && - (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { - if (!RSRCISIOREGION(pcidev, 0)) - continue; - if (pcidev->irq == 0) - continue; - if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { - printk(KERN_WARNING "es1371: out of memory\n"); - continue; - } - memset(s, 0, sizeof(struct es1371_state)); - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac1.wait); - init_waitqueue_head(&s->dma_dac2.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - init_MUTEX(&s->open_sem); - spin_lock_init(&s->lock); - s->magic = ES1371_MAGIC; - s->io = RSRCADDRESS(pcidev, 0); - s->irq = pcidev->irq; - pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev); - if (check_region(s->io, ES1371_EXTENT)) { - printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); - goto err_region; - } - request_region(s->io, ES1371_EXTENT, "es1371"); - if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) { - printk(KERN_ERR "es1371: irq %u in use\n", s->irq); - goto err_irq; - } - printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n" - KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]); - /* register devices */ - if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) - goto err_dev1; - if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0) - goto err_dev2; - if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0) - goto err_dev3; - if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0) - goto err_dev4; + int i, val, val2; + unsigned char id[4]; + unsigned long tmo; + signed long tmo2; + unsigned int cssr; + + if (!RSRCISIOREGION(pcidev, 0)) + return -1; + if (pcidev->irq == 0) + return -1; + if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { + printk(KERN_WARNING "es1371: out of memory\n"); + return -1; + } + memset(s, 0, sizeof(struct es1371_state)); + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac1.wait); + init_waitqueue_head(&s->dma_dac2.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); + s->magic = ES1371_MAGIC; + s->io = RSRCADDRESS(pcidev, 0); + s->irq = pcidev->irq; + s->vendor = pcidev->vendor; + s->device = pcidev->device; + pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev); + printk(KERN_INFO "es1371: found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", + s->vendor, s->device, s->rev); + if (check_region(s->io, ES1371_EXTENT)) { + printk(KERN_ERR "es1371: io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); + goto err_region; + } + request_region(s->io, ES1371_EXTENT, "es1371"); + if (request_irq(s->irq, es1371_interrupt, SA_SHIRQ, "es1371", s)) { + printk(KERN_ERR "es1371: irq %u in use\n", s->irq); + goto err_irq; + } + printk(KERN_INFO "es1371: found es1371 rev %d at io %#lx irq %u\n" + KERN_INFO "es1371: features: joystick 0x%x\n", s->rev, s->io, s->irq, joystick[index]); + /* register devices */ + if ((s->dev_audio = register_sound_dsp(&es1371_audio_fops, -1)) < 0) + goto err_dev1; + if ((s->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1)) < 0) + goto err_dev2; + if ((s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1)) < 0) + goto err_dev3; + if ((s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)) < 0) + goto err_dev4; #ifdef ES1371_DEBUG - /* intialize the debug proc device */ - s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL); - if (s->ps) - s->ps->read_proc = proc_es1371_dump; + /* intialize the debug proc device */ + s->ps = create_proc_entry("es1371", S_IFREG | S_IRUGO, NULL); + if (s->ps) + s->ps->read_proc = proc_es1371_dump; #endif /* ES1371_DEBUG */ - - /* initialize codec registers */ - s->ctrl = 0; - if ((joystick[index] & ~0x18) == 0x200) { - if (check_region(joystick[index], JOY_EXTENT)) - printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[index]); - else { - s->ctrl |= CTRL_JYSTK_EN | (((joystick[index] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); - } - } - s->sctrl = 0; - cssr = 0; - /* check to see if s/pdif mode is being requested */ - if (spdif[index]) { - if (s->rev >= 4) { - printk(KERN_INFO "es1371: enabling S/PDIF output\n"); - cssr |= STAT_EN_SPDIF; - s->ctrl |= CTRL_SPDIFEN_B; - } else { - printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev); - } + + /* initialize codec registers */ + s->ctrl = 0; + if ((joystick[index] & ~0x18) == 0x200) { + if (check_region(joystick[index], JOY_EXTENT)) + printk(KERN_ERR "es1371: joystick address 0x%x already in use\n", joystick[index]); + else { + s->ctrl |= CTRL_JYSTK_EN | (((joystick[index] >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); } - /* initialize the chips */ - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - outl(0, s->io+ES1371_REG_LEGACY); - pci_set_master(pcidev); /* enable bus mastering */ - /* AC97 warm reset to start the bitclk */ - outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL); - udelay(2); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - /* init the sample rate converter */ - src_init(s); - /* codec init */ - wrcodec(s, AC97_RESET, 0); /* reset codec */ - s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */ - val = rdcodec(s, AC97_VENDOR_ID1); - val2 = rdcodec(s, AC97_VENDOR_ID2); - printk(KERN_INFO "es1371: codec vendor %c%c%c revision %d\n", - (val >> 8) & 0xff, val & 0xff, (val2 >> 8) & 0xff, val2 & 0xff); - printk(KERN_INFO "es1371: codec features"); - if (s->mix.codec_id & CODEC_ID_DEDICATEDMIC) - printk(" dedicated MIC PCM in"); - if (s->mix.codec_id & CODEC_ID_MODEMCODEC) - printk(" Modem Line Codec"); - if (s->mix.codec_id & CODEC_ID_BASSTREBLE) - printk(" Bass & Treble"); - if (s->mix.codec_id & CODEC_ID_SIMULATEDSTEREO) - printk(" Simulated Stereo"); - if (s->mix.codec_id & CODEC_ID_HEADPHONEOUT) - printk(" Headphone out"); - if (s->mix.codec_id & CODEC_ID_LOUDNESS) - printk(" Loudness"); - if (s->mix.codec_id & CODEC_ID_18BITDAC) - printk(" 18bit DAC"); - if (s->mix.codec_id & CODEC_ID_20BITDAC) - printk(" 20bit DAC"); - if (s->mix.codec_id & CODEC_ID_18BITADC) - printk(" 18bit ADC"); - if (s->mix.codec_id & CODEC_ID_20BITADC) - printk(" 20bit ADC"); - printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none"); - val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK; - printk(KERN_INFO "es1371: stereo enhancement: %s\n", (val <= 20) ? stereo_enhancement[val] : "unknown"); - - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE; - mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { - val = initvol[i].vol; - mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); + } + s->sctrl = 0; + cssr = 0; + /* check to see if s/pdif mode is being requested */ + if (spdif[index]) { + if (s->rev >= 4) { + printk(KERN_INFO "es1371: enabling S/PDIF output\n"); + cssr |= STAT_EN_SPDIF; + s->ctrl |= CTRL_SPDIFEN_B; + } else { + printk(KERN_ERR "es1371: revision %d does not support S/PDIF\n", s->rev); } - set_fs(fs); - /* turn on S/PDIF output driver if requested */ + } + /* initialize the chips */ + outl(s->ctrl, s->io+ES1371_REG_CONTROL); + outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); + outl(0, s->io+ES1371_REG_LEGACY); + pci_set_master(pcidev); /* enable bus mastering */ + /* if we are a 5880 turn on the AC97 */ + if (s->vendor == PCI_VENDOR_ID_ENSONIQ && + s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && + s->rev == CT5880REV_CT5880_C) { + cssr |= CSTAT_5880_AC97_RST; outl(cssr, s->io+ES1371_REG_STATUS); - /* queue it for later freeing */ - s->next = devs; - devs = s; - index++; - continue; + /* need to delay around 20ms(bleech) to give + some CODECs enough time to wakeup */ + tmo = jiffies + (HZ / 50) + 1; + for (;;) { + tmo2 = tmo - jiffies; + if (tmo2 <= 0) + break; + schedule_timeout(tmo2); + } + } + /* AC97 warm reset to start the bitclk */ + outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL); + udelay(2); + outl(s->ctrl, s->io+ES1371_REG_CONTROL); + /* init the sample rate converter */ + src_init(s); + /* codec init */ + wrcodec(s, AC97_RESET, 0); /* reset codec */ + s->mix.codec_id = rdcodec(s, AC97_RESET); /* get codec ID */ + val = rdcodec(s, AC97_VENDOR_ID1); + val2 = rdcodec(s, AC97_VENDOR_ID2); + id[0] = val >> 8; + id[1] = val; + id[2] = val2 >> 8; + id[3] = 0; + if (id[0] <= ' ' || id[0] > 0x7f) + id[0] = ' '; + if (id[1] <= ' ' || id[1] > 0x7f) + id[1] = ' '; + if (id[2] <= ' ' || id[2] > 0x7f) + id[2] = ' '; + printk(KERN_INFO "es1371: codec vendor %s (0x%04x%02x) revision %d (0x%02x)\n", + id, val & 0xffff, (val2 >> 8) & 0xff, val2 & 0xff, val2 & 0xff); + printk(KERN_INFO "es1371: codec features"); + if (s->mix.codec_id & CODEC_ID_DEDICATEDMIC) + printk(" dedicated MIC PCM in"); + if (s->mix.codec_id & CODEC_ID_MODEMCODEC) + printk(" Modem Line Codec"); + if (s->mix.codec_id & CODEC_ID_BASSTREBLE) + printk(" Bass & Treble"); + if (s->mix.codec_id & CODEC_ID_SIMULATEDSTEREO) + printk(" Simulated Stereo"); + if (s->mix.codec_id & CODEC_ID_HEADPHONEOUT) + printk(" Headphone out"); + if (s->mix.codec_id & CODEC_ID_LOUDNESS) + printk(" Loudness"); + if (s->mix.codec_id & CODEC_ID_18BITDAC) + printk(" 18bit DAC"); + if (s->mix.codec_id & CODEC_ID_20BITDAC) + printk(" 20bit DAC"); + if (s->mix.codec_id & CODEC_ID_18BITADC) + printk(" 18bit ADC"); + if (s->mix.codec_id & CODEC_ID_20BITADC) + printk(" 20bit ADC"); + printk("%s\n", (s->mix.codec_id & 0x3ff) ? "" : " none"); + val = (s->mix.codec_id >> CODEC_ID_SESHIFT) & CODEC_ID_SEMASK; + printk(KERN_INFO "es1371: stereo enhancement: %s\n", + (val <= 26 && stereo_enhancement[val]) ? stereo_enhancement[val] : "unknown"); + + fs = get_fs(); + set_fs(KERNEL_DS); + val = SOUND_MASK_LINE; + mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); + for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { + val = initvol[i].vol; + mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); + } + set_fs(fs); + /* turn on S/PDIF output driver if requested */ + outl(cssr, s->io+ES1371_REG_STATUS); + /* queue it for later freeing */ + s->next = devs; + devs = s; + return 0; + + err_dev4: + unregister_sound_dsp(s->dev_dac); + err_dev3: + unregister_sound_mixer(s->dev_mixer); + err_dev2: + unregister_sound_dsp(s->dev_audio); + err_dev1: + printk(KERN_ERR "es1371: cannot register misc device\n"); + free_irq(s->irq, s); + err_irq: + release_region(s->io, ES1371_EXTENT); + err_region: + kfree_s(s, sizeof(struct es1371_state)); + return -1; +} - err_dev4: - unregister_sound_dsp(s->dev_dac); - err_dev3: - unregister_sound_mixer(s->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR "es1371: cannot register misc device\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->io, ES1371_EXTENT); - err_region: - kfree_s(s, sizeof(struct es1371_state)); + +static int __init init_es1371(void) +{ + struct pci_dev *pcidev = NULL; + int index = 0; + + if (!pci_present()) /* No PCI bus in this machine! */ + return -ENODEV; + printk(KERN_INFO "es1371: version v0.22 time " __TIME__ " " __DATE__ "\n"); + while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pcidev))) { + if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) { + if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 && + pcidev->device != PCI_DEVICE_ID_ENSONIQ_CT5880) + continue; + } else if (pcidev->vendor == PCI_VENDOR_ID_ECTIVA) { + if (pcidev->device != PCI_DEVICE_ID_ECTIVA_EV1938) + continue; + } else + continue; + if (!probe_chip(pcidev, index)) + index++; } if (!devs) return -ENODEV; diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index ec41d0b6a1d8..718c44aa6e1d 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -60,6 +60,7 @@ * OSS more closely; remove possible wakeup race * 07.10.99 0.9 Fix initialization; complain if sequencer writes time out * Revised resource grabbing for the FM synthesizer + * 28.10.99 0.10 More waitqueue races fixed * */ @@ -101,7 +102,7 @@ #define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1) -#define DDMABASE_OFFSET 0x10 /* chip bug workaround kludge */ +#define DDMABASE_OFFSET 0 /* chip bug workaround kludge */ #define DDMABASE_EXTENT 16 #define IOBASE_EXTENT 16 @@ -939,9 +940,9 @@ static int drain_dac(struct solo1_state *s, int nonblock) if (s->dma_dac.mapped) return 0; - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { + set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); @@ -974,6 +975,7 @@ static int drain_dac(struct solo1_state *s, int nonblock) static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct solo1_state *s = (struct solo1_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -989,12 +991,15 @@ static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; ret = 0; + add_wait_queue(&s->dma_adc.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); swptr = s->dma_adc.swptr; cnt = s->dma_adc.dmasize-swptr; if (s->dma_adc.count < cnt) cnt = s->dma_adc.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -1015,9 +1020,12 @@ static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t #endif if (inb(s->ddmabase+15) & 1) printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n"); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_adc.wait); + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); #ifdef DEBUGREC printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n" KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n" @@ -1027,12 +1035,18 @@ static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt); #endif - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_adc.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; @@ -1047,12 +1061,15 @@ static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc)); #endif } + remove_wait_queue(&s->dma_adc.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct solo1_state *s = (struct solo1_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -1076,6 +1093,7 @@ static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc)); #endif ret = 0; + add_wait_queue(&s->dma_dac.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac.count < 0) { @@ -1086,20 +1104,31 @@ static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, cnt = s->dma_dac.dmasize-swptr; if (s->dma_dac.count + cnt > s->dma_dac.dmasize) cnt = s->dma_dac.dmasize - s->dma_dac.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_dac.wait); - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + schedule(); + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_dac.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac.swptr = swptr; @@ -1111,6 +1140,8 @@ static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, ret += cnt; start_dac(s); } + remove_wait_queue(&s->dma_dac.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } @@ -1473,8 +1504,8 @@ static int solo1_release(struct inode *inode, struct file *file) dealloc_dmabuf(&s->dma_adc); } s->open_mode &= ~(FMODE_READ | FMODE_WRITE); - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -1482,6 +1513,7 @@ static int solo1_release(struct inode *inode, struct file *file) static int solo1_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = devs; while (s && ((s->dev_audio ^ minor) & ~0xf)) @@ -1497,8 +1529,12 @@ static int solo1_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -1630,6 +1666,8 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, lo cnt = MIDIINBUF - ptr; if (s->midi.icnt < cnt) cnt = s->midi.icnt; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -1639,7 +1677,6 @@ static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, lo ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -1692,8 +1729,10 @@ static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t co cnt = MIDIOUTBUF - ptr; if (s->midi.ocnt + cnt > MIDIOUTBUF) cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) + if (cnt <= 0) { + __set_current_state(TASK_INTERRUPTIBLE); solo1_handle_midi(s); + } spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -1703,7 +1742,6 @@ static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t co ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -1761,6 +1799,7 @@ static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct static int solo1_midi_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = devs; unsigned long flags; @@ -1777,8 +1816,12 @@ static int solo1_midi_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -1822,9 +1865,9 @@ static int solo1_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->midi.ocnt; spin_unlock_irqrestore(&s->lock, flags); @@ -1852,8 +1895,8 @@ static int solo1_midi_release(struct inode *inode, struct file *file) del_timer(&s->midi.timer); } spin_unlock_irqrestore(&s->lock, flags); - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -1978,6 +2021,7 @@ static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int static int solo1_dmfm_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = devs; while (s && s->dev_dmfm != minor) @@ -1993,8 +2037,12 @@ static int solo1_dmfm_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2033,8 +2081,8 @@ static int solo1_dmfm_release(struct inode *inode, struct file *file) outb(0, s->sbbase+3); } release_region(s->sbbase, FMSYNTH_EXTENT); - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -2094,7 +2142,7 @@ static int __init init_solo1(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.7 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "solo1: version v0.10 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) { if (!RSRCISIOREGION(pcidev, 0) || diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 8b8190cb1625..71c22f78df4c 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -81,6 +81,7 @@ * replaced current->state = x with set_current_state(x) * 03.09.99 0.21 change read semantics for MIDI to match * OSS more closely; remove possible wakeup race + * 28.10.99 0.22 More waitqueue races fixed * */ @@ -1267,9 +1268,9 @@ static int drain_dac(struct sv_state *s, int nonblock) if (s->dma_dac.mapped || !s->dma_dac.ready) return 0; - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->dma_dac.wait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->dma_dac.count; spin_unlock_irqrestore(&s->lock, flags); @@ -1299,6 +1300,7 @@ static int drain_dac(struct sv_state *s, int nonblock) static ssize_t sv_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct sv_state *s = (struct sv_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -1315,24 +1317,30 @@ static ssize_t sv_read(struct file *file, char *buffer, size_t count, loff_t *pp return -EFAULT; ret = 0; #if 0 - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - spin_unlock_irqrestore(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); + sv_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); #endif + add_wait_queue(&s->dma_adc.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); swptr = s->dma_adc.swptr; cnt = s->dma_adc.dmasize-swptr; if (s->dma_adc.count < cnt) cnt = s->dma_adc.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_adc(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (!schedule_timeout(HZ)) { printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, s->dma_adc.hwptr, s->dma_adc.swptr); @@ -1345,12 +1353,18 @@ static ssize_t sv_read(struct file *file, char *buffer, size_t count, loff_t *pp s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); } - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) - return ret ? ret : -EFAULT; + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_adc.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; @@ -1361,12 +1375,15 @@ static ssize_t sv_read(struct file *file, char *buffer, size_t count, loff_t *pp ret += cnt; start_adc(s); } + remove_wait_queue(&s->dma_adc.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } static ssize_t sv_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) { struct sv_state *s = (struct sv_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); ssize_t ret; unsigned long flags; unsigned swptr; @@ -1383,10 +1400,11 @@ static ssize_t sv_write(struct file *file, const char *buffer, size_t count, lof return -EFAULT; ret = 0; #if 0 - spin_lock_irqsave(&s->lock, flags); - sv_update_ptr(s); - spin_unlock_irqrestore(&s->lock, flags); + spin_lock_irqsave(&s->lock, flags); + sv_update_ptr(s); + spin_unlock_irqrestore(&s->lock, flags); #endif + add_wait_queue(&s->dma_dac.wait, &wait); while (count > 0) { spin_lock_irqsave(&s->lock, flags); if (s->dma_dac.count < 0) { @@ -1397,14 +1415,19 @@ static ssize_t sv_write(struct file *file, const char *buffer, size_t count, lof cnt = s->dma_dac.dmasize-swptr; if (s->dma_dac.count + cnt > s->dma_dac.dmasize) cnt = s->dma_dac.dmasize - s->dma_dac.count; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { start_dac(s); - if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; - if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (!schedule_timeout(HZ)) { printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, s->dma_dac.hwptr, s->dma_dac.swptr); @@ -1417,12 +1440,18 @@ static ssize_t sv_write(struct file *file, const char *buffer, size_t count, lof s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; spin_unlock_irqrestore(&s->lock, flags); } - if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } continue; } - if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } swptr = (swptr + cnt) % s->dma_dac.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac.swptr = swptr; @@ -1434,6 +1463,8 @@ static ssize_t sv_write(struct file *file, const char *buffer, size_t count, lof ret += cnt; start_dac(s); } + remove_wait_queue(&s->dma_dac.wait, &wait); + set_current_state(TASK_RUNNING); return ret; } @@ -1798,6 +1829,7 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un static int sv_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct sv_state *s = devs; unsigned char fmtm = ~0, fmts = 0; @@ -1814,8 +1846,12 @@ static int sv_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -1858,8 +1894,8 @@ static int sv_release(struct inode *inode, struct file *file) dealloc_dmabuf(&s->dma_adc); } s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -1908,6 +1944,8 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_ cnt = MIDIINBUF - ptr; if (s->midi.icnt < cnt) cnt = s->midi.icnt; + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -1917,7 +1955,6 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_ ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -1970,8 +2007,10 @@ static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count cnt = MIDIOUTBUF - ptr; if (s->midi.ocnt + cnt > MIDIOUTBUF) cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) + if (cnt <= 0) { + __set_current_state(TASK_INTERRUPTIBLE); sv_handle_midi(s); + } spin_unlock_irqrestore(&s->lock, flags); if (cnt > count) cnt = count; @@ -1981,7 +2020,6 @@ static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count ret = -EAGAIN; break; } - __set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { if (!ret) @@ -2039,6 +2077,7 @@ static unsigned int sv_midi_poll(struct file *file, struct poll_table_struct *wa static int sv_midi_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct sv_state *s = devs; unsigned long flags; @@ -2055,8 +2094,12 @@ static int sv_midi_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2103,9 +2146,9 @@ static int sv_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); if (file->f_mode & FMODE_WRITE) { - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&s->lock, flags); count = s->midi.ocnt; spin_unlock_irqrestore(&s->lock, flags); @@ -2133,8 +2176,8 @@ static int sv_midi_release(struct inode *inode, struct file *file) del_timer(&s->midi.timer); } spin_unlock_irqrestore(&s->lock, flags); - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -2259,6 +2302,7 @@ static int sv_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cm static int sv_dmfm_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + DECLARE_WAITQUEUE(wait, current); struct sv_state *s = devs; while (s && s->dev_dmfm != minor) @@ -2274,8 +2318,12 @@ static int sv_dmfm_open(struct inode *inode, struct file *file) up(&s->open_sem); return -EBUSY; } + add_wait_queue(&s->open_wait, &wait); + __set_current_state(TASK_INTERRUPTIBLE); up(&s->open_sem); - interruptible_sleep_on(&s->open_wait); + schedule(); + remove_wait_queue(&s->open_wait, &wait); + set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; down(&s->open_sem); @@ -2307,8 +2355,8 @@ static int sv_dmfm_release(struct inode *inode, struct file *file) outb(regb, s->iosynth+2); outb(0, s->iosynth+3); } - up(&s->open_sem); wake_up(&s->open_wait); + up(&s->open_sem); MOD_DEC_USE_COUNT; return 0; } @@ -2385,7 +2433,7 @@ static int __init init_sonicvibes(void) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.20 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.22 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 631dea62ef0b..97d05c93bf39 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -297,14 +297,6 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len return len; } -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_root_sound = { - PROC_SOUND, 5, "sound", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, NULL, sound_proc_get_info -}; -#endif - #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif @@ -756,7 +748,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) /* printk("Sound: mmap() called twice for the same DMA buffer\n");*/ return -EIO; } - if (vma->vm_offset != 0) + if (vma->vm_pgoff != 0) { /* printk("Sound: mmap() offset must be 0.\n");*/ return -EINVAL; @@ -855,7 +847,7 @@ soundcard_init(void) } #endif #ifdef CONFIG_PROC_FS - if (proc_register(&proc_root, &proc_root_sound)) + if (!create_proc_info_entry("sound", 0, NULL, sound_proc_get_info)) printk(KERN_ERR "sound: registering /proc/sound failed\n"); #endif } @@ -935,10 +927,7 @@ void cleanup_module(void) { return; } -#ifdef CONFIG_PROC_FS - if (proc_unregister(&proc_root, PROC_SOUND)) - printk(KERN_ERR "sound: unregistering /proc/sound failed\n"); -#endif + remove_proc_entry("sound", NULL); if (chrdev_registered) destroy_special_devices(); diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c index a47920d00989..3be238440084 100644 --- a/drivers/usb/acm.c +++ b/drivers/usb/acm.c @@ -73,6 +73,8 @@ #define CTRL_STAT_DTR 1 #define CTRL_STAT_RTS 2 +static struct usb_driver acm_driver; + static int acm_refcount; static struct tty_driver acm_tty_driver; @@ -83,6 +85,7 @@ static struct acm_state acm_state_table[NR_PORTS]; struct acm_state { struct usb_device *dev; //the coresponding usb device + int cfgnum; //configuration number on this device struct tty_struct *tty; //the coresponding tty char present; //a device for this struct was detected => this tty is used char active; //someone has this acm's device open @@ -194,7 +197,7 @@ static int acm_read_irq(int state, void *__buffer, int count, void *dev_id) info("ACM_READ_IRQ: state %d, %d bytes\n", state, count); if (state) { printk( "acm_read_irq: strange state received: %x\n", state ); - return 1; + return 0; } if (!ACM_READY) @@ -204,7 +207,7 @@ static int acm_read_irq(int state, void *__buffer, int count, void *dev_id) tty_insert_flip_char(tty,data[i],0); tty_flip_buffer_push(tty); - return 1; /* continue transfer */ + return 0; /* Never return 1 from this routine. It makes uhci do bad things. */ } static int acm_write_irq(int state, void *__buffer, int count, void *dev_id) @@ -382,7 +385,7 @@ static int get_free_acm(void) return -1; } -static int acm_probe(struct usb_device *dev) +static void * acm_probe(struct usb_device *dev, unsigned int ifnum) { struct acm_state *acm; struct usb_interface_descriptor *interface; @@ -394,7 +397,7 @@ static int acm_probe(struct usb_device *dev) if (0>(acmno=get_free_acm())) { info("Too many acm devices connected\n"); - return -1; + return NULL; } acm = &acm_state_table[acmno]; @@ -402,10 +405,14 @@ static int acm_probe(struct usb_device *dev) if (dev->descriptor.bDeviceClass != 2 || dev->descriptor.bDeviceSubClass != 0 || dev->descriptor.bDeviceProtocol != 0) - return -1; + return NULL; #define IFCLASS(if) ((if->bInterfaceClass << 24) | (if->bInterfaceSubClass << 16) | (if->bInterfaceProtocol << 8) | (if->bNumEndpoints)) + /* FIXME: should the driver really be doing the configuration + * selecting or should the usbcore? [different configurations + * can have different bandwidth requirements] -greg */ + /* Now scan all configs for a ACM configuration*/ for (cfgnum=0;cfgnumdescriptor.bNumConfigurations;cfgnum++) { /* The first one should be Communications interface? */ @@ -425,7 +432,14 @@ static int acm_probe(struct usb_device *dev) interface->bNumEndpoints != 2) continue; - /* if ((endpoint->bEndpointAddress & 0x80) == 0x80) */ + /* make sure both interfaces are available for our use */ + if (usb_interface_claimed(&dev->config[cfgnum].interface[0]) || + usb_interface_claimed(&dev->config[cfgnum].interface[1])) { + printk("usb-acm: required interface already has a driver\n"); + continue; + } + + endpoint = &interface->endpoint[0]; if ((endpoint->bEndpointAddress & 0x80) != 0x80) swapped = 1; @@ -445,7 +459,6 @@ static int acm_probe(struct usb_device *dev) usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue); acm->dev=dev; - dev->private=acm; acm->readendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0^swapped].bEndpointAddress; acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp); @@ -453,7 +466,7 @@ static int acm_probe(struct usb_device *dev) acm->reading=0; if (!acm->readbuffer) { printk("ACM: Couldn't allocate readbuffer\n"); - return -1; + return NULL; } acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1^swapped].bEndpointAddress; @@ -463,23 +476,29 @@ static int acm_probe(struct usb_device *dev) if (!acm->writebuffer) { printk("ACM: Couldn't allocate writebuffer\n"); kfree(acm->readbuffer); - return -1; + return NULL; } acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress; acm->ctrlpipe=usb_rcvctrlpipe(acm->dev,acm->ctrlendp); acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval; + acm->cfgnum = cfgnum; acm->present=1; MOD_INC_USE_COUNT; - return 0; + + usb_driver_claim_interface(&acm_driver, + &dev->config[cfgnum].interface[0], acm); + usb_driver_claim_interface(&acm_driver, + &dev->config[cfgnum].interface[1], acm); + return acm; } - return -1; + return NULL; } -static void acm_disconnect(struct usb_device *dev) +static void acm_disconnect(struct usb_device *dev, void *ptr) { - struct acm_state *acm = (struct acm_state *) dev->private; + struct acm_state *acm = ptr; info("acm_disconnect\n"); @@ -501,6 +520,12 @@ static void acm_disconnect(struct usb_device *dev) kfree(acm->writebuffer); kfree(acm->readbuffer); + /* release the interfaces so that other drivers can have at them */ + usb_driver_release_interface(&acm_driver, + &dev->config[acm->cfgnum].interface[0]); + usb_driver_release_interface(&acm_driver, + &dev->config[acm->cfgnum].interface[1]); + MOD_DEC_USE_COUNT; } @@ -584,7 +609,7 @@ void usb_acm_cleanup(void) acm=&acm_state_table[i]; if (acm->present) { printk("disconnecting %d\n",i); - acm_disconnect(acm->dev); + acm_disconnect(acm->dev, acm); } } tty_unregister_driver(&acm_tty_driver); diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c index 291f424dcbaf..7b85d3359cfd 100644 --- a/drivers/usb/audio.c +++ b/drivers/usb/audio.c @@ -542,11 +542,24 @@ static void usbin_stop(struct usb_audiodev *as) i = u->flags; spin_unlock_irqrestore(&as->lock, flags); while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); + if (signal_pending(current)) { + if (i & FLG_ID0RUNNING) + usb_kill_isoc(u->dataiso[0]); + if (i & FLG_ID1RUNNING) + usb_kill_isoc(u->dataiso[1]); + if (i & FLG_SYNC0RUNNING) + usb_kill_isoc(u->synciso[0]); + if (i & FLG_SYNC1RUNNING) + usb_kill_isoc(u->synciso[1]); + break; + } spin_lock_irqsave(&as->lock, flags); i = u->flags; spin_unlock_irqrestore(&as->lock, flags); } + set_current_state(TASK_RUNNING); if (u->dataiso[0]) usb_free_isoc(u->dataiso[0]); if (u->dataiso[1]) @@ -801,6 +814,7 @@ static int usbin_completed(int status, void *__buffer, int rval, void *dev_id) printk(KERN_DEBUG "usbin_completed: killing id\n"); usb_kill_isoc(id); printk(KERN_DEBUG "usbin_completed: id killed\n"); + wake_up(&u->dma.wait); } spin_unlock_irqrestore(&as->lock, flags); return 0; @@ -873,6 +887,7 @@ static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_ printk(KERN_DEBUG "usbin_sync_completed: killing id\n"); usb_kill_isoc(id); printk(KERN_DEBUG "usbin_sync_completed: id killed\n"); + wake_up(&u->dma.wait); } spin_unlock_irqrestore(&as->lock, flags); return 0; @@ -1005,12 +1020,25 @@ printk(KERN_DEBUG "usb_audio: usbout_stop (1) flags 0x%04x\n", u->flags); spin_unlock_irqrestore(&as->lock, flags); printk(KERN_DEBUG "usb_audio: usbout_stop (2) flags 0x%04x\n", i); while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); + if (signal_pending(current)) { + if (i & FLG_ID0RUNNING) + usb_kill_isoc(u->dataiso[0]); + if (i & FLG_ID1RUNNING) + usb_kill_isoc(u->dataiso[1]); + if (i & FLG_SYNC0RUNNING) + usb_kill_isoc(u->synciso[0]); + if (i & FLG_SYNC1RUNNING) + usb_kill_isoc(u->synciso[1]); + break; + } spin_lock_irqsave(&as->lock, flags); i = u->flags; spin_unlock_irqrestore(&as->lock, flags); printk(KERN_DEBUG "usb_audio: usbout_stop (3) flags 0x%04x\n", i); } + set_current_state(TASK_RUNNING); if (u->dataiso[0]) usb_free_isoc(u->dataiso[0]); if (u->dataiso[1]) @@ -1272,6 +1300,7 @@ static int usbout_completed(int status, void *__buffer, int rval, void *dev_id) printk(KERN_DEBUG "usbout_completed: killing id\n"); usb_kill_isoc(id); printk(KERN_DEBUG "usbout_completed: id killed\n"); + wake_up(&u->dma.wait); } spin_unlock_irqrestore(&as->lock, flags); return 0; @@ -1347,6 +1376,7 @@ static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev printk(KERN_DEBUG "usbout_sync_completed: killing id\n"); usb_kill_isoc(id); printk(KERN_DEBUG "usbout_sync_completed: id killed\n"); + wake_up(&u->dma.wait); } spin_unlock_irqrestore(&as->lock, flags); return 0; @@ -1952,10 +1982,10 @@ static int drain_out(struct usb_audiodev *as, int nonblock) if (as->usbout.dma.mapped || !as->usbout.dma.ready) return 0; - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&as->usbout.dma.wait, &wait); for (;;) { - spin_lock_irqsave(&as->lock, flags); + __set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&as->lock, flags); count = as->usbout.dma.count; spin_unlock_irqrestore(&as->lock, flags); if (count <= 0) @@ -1969,8 +1999,10 @@ static int drain_out(struct usb_audiodev *as, int nonblock) } tmo = 3 * HZ * count / as->usbout.dma.srate; tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format); - if (!schedule_timeout(tmo + 1)) + if (!schedule_timeout(tmo + 1)) { printk(KERN_DEBUG "usbaudio: dma timed out??\n"); + break; + } } remove_wait_queue(&as->usbout.dma.wait, &wait); set_current_state(TASK_RUNNING); @@ -1998,12 +2030,14 @@ static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, lof return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&as->usbin.dma.wait, &wait); while (count > 0) { spin_lock_irqsave(&as->lock, flags); ptr = as->usbin.dma.rdptr; cnt = as->usbin.dma.count; + /* set task state early to avoid wakeup races */ + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&as->lock, flags); if (cnt > count) cnt = count; @@ -2060,9 +2094,13 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; - __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&as->usbout.dma.wait, &wait); while (count > 0) { +#if 0 + printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%x\n", + count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize, + as->usbout.flags, current->state); +#endif spin_lock_irqsave(&as->lock, flags); if (as->usbout.dma.count < 0) { as->usbout.dma.count = 0; @@ -2070,6 +2108,9 @@ static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t cou } ptr = as->usbout.dma.wrptr; cnt = as->usbout.dma.dmasize - as->usbout.dma.count; + /* set task state early to avoid wakeup races */ + if (cnt <= 0) + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(&as->lock, flags); if (cnt > count) cnt = count; @@ -2532,14 +2573,16 @@ static /*const*/ struct file_operations usb_audio_fops = { * zero bandwidth (idle) config and one or more live one pers interface. */ -static int usb_audio_probe(struct usb_device *dev); -static void usb_audio_disconnect(struct usb_device *dev); +static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum); +static void usb_audio_disconnect(struct usb_device *dev, void *ptr); static struct usb_driver usb_audio_driver = { "audio", usb_audio_probe, usb_audio_disconnect, - { NULL, NULL } + /*{ NULL, NULL }, */ LIST_HEAD_INIT(usb_audio_driver.driver_list), + NULL, + 0 }; @@ -3298,7 +3341,7 @@ static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *b list_add_tail(&ms->list, &s->mixerlist); } -static int usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif) +static void * usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif) { struct usb_audio_state *s; struct usb_config_descriptor *config = dev->actconfig; @@ -3308,7 +3351,7 @@ static int usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int i, j, numifin = 0, numifout = 0; if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL))) - return -1; + return NULL; memset(s, 0, sizeof(struct usb_audio_state)); INIT_LIST_HEAD(&s->audiolist); INIT_LIST_HEAD(&s->mixerlist); @@ -3365,11 +3408,15 @@ static int usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, /* note: this requires the data endpoint to be ep0 and the optional sync ep to be ep1, which seems to be the case */ if (iface->altsetting[1].endpoint[0].bEndpointAddress & USB_DIR_IN) { - if (numifin < USB_MAXINTERFACES) + if (numifin < USB_MAXINTERFACES) { ifin[numifin++] = j; + usb_driver_claim_interface(&usb_audio_driver, iface, s); + } } else { - if (numifout < USB_MAXINTERFACES) + if (numifout < USB_MAXINTERFACES) { ifout[numifout++] = j; + usb_driver_claim_interface(&usb_audio_driver, iface, s); + } } } printk(KERN_INFO "usb_audio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n", @@ -3391,20 +3438,19 @@ static int usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, ret: if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) { kfree(s); - return -1; + return NULL; } /* everything successful */ - dev->private = s; down(&open_sem); list_add_tail(&s->audiodev, &audiodevs); up(&open_sem); MOD_INC_USE_COUNT; - return 0; + return s; } /* we only care for the currently active configuration */ -static int usb_audio_probe(struct usb_device *dev) +static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_config_descriptor *config = dev->actconfig; unsigned char *buffer; @@ -3418,7 +3464,7 @@ static int usb_audio_probe(struct usb_device *dev) goto audioctrlfound; printk(KERN_DEBUG "usb_audio: vendor id 0x%04x, product id 0x%04x contains no AudioControl interface\n", dev->descriptor.idVendor, dev->descriptor.idProduct); - return -1; + return NULL; audioctrlfound: /* find which configuration number is active */ @@ -3426,30 +3472,26 @@ static int usb_audio_probe(struct usb_device *dev) if (dev->config+i == config) goto configfound; printk(KERN_ERR "usb_audio: cannot find active configuration number of device %d\n", dev->devnum); - return -1; + return NULL; configfound: - if (usb_set_configuration(dev, config->bConfigurationValue) < 0) { - printk(KERN_ERR "usb_audio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue); - return -1; - } ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8); if (ret) { printk(KERN_ERR "usb_audio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum); - return -1; + return NULL; } if (buf[1] != USB_DT_CONFIG || buf[0] < 9) { printk(KERN_ERR "usb_audio: invalid config descriptor %d of device %d\n", i, dev->devnum); - return -1; + return NULL; } buflen = buf[2] | (buf[3] << 8); if (!(buffer = kmalloc(buflen, GFP_KERNEL))) - return -1; + return NULL; ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen); if (ret) { kfree(buffer); printk(KERN_ERR "usb_audio: cannot get config descriptor %d of device %d\n", i, dev->devnum); - return -1; + return NULL; } /* find first audio control interface; we currently cannot handle more than one */ for (i = 0; i < config->bNumInterfaces; i++) { @@ -3457,18 +3499,17 @@ static int usb_audio_probe(struct usb_device *dev) config->interface[i].altsetting[0].bInterfaceSubClass != 1) continue; /* audiocontrol interface found */ - if (!usb_audio_parsecontrol(dev, buffer, buflen, i)) - return 0; + return usb_audio_parsecontrol(dev, buffer, buflen, i); } - return -1; + return NULL; } /* a revoke facility would make things simpler */ -static void usb_audio_disconnect(struct usb_device *dev) +static void usb_audio_disconnect(struct usb_device *dev, void *ptr) { - struct usb_audio_state *s = (struct usb_audio_state *)dev->private; + struct usb_audio_state *s = (struct usb_audio_state *)ptr; struct list_head *list; struct usb_audiodev *as; struct usb_mixerdev *ms; @@ -3496,7 +3537,6 @@ static void usb_audio_disconnect(struct usb_device *dev) #endif release(s); wake_up(&open_wait); - dev->private = NULL; } int usb_audio_init(void) diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c index e6515c710a1d..a7536d6fe1ea 100644 --- a/drivers/usb/cpia.c +++ b/drivers/usb/cpia.c @@ -37,6 +37,8 @@ #define MDEBUG(x) do { } while(0) /* Debug memory management */ +static struct usb_driver cpia_driver; + /* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */ @@ -1195,12 +1197,11 @@ static int usb_cpia_configure(struct usb_cpia *cpia) struct usb_device *dev = cpia->dev; unsigned char version[4]; - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) < 0) { - printk(KERN_INFO "cpia: usb_set_configuration failed\n"); - return -EBUSY; - } + /* claim interface 1 */ + usb_driver_claim_interface(&cpia_driver, + &dev->actconfig->interface[1], cpia); - /* Set packet size to 0 */ + /* Set altsetting 0 on interface 1 */ if (usb_set_interface(dev, 1, 0) < 0) { printk(KERN_INFO "usb_set_interface error\n"); return -EBUSY; @@ -1267,57 +1268,63 @@ static int usb_cpia_configure(struct usb_cpia *cpia) error: video_unregister_device(&cpia->vdev); + usb_driver_release_interface(&cpia_driver, + &dev->actconfig->interface[1]); kfree(cpia); return -EBUSY; } -static int cpia_probe(struct usb_device *dev) +static void * cpia_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_interface_descriptor *interface; struct usb_cpia *cpia; /* We don't handle multi-config cameras */ if (dev->descriptor.bNumConfigurations != 1) - return -1; + return NULL; - interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[ifnum].altsetting[0]; /* Is it a CPiA? */ if (dev->descriptor.idVendor != 0x0553) - return -1; + return NULL; if (dev->descriptor.idProduct != 0x0002) - return -1; + return NULL; /* Checking vendor/product should be enough, but what the hell */ if (interface->bInterfaceClass != 0xFF) - return -1; + return NULL; if (interface->bInterfaceSubClass != 0x00) - return -1; + return NULL; /* We found a CPiA */ printk("USB CPiA camera found\n"); if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) { printk("couldn't kmalloc cpia struct\n"); - return -1; + return NULL; } memset(cpia, 0, sizeof(*cpia)); - dev->private = cpia; cpia->dev = dev; - return usb_cpia_configure(cpia); + if (!usb_cpia_configure(cpia)) { + return cpia; + } else return NULL; } -static void cpia_disconnect(struct usb_device *dev) +static void cpia_disconnect(struct usb_device *dev, void *ptr) { - struct usb_cpia *cpia = dev->private; + struct usb_cpia *cpia = (struct usb_cpia *) ptr; video_unregister_device(&cpia->vdev); + usb_driver_release_interface(&cpia_driver, + &cpia->dev->actconfig->interface[1]); + /* Free the memory */ kfree(cpia); } diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c index c6433569952d..ed78254ada2a 100644 --- a/drivers/usb/ezusb.c +++ b/drivers/usb/ezusb.c @@ -968,7 +968,7 @@ static struct file_operations ezusb_fops = { /* --------------------------------------------------------------------- */ -static int ezusb_probe(struct usb_device *usbdev) +static void * ezusb_probe(struct usb_device *usbdev, unsigned int ifnum) { struct ezusb *ez = &ezusb[0]; struct usb_interface_descriptor *interface; @@ -982,56 +982,49 @@ static int ezusb_probe(struct usb_device *usbdev) /* the 1234:5678 is just a self assigned test ID */ if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131) && (usbdev->descriptor.idVendor != 0x1234 || usbdev->descriptor.idProduct != 0x5678)) - return -1; + return NULL; /* We don't handle multiple configurations */ if (usbdev->descriptor.bNumConfigurations != 1) - return -1; + return NULL; #if 0 /* We don't handle multiple interfaces */ - if (usbdev->config[0].bNumInterfaces != 1) - return -1; + if (usbdev->actconfig.bNumInterfaces != 1) + return NULL; #endif down(&ez->mutex); if (ez->usbdev) { up(&ez->mutex); printk(KERN_INFO "ezusb: device already used\n"); - return -1; + return NULL; } ez->usbdev = usbdev; - usbdev->private = ez; - if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue) < 0) { - printk(KERN_ERR "ezusb: set_configuration failed\n"); - goto err; - } - interface = &usbdev->config[0].interface[0].altsetting[1]; - if (usb_set_interface(usbdev, 0, 1) < 0) { + interface = &usbdev->actconfig->interface[ifnum].altsetting[1]; + if (usb_set_interface(usbdev, ifnum, 1) < 0) { printk(KERN_ERR "ezusb: set_interface failed\n"); goto err; } up(&ez->mutex); MOD_INC_USE_COUNT; - return 0; + return ez; err: up(&ez->mutex); ez->usbdev = NULL; - usbdev->private = NULL; - return -1; + return NULL; } -static void ezusb_disconnect(struct usb_device *usbdev) +static void ezusb_disconnect(struct usb_device *usbdev, void *ptr) { - struct ezusb *ez = (struct ezusb *)usbdev->private; + struct ezusb *ez = (struct ezusb *) ptr; down(&ez->mutex); destroy_all_async(ez); ez->usbdev = NULL; up(&ez->mutex); wake_up(&ez->wait); - usbdev->private = NULL; MOD_DEC_USE_COUNT; } diff --git a/drivers/usb/hp_scanner.c b/drivers/usb/hp_scanner.c index 1da9f605a38b..ae503ae3877a 100644 --- a/drivers/usb/hp_scanner.c +++ b/drivers/usb/hp_scanner.c @@ -217,8 +217,8 @@ read_scanner(struct file * file, char * buffer, return read_count; } -static int -probe_scanner(struct usb_device *dev) +static void * +probe_scanner(struct usb_device *dev, unsigned int ifnum) { struct hpscan_usb_data *hps = &hpscan; @@ -228,41 +228,36 @@ probe_scanner(struct usb_device *dev) * soon. */ if (dev->descriptor.idVendor != 0x3f0 ) { printk(KERN_INFO "Scanner is not an HP Scanner.\n"); - return -1; + return NULL; } if (dev->descriptor.idProduct != 0x101 && /* HP 4100C */ dev->descriptor.idProduct != 0x202 && /* HP 5100C */ dev->descriptor.idProduct != 0x601) { /* HP 6300C */ printk(KERN_INFO "Scanner model not supported/tested.\n"); - return -1; + return NULL; } printk(KERN_DEBUG "USB Scanner found at address %d\n", dev->devnum); - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk(KERN_DEBUG "Failed to set configuration\n"); - return -1; - } - hps->present = 1; hps->hpscan_dev = dev; if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) { - return -ENOMEM; + return NULL; } if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) { - return -ENOMEM; + return NULL; } - return 0; + return hps; } static void -disconnect_scanner(struct usb_device *dev) +disconnect_scanner(struct usb_device *dev, void *ptr) { - struct hpscan_usb_data *hps = &hpscan; + struct hpscan_usb_data *hps = (struct hpscan_usb_data *) ptr; if (hps->isopen) { /* better let it finish - the release will do whats needed */ @@ -272,7 +267,6 @@ disconnect_scanner(struct usb_device *dev) kfree(hps->ibuf); kfree(hps->obuf); - dev->private = NULL; /* just in case */ hps->present = 0; } diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c index 98c1c540ce6f..6f6aa86fd772 100644 --- a/drivers/usb/hub.c +++ b/drivers/usb/hub.c @@ -22,7 +22,6 @@ /* Wakes up khubd */ static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t hub_list_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ static LIST_HEAD(hub_list); /* List containing all of the hubs (for cleanup) */ @@ -105,9 +104,6 @@ static int usb_hub_configure(struct usb_hub *hub) struct usb_hub_status *hubsts; int i; - /* Set it to the first configuration */ - usb_set_configuration(dev, dev->config[0].bConfigurationValue); - /* Get the length first */ if (usb_get_hub_descriptor(dev, buffer, 4)) return -1; @@ -188,7 +184,7 @@ static int usb_hub_configure(struct usb_hub *hub) return 0; } -static int hub_probe(struct usb_device *dev) +static void * hub_probe(struct usb_device *dev, unsigned int i) { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; @@ -196,60 +192,50 @@ static int hub_probe(struct usb_device *dev) unsigned long flags; int ret; - /* We don't handle multi-config hubs */ - if (dev->descriptor.bNumConfigurations != 1) - return -1; - - /* We don't handle multi-interface hubs */ - if (dev->config[0].bNumInterfaces != 1) - return -1; - - interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[i].altsetting[0]; /* Is it a hub? */ if (interface->bInterfaceClass != USB_CLASS_HUB) - return -1; + return NULL; /* Some hubs have a subclass of 1, which AFAICT according to the */ /* specs is not defined, but it works */ if ((interface->bInterfaceSubClass != 0) && (interface->bInterfaceSubClass != 1)) - return -1; + return NULL; /* Multiple endpoints? What kind of mutant ninja-hub is this? */ if (interface->bNumEndpoints != 1) - return -1; + return NULL; endpoint = &interface->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(endpoint->bEndpointAddress & USB_DIR_IN)) - return -1; + return NULL; /* If it's not an interrupt endpoint, we'd better punt! */ if ((endpoint->bmAttributes & 3) != 3) - return -1; + return NULL; /* We found a hub */ printk(KERN_INFO "USB hub found\n"); if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) { printk(KERN_ERR "couldn't kmalloc hub struct\n"); - return -1; + return NULL; } memset(hub, 0, sizeof(*hub)); - dev->private = hub; - INIT_LIST_HEAD(&hub->event_list); hub->dev = dev; /* Record the new hub's existence */ - spin_lock_irqsave(&hub_list_lock, flags); + spin_lock_irqsave(&hub_event_lock, flags); INIT_LIST_HEAD(&hub->hub_list); list_add(&hub->hub_list, &hub_list); - spin_unlock_irqrestore(&hub_list_lock, flags); + spin_unlock_irqrestore(&hub_event_lock, flags); if (usb_hub_configure(hub) >= 0) { hub->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress); @@ -258,20 +244,32 @@ static int hub_probe(struct usb_device *dev) hub, &hub->irq_handle); if (ret) { printk (KERN_WARNING "usb-hub: usb_request_irq failed (0x%x)\n", ret); - /* FIXME: need to free but first clean up its list. */ - return -1; + /* free hub, but first clean up its list. */ + spin_lock_irqsave(&hub_event_lock, flags); + + /* Delete it and then reset it */ + list_del(&hub->event_list); + INIT_LIST_HEAD(&hub->event_list); + list_del(&hub->hub_list); + INIT_LIST_HEAD(&hub->hub_list); + + spin_unlock_irqrestore(&hub_event_lock, flags); + + kfree(hub); + + return NULL; } /* Wake up khubd */ wake_up(&khubd_wait); } - return 0; + return hub; } -static void hub_disconnect(struct usb_device *dev) +static void hub_disconnect(struct usb_device *dev, void *ptr) { - struct usb_hub *hub = dev->private; + struct usb_hub *hub = ptr; unsigned long flags; spin_lock_irqsave(&hub_event_lock, flags); diff --git a/drivers/usb/inits.h b/drivers/usb/inits.h index b3b45f59aa55..e47b062e0433 100644 --- a/drivers/usb/inits.h +++ b/drivers/usb/inits.h @@ -4,6 +4,7 @@ int usb_hub_init(void); void usb_hub_cleanup(void); int usb_kbd_init(void); void usb_major_init(void); +void usb_major_cleanup(void); void usb_mouse_cleanup(void); int usb_hp_scanner_init(void); void usb_hp_scanner_cleanup(void); diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c index f35f1b091b10..96e9cfa6cf7d 100644 --- a/drivers/usb/keyboard.c +++ b/drivers/usb/keyboard.c @@ -45,8 +45,8 @@ struct usb_keyboard extern unsigned char usb_kbd_map[]; -static int usb_kbd_probe(struct usb_device *dev); -static void usb_kbd_disconnect(struct usb_device *dev); +static void * usb_kbd_probe(struct usb_device *dev, unsigned int i); +static void usb_kbd_disconnect(struct usb_device *dev, void *ptr); static void usb_kbd_repeat(unsigned long dummy); static LIST_HEAD(usb_kbd_list); @@ -190,25 +190,22 @@ usb_kbd_irq(int state, void *buffer, int len, void *dev_id) return 1; } -static int -usb_kbd_probe(struct usb_device *dev) +static void * +usb_kbd_probe(struct usb_device *dev, unsigned int i) { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct usb_keyboard *kbd; int ret; - if (dev->descriptor.bNumConfigurations < 1) - return -1; - - interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[i].altsetting[0]; endpoint = &interface->endpoint[0]; if(interface->bInterfaceClass != 3 || interface->bInterfaceSubClass != 1 || interface->bInterfaceProtocol != 1) { - return -1; + return NULL; } printk(KERN_INFO "USB HID boot protocol keyboard detected.\n"); @@ -218,12 +215,7 @@ usb_kbd_probe(struct usb_device *dev) { memset(kbd, 0, sizeof(*kbd)); kbd->dev = dev; - dev->private = kbd; - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk (KERN_INFO " Failed usb_set_configuration: kbd\n"); - goto probe_err; - } usb_set_protocol(dev, 0); usb_set_idle(dev, 0, 0); @@ -238,23 +230,22 @@ usb_kbd_probe(struct usb_device *dev) list_add(&kbd->list, &usb_kbd_list); - return 0; + return kbd; } probe_err: if (kbd) kfree (kbd); - return -1; + return NULL; } static void -usb_kbd_disconnect(struct usb_device *dev) +usb_kbd_disconnect(struct usb_device *dev, void *ptr) { - struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private; + struct usb_keyboard *kbd = (struct usb_keyboard*) ptr; if (kbd) { usb_release_irq(dev, kbd->irq_handler, kbd->irqpipe); - dev->private = NULL; list_del(&kbd->list); del_timer(&kbd->repeat_timer); kfree(kbd); diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c index 7d1c80aeb9c7..1254864f09bb 100644 --- a/drivers/usb/mouse.c +++ b/drivers/usb/mouse.c @@ -316,51 +316,38 @@ struct file_operations usb_mouse_fops = { fasync_mouse, }; -static int mouse_probe(struct usb_device *dev) +static void* mouse_probe(struct usb_device *dev, unsigned int i) { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct mouse_state *mouse = &static_mouse_state; int ret; - /* We don't handle multi-config mice */ - if (dev->descriptor.bNumConfigurations != 1) - return -1; - - /* We don't handle multi-interface mice */ - if (dev->config[0].bNumInterfaces != 1) - return -1; - /* Is it a mouse interface? */ - interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[i].altsetting[0]; if (interface->bInterfaceClass != 3) - return -1; + return NULL; if (interface->bInterfaceSubClass != 1) - return -1; + return NULL; if (interface->bInterfaceProtocol != 2) - return -1; + return NULL; /* Multiple endpoints? What kind of mutant ninja-mouse is this? */ if (interface->bNumEndpoints != 1) - return -1; + return NULL; endpoint = &interface->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(endpoint->bEndpointAddress & 0x80)) - return -1; + return NULL; /* If it's not an interrupt endpoint, we'd better punt! */ if ((endpoint->bmAttributes & 3) != 3) - return -1; + return NULL; printk("USB mouse found\n"); - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk (KERN_INFO " Failed usb_set_configuration: mouse\n"); - return -1; - } - /* these are used to request the irq when the mouse is opened */ mouse->dev = dev; mouse->bEndpointAddress = endpoint->bEndpointAddress; @@ -379,17 +366,17 @@ static int mouse_probe(struct usb_device *dev) NULL, &mouse->irq_handle); if (ret) { printk (KERN_WARNING "usb-mouse: usb_request_irq failed (0x%x)\n", ret); - return ret; + return NULL; } mouse->suspended = 0; } - return 0; + return mouse; } -static void mouse_disconnect(struct usb_device *dev) +static void mouse_disconnect(struct usb_device *dev, void *ptr) { - struct mouse_state *mouse = &static_mouse_state; + struct mouse_state *mouse = ptr; /* stop the usb interrupt transfer */ if (mouse->present) { @@ -402,7 +389,7 @@ static void mouse_disconnect(struct usb_device *dev) /* this might need work */ mouse->present = 0; - printk("Mouse disconnected\n"); + printk("USB Mouse disconnected\n"); } static struct usb_driver mouse_driver = { diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c index 3345e12be34c..3a3104f3fdd7 100644 --- a/drivers/usb/ohci-hcd.c +++ b/drivers/usb/ohci-hcd.c @@ -1540,8 +1540,8 @@ void cleanup_module(void) # endif while(!list_empty(&ohci_hcd_list)) { ohci = list_entry(ohci_hcd_list.next, struct ohci, ohci_hcd_list); - list_del(ohci->ohci_hcd_list); - INIT_LIST_HEAD(ohci->ohci_hcd_list); + list_del(&ohci->ohci_hcd_list); + INIT_LIST_HEAD(&ohci->ohci_hcd_list); release_ohci(ohci); } } diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 8bc2cfc1c90c..8a66930616b3 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -254,9 +254,10 @@ static ssize_t read_printer(struct file * file, return read_count; } -static int printer_probe(struct usb_device *dev) +static void * printer_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_interface_descriptor *interface; + struct pp_usb_data *pp; int i; /* @@ -265,29 +266,29 @@ static int printer_probe(struct usb_device *dev) if ((dev->descriptor.bDeviceClass != USB_CLASS_PRINTER && dev->descriptor.bDeviceClass != 0) || dev->descriptor.bNumConfigurations != 1 || - dev->config[0].bNumInterfaces != 1) { - return -1; + dev->actconfig->bNumInterfaces != 1) { + return NULL; } - interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[ifnum].altsetting[0]; /* Let's be paranoid (for the moment). */ if (interface->bInterfaceClass != USB_CLASS_PRINTER || interface->bInterfaceSubClass != 1 || (interface->bInterfaceProtocol != 2 && interface->bInterfaceProtocol != 1) || interface->bNumEndpoints > 2) { - return -1; + return NULL; } /* Does this (these) interface(s) support bulk transfers? */ if ((interface->endpoint[0].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { - return -1; + return NULL; } if ((interface->bNumEndpoints > 1) && ((interface->endpoint[1].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)) { - return -1; + return NULL; } /* @@ -299,7 +300,7 @@ static int printer_probe(struct usb_device *dev) (interface->bNumEndpoints > 1 && (interface->endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT)) { - return -1; + return NULL; } for (i=0; i= MAX_PRINTERS) { printk("No minor table space available for USB Printer\n"); - return -1; + return NULL; } printk(KERN_INFO "USB Printer found at address %d\n", dev->devnum); - if (!(dev->private = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) { + if (!(pp = kmalloc(sizeof(struct pp_usb_data), GFP_KERNEL))) { printk(KERN_DEBUG "usb_printer: no memory!\n"); - return -1; + return NULL; } - memset(dev->private, 0, sizeof(struct pp_usb_data)); - minor_data[i] = PPDATA(dev->private); + memset(pp, 0, sizeof(struct pp_usb_data)); + minor_data[i] = PPDATA(pp); minor_data[i]->minor = i; minor_data[i]->pusb_dev = dev; minor_data[i]->maxout = (BIG_BUF_SIZE > PAGE_SIZE) ? PAGE_SIZE : BIG_BUF_SIZE; @@ -342,11 +343,6 @@ static int printer_probe(struct usb_device *dev) interface->endpoint[minor_data[i]->bulk_in_index].wMaxPacketSize; } - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk(KERN_INFO " Failed usb_set_configuration: printer\n"); - return -1; - } - printk(KERN_INFO "USB Printer Summary:\n"); printk(KERN_INFO "index=%d, maxout=%d, noinput=%d\n", i, minor_data[i]->maxout, minor_data[i]->noinput); @@ -374,19 +370,19 @@ static int printer_probe(struct usb_device *dev) printk(KERN_INFO " USB Printer ID is %s\n", &ieee_id[2]); } - status = printer_read_status(PPDATA(dev->private)); + status = printer_read_status(PPDATA(pp)); printk(KERN_INFO " Status is %s,%s,%s\n", (status & LP_PSELECD) ? "Selected" : "Not Selected", (status & LP_POUTPA) ? "No Paper" : "Paper", (status & LP_PERRORP) ? "No Error" : "Error"); } #endif - return 0; + return pp; } -static void printer_disconnect(struct usb_device *dev) +static void printer_disconnect(struct usb_device *dev, void *ptr) { - struct pp_usb_data *pp = dev->private; + struct pp_usb_data *pp = ptr; if (pp->isopen) { /* better let it finish - the release will do whats needed */ @@ -395,7 +391,6 @@ static void printer_disconnect(struct usb_device *dev) } minor_data[pp->minor] = NULL; kfree(pp); - dev->private = NULL; /* just in case */ } static struct file_operations usb_printer_fops = { diff --git a/drivers/usb/proc_usb.c b/drivers/usb/proc_usb.c index 53c5e87e0dff..332e9c0efd1d 100644 --- a/drivers/usb/proc_usb.c +++ b/drivers/usb/proc_usb.c @@ -62,8 +62,8 @@ static char *format_topo = -/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s */ - "T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s If#=%3d MxCh=%2d Driver=%s\n"; +/* T: Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */ + "T: Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n"; static char *format_bandwidth = /* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */ @@ -83,7 +83,7 @@ static char *format_config = static char *format_iface = /* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx */ - "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n"; + "I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; static char *format_endpt = /* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */ @@ -161,9 +161,12 @@ static int usb_dump_endpoint (const struct usb_endpoint_descriptor *endpoint, return 0; } -static int usb_dump_interface_descriptor (const struct usb_interface_descriptor *desc, - char *buf, int *len) +static int usb_dump_interface_descriptor (const struct usb_interface *iface, + int setno, char *buf, int *len) { + struct usb_interface_descriptor *desc = + &iface->altsetting[setno]; + *len += sprintf (buf + *len, format_iface, desc->bInterfaceNumber, desc->bAlternateSetting, @@ -171,22 +174,25 @@ static int usb_dump_interface_descriptor (const struct usb_interface_descriptor desc->bInterfaceClass, class_decode (desc->bInterfaceClass), desc->bInterfaceSubClass, - desc->bInterfaceProtocol + desc->bInterfaceProtocol, + iface->driver ? iface->driver->name : "(none)" ); return (*len >= DUMP_LIMIT) ? -1 : 0; } -static int usb_dump_interface (const struct usb_interface_descriptor *interface, - char *buf, int *len) +static int usb_dump_interface (const struct usb_interface *iface, + int setno, char *buf, int *len) { int i; + struct usb_interface_descriptor *desc = + &iface->altsetting[setno]; - if (usb_dump_interface_descriptor (interface, buf, len) < 0) + if (usb_dump_interface_descriptor (iface, setno, buf, len) < 0) return -1; - for (i = 0; i < interface->bNumEndpoints; i++) { - if (usb_dump_endpoint (interface->endpoint + i, buf, len) < 0) + for (i = 0; i < desc->bNumEndpoints; i++) { + if (usb_dump_endpoint (desc->endpoint + i, buf, len) < 0) return -1; } @@ -234,7 +240,7 @@ static int usb_dump_config (const struct usb_config_descriptor *config, break; for (j = 0; j < interface->num_altsetting; j++) - if (usb_dump_interface (interface->altsetting + j, buf, len) < 0) + if (usb_dump_interface (interface, j, buf, len) < 0) return -1; } @@ -349,9 +355,7 @@ static int usb_device_dump (char *buf, int *len, level, parent_devnum, index, count, usbdev->devnum, usbdev->slow ? "1.5" : "12 ", - usbdev->ifnum, usbdev->maxchild, - usbdev->driver ? usbdev->driver->name : - (level == 0) ? "(root hub)" : "(none)" + usbdev->maxchild ); /* * level = topology-tier level; @@ -1036,21 +1040,21 @@ int proc_usb_init (void) return -1; } - driversdir = create_proc_entry ("drivers", 0, usbdir); + driversdir = create_proc_read_entry("drivers", 0, usbdir, + usb_driver_list_dump, NULL); if (!driversdir) { printk ("proc_usb: cannot create /proc/bus/usb/drivers entry\n"); proc_usb_cleanup (); return -1; } - driversdir->read_proc = usb_driver_list_dump; - devicesdir = create_proc_entry ("devices", 0, usbdir); + devicesdir = create_proc_read_entry ("devices", 0, usbdir, + usb_bus_list_dump_devices, NULL); if (!devicesdir) { printk ("proc_usb: cannot create /proc/bus/usb/devices entry\n"); proc_usb_cleanup (); return -1; } - devicesdir->read_proc = usb_bus_list_dump_devices; return 0; } diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c index ebddb35a3ccf..8051b8d314fe 100644 --- a/drivers/usb/usb-core.c +++ b/drivers/usb/usb-core.c @@ -83,6 +83,7 @@ int usb_init(void) */ void cleanup_drivers(void) { + usb_major_cleanup(); #ifdef CONFIG_USB_PROC proc_usb_cleanup (); #endif diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index 6eb2d6455c1c..42c47452ca99 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -67,8 +67,8 @@ /* into dynamically creating them at insertion time. */ -static int usb_serial_probe(struct usb_device *dev); -static void usb_serial_disconnect(struct usb_device *dev); +static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum); +static void usb_serial_disconnect(struct usb_device *dev, void *ptr); typedef enum { unknown = 0, @@ -441,7 +441,7 @@ static int Get_Free_Serial (void) } -static int usb_serial_probe(struct usb_device *dev) +static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_serial_state *serial; struct usb_interface_descriptor *interface; @@ -466,18 +466,13 @@ static int usb_serial_probe(struct usb_device *dev) } if (type == unknown) - return (-1); + return NULL; printk (KERN_INFO "USB serial converter detected.\n"); - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { - printk (KERN_INFO " Failed usb_set_configuration: serial\n"); - return (-1); - } - if (0>(serial_num = Get_Free_Serial())) { debug_info("USB Serial: Too many devices connected\n"); - return (-1); + return NULL; } serial = &serial_state_table[serial_num]; @@ -485,10 +480,9 @@ static int usb_serial_probe(struct usb_device *dev) memset(serial, 0, sizeof(serial)); serial->dev = dev; serial->type = type; - dev->private = serial; /* we should have 1 bulk in, 1 bulk out, and 1 interrupt in endpoints */ - interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[ifnum].altsetting[0]; for (i = 0; i < interface->bNumEndpoints; ++i) { endpoint = &interface->endpoint[i]; @@ -564,7 +558,7 @@ static int usb_serial_probe(struct usb_device *dev) serial->present = 1; MOD_INC_USE_COUNT; - return (0); + return serial; probe_error: if (serial) { @@ -575,13 +569,13 @@ probe_error: if (serial->interrupt_in_buffer) kfree (serial->interrupt_in_buffer); } - return (-1); + return NULL; } -static void usb_serial_disconnect(struct usb_device *dev) +static void usb_serial_disconnect(struct usb_device *dev, void *ptr) { - struct usb_serial_state *serial = (struct usb_serial_state *)dev->private; + struct usb_serial_state *serial = (struct usb_serial_state *) ptr; if (serial) { if (!serial->present) { @@ -610,7 +604,6 @@ static void usb_serial_disconnect(struct usb_device *dev) serial->present = 0; serial->active = 0; } - dev->private = NULL; MOD_DEC_USE_COUNT; diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index add3bb463323..105de5fffe3c 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -3,6 +3,8 @@ * * (C) Copyright Linus Torvalds 1999 * (C) Copyright Johannes Erdfelt 1999 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the @@ -27,9 +29,12 @@ #include "usb.h" -static int usb_find_driver(struct usb_device *); +/* + * Prototypes for the device driver probing/loading functions + */ +static void usb_find_drivers(struct usb_device *); +static int usb_find_interface_driver(struct usb_device *, unsigned int); static void usb_check_support(struct usb_device *); -static void usb_driver_purge(struct usb_driver *, struct usb_device *); /* * We have a per-interface "registered driver" list. @@ -37,6 +42,8 @@ static void usb_driver_purge(struct usb_driver *, struct usb_device *); static LIST_HEAD(usb_driver_list); static LIST_HEAD(usb_bus_list); +static struct usb_busmap busmap; + static struct usb_driver *usb_minors[16]; int usb_register(struct usb_driver *new_driver) @@ -70,6 +77,44 @@ int usb_register(struct usb_driver *new_driver) return 0; } +/* + * This function is part of a depth-first search down the device tree, + * removing any instances of a device driver. + */ +static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev) +{ + int i; + + if (!dev) { + printk(KERN_ERR "usbcore: null device being purged!!!\n"); + return; + } + + for (i=0; ichildren[i]) + usb_drivers_purge(driver, dev->children[i]); + + if (!dev->actconfig) + return; + + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *interface = &dev->actconfig->interface[i]; + + if (interface->driver == driver) { + driver->disconnect(dev, interface->private_data); + usb_driver_release_interface(driver, interface); + /* + * This will go through the list looking for another + * driver that can handle the device + */ + usb_find_interface_driver(dev, i); + } + } +} + +/* + * Unlink a driver from the driver list when it is unloaded + */ void usb_deregister(struct usb_driver *driver) { struct list_head *tmp; @@ -89,45 +134,10 @@ void usb_deregister(struct usb_driver *driver) struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list); tmp = tmp->next; - usb_driver_purge(driver, bus->root_hub); + usb_drivers_purge(driver, bus->root_hub); } } -/* - * This function is part of a depth-first search down the device tree, - * removing any instances of a device driver. - */ -static void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) -{ - int i; - - if (!dev) { - printk(KERN_ERR "usbcore: null device being purged!!!\n"); - return; - } - - for (i=0; ichildren[i]) - usb_driver_purge(driver, dev->children[i]); - - /* now we check this device */ - if (dev->driver == driver) { - /* - * Note: this is not the correct way to do this, this - * uninitializes and reinitializes EVERY driver - */ - printk(KERN_INFO "disconnect driverless device %d\n", - dev->devnum); - dev->driver->disconnect(dev); - dev->driver = NULL; - - /* - * This will go back through the list looking for a driver - * that can handle the device - */ - usb_find_driver(dev); - } -} /* * calc_bus_time: @@ -222,6 +232,7 @@ struct usb_bus *usb_alloc_bus(struct usb_operations *op) bus->op = op; bus->root_hub = NULL; bus->hcpriv = NULL; + bus->busnum = -1; bus->bandwidth_allocated = 0; bus->bandwidth_int_reqs = 0; bus->bandwidth_isoc_reqs = 0; @@ -241,16 +252,27 @@ void usb_free_bus(struct usb_bus *bus) void usb_register_bus(struct usb_bus *bus) { + int busnum; + + busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1); + if (busnum < USB_MAXBUS) { + set_bit(busnum, busmap.busmap); + bus->busnum = busnum; + } else + printk(KERN_INFO "usb: too many bus'\n"); + proc_usb_add_bus(bus); /* Add it to the list of buses */ list_add(&bus->bus_list, &usb_bus_list); - printk("New USB bus registered\n"); + printk("New USB bus registered, assigned bus number %d\n", bus->busnum); } void usb_deregister_bus(struct usb_bus *bus) { + printk("usbcore: USB bus %d deregistered\n", bus->busnum); + /* * NOTE: make sure that all the devices are removed by the * controller code, as well as having it call this when cleaning @@ -259,6 +281,8 @@ void usb_deregister_bus(struct usb_bus *bus) list_del(&bus->bus_list); proc_usb_remove_bus(bus); + + clear_bit(bus->busnum, busmap.busmap); } /* @@ -278,37 +302,123 @@ static void usb_check_support(struct usb_device *dev) if (dev->children[i]) usb_check_support(dev->children[i]); + if (!dev->actconfig) + return; + /* now we check this device */ - if (!dev->driver && dev->devnum > 0) - usb_find_driver(dev); + if (dev->devnum > 0) + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) + usb_find_interface_driver(dev, i); +} + + +/* + * This is intended to be used by usb device drivers that need to + * claim more than one interface on a device at once when probing + * (audio and acm are good examples). No device driver should have + * to mess with the internal usb_interface or usb_device structure + * members. + */ +void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv) +{ + if (!iface || !driver) + return; + + printk(KERN_DEBUG "usbcore: %s driver claimed interface %p\n", driver->name, iface); + + iface->driver = driver; + iface->private_data = priv; +} /* usb_driver_claim_interface() */ + +/* + * This should be used by drivers to check other interfaces to see if + * they are available or not. + */ +int usb_interface_claimed(struct usb_interface *iface) +{ + if (!iface) + return 0; + + return (iface->driver != NULL); +} /* usb_interface_claimed() */ + +/* + * This should be used by drivers to release their claimed interfaces + */ +void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface) +{ + /* this should never happen, don't release something that's not ours */ + if (iface->driver != driver || !iface) + return; + + iface->driver = NULL; + iface->private_data = NULL; } /* * This entrypoint gets called for each new device. * * We now walk the list of registered USB drivers, - * looking for one that will accept this device as - * his.. + * looking for one that will accept this interface. + * + * The probe return value is changed to be a private pointer. This way + * the drivers don't have to dig around in our structures to set the + * private pointer if they only need one interface. + * + * Returns: 0 if a driver accepted the interface, -1 otherwise */ -static int usb_find_driver(struct usb_device *dev) +static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum) { struct list_head *tmp = usb_driver_list.next; - - while (tmp != &usb_driver_list) { - struct usb_driver *driver = list_entry(tmp, struct usb_driver, - driver_list); - tmp = tmp->next; - if (driver->probe(dev)) - continue; - dev->driver = driver; - return 1; + struct usb_interface *interface; + + if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) { + printk(KERN_ERR "usb-core: bad find_interface_driver params\n"); + return -1; } - /* - * Ok, no driver accepted the device, so show the info - * for debugging.. - */ - return 0; + interface = &dev->actconfig->interface[ifnum]; + + if (usb_interface_claimed(interface)) + return -1; + + while (tmp != &usb_driver_list) { + void *private; + struct usb_driver *driver = list_entry(tmp, struct usb_driver, + driver_list); + + tmp = tmp->next; + if (!(private = driver->probe(dev, ifnum))) + continue; + usb_driver_claim_interface(driver, interface, private); + + return 0; + } + + return -1; +} + +/* + * This entrypoint gets called for each new device. + * + * All interfaces are scanned for matching drivers. + */ +static void usb_find_drivers(struct usb_device *dev) +{ + unsigned ifnum; + unsigned rejected = 0; + + for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) { + /* if this interface hasn't already been claimed */ + if (!usb_interface_claimed(dev->actconfig->interface)) { + if (usb_find_interface_driver(dev, ifnum)) + rejected++; + } + } + + if (rejected) { + printk(KERN_DEBUG "usbcore: unhandled interfaces on device.\n"); + } } /* @@ -631,6 +741,7 @@ void usb_init_root_hub(struct usb_device *dev) { dev->devnum = -1; dev->slow = 0; + dev->actconfig = NULL; } /* @@ -646,10 +757,18 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; - printk("USB disconnect on device %d\n", dev->devnum); + printk("usbcore: USB disconnect on device %d\n", dev->devnum); - if (dev->driver) - dev->driver->disconnect(dev); + if (dev->actconfig) { + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *interface = &dev->actconfig->interface[i]; + struct usb_driver *driver = interface->driver; + if (driver) { + driver->disconnect(dev, interface->private_data); + usb_driver_release_interface(driver, interface); + } + } + } /* Free up all the children.. */ for (i = 0; i < USB_MAXCHILDREN; i++) { @@ -894,7 +1013,6 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) if (err) return err; - dev->ifnum = interface; dev->actconfig->interface[interface].act_altsetting = alternate; usb_set_maxpacket(dev); return 0; @@ -1113,9 +1231,14 @@ int usb_new_device(struct usb_device *dev) } dev->actconfig = dev->config; - dev->ifnum = 0; usb_set_maxpacket(dev); + /* we set the default configuration here */ + if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { + printk(KERN_ERR "usbcore: failed to set default configuration\n"); + return -1; + } + usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer); usb_show_string(dev, "Product", dev->descriptor.iProduct); usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); @@ -1123,14 +1246,8 @@ int usb_new_device(struct usb_device *dev) /* now that the basic setup is over, add a /proc/bus/usb entry */ proc_usb_add_device(dev); - if (!usb_find_driver(dev)) { - /* - * Ok, no driver accepted the device, so show the info for - * debugging - */ - printk(KERN_DEBUG "Unknown new USB device:\n"); - usb_show_device(dev); - } + /* find drivers willing to handle this device */ + usb_find_drivers(dev); return 0; } @@ -1226,12 +1343,12 @@ int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe) * returns the current frame number for the parent USB bus/controller * of the given USB device. */ -int usb_get_current_frame_number (struct usb_device *usb_dev) +int usb_get_current_frame_number(struct usb_device *usb_dev) { return usb_dev->bus->op->get_frame_number (usb_dev); } -int usb_init_isoc (struct usb_device *usb_dev, +int usb_init_isoc(struct usb_device *usb_dev, unsigned int pipe, int frame_count, void *context, @@ -1302,7 +1419,7 @@ static int usb_open(struct inode * inode, struct file * file) struct usb_driver *c = usb_minors[minor/16]; file->f_op = NULL; - if ((file->f_op = c->fops) && file->f_op->open) + if (c && (file->f_op = c->fops) && file->f_op->open) return file->f_op->open(inode,file); else return -ENODEV; @@ -1323,12 +1440,17 @@ static struct file_operations usb_fops = { void usb_major_init(void) { - if (register_chrdev(180,"usb",&usb_fops)) { + if (register_chrdev(USB_MAJOR,"usb",&usb_fops)) { printk("unable to get major %d for usb devices\n", - MISC_MAJOR); + USB_MAJOR); } } +void usb_major_cleanup(void) +{ + unregister_chrdev(USB_MAJOR, "usb"); +} + #ifdef CONFIG_PROC_FS struct list_head *usb_driver_get_list(void) diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index f31c5b60ba3f..e8b8dfc41ff1 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -175,6 +175,8 @@ struct usb_proc_setinterface { #include #include +#define USB_MAJOR 180 + extern int usb_hub_init(void); extern int usb_kbd_init(void); extern int usb_cpia_init(void); @@ -235,6 +237,12 @@ struct usb_devmap { unsigned long devicemap[128 / (8*sizeof(unsigned long))]; }; +#define USB_MAXBUS 64 + +struct usb_busmap { + unsigned long busmap[USB_MAXBUS / (8*sizeof(unsigned long))]; +}; + /* * This is a USB device descriptor. * @@ -320,6 +328,9 @@ struct usb_interface { int act_altsetting; /* active alternate setting */ int num_altsetting; /* number of alternate settings */ + + struct usb_driver *driver; /* driver */ + void *private_data; }; /* Configuration descriptor information.. */ @@ -348,8 +359,8 @@ struct usb_device; struct usb_driver { const char *name; - int (*probe)(struct usb_device *); - void (*disconnect)(struct usb_device *); + void * (*probe)(struct usb_device *, unsigned int); + void (*disconnect)(struct usb_device *, void *); struct list_head driver_list; @@ -476,6 +487,8 @@ struct usb_operations { * Allocated per bus we have */ struct usb_bus { + int busnum; /* Bus number (in order of reg) */ + struct usb_devmap devmap; /* Device map */ struct usb_operations *op; /* Operations (specific to the HC) */ struct usb_device *root_hub; /* Root hub */ @@ -510,11 +523,9 @@ struct usb_device { struct usb_config_descriptor *actconfig;/* the active configuration */ int epmaxpacketin[16]; /* INput endpoint specific maximums */ int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ - int ifnum; /* active interface number */ struct usb_device *parent; struct usb_bus *bus; /* Bus we're part of */ - struct usb_driver *driver; /* Driver */ struct usb_device_descriptor descriptor;/* Descriptor */ struct usb_config_descriptor *config; /* All of the configs */ @@ -523,7 +534,6 @@ struct usb_device { int string_langid; /* language ID for strings */ void *hcpriv; /* Host Controller private data */ - void *private; /* Upper layer private data */ void *audiopriv; /* May be both audio and HID */ /* procfs entry */ struct proc_dir_entry *proc_entry; @@ -543,6 +553,11 @@ struct usb_device { extern int usb_register(struct usb_driver *); extern void usb_deregister(struct usb_driver *); +/* used these for multi-interface device registration */ +extern void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv); +extern int usb_interface_claimed(struct usb_interface *iface); +extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface); + extern struct usb_bus *usb_alloc_bus(struct usb_operations *); extern void usb_free_bus(struct usb_bus *); extern void usb_register_bus(struct usb_bus *); @@ -621,6 +636,11 @@ int usb_kill_isoc (struct usb_isoc_desc *isocdesc); #define PIPE_CONTROL 2 #define PIPE_BULK 3 +#define USB_ISOCHRONOUS 0 +#define USB_INTERRUPT 1 +#define USB_CONTROL 2 +#define USB_BULK 3 + #define usb_maxpacket(dev, pipe, out) (out \ ? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \ : (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] ) diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c index 6f34e1afaa29..ee2c9a163197 100644 --- a/drivers/usb/usb_scsi.c +++ b/drivers/usb/usb_scsi.c @@ -69,6 +69,7 @@ struct us_data { struct usb_scsi_filter *filter; /* filter driver */ void *fdata; /* filter data */ unsigned int flags; /* from filter initially*/ + __u8 ifnum; /* interface number */ __u8 ep_in; /* in endpoint */ __u8 ep_out; /* out ....... */ __u8 ep_int; /* interrupt . */ @@ -118,8 +119,8 @@ static struct us_data *us_list; static struct usb_scsi_filter *filters; -static int scsi_probe(struct usb_device *dev); -static void scsi_disconnect(struct usb_device *dev); +static void * scsi_probe(struct usb_device *dev, unsigned int ifnum); +static void scsi_disconnect(struct usb_device *dev, void *ptr); static struct usb_driver scsi_driver = { "usb_scsi", scsi_probe, @@ -269,7 +270,7 @@ static int pop_CB_reset(struct us_data *us) cmd[1] = 4; result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE, - 0, us->pusb_dev->ifnum, cmd, sizeof(cmd), HZ*5); + 0, us->ifnum, cmd, sizeof(cmd), HZ*5); /* long wait for reset */ @@ -324,7 +325,7 @@ static int pop_CB_command(Scsi_Cmnd *srb) } result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE, - 0, us->pusb_dev->ifnum, + 0, us->ifnum, cmd, us->fixedlength, HZ*5); if (!done_start && (us->subclass == US_SC_UFI /*|| us->subclass == US_SC_8070*/) && cmd[0] == TEST_UNIT_READY && result) { @@ -336,7 +337,7 @@ static int pop_CB_command(Scsi_Cmnd *srb) cmd[4] = 1; /* start */ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE, - 0, us->pusb_dev->ifnum, + 0, us->ifnum, cmd, us->fixedlength, HZ*5); wait_ms(100); retry++; @@ -345,7 +346,7 @@ static int pop_CB_command(Scsi_Cmnd *srb) } else { result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_CBI_ADSC, USB_TYPE_CLASS | USB_RT_INTERFACE, - 0, us->pusb_dev->ifnum, + 0, us->ifnum, srb->cmnd, srb->cmd_len, HZ*5); } if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT) @@ -374,7 +375,7 @@ static int pop_CB_status(Scsi_Cmnd *srb) while (retry--) { result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_TYPE_STANDARD | USB_RT_DEVICE, - 0, 0, + 0, us->ifnum, status, sizeof(status), HZ*5); if (result != USB_ST_TIMEOUT) break; @@ -479,7 +480,7 @@ static int pop_Bulk_reset(struct us_data *us) result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), US_BULK_RESET, USB_TYPE_CLASS | USB_RT_INTERFACE, - US_BULK_RESET_HARD, 0, + US_BULK_RESET_HARD, us->ifnum, NULL, 0, HZ*5); if (result) US_DEBUGP("Bulk hard reset failed %d\n", result); @@ -1052,7 +1053,7 @@ static int usbscsi_control_thread(void * __us) return 0; } -static int scsi_probe(struct usb_device *dev) +static void * scsi_probe(struct usb_device *dev, unsigned int ifnum) { struct usb_interface_descriptor *interface; int i; @@ -1098,11 +1099,11 @@ static int scsi_probe(struct usb_device *dev) protocol = US_PR_CB; subclass = US_SC_8070; /* an assumption */ } else if (dev->descriptor.bDeviceClass != 0 || - dev->config[0].interface[0].altsetting[0].bInterfaceClass != + dev->actconfig->interface[ifnum].altsetting[0].bInterfaceClass != USB_CLASS_MASS_STORAGE || - dev->config[0].interface[0].altsetting[0].bInterfaceSubClass < US_SC_MIN || - dev->config[0].interface[0].altsetting[0].bInterfaceSubClass > US_SC_MAX) { - return -1; + dev->actconfig->interface[ifnum].altsetting[0].bInterfaceSubClass < US_SC_MIN || + dev->actconfig->interface[ifnum].altsetting[0].bInterfaceSubClass > US_SC_MAX) { + return NULL; } /* now check if we have seen it before */ @@ -1130,12 +1131,12 @@ static int scsi_probe(struct usb_device *dev) printk(KERN_WARNING USB_SCSI "Out of memory\n"); if (filter) filter->release(fdata); - return -1; + return NULL; } memset(ss, 0, sizeof(struct us_data)); } - interface = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->actconfig->interface[ifnum].altsetting[0]; ss->filter = filter; ss->fdata = fdata; ss->flags = flags; @@ -1195,10 +1196,12 @@ static int scsi_probe(struct usb_device *dev) US_DEBUGP("Endpoints In %d Out %d Int %d\n", ss->ep_in, ss->ep_out, ss->ep_int); + /* save the interface number */ + ss->ifnum = ifnum; + /* exit if strange looking */ - if (usb_set_configuration(dev, dev->config[0].bConfigurationValue) || - usb_set_interface(dev, interface->bInterfaceNumber, 0) || + if (usb_set_interface(dev, interface->bInterfaceNumber, 0) || !ss->ep_in || !ss->ep_out || (ss->protocol == US_PR_CBI && ss->ep_int == 0)) { US_DEBUGP("Problems with device\n"); if (ss->host) { @@ -1209,12 +1212,12 @@ static int scsi_probe(struct usb_device *dev) if (filter) filter->release(fdata); kfree(ss); - return -1; /* no endpoints */ + return NULL; /* no endpoints */ } - if (dev->config[0].iConfiguration && usb_string(dev, dev->config[0].iConfiguration)) + if (dev->actconfig->iConfiguration && usb_string(dev, dev->actconfig->iConfiguration)) US_DEBUGP("Configuration %s\n", - usb_string(dev, dev->config[0].iConfiguration)); + usb_string(dev, dev->actconfig->iConfiguration)); if (interface->iInterface && usb_string(dev, interface->iInterface)) US_DEBUGP("Interface %s\n", usb_string(dev, interface->iInterface)); @@ -1268,7 +1271,7 @@ static int scsi_probe(struct usb_device *dev) if (filter) filter->release(fdata); kfree(ss); - return -1; + return NULL; } memcpy(htmplt, &my_host_template, sizeof(my_host_template)); ss->host_number = my_host_number++; @@ -1284,7 +1287,7 @@ static int scsi_probe(struct usb_device *dev) /* shuttle E-USB */ result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), 1, 0xC0, - 0, 0, + 0, ss->ifnum, qstat, 2, HZ*5); US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]); init_waitqueue_head(&ss->ip_waitq); @@ -1292,7 +1295,7 @@ static int scsi_probe(struct usb_device *dev) result = usb_request_irq(ss->pusb_dev, ss->irqpipe, pop_CBI_irq, 0, (void *)ss, &ss->irq_handle); if (result) - return -1; + return NULL; interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6); } else if (ss->protocol == US_PR_CBI) @@ -1314,7 +1317,7 @@ static int scsi_probe(struct usb_device *dev) if (filter) filter->release(fdata); kfree(ss); - return -1; + return NULL; } /* wait for it to start */ @@ -1336,20 +1339,18 @@ static int scsi_probe(struct usb_device *dev) printk(KERN_INFO "USB SCSI device found at address %d\n", dev->devnum); - dev->private = ss; - return 0; + return ss; } -static void scsi_disconnect(struct usb_device *dev) +static void scsi_disconnect(struct usb_device *dev, void *ptr) { - struct us_data *ss = dev->private; + struct us_data *ss = ptr; if (!ss) return; if (ss->filter) ss->filter->release(ss->fdata); ss->pusb_dev = NULL; - dev->private = NULL; /* just in case */ MOD_DEC_USE_COUNT; } diff --git a/drivers/usb/uss720.c b/drivers/usb/uss720.c index 9fb30b1a3f08..60aba7bafecd 100644 --- a/drivers/usb/uss720.c +++ b/drivers/usb/uss720.c @@ -538,7 +538,7 @@ static struct parport_operations parport_uss720_ops = /* --------------------------------------------------------------------- */ -static int uss720_probe(struct usb_device *usbdev) +static void * uss720_probe(struct usb_device *usbdev, unsigned int ifnum) { struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; @@ -552,31 +552,16 @@ static int uss720_probe(struct usb_device *usbdev) if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) && (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) && (usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284)) - return -1; + return NULL; - /* We don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) - return -1; + /* our known interfaces have 3 alternate settings */ + if (usbdev->actconfig->interface[ifnum].num_altsetting != 3) + return NULL; - /* We don't handle multiple interfaces */ - if (usbdev->config[0].bNumInterfaces != 1) - return -1; - - /* We don't handle multiple interfaces */ - if (usbdev->config[0].interface[0].num_altsetting != 3) - return -1; - - printk(KERN_DEBUG "uss720: set configuration\n"); - usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue); - - i = usb_set_interface(usbdev, 0, 2); + i = usb_set_interface(usbdev, ifnum, 2); printk(KERN_DEBUG "uss720: set inteface result %d\n", i); - interface = &usbdev->config[0].interface[0].altsetting[2]; - - //printk(KERN_DEBUG "uss720: get interface\n"); - //i = usb_get_interface(usbdev, 0); - //printk(KERN_DEBUG "uss720: is in alternate setting %d\n", i); + interface = &usbdev->actconfig->interface[ifnum].altsetting[2]; /* * Allocate parport interface @@ -584,13 +569,13 @@ static int uss720_probe(struct usb_device *usbdev) printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, \n"); if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL))) - return -1; + return NULL; if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) { - kfree(priv); - return -1; + printk(KERN_WARNING "usb-uss720: could not register parport\n"); + goto probe_abort; } + pp->private_data = priv; - usbdev->private = pp; priv->usbdev = usbdev; pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; @@ -612,26 +597,28 @@ static int uss720_probe(struct usb_device *usbdev) pp, &priv->irqhandle); if (i) { printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i); - /* FIXME: undo some stuff and free some memory. */ - return -1; + goto probe_abort_port; } #endif parport_proc_register(pp); parport_announce_port(pp); MOD_INC_USE_COUNT; - return 0; + return pp; + +probe_abort_port: + parport_unregister_port(pp); +probe_abort: + kfree(priv); + return NULL; } -static void uss720_disconnect(struct usb_device *usbdev) +static void uss720_disconnect(struct usb_device *usbdev, void *ptr) { - struct parport *pp = (struct parport *)usbdev->private; + struct parport *pp = (struct parport *)ptr; struct parport_uss720_private *priv = pp->private_data; -#if 0 usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe); -#endif - usbdev->private = NULL; priv->usbdev = NULL; parport_proc_unregister(pp); parport_unregister_port(pp); diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 8efdcbe59796..eec19a2858d7 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -1,5 +1,5 @@ /* - * linux/drivers/video/acorn.c + * linux/drivers/video/acornfb.c * * Copyright (C) 1998,1999 Russell King * @@ -36,6 +36,8 @@ #include