]> git.neil.brown.name Git - history.git/commitdiff
v2.5.2.3 -> v2.5.2.4
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 08:16:46 +0000 (00:16 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 08:16:46 +0000 (00:16 -0800)
- Patrick Mochel: initcall levels
- Patrick Mochel: devicefs updates, add PCI devices into the hierarchy
- Denis Oliver Kropp: neomagic fb driver
- David Miller: sparc64 and network updates
- Kai Mäkisara: scsi tape update
- Al Viro: more inode trimming, VFS cleanup
- Greg KH: USB update - proper urb allocations
- Eric Raymond: kdev_t updates for fb devices

224 files changed:
Documentation/Configure.help
Makefile
arch/alpha/kernel/time.c
arch/alpha/vmlinux.lds.in
arch/arm/kernel/ecard.c
arch/arm/vmlinux-armo.lds.in
arch/arm/vmlinux-armv.lds.in
arch/cris/cris.ld
arch/i386/kernel/mca.c
arch/i386/kernel/time.c
arch/i386/vmlinux.lds
arch/ia64/kernel/time.c
arch/ia64/vmlinux.lds.S
arch/m68k/vmlinux-sun3.lds
arch/m68k/vmlinux.lds
arch/mips/ld.script.in
arch/mips64/ld.script.elf32.S
arch/mips64/ld.script.elf64
arch/parisc/vmlinux.lds
arch/ppc/kernel/setup.c
arch/ppc/kernel/time.c
arch/ppc/vmlinux.lds
arch/s390/kernel/time.c
arch/s390/vmlinux-shared.lds
arch/s390/vmlinux.lds
arch/s390x/kernel/time.c
arch/s390x/vmlinux-shared.lds
arch/s390x/vmlinux.lds
arch/sh/vmlinux.lds.S
arch/sparc/kernel/pcic.c
arch/sparc/kernel/process.c
arch/sparc/kernel/time.c
arch/sparc/vmlinux.lds
arch/sparc64/defconfig
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/pci_schizo.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/sbus.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/time.c
arch/sparc64/kernel/ttable.S
arch/sparc64/mm/ultra.S
arch/sparc64/vmlinux.lds
drivers/char/joystick/iforce.c
drivers/dio/dio.c
drivers/ieee1394/video1394.c
drivers/input/evdev.c
drivers/media/video/zr36067.c
drivers/net/irda/ali-ircc.c
drivers/net/irda/irda-usb.c
drivers/net/irda/nsc-ircc.c
drivers/net/sungem.c
drivers/net/sungem.h
drivers/nubus/nubus.c
drivers/pci/pci.c
drivers/pcmcia/ds.c
drivers/pnp/isapnp.c
drivers/sbus/sbus.c
drivers/scsi/README.st
drivers/scsi/st.c
drivers/scsi/st.h
drivers/scsi/st_options.h
drivers/sound/cmpci.c
drivers/sound/ymfpci.c
drivers/tc/tc.c
drivers/usb/CDCEther.c
drivers/usb/CDCEther.h
drivers/usb/audio.c
drivers/usb/catc.c
drivers/usb/devio.c
drivers/usb/dsbr100.c
drivers/usb/hpusbscsi.c
drivers/usb/hpusbscsi.h
drivers/usb/inode.c
drivers/usb/microtek.c
drivers/usb/microtek.h
drivers/usb/pegasus.c
drivers/usb/pegasus.h
drivers/usb/scanner.c
drivers/usb/scanner.h
drivers/usb/usb-uhci.c
drivers/usb/usbkbd.c
drivers/usb/usbmouse.c
drivers/usb/vicam.c
drivers/usb/vicam.h
drivers/usb/wacom.c
drivers/video/Config.in
drivers/video/Makefile
drivers/video/S3triofb.c
drivers/video/acornfb.c
drivers/video/amifb.c
drivers/video/atafb.c
drivers/video/aty128fb.c
drivers/video/chipsfb.c
drivers/video/clgenfb.c
drivers/video/controlfb.c
drivers/video/cyberfb.c
drivers/video/dn_cfb4.c
drivers/video/dn_cfb8.c
drivers/video/dnfb.c
drivers/video/epson1355fb.c
drivers/video/fbmem.c
drivers/video/fm2fb.c
drivers/video/g364fb.c
drivers/video/hgafb.c
drivers/video/hitfb.c
drivers/video/hpfb.c
drivers/video/igafb.c
drivers/video/imsttfb.c
drivers/video/macfb.c
drivers/video/maxinefb.c
drivers/video/neofb.c [new file with mode: 0644]
drivers/video/neofb.h [new file with mode: 0644]
drivers/video/offb.c
drivers/video/platinumfb.c
drivers/video/pmag-ba-fb.c
drivers/video/pmagb-b-fb.c
drivers/video/pvr2fb.c
drivers/video/q40fb.c
drivers/video/radeonfb.c
drivers/video/retz3fb.c
drivers/video/sgivwfb.c
drivers/video/skeletonfb.c
drivers/video/sstfb.c
drivers/video/stifb.c
drivers/video/sun3fb.c
drivers/video/tdfxfb.c
drivers/video/tgafb.c
drivers/video/tx3912fb.c
drivers/video/valkyriefb.c
drivers/video/vfb.c
drivers/video/vga16fb.c
drivers/video/virgefb.c
drivers/zorro/zorro.c
fs/Config.in
fs/coda/inode.c
fs/driverfs/inode.c
fs/minix/bitmap.c
fs/minix/inode.c
fs/minix/itree_v1.c
fs/minix/itree_v2.c
fs/namespace.c
fs/ncpfs/inode.c
fs/nfsd/nfssvc.c
fs/reiserfs/bitmap.c
fs/reiserfs/buffer2.c
fs/reiserfs/file.c
fs/reiserfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/journal.c
fs/reiserfs/stree.c
fs/reiserfs/super.c
fs/reiserfs/tail_conversion.c
fs/super.c
fs/sysv/ChangeLog
fs/sysv/dir.c
fs/sysv/ialloc.c
fs/sysv/inode.c
fs/sysv/itree.c
fs/sysv/super.c
fs/sysv/symlink.c
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/super.c
fs/udf/udf_i.h
include/asm-sparc/ide.h
include/asm-sparc64/ide.h
include/asm-sparc64/irq.h
include/asm-sparc64/pil.h [new file with mode: 0644]
include/linux/device.h
include/linux/driverfs_fs.h
include/linux/fb.h
include/linux/fs.h
include/linux/init.h
include/linux/minix_fs.h
include/linux/minix_fs_i.h
include/linux/ncp_fs.h
include/linux/ncp_fs_i.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv4/ipt_ULOG.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_ah.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_esp.h [new file with mode: 0644]
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netlink.h
include/linux/pci.h
include/linux/reiserfs_fs.h
include/linux/reiserfs_fs_i.h
include/linux/rtnetlink.h
include/linux/sysv_fs.h
include/linux/sysv_fs_i.h
include/linux/time.h
include/linux/udf_fs_i.h
init/main.c
kernel/device.c
kernel/ksyms.c
kernel/time.c
net/bridge/br_fdb.c
net/core/dev.c
net/ipv4/netfilter/Config.in
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ip_fw_compat_masq.c
net/ipv4/netfilter/ip_nat_rule.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipchains_core.c
net/ipv4/netfilter/ipfwadm_core.c
net/ipv4/netfilter/ipt_LOG.c
net/ipv4/netfilter/ipt_REDIRECT.c
net/ipv4/netfilter/ipt_ULOG.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_ah.c [new file with mode: 0644]
net/ipv4/netfilter/ipt_esp.c [new file with mode: 0644]
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv6/ndisc.c
net/ipv6/netfilter/Config.in
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6_queue.c [new file with mode: 0644]
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6t_MARK.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/irda/af_irda.c
net/netlink/af_netlink.c
net/netsyms.c

index 9c3c11539fc16b7223002c3c11e9ae142608d5a3..59657c82ab3b129b06b18186c5ff44325f9332af 100644 (file)
@@ -2433,6 +2433,14 @@ CONFIG_IP_NF_MATCH_LENGTH
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+AH/ESP match support
+CONFIG_IP_NF_MATCH_AH_ESP
+  These two match extensions (`ah' and `esp') allow you to match a
+  range of SPIs inside AH or ESP headers of IPSec packets.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 TOS match support
 CONFIG_IP_NF_MATCH_TOS
   TOS matching allows you to match packets based on the Type Of
@@ -2600,6 +2608,19 @@ CONFIG_IP_NF_MATCH_TCPMSS
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+ULOG target support
+CONFIG_IP_NF_TARGET_ULOG
+  This option adds a `ULOG' target, which allows you to create rules in
+  any iptables table. The packet is passed to a userspace logging
+  daemon using netlink multicast sockets; unlike the LOG target
+  which can only be viewed through syslog.
+
+  The apropriate userspace logging daemon (ulogd) may be obtained from
+  http://www.gnumonks.org/projects/ulogd
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 LOG target support
 CONFIG_IP_NF_TARGET_LOG
   This option adds a `LOG' target, which allows you to create rules in
@@ -2656,6 +2677,23 @@ CONFIG_IP6_NF_MATCH_MULTIPORT
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+IPV6 queue handler (EXPERIMENTAL)
+CONFIG_IP6_NF_QUEUE
+
+  This option adds a queue handler to the kernel for IPv6
+  packets which lets us to receive the filtered packets
+  with QUEUE target using libiptc as we can do with
+  the IPv4 now.
+
+  (C) Fernando Anton 2001
+  IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+  Universidad Carlos III de Madrid
+  Universidad Politecnica de Alcala de Henares
+  email: fanton@it.uc3m.es
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. If unsure, say `N'.
+
 Owner match support
 CONFIG_IP6_NF_MATCH_OWNER
   Packet owner matching allows you to match locally-generated packets
@@ -4128,6 +4166,16 @@ CONFIG_FB_L7200
   This driver supports the L7200 Color LCD.
   Say Y if you want graphics support.
 
+NeoMagic display support (EXPERIMENTAL)
+CONFIG_FB_NEOMAGIC
+  This driver supports notebooks with NeoMagic PCI chips.
+  Say Y if you have such a graphics card. 
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called neofb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 PowerMac "control" frame buffer device support
 CONFIG_FB_CONTROL
   This driver supports a frame buffer for the graphics adapter in the
index e4a9258e6acbe4bba5a30fde0c287adcbd088153..9b4a307d9c9b24373a9c5cf21916aae7f073fb7e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 3
-EXTRAVERSION =-pre3
+EXTRAVERSION =-pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index 01bf82bd8f0fc36edd134fb70aeaa3548b5ec20c..0be250e543e81ded9cce980c5f8ffab73f08b5f2 100644 (file)
@@ -379,8 +379,6 @@ time_init(void)
        /* Startup the timer source. */
        alpha_mv.init_rtc();
 
-       do_get_fast_time = do_gettimeofday;
-
        /*
         * If we had wanted SRM console printk echoing early, undo it now.
         *
index ba7ad8f9f77624de4e118e11dd2be67510ec2953..ee7a7e245e35204e2dc1e01e148c67740ec6260f 100644 (file)
@@ -41,7 +41,15 @@ SECTIONS
 
   . = ALIGN(8);
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
 
   . = ALIGN(2*8192);   /* Align double page for init_task_union */
index c60ca78c65c5639d341b9879d4d23b23dab72818..63121715e591bf44dfab9e70d00605d4c8aa108f 100644 (file)
@@ -1097,6 +1097,8 @@ void __init ecard_init(void)
        ecard_proc_init();
 }
 
+subsys_initcall(ecard_init);
+
 EXPORT_SYMBOL(ecard_startfind);
 EXPORT_SYMBOL(ecard_find);
 EXPORT_SYMBOL(ecard_readchunk);
index 4581c2a0b04e9f96130fcdfa047e714d905ff0c8..c83777929ce5a9a5089a21af18ec5f25912d65f7 100644 (file)
@@ -27,7 +27,13 @@ SECTIONS
                        *(.setup.init)
                __setup_end = .;
                __initcall_start = .;
-                       *(.initcall.init)
+                       *(.initcall1.init)
+                       *(.initcall2.init)
+                       *(.initcall3.init)
+                       *(.initcall4.init)
+                       *(.initcall5.init)
+                       *(.initcall6.init)
+                       *(.initcall7.init)
                __initcall_end = .;
                . = ALIGN(32768);
                __init_end = .;
index 6585b766d6d7ae5b0391d9c0c2bf2963b6baa4ab..618d9f28f1535220821ce404adf2be88d0b83db2 100644 (file)
@@ -26,7 +26,13 @@ SECTIONS
                        *(.setup.init)
                __setup_end = .;
                __initcall_start = .;
-                       *(.initcall.init)
+                       *(.initcall1.init)
+                       *(.initcall2.init)
+                       *(.initcall3.init)
+                       *(.initcall4.init)
+                       *(.initcall5.init)
+                       *(.initcall6.init)
+                       *(.initcall7.init)
                __initcall_end = .;
                . = ALIGN(4096);
                __init_end = .;
index 66e797309af817157bc62f92523209d1eee5ea19..d0d2af1f80471900f2e34d71042e49203108f3c3 100644 (file)
@@ -63,7 +63,13 @@ SECTIONS
        __setup_end = .;
        .initcall.init : {
                __initcall_start = .;
-               *(.initcall.init);
+               *(.initcall1.init);
+               *(.initcall2.init);
+               *(.initcall3.init);
+               *(.initcall4.init);
+               *(.initcall5.init);
+               *(.initcall6.init);
+               *(.initcall7.init);
                __initcall_end = .;
 
                /* We fill to the next page, so we can discard all init
index 104ae9e9e1d3c9413ac553918b14ab3ca087991c..dc7db1cdce4cca2cd52855bf8daddb9f4f3a9dab 100644 (file)
@@ -311,6 +311,8 @@ void __init mca_init(void)
 #endif
 }
 
+subsys_initcall(mca_init);
+
 /*--------------------------------------------------------------------*/
 
 static void mca_handle_nmi_slot(int slot, int check_flag)
index b4d807436ec521a898ac1dd8f1ae42a6cae8631f..c2c3b624747785ac01e0b154d28067bd4b370880 100644 (file)
@@ -681,7 +681,6 @@ void __init time_init(void)
 #ifndef do_gettimeoffset
                        do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-                       do_get_fast_time = do_gettimeofday;
 
                        /* report CPU clock rate in Hz.
                         * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
index ce14066f48f5fe1e05811f189d96e116d330ce23..1a7da033d8a3167107a3daca16b37ec4208b64a2 100644 (file)
@@ -48,7 +48,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
index d11dcf4534c47baaeec7b5c0fbc7d709c89b3152..dc6500b7a1676ada3120be0bd74951d207b4f017 100644 (file)
@@ -145,9 +145,6 @@ do_gettimeofday (struct timeval *tv)
        tv->tv_usec = usec;
 }
 
-/* XXX there should be a cleaner way for declaring an alias... */
-asm (".global get_fast_time; get_fast_time = do_gettimeofday");
-
 static void
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
index 727e44ba264a5d3ab972695257b236fea6c090b7..d496ad104b973310381988b80f7239cd9c335f43 100644 (file)
@@ -104,8 +104,16 @@ SECTIONS
         { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET)
-        { *(.initcall.init) }
+  .initcall.init : AT(ADDR(.initcall1.init) - PAGE_OFFSET)
+       {
+                *(.initcall1.init) 
+                *(.initcall2.init) 
+                *(.initcall3.init) 
+                *(.initcall4.init) 
+                *(.initcall5.init) 
+                *(.initcall6.init) 
+                *(.initcall7.init) 
+       }
   __initcall_end = .;
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
index 4848631fe03820797ce3be33690832c2158ab63b..164b11ac48e5175ff858c82a5593e18f302d7f35 100644 (file)
@@ -43,7 +43,15 @@ __init_begin = .;
        .setup.init : { *(.setup.init) }
        __setup_end = .;
        __initcall_start = .;
-       .initcall.init : { *(.initcall.init) }
+       .initcall.init : {
+               *(.initcall1.init) 
+               *(.initcall2.init) 
+               *(.initcall3.init) 
+               *(.initcall4.init) 
+               *(.initcall5.init) 
+               *(.initcall6.init) 
+               *(.initcall7.init)
+       }
        __initcall_end = .;
        . = ALIGN(8192);
        __init_end = .;
index f24a564db1f2b862fd2df0177e0e5d86e00a62df..3b9eb25b52843314356fde5b169c50135c8f70a4 100644 (file)
@@ -47,7 +47,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
index b8cbfd6e650461835a1d67781f0ea8874a3a28b8..72151b12408cc1093f3fab6034a1fa8730b38ae3 100644 (file)
@@ -44,7 +44,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);     /* Align double page for init_task_union */
   __init_end = .;
index 3a00edf0aa54c81ae19b706c5608541acc626e71..4ffd13a3b49a763fe735519e882f0e86da561f6b 100644 (file)
@@ -40,7 +40,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);     /* Align double page for init_task_union */
   __init_end = .;
index d7c3c94539a897c97f2abe3e162303bcf233f02f..5b35543718316da76b78d7c1bf6e8a3b14f399b6 100644 (file)
@@ -49,7 +49,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);     /* Align double page for init_task_union */
   __init_end = .;
index b06a86f167167977a597143f9f3f694787e7d272..77ed2059623aa041137dd1ec461c180753bc03f1 100644 (file)
@@ -51,7 +51,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) } 
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   __init_end = .;
 
index 7d0fd42462a87e610f5c4c5a7075783537d68a93..a8765201c99ab5219244597f41d762965e232fc6 100644 (file)
@@ -535,6 +535,8 @@ void __init ppc_init(void)
        }
 }
 
+subsys_initcall(ppc_init);
+
 /* Warning, IO base is not yet inited */
 void __init setup_arch(char **cmdline_p)
 {
index 92e0854a0dba4d89d9af6fcd494159dcae965490..381f1833339c4d1d4966aacbae53fccdeac56fc6 100644 (file)
@@ -352,8 +352,6 @@ void __init time_init(void)
                tz.tz_dsttime = 0;
                do_sys_settimeofday(NULL, &tz);
         }
-
-       do_get_fast_time = do_gettimeofday;
 }
 
 #define TICK_SIZE tick
index 564c9548524fa0bfa42ef16cb806bf630ea8d3dd..3549b03f49fb2730a81c6b78eef468f4e2755c15 100644 (file)
@@ -94,7 +94,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
index 7f0967d1de30c38f3f21d4cadd072c73f36cc4cf..aadf5285d98182d6520894e7a451508b771fff07 100644 (file)
@@ -249,7 +249,4 @@ void __init time_init(void)
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
-
-       /* Set do_get_fast_time function pointer.  */
-       do_get_fast_time = do_gettimeofday;
 }
index d42574bf75bc9bf90280b5190e39bfe42adee2a6..4956b7c7eab4b746fb9b2691ba44d08896b70886 100644 (file)
@@ -55,7 +55,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
index 2bf285009f05cba2eed56d56df1e8ba12ff4946e..1b53d5bafafe017dfa63d246c433e544889546b8 100644 (file)
@@ -53,7 +53,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
index 0371537ecd0d8cc303e2cd5e78a481e97fe3aaf4..0a23ef72b6905d43cf4eac41fe242e28f3a49cb4 100644 (file)
@@ -255,7 +255,4 @@ void __init time_init(void)
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
-
-       /* Set do_get_fast_time function pointer.  */
-       do_get_fast_time = do_gettimeofday;
 }
index 8eb5b04f44bf87d55b5cacdda4229578728158bb..8f6d74e69247e43f5b6c090b18dc0d20df4d8c2b 100644 (file)
@@ -55,7 +55,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
index f8dd0265bee36d10c625d32ac8058d9a89bdc4b4..2cc3355c8a27ea94760097a6480e86d4d8c656e1 100644 (file)
@@ -53,7 +53,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
index c8df952e031e040abdfbdbcd5e38cf98a5f716cd..fcbc7bd32c9c772dbb4e6c89cac357ecacfbbfad 100644 (file)
@@ -63,7 +63,15 @@ SECTIONS
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   __machvec_start = .;
   .machvec.init : { *(.machvec.init) }
index 6ccc271533cac6fa8e64122f7f8adf461a92d78e..53c2aaa296e41d88b450bcda9da46afa65c00c74 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.22 2001/02/13 01:16:43 davem Exp $
+/* $Id: pcic.c,v 1.23 2002/01/23 14:33:55 davem Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -759,7 +759,6 @@ void __init pci_time_init(void)
        unsigned long v;
        int timer_irq, irq;
 
-       do_get_fast_time = pci_do_gettimeofday;
        /* A hack until do_gettimeofday prototype is moved to arch specific headers
           and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
        ((unsigned int *)do_gettimeofday)[0] = 
index 00c1de5e877f7c4f674b103b98b2fdf2eae3479f..6d96f8dac8c18844ebb9bac2212a141305e3de60 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.160 2002/01/11 08:45:38 davem Exp $
+/*  $Id: process.c,v 1.161 2002/01/23 11:27:32 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 56f82ab06866a701b683bd72611b006a4648f456..8e40a700e7999a179837d4b8b9bb288c028b6dc3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.59 2001/10/30 04:54:21 davem Exp $
+/* $Id: time.c,v 1.60 2002/01/23 14:33:55 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -371,7 +371,6 @@ void __init sbus_time_init(void)
        struct intersil *iregs;
 #endif
 
-       do_get_fast_time = do_gettimeofday;
        BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
        btfixup();
 
index bd177538eac937d90a1ea39c29e1fedb3f315bd9..ed00b4f28bb353bd35ba9985eadad3e01098ef52 100644 (file)
@@ -45,7 +45,15 @@ SECTIONS
   .setup_init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
index 2d80c59f8e50fee3fed7ff278f790d46632df8bd..728c010c8b01fb92523509a652f34fad5274f579 100644 (file)
@@ -253,6 +253,7 @@ CONFIG_BLK_DEV_IDE=y
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -267,6 +268,7 @@ CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -278,12 +280,15 @@ CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 CONFIG_BLK_DEV_ALI15X3=y
@@ -298,6 +303,7 @@ CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
index 59ea29a97a415019d23aad405cb4a2233e35d023..5adac65952c6b2ec9c9a40d9f175f2e5b86d60d3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.31 2002/01/05 07:33:16 davem Exp $
+/* $Id: pci_psycho.c,v 1.32 2002/01/23 11:27:32 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -345,7 +345,7 @@ static unsigned char psycho_pil_table[] = {
 /*0x2f*/15,            /* Correctable ECC              */
 /*0x30*/15,            /* PCI Bus A Error              */
 /*0x31*/15,            /* PCI Bus B Error              */
-/*0x32*/1            /* Power Management             */
+/*0x32*/15,            /* Power Management             */
 };
 
 static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -354,7 +354,7 @@ static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
 
        ret = psycho_pil_table[ino];
        if (ret == 0 && pdev == NULL) {
-               ret = 1;
+               ret = 2;
        } else if (ret == 0) {
                switch ((pdev->class >> 16) & 0xff) {
                case PCI_BASE_CLASS_STORAGE:
@@ -377,7 +377,7 @@ static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
                        break;
 
                default:
-                       ret = 1;
+                       ret = 2;
                        break;
                };
        }
@@ -410,6 +410,10 @@ static unsigned int __init psycho_irq_build(struct pci_pbm_info *pbm,
 
        /* Now build the IRQ bucket. */
        pil = psycho_ino_to_pil(pdev, ino);
+
+       if (PIL_RESERVED(pil))
+               BUG();
+
        imap = p->controller_regs + imap_off;
        imap += 4;
 
index 7f86b6f0189fb368f6af46427d5e94c11a7d6ff4..db1c48044afef1d3dc7d0c6e3348bc7217b39758 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -582,7 +582,7 @@ static unsigned char sabre_pil_table[] = {
 /*0x2f*/15,            /* Correctable ECC              */
 /*0x30*/15,            /* PCI Bus A Error              */
 /*0x31*/15,            /* PCI Bus B Error              */
-/*0x32*/1            /* Power Management             */
+/*0x32*/15,            /* Power Management             */
 };
 
 static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -596,7 +596,7 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
 
        ret = sabre_pil_table[ino];
        if (ret == 0 && pdev == NULL) {
-               ret = 1;
+               ret = 2;
        } else if (ret == 0) {
                switch ((pdev->class >> 16) & 0xff) {
                case PCI_BASE_CLASS_STORAGE:
@@ -619,7 +619,7 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
                        break;
 
                default:
-                       ret = 1;
+                       ret = 2;
                        break;
                };
        }
@@ -651,6 +651,10 @@ static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm,
 
        /* Now build the IRQ bucket. */
        pil = sabre_ino_to_pil(pdev, ino);
+
+       if (PIL_RESERVED(pil))
+               BUG();
+
        imap = p->controller_regs + imap_off;
        imap += 4;
 
index a660d05199aa8731432df943ec2be77e2ed09b67..86bb91fa394dbfb8958245e9aff2c9c833bf701b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -344,7 +344,7 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
 
        ret = schizo_pil_table[ino];
        if (ret == 0 && pdev == NULL) {
-               ret = 1;
+               ret = 2;
        } else if (ret == 0) {
                switch ((pdev->class >> 16) & 0xff) {
                case PCI_BASE_CLASS_STORAGE:
@@ -367,7 +367,7 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
                        break;
 
                default:
-                       ret = 1;
+                       ret = 2;
                        break;
                };
        }
@@ -395,6 +395,10 @@ static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
 
        /* Now build the IRQ bucket. */
        pil = schizo_ino_to_pil(pdev, ino);
+
+       if (PIL_RESERVED(pil))
+               BUG();
+
        imap = p->controller_regs + pbm_off + imap_off;
        imap += 4;
 
index 8c2cbcb5bc79912b3f374e8a9b4c39da8674b42f..7151f73a6c7288039a11c96633f4d0c9126ce307 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.128 2002/01/11 08:45:38 davem Exp $
+/*  $Id: process.c,v 1.129 2002/01/23 11:27:32 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
index 4998dcfefb1ca2a68e8f25613187cb17673506a2..b37ad90353b19ca6140022f98abb5c70f91eb7a3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.18 2001/12/17 07:05:09 davem Exp $
+/* $Id: sbus.c,v 1.19 2002/01/23 11:27:32 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -628,10 +628,10 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
 
 /* SBUS SYSIO INO number to Sparc PIL level. */
 static unsigned char sysio_ino_to_pil[] = {
-       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 0 */
-       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 1 */
-       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 2 */
-       0, 1, 2, 7, 5, 7, 8, 9,         /* SBUS slot 3 */
+       0, 2, 2, 7, 5, 7, 8, 9,         /* SBUS slot 0 */
+       0, 2, 2, 7, 5, 7, 8, 9,         /* SBUS slot 1 */
+       0, 2, 2, 7, 5, 7, 8, 9,         /* SBUS slot 2 */
+       0, 2, 2, 7, 5, 7, 8, 9,         /* SBUS slot 3 */
        3, /* Onboard SCSI */
        5, /* Onboard Ethernet */
 /*XXX*/        8, /* Onboard BPP */
@@ -754,6 +754,10 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
                printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
                panic("Bad SYSIO IRQ translations...");
        }
+
+       if (PIL_RESERVED(pil))
+               BUG();
+
        imap = sysio_irq_offsets[ino];
        if (imap == ((unsigned long)-1)) {
                prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
index f5a9badf722c844af289656a9e9cd2d3771616eb..8ff3e19b5ae8061b94e42d34907e6438a6862d19 100644 (file)
@@ -218,10 +218,12 @@ void __init smp_callin(void)
        atomic_inc(&init_mm.mm_count);
        current->active_mm = &init_mm;
 
+       init_idle();
+
        while (!smp_threads_ready)
                membar("#LoadLoad");
 
-       init_idle();
+       idle_startup_done();
 }
 
 void cpu_panic(void)
@@ -875,6 +877,48 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
        }
 }
 
+/* Process migration IPIs. */
+
+extern unsigned long xcall_migrate_task;
+
+static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
+static task_t *new_task;
+
+void smp_migrate_task(int cpu, task_t *p)
+{
+       unsigned long mask = 1UL << cpu;
+
+       if (cpu == smp_processor_id())
+               return;
+
+       if (smp_processors_ready && (cpu_present_map & mask) != 0) {
+               u64 data0 = (((u64)&xcall_migrate_task) & 0xffffffff);
+
+               spin_lock(&migration_lock);
+               new_task = p;
+
+               if (tlb_type == spitfire)
+                       spitfire_xcall_deliver(data0, 0, 0, mask);
+               else
+                       cheetah_xcall_deliver(data0, 0, 0, mask);
+       }
+}
+
+/* Called at PIL level 1. */
+asmlinkage void smp_task_migration_interrupt(int irq, struct pt_regs *regs)
+{
+       task_t *p;
+
+       if (irq != PIL_MIGRATE)
+               BUG();
+
+       clear_softint(1 << irq);
+
+       p = new_task;
+       spin_unlock(&migration_lock);
+       sched_task_migrated(p);
+}
+
 /* CPU capture. */
 /* #define CAPTURE_DEBUG */
 extern unsigned long xcall_capture;
index 3119c67b398ac990bca52baba11f0d59607793b4..0aa8fe8e691065e548e00a8f23bd3634cbad357a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
+/* $Id: time.c,v 1.42 2002/01/23 14:33:55 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -330,8 +330,6 @@ static void __init set_system_time(void)
 #endif
        u8 tmp;
 
-       do_get_fast_time = do_gettimeofday;
-
        if (!mregs && !dregs) {
                prom_printf("Something wrong, clock regs not mapped yet.\n");
                prom_halt();
index 9b2e54e269074f2d9de16fc55036379edc17a26f..576127bead268030c1e05b675b4d2bfc60cf867f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $
+/* $Id: ttable.S,v 1.37 2002/01/23 11:27:32 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
  *
  * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,12 @@ tl0_stdfmna: TRAP_NOSAVE(do_stdfmna)
 tl0_privact:   TRAP_NOSAVE(__do_privact)
 tl0_resv038:   BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
 tl0_resv03e:   BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
-tl0_irq1:      TRAP_IRQ(handler_irq, 1)  TRAP_IRQ(handler_irq, 2)
+#ifdef CONFIG_SMP
+tl0_irq1:      TRAP_IRQ(smp_task_migration_interrupt, 1)
+#else
+tl0_irq1:      BTRAP(0x41)
+#endif
+tl0_irq2:      TRAP_IRQ(handler_irq, 2)
 tl0_irq3:      TRAP_IRQ(handler_irq, 3)  TRAP_IRQ(handler_irq, 4)
 tl0_irq5:      TRAP_IRQ(handler_irq, 5)  TRAP_IRQ(handler_irq, 6)
 tl0_irq7:      TRAP_IRQ(handler_irq, 7)  TRAP_IRQ(handler_irq, 8)
index 828749fac6ecc8a57e288c3f86191867557915d7..0fdf597c1e423c726d7c3e1a5171ff24186ed2ef 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $
+/* $Id: ultra.S,v 1.71 2002/01/23 11:27:36 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -10,6 +10,7 @@
 #include <asm/page.h>
 #include <asm/spitfire.h>
 #include <asm/mmu_context.h>
+#include <asm/pil.h>
 
        /* Basically, all this madness has to do with the
         * fact that Cheetah does not support IMMU flushes
@@ -691,4 +692,11 @@ xcall_call_function:
        b,pt            %xcc, rtrap
         clr            %l6
 
+       .globl          xcall_migrate_task
+xcall_migrate_task:
+       mov             1, %g2
+       sllx            %g2, (PIL_MIGRATE), %g2
+       wr              %g2, 0x0, %set_softint
+       retry
+
 #endif /* CONFIG_SMP */
index 343fbee58df0103e7c7bdfd00ca3e64b4bec0e2a..a6975bc8b837040e7e6ef0096dd3987752cc48e0 100644 (file)
@@ -46,7 +46,15 @@ SECTIONS
   .setup_init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+       *(.initcall1.init) 
+       *(.initcall2.init) 
+       *(.initcall3.init) 
+       *(.initcall4.init) 
+       *(.initcall5.init) 
+       *(.initcall6.init) 
+       *(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
index 4998a1a7bbdaf780d85f074b6fef16dd6b5ee346..d967c372531b22881418988f641a3e3a318f04c9 100644 (file)
@@ -133,7 +133,7 @@ struct iforce {
 #endif
 #ifdef IFORCE_USB
        struct usb_device *usbdev;      /* USB transfer */
-       struct urb irq, out, ctrl;
+       struct urb *irq, *out, *ctrl;
        struct usb_ctrlrequest dr;
 #endif
                                        /* Force Feedback */
@@ -196,28 +196,28 @@ static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
                        DECLARE_WAITQUEUE(wait, current);
                        int timeout = HZ; /* 1 second */
 
-                       memcpy(iforce->out.transfer_buffer + 1, data, LO(cmd));
-                       ((char*)iforce->out.transfer_buffer)[0] = HI(cmd);
-                       iforce->out.transfer_buffer_length = LO(cmd) + 2;
-                       iforce->out.dev = iforce->usbdev;
+                       memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
+                       ((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
+                       iforce->out->transfer_buffer_length = LO(cmd) + 2;
+                       iforce->out->dev = iforce->usbdev;
 
                        set_current_state(TASK_INTERRUPTIBLE);
                        add_wait_queue(&iforce->wait, &wait);
 
-                       if (usb_submit_urb(&iforce->out)) {
+                       if (usb_submit_urb(iforce->out)) {
                                set_current_state(TASK_RUNNING);
                                remove_wait_queue(&iforce->wait, &wait);
                                return;
                        }
 
-                       while (timeout && iforce->out.status == -EINPROGRESS)
+                       while (timeout && iforce->out->status == -EINPROGRESS)
                                timeout = schedule_timeout(timeout);
 
                        set_current_state(TASK_RUNNING);
                        remove_wait_queue(&iforce->wait, &wait);
 
                        if (!timeout)
-                               usb_unlink_urb(&iforce->out);
+                               usb_unlink_urb(iforce->out);
 
                        return;
                }
@@ -284,25 +284,25 @@ static int get_id_packet(struct iforce *iforce, char *packet)
                case IFORCE_USB:
 
                        iforce->dr.bRequest = packet[0];
-                       iforce->ctrl.dev = iforce->usbdev;
+                       iforce->ctrl->dev = iforce->usbdev;
 
                        set_current_state(TASK_INTERRUPTIBLE);
                        add_wait_queue(&iforce->wait, &wait);
 
-                       if (usb_submit_urb(&iforce->ctrl)) {
+                       if (usb_submit_urb(iforce->ctrl)) {
                                set_current_state(TASK_RUNNING);
                                remove_wait_queue(&iforce->wait, &wait);
                                return -1;
                        }
 
-                       while (timeout && iforce->ctrl.status == -EINPROGRESS)
+                       while (timeout && iforce->ctrl->status == -EINPROGRESS)
                                timeout = schedule_timeout(timeout);
 
                        set_current_state(TASK_RUNNING);
                        remove_wait_queue(&iforce->wait, &wait);
 
                        if (!timeout) {
-                               usb_unlink_urb(&iforce->ctrl);
+                               usb_unlink_urb(iforce->ctrl);
                                return -1;
                        }
 
@@ -344,8 +344,8 @@ static int iforce_open(struct input_dev *dev)
                case IFORCE_USB:
                        if (iforce->open++)
                                break;
-                       iforce->irq.dev = iforce->usbdev;
-                       if (usb_submit_urb(&iforce->irq))
+                       iforce->irq->dev = iforce->usbdev;
+                       if (usb_submit_urb(iforce->irq))
                                        return -EIO;
                        break;
 #endif
@@ -361,7 +361,7 @@ static void iforce_close(struct input_dev *dev)
 #ifdef IFORCE_USB
                case IFORCE_USB:
                        if (!--iforce->open)
-                               usb_unlink_urb(&iforce->irq);
+                               usb_unlink_urb(iforce->irq);
                        break;
 #endif
        }
@@ -1024,6 +1024,25 @@ static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
        if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
        memset(iforce, 0, sizeof(struct iforce));
 
+       iforce->irq = usb_alloc_urb(0);
+       if (!iforce->irq) {
+               kfree(iforce);
+               return NULL;
+       }
+       iforce->out = usb_alloc_urb(0);
+       if (!iforce->out) {
+               usb_free_urb(iforce->irq);
+               kfree(iforce);
+               return NULL;
+       }
+       iforce->ctrl = usb_alloc_urb(0);
+       if (!iforce->ctrl) {
+               usb_free_urb(iforce->out);
+               usb_free_urb(iforce->irq);
+               kfree(iforce);
+               return NULL;
+       }
+
        iforce->bus = IFORCE_USB;
        iforce->usbdev = dev;
 
@@ -1031,16 +1050,19 @@ static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
        iforce->dr.wIndex = 0;
        iforce->dr.wLength = 16;
 
-       FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+       FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
                        iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
 
-       FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+       FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
                        iforce + 1, 32, iforce_usb_out, iforce);
 
-       FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+       FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
                        (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
 
        if (iforce_init_device(iforce)) {
+               usb_free_urb(iforce->ctrl);
+               usb_free_urb(iforce->out);
+               usb_free_urb(iforce->irq);
                kfree(iforce);
                return NULL;
        }
@@ -1055,8 +1077,11 @@ static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
 static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
 {
        struct iforce *iforce = ptr;
-       usb_unlink_urb(&iforce->irq);
+       usb_unlink_urb(iforce->irq);
        input_unregister_device(&iforce->dev);
+       usb_free_urb(iforce->ctrl);
+       usb_free_urb(iforce->out);
+       usb_free_urb(iforce->irq);
        kfree(iforce);
 }
 
index bf8468cfa4a19e9ec2f7e4473e835c0738b26ed6..2ddffd21d393ad27e07fdd37aa8acfca0b165eed 100644 (file)
@@ -208,6 +208,8 @@ void __init dio_init(void)
         }
 }
 
+subsys_initcall(dio_init);
+
 /* Bear in mind that this is called in the very early stages of initialisation
  * in order to get the virtual address of the serial port for the console...
  */
index b435f99dd3741f2dc93f11655d4361cabafaf9db..ead267c6d2fee4a0f56df244c11d4e79765a93b0 100644 (file)
@@ -639,7 +639,7 @@ int wakeup_dma_ir_ctx(struct ti_ohci *ohci, struct dma_iso_ctx *d)
                if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
                        reset_ir_status(d, i);
                        d->buffer_status[i] = VIDEO1394_BUFFER_READY;
-                       get_fast_time(&d->buffer_time[i]);
+                       do_gettimeofday(&d->buffer_time[i]);
                }
        }
        spin_unlock(&d->lock);
index 62f5adcdde4d7d45cbe87aa00262850d3d54d9c7..4fa77c99ccf7e9de3ae245eef3c12b986b3938a5 100644 (file)
@@ -67,7 +67,7 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
 
        while (list) {
 
-               get_fast_time(&list->buffer[list->head].time);
+               do_gettimeofday(&list->buffer[list->head].time);
                list->buffer[list->head].type = type;
                list->buffer[list->head].code = code;
                list->buffer[list->head].value = value;
index 998ea23529b3f12f3e06601f1329d98b3528e7bb..9db0d527f572b5f6ed562c4c01aedd350adef0e8 100644 (file)
@@ -2608,7 +2608,7 @@ static void zoran_reap_stat_com(struct zoran *zr)
                }
                frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
                gbuf = &zr->jpg_gbuf[frame];
-               get_fast_time(&gbuf->bs.timestamp);
+               do_gettimeofday(&gbuf->bs.timestamp);
 
                if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
                        gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
index 4aaef91ab021dd88a70768509501e2f8d9d1d506..ed926cbea5d42d897ceaf34a6df4a397c4b86794 100644 (file)
@@ -1496,7 +1496,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                if (mtt) 
                {
                        /* Check how much time we have used already */
-                       get_fast_time(&self->now);
+                       do_gettimeofday(&self->now);
                        
                        diff = self->now.tv_usec - self->stamp.tv_usec;
                        /* self->stamp is set from ali_ircc_dma_receive_complete() */
@@ -1913,7 +1913,7 @@ static int  ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
                         * reduce the min turn time a bit since we will know
                         * how much time we have used for protocol processing
                         */
-                       get_fast_time(&self->stamp);
+                       do_gettimeofday(&self->stamp);
 
                        skb = dev_alloc_skb(len+1);
                        if (skb == NULL)  
index 08e548505866cbdfbc0d5c3510a9cc1ec86845b6..99682aa9a3e751f484386ec7b108647c9a466a7b 100644 (file)
@@ -427,7 +427,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
                mtt = irda_get_mtt(skb);
                if (mtt) {
                        int diff;
-                       get_fast_time(&self->now);
+                       do_gettimeofday(&self->now);
                        diff = self->now.tv_usec - self->stamp.tv_usec;
 #ifdef IU_USB_MIN_RTT
                        /* Factor in USB delays -> Get rid of udelay() that
@@ -798,7 +798,7 @@ static void irda_usb_receive(struct urb *urb)
         * reduce the min turn time a bit since we will know
         * how much time we have used for protocol processing
         */
-        get_fast_time(&self->stamp);
+        do_gettimeofday(&self->stamp);
 
        /* Fix skb, and remove USB-IrDA header */
        skb_put(skb, urb->actual_length);
index 1cb4bb70a48dd9b425235f3bbec6e58e4659d4d5..e3e775dbed5ec1d50e0062bda74d9ee05c3371d7 100644 (file)
@@ -1163,7 +1163,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
                mtt = irda_get_mtt(skb);
                if (mtt) {
                        /* Check how much time we have used already */
-                       get_fast_time(&self->now);
+                       do_gettimeofday(&self->now);
                        diff = self->now.tv_usec - self->stamp.tv_usec;
                        if (diff < 0) 
                                diff += 1000000;
@@ -1535,7 +1535,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
                         * reduce the min turn time a bit since we will know
                         * how much time we have used for protocol processing
                         */
-                       get_fast_time(&self->stamp);
+                       do_gettimeofday(&self->stamp);
 
                        skb = dev_alloc_skb(len+1);
                        if (skb == NULL)  {
index 5b2f03a83623942e9324c182aae8ad92b1a97c51..cd8dce3f18f72b1ed3c2cf68a8f9783f569ca46e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.48 2002/01/15 06:26:37 davem Exp $
+/* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
  *  - Get rid of all those nasty mdelay's and replace them
  * with schedule_timeout.
  *  - Implement WOL
+ *  - Currently, forced Gb mode is only supported on bcm54xx
+ *    PHY for which I use the SPD2 bit of the control register.
+ *    On m1011 PHY, I can't force as I don't have the specs, but
+ *    I can at least detect gigabit with autoneg.
  */
 
 #include <linux/module.h>
@@ -86,7 +90,7 @@ static u16 link_modes[] __devinitdata = {
        BMCR_ANENABLE,                  /* 0 : autoneg */
        0,                              /* 1 : 10bt half duplex */
        BMCR_SPEED100,                  /* 2 : 100bt half duplex */
-       BMCR_SPD2, /* verify this */    /* 3 : 1000bt half duplex */
+       BMCR_SPD2, /* bcm54xx only */   /* 3 : 1000bt half duplex */
        BMCR_FULLDPLX,                  /* 4 : 10bt full duplex */
        BMCR_SPEED100|BMCR_FULLDPLX,    /* 5 : 100bt full duplex */
        BMCR_SPD2|BMCR_FULLDPLX         /* 6 : 1000bt full duplex */
@@ -1004,6 +1008,14 @@ static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause
                        *fd = 1;
                if (val & (LPA_100FULL | LPA_100HALF))
                        *spd = 100;
+
+               if (gp->phy_mod == phymod_m1011) {
+                       val = phy_read(gp, 0x0a);
+                       if (val & 0xc00)
+                               *spd = 1000;
+                       if (val & 0x800)
+                               *fd = 1;
+               }
        }
 }
 
@@ -1579,6 +1591,11 @@ static void gem_init_phy(struct gem *gp)
                        gem_init_bcm5411_phy(gp);
                        gp->gigabit_capable = 1;
                        break;
+               case 0x1410c60:
+                       printk("M1011 (Marvel ?)\n");
+                       gp->phy_mod = phymod_m1011;
+                       gp->gigabit_capable = 1;
+                       break;
 
                case 0x18074c0:
                        printk("Lucent\n");
@@ -1591,7 +1608,7 @@ static void gem_init_phy(struct gem *gp)
                        break;
 
                default:
-                       printk("Unknown\n");
+                       printk("Unknown (Using generic mode)\n");
                        gp->phy_mod = phymod_generic;
                        break;
                };
@@ -1662,6 +1679,12 @@ static void gem_init_phy(struct gem *gp)
                writel(val, gp->regs + PCS_SCTRL);
                gp->gigabit_capable = 1;
        }
+
+       /* BMCR_SPD2 is a broadcom 54xx specific thing afaik */
+       if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
+           gp->phy_mod != phymod_bcm5411)
+               gp->link_cntl &= ~BMCR_SPD2;
+           
 }
 
 static void gem_init_dma(struct gem *gp)
@@ -1851,9 +1874,8 @@ static int gem_check_invariants(struct gem *gp)
        u32 mif_cfg;
 
        /* On Apple's sungem, we can't rely on registers as the chip
-        * was been powered down by the firmware. We do the PHY lookup
-        * when the interface is opened and we configure the driver
-        * with known values.
+        * was been powered down by the firmware. The PHY is looked
+        * up later on.
         */
        if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
                gp->phy_type = phy_mii_mdio0;
@@ -1978,7 +2000,8 @@ static void gem_apple_powerup(struct gem *gp)
 
        pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
 
-       udelay(100);
+       current->state = TASK_UNINTERRUPTIBLE;
+       schedule_timeout((21 * HZ) / 1000);
 
        pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd);
        cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
@@ -2048,7 +2071,8 @@ static void gem_stop_phy(struct gem *gp)
                                  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
 #endif                         
                        phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-               }
+               } else if (gp->phy_mod == phymod_m1011)
+                       phy_write(gp, MII_BMCR, BMCR_PDOWN);
 
                /* According to Apple, we must set the MDIO pins to this begnign
                 * state or we may 1) eat more current, 2) damage some PHYs
index 0c00ce16dfe3f2ccb31e3e08f67b6f3328151f44..971db64a446a9a0c132490a57b135cc1466b831d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.11 2002/01/12 07:19:55 davem Exp $
+/* $Id: sungem.h,v 1.12 2002/01/23 15:40:45 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -941,6 +941,7 @@ enum gem_phy_model {
        phymod_bcm5400,
        phymod_bcm5401,
        phymod_bcm5411,
+       phymod_m1011,
 };
 
 enum link_state {
index 735c0d17eeb4c6aa036df815849c2584faf1bfbe..766376671e9567fc24972b1104f51e250e753cab 100644 (file)
@@ -1039,3 +1039,5 @@ void __init nubus_init(void)
        nubus_proc_init();
 #endif
 }
+
+subsys_initcall(nubus_init);
index 471ae4bb3e398936a7faa15131029dddc9a77ba6..03ce2466b4b164d35a94e71fd219ce78f46c7fa4 100644 (file)
@@ -1064,6 +1064,7 @@ static struct pci_bus * __devinit  pci_alloc_bus(void)
                memset(b, 0, sizeof(*b));
                INIT_LIST_HEAD(&b->children);
                INIT_LIST_HEAD(&b->devices);
+               iobus_init(&b->iobus);
        }
        return b;
 }
@@ -1085,6 +1086,13 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de
        child->ops = parent->ops;
        child->sysdata = parent->sysdata;
 
+       /* init generic fields */
+       child->iobus.self = &dev->dev;
+       child->iobus.parent = &parent->iobus;
+       dev->dev.subordinate = &child->iobus;
+
+       strcpy(child->iobus.name,dev->dev.name);
+
        /*
         * Set up the primary, secondary and subordinate
         * bus numbers.
@@ -1180,6 +1188,7 @@ static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev,
                pci_write_config_word(dev, PCI_COMMAND, cr);
        }
        sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+
        return max;
 }
 
@@ -1288,13 +1297,22 @@ struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
        dev->vendor = l & 0xffff;
        dev->device = (l >> 16) & 0xffff;
 
+       /* make sure generic fields are setup properly */
+       device_init_dev(&dev->dev);
+
        /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
           set this higher, assuming the system even supports it.  */
        dev->dma_mask = 0xffffffff;
        if (pci_setup_device(dev) < 0) {
                kfree(dev);
-               dev = NULL;
+               return NULL;
        }
+
+       /* now put in global tree */
+       strcpy(dev->dev.name,dev->name);
+       strcpy(dev->dev.bus_id,dev->slot_name);
+
+       device_register(&dev->dev);
        return dev;
 }
 
@@ -1345,10 +1363,17 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
        DBG("Scanning bus %02x\n", bus->number);
        max = bus->secondary;
 
+       /* we should know for sure what the bus number is, so set the bus ID
+        * for the bus and make sure it's registered in the device tree */
+       sprintf(bus->iobus.bus_id,"pci%d",bus->number);
+       iobus_register(&bus->iobus);
+
        /* Create a device template */
        memset(&dev0, 0, sizeof(dev0));
+       device_init_dev(&dev0.dev);
        dev0.bus = bus;
        dev0.sysdata = bus->sysdata;
+       dev0.dev.parent = &bus->iobus;
 
        /* Go find them, Rover! */
        for (devfn = 0; devfn < 0x100; devfn += 8) {
@@ -1403,8 +1428,14 @@ struct pci_bus * __devinit  pci_alloc_primary_bus(int bus)
        }
 
        b = pci_alloc_bus();
+       if (!b)
+               return NULL;
        list_add_tail(&b->node, &pci_root_buses);
 
+       sprintf(b->iobus.bus_id,"pci%d",bus);
+       strcpy(b->iobus.name,"Host/PCI Bridge");
+       iobus_register(&b->iobus);
+
        b->number = b->secondary = bus;
        b->resource[0] = &ioport_resource;
        b->resource[1] = &iomem_resource;
@@ -1929,7 +1960,7 @@ pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
 }
 
 
-void __devinit  pci_init(void)
+static int __devinit pci_init(void)
 {
        struct pci_dev *dev;
 
@@ -1942,6 +1973,7 @@ void __devinit  pci_init(void)
 #ifdef CONFIG_PM
        pm_register(PM_PCI_DEV, 0, pci_pm_callback);
 #endif
+       return 0;
 }
 
 static int __devinit  pci_setup(char *str)
@@ -1959,6 +1991,8 @@ static int __devinit  pci_setup(char *str)
        return 1;
 }
 
+subsys_initcall(pci_init);
+
 __setup("pci=", pci_setup);
 
 EXPORT_SYMBOL(pci_read_config_byte);
index d27aa6f63783054a5e9893a9c4331380dcc3f157..d843e9e4ff3ee139bfa9db48633e5859693afc08 100644 (file)
@@ -966,12 +966,9 @@ int __init init_pcmcia_ds(void)
     return 0;
 }
 
-#ifdef MODULE
+late_initcall(init_pcmcia_ds);
 
-int __init init_module(void)
-{
-    return init_pcmcia_ds();
-}
+#ifdef MODULE
 
 void __exit cleanup_module(void)
 {
index 17efd648290d6425d7bff7a62ed4eda6c5354550..250e8dc4fd754fd558be4cc721fe17b229cace5a 100644 (file)
@@ -2356,12 +2356,9 @@ int __init isapnp_init(void)
        return 0;
 }
 
-#ifdef MODULE
+subsys_initcall(isapnp_init);
 
-int init_module(void)
-{
-       return isapnp_init();
-}
+#ifdef MODULE
 
 void cleanup_module(void)
 {
index c64a0901bc33437e83a19241b2284934a7f41ba4..9b9344d781c0cca3192ffb380e398f8d765817a0 100644 (file)
@@ -509,3 +509,5 @@ void __init sbus_init(void)
        }
 #endif
 }
+
+subsys_initcall(sbus_init);
index 1fa617468ed21a6b7f602d4dcec1514cfe049b95..e06a21597910831c9c6e0ab68864c185388bd315 100644 (file)
@@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver.
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Thu Nov  1 22:41:59 2001 by makisara@kai.makisara.local
+Last modified: Tue Jan 22 21:08:57 2002 by makisara
 
 
 BASICS
@@ -86,6 +86,11 @@ returning zero bytes for two consecutive reads.
 
 The compile options are defined in the file linux/drivers/scsi/st_options.h.
 
+4. If the open option O_NONBLOCK is used, open succeeds even if the
+drive is not ready. If O_NONBLOCK is not used, the driver waits for
+the drive to become ready. If this does not happen in ST_BLOCK_SECONDS
+seconds, open fails with the errno value EIO.
+
 
 BSD AND SYS V SEMANTICS
 
@@ -327,12 +332,19 @@ MTSETDRVBUFFER
           0xffffff means that the default is not used any more.
        MT_ST_DEF_DENSITY
        MT_ST_DEF_DRVBUFFER
+          Used to set or clear the density (8 bits), and drive buffer
+          state (3 bits). If the value is MT_ST_CLEAR_DEFAULT
+          (0xfffff) the default will not be used any more. Otherwise
+          the lowermost bits of the value contain the new value of
+          the parameter.
        MT_ST_DEF_COMPRESSION
-          Used to set or clear the density (8 bits), drive buffer
-          state (3 bits), and compression (single bit). If the value is
-          MT_ST_CLEAR_DEFAULT (0xfffff), the default will not be used
-          any more. Otherwise the lower-most bits of the value contain
-          the new value of the parameter.
+          The compression default will not be used if the value of
+          the lowermost byte is 0xff. Otherwise the lowermost bit
+          contains the new default. If the bits 8-15 are set to a
+          non-zero number, and this number is not 0xff, the number is
+          used as the compression algorithm. The value
+          MT_ST_CLEAR_DEFAULT can be used to clear the compression
+          default.
        MT_ST_SET_TIMEOUT
           Set the normal timeout in seconds for this device. The
           default is 900 seconds (15 minutes). The timeout should be
index 8bcc0a2d02a5911630a60e5e27d7246a9226df0d..022f5caf1f8b7aba254ac8c41654eb0cc250869a 100644 (file)
@@ -9,19 +9,16 @@
    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
    Michael Schaefer, J"org Weule, and Eric Youngdale.
 
-   Copyright 1992 - 2001 Kai Makisara
+   Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Sat Nov  3 19:30:55 2001 by makisara@kai.makisara.local
+   Last modified: Wed Jan 23 20:22:42 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
-
-   Reminder: write_lock_irqsave() can be replaced by write_lock() when the old SCSI
-   error handling will be discarded.
  */
 
-static char *verstr = "20011103";
+static char *verstr = "20020123";
 
 #include <linux/module.h>
 
@@ -160,21 +157,19 @@ static void normalize_buffer(ST_buffer *);
 static int append_to_buffer(const char *, ST_buffer *, int);
 static int from_buffer(ST_buffer *, char *, int);
 
-static int st_init(void);
 static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
 
-static struct Scsi_Device_Template st_template =
-{
-       name:"tape", 
-       tag:"st", 
-       scsi_type:TYPE_TAPE,
-       major:SCSI_TAPE_MAJOR, 
-       detect:st_detect, 
-       init:st_init,
-       attach:st_attach, 
-       detach:st_detach
+static struct Scsi_Device_Template st_template = {
+       module:         THIS_MODULE,
+       name:           "tape", 
+       tag:            "st", 
+       scsi_type:      TYPE_TAPE,
+       major:          SCSI_TAPE_MAJOR, 
+       detect:         st_detect, 
+       attach:         st_attach, 
+       detach:         st_detach
 };
 
 static int st_compression(Scsi_Tape *, int);
@@ -239,7 +234,7 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
                return 0;
        }
 
-       if (driver_byte(result) & DRIVER_SENSE)
+       if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
                scode = sense[2] & 0x0f;
        else {
                sense[0] = 0;
@@ -638,20 +633,96 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
        return 0;
 }
 \f
+/* Test if the drive is ready. Returns either one of the codes below or a negative system
+   error code. */
+#define CHKRES_READY       0
+#define CHKRES_NEW_SESSION 1
+#define CHKRES_NOT_READY   2
+#define CHKRES_NO_TAPE     3
+
+#define MAX_ATTENTIONS    10
+
+static int test_ready(Scsi_Tape *STp, int do_wait)
+{
+       int attentions, waits, max_wait, scode;
+       int retval = CHKRES_READY, new_session = FALSE;
+       unsigned char cmd[MAX_COMMAND_SIZE];
+       Scsi_Request *SRpnt = NULL;
+
+       max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
+
+       for (attentions=waits=0; ; ) {
+               memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+               cmd[0] = TEST_UNIT_READY;
+               SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+                                  STp->long_timeout, MAX_READY_RETRIES, TRUE);
+
+               if (!SRpnt) {
+                       retval = (STp->buffer)->syscall_result;
+                       break;
+               }
+
+               if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
+
+                       scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
+
+                       if (scode == UNIT_ATTENTION) { /* New media? */
+                               new_session = TRUE;
+                               if (attentions < MAX_ATTENTIONS) {
+                                       attentions++;
+                                       continue;
+                               }
+                               else {
+                                       retval = (-EIO);
+                                       break;
+                               }
+                       }
+
+                       if (scode == NOT_READY) {
+                               if (waits < max_wait) {
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(HZ);
+                                       if (signal_pending(current)) {
+                                               retval = (-EINTR);
+                                               break;
+                                       }
+                                       waits++;
+                                       continue;
+                               }
+                               else {
+                                       if ((STp->device)->scsi_level >= SCSI_2 &&
+                                           SRpnt->sr_sense_buffer[12] == 0x3a) /* Check ASC */
+                                               retval = CHKRES_NO_TAPE;
+                                       else
+                                               retval = CHKRES_NOT_READY;
+                                       break;
+                               }
+                       }
+               }
+
+               retval = (STp->buffer)->syscall_result;
+               if (!retval)
+                       retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
+               break;
+       }
+
+       if (SRpnt != NULL)
+               scsi_release_request(SRpnt);
+       return retval;
+}
+
+
 /* See if the drive is ready and gather information about the tape. Return values:
    < 0   negative error code from errno.h
    0     drive ready
    1     drive not ready (possibly no tape)
 */
-#define CHKRES_READY      0
-#define CHKRES_NOT_READY  1
-
 static int check_tape(Scsi_Tape *STp, struct file *filp)
 {
-       int i, retval, new_session = FALSE;
+       int i, retval, new_session = FALSE, do_wait;
        unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
        unsigned short st_flags = filp->f_flags;
-       Scsi_Request *SRpnt;
+       Scsi_Request *SRpnt = NULL;
        ST_mode *STm;
        ST_partstat *STps;
        int dev = TAPE_NR(STp->devt);
@@ -668,32 +739,16 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
        }
        STm = &(STp->modes[STp->current_mode]);
 
-       memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-       cmd[0] = TEST_UNIT_READY;
-
        saved_cleaning = STp->cleaning_req;
        STp->cleaning_req = 0;
-       SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
-                          MAX_READY_RETRIES, TRUE);
-       if (!SRpnt) {
-               retval = (STp->buffer)->syscall_result;
-               goto err_out;
-       }
 
-       if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-           (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+       do_wait = ((filp->f_flags & O_NONBLOCK) == 0);
+       retval = test_ready(STp, do_wait);
 
-               /* Flush the queued UNIT ATTENTION sense data */
-               for (i=0; i < 10; i++) {
-                        memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-                        cmd[0] = TEST_UNIT_READY;
-                        SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
-                                          STp->long_timeout, MAX_READY_RETRIES, TRUE);
-                        if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
-                            (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
-                                break;
-               }
+       if (retval < 0)
+           goto err_out;
 
+       if (retval == CHKRES_NEW_SESSION) {
                (STp->device)->was_reset = 0;
                STp->partition = STp->new_partition = 0;
                if (STp->can_partitions)
@@ -710,26 +765,23 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
                }
                new_session = TRUE;
        }
-       else
+       else {
                STp->cleaning_req |= saved_cleaning;
 
-       if ((STp->buffer)->syscall_result != 0) {
-               if ((STp->device)->scsi_level >= SCSI_2 &&
-                   (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-                   (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
-                   SRpnt->sr_sense_buffer[12] == 0x3a) {       /* Check ASC */
-                       STp->ready = ST_NO_TAPE;
-               } else
-                       STp->ready = ST_NOT_READY;
-               scsi_release_request(SRpnt);
-               SRpnt = NULL;
-               STp->density = 0;       /* Clear the erroneous "residue" */
-               STp->write_prot = 0;
-               STp->block_size = 0;
-               STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
-               STp->partition = STp->new_partition = 0;
-               STp->door_locked = ST_UNLOCKED;
-               return CHKRES_NOT_READY;
+               if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
+                       if (retval == CHKRES_NO_TAPE)
+                               STp->ready = ST_NO_TAPE;
+                       else
+                               STp->ready = ST_NOT_READY;
+
+                       STp->density = 0;       /* Clear the erroneous "residue" */
+                       STp->write_prot = 0;
+                       STp->block_size = 0;
+                       STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+                       STp->partition = STp->new_partition = 0;
+                       STp->door_locked = ST_UNLOCKED;
+                       return CHKRES_NOT_READY;
+               }
        }
 
        if (STp->omit_blklims)
@@ -740,6 +792,10 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
 
                SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
                                   MAX_READY_RETRIES, TRUE);
+               if (!SRpnt) {
+                       retval = (STp->buffer)->syscall_result;
+                       goto err_out;
+               }
 
                if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
                        STp->max_block = ((STp->buffer)->b_data[1] << 16) |
@@ -763,6 +819,10 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
 
        SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
                           MAX_READY_RETRIES, TRUE);
+       if (!SRpnt) {
+               retval = (STp->buffer)->syscall_result;
+               goto err_out;
+       }
 
        if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
@@ -862,22 +922,21 @@ static int st_open(struct inode *inode, struct file *filp)
        Scsi_Tape *STp;
        ST_partstat *STps;
        int dev = TAPE_NR(inode->i_rdev);
-       unsigned long flags;
 
-       write_lock_irqsave(&st_dev_arr_lock, flags);
+       write_lock(&st_dev_arr_lock);
        STp = scsi_tapes[dev];
        if (dev >= st_template.dev_max || STp == NULL) {
-               write_unlock_irqrestore(&st_dev_arr_lock, flags);
+               write_unlock(&st_dev_arr_lock);
                return (-ENXIO);
        }
 
        if (STp->in_use) {
-               write_unlock_irqrestore(&st_dev_arr_lock, flags);
+               write_unlock(&st_dev_arr_lock);
                DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
                return (-EBUSY);
        }
        STp->in_use = 1;
-       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+       write_unlock(&st_dev_arr_lock);
        STp->rew_at_close = STp->autorew_dev = (minor(inode->i_rdev) & 0x80) == 0;
 
        if (STp->device->host->hostt->module)
@@ -891,7 +950,7 @@ static int st_open(struct inode *inode, struct file *filp)
 
        /* Allocate a buffer for this user */
        need_dma_buffer = STp->restr_dma;
-       write_lock_irqsave(&st_dev_arr_lock, flags);
+       write_lock(&st_dev_arr_lock);
        for (i = 0; i < st_nbr_buffers; i++)
                if (!st_buffers[i]->in_use &&
                    (!need_dma_buffer || st_buffers[i]->dma)) {
@@ -899,7 +958,7 @@ static int st_open(struct inode *inode, struct file *filp)
                        (STp->buffer)->in_use = 1;
                        break;
                }
-       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+       write_unlock(&st_dev_arr_lock);
        if (i >= st_nbr_buffers) {
                STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE);
                if (STp->buffer == NULL) {
@@ -935,6 +994,11 @@ static int st_open(struct inode *inode, struct file *filp)
        retval = check_tape(STp, filp);
        if (retval < 0)
                goto err_out;
+       if ((filp->f_flags & O_NONBLOCK) == 0 &&
+           retval != CHKRES_READY) {
+               retval = (-EIO);
+               goto err_out;
+       }
        return 0;
 
  err_out:
@@ -1076,7 +1140,6 @@ static int st_release(struct inode *inode, struct file *filp)
 {
        int result = 0;
        Scsi_Tape *STp;
-       unsigned long flags;
 
        kdev_t devt = inode->i_rdev;
        int dev;
@@ -1091,16 +1154,16 @@ static int st_release(struct inode *inode, struct file *filp)
 
        if (STp->buffer != NULL) {
                normalize_buffer(STp->buffer);
-               write_lock_irqsave(&st_dev_arr_lock, flags);
+               write_lock(&st_dev_arr_lock);
                (STp->buffer)->in_use = 0;
                STp->buffer = NULL;
        }
        else {
-               write_lock_irqsave(&st_dev_arr_lock, flags);
+               write_lock(&st_dev_arr_lock);
        }
 
        STp->in_use = 0;
-       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+       write_unlock(&st_dev_arr_lock);
        STp->device->access_count--;
        if (STp->device->host->hostt->module)
                __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
@@ -1944,6 +2007,10 @@ static int st_set_options(Scsi_Tape *STp, long options)
                        STm->default_blksize = value;
                        printk(KERN_INFO "st%d: Default block size set to %d bytes.\n",
                               dev, STm->default_blksize);
+                       if (STp->ready == ST_READY) {
+                               STp->blksize_changed = FALSE;
+                               set_mode_densblk(STp, STm);
+                       }
                }
        } else if (code == MT_ST_TIMEOUTS) {
                value = (options & ~MT_ST_OPTIONS);
@@ -1979,6 +2046,10 @@ static int st_set_options(Scsi_Tape *STp, long options)
                                STm->default_density = value & 0xff;
                                printk(KERN_INFO "st%d: Density default set to %x\n",
                                       dev, STm->default_density);
+                               if (STp->ready == ST_READY) {
+                                       STp->density_changed = FALSE;
+                                       set_mode_densblk(STp, STm);
+                               }
                        }
                } else if (code == MT_ST_DEF_DRVBUFFER) {
                        if (value == MT_ST_CLEAR_DEFAULT) {
@@ -1990,6 +2061,8 @@ static int st_set_options(Scsi_Tape *STp, long options)
                                printk(KERN_INFO
                                        "st%d: Drive buffer default set to %x\n",
                                       dev, STp->default_drvbuffer);
+                               if (STp->ready == ST_READY)
+                                       st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
                        }
                } else if (code == MT_ST_DEF_COMPRESSION) {
                        if (value == MT_ST_CLEAR_DEFAULT) {
@@ -1997,9 +2070,20 @@ static int st_set_options(Scsi_Tape *STp, long options)
                                printk(KERN_INFO
                                        "st%d: Compression default disabled.\n", dev);
                        } else {
-                               STm->default_compression = (value & 1 ? ST_YES : ST_NO);
-                               printk(KERN_INFO "st%d: Compression default set to %x\n",
-                                      dev, (value & 1));
+                               if ((value & 0xff00) != 0) {
+                                       STp->c_algo = (value & 0xff00) >> 8;
+                                       printk(KERN_INFO "st%d: Compression algorithm set to 0x%x.\n",
+                                              dev, STp->c_algo);
+                               }
+                               if ((value & 0xff) != 0xff) {
+                                       STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+                                       printk(KERN_INFO "st%d: Compression default set to %x\n",
+                                              dev, (value & 1));
+                                       if (STp->ready == ST_READY) {
+                                               STp->compression_changed = FALSE;
+                                               st_compression(STp, (STm->default_compression == ST_YES));
+                                       }
+                               }
                        }
                }
        } else
@@ -2087,6 +2171,7 @@ static int write_mode_page(Scsi_Tape *STp, int page)
 #define COMPRESSION_PAGE_LENGTH 16
 
 #define CP_OFF_DCE_DCC          2
+#define CP_OFF_C_ALGO           7
 
 #define DCE_MASK  0x80
 #define DCC_MASK  0x40
@@ -2122,16 +2207,22 @@ static int st_compression(Scsi_Tape * STp, int state)
                     (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
 
        /* Check if compression can be changed */
-       if ((b_data[mpoffs + 2] & DCC_MASK) == 0) {
+       if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
                return (-EIO);
        }
 
        /* Do the change */
-       if (state)
+       if (state) {
                b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
-       else
+               if (STp->c_algo != 0)
+                       b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
+       }
+       else {
                b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
+               if (STp->c_algo != 0)
+                       b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
+       }
 
        retval = write_mode_page(STp, COMPRESSION_PAGE);
        if (retval) {
@@ -2171,7 +2262,7 @@ static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code)
         */
        if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
            && load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
-               DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
+               DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2d.\n",
                            dev, (cmd[4]) ? "" : "un",
                            load_code - MT_ST_HPLOADER_OFFSET));
                cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
@@ -2202,12 +2293,12 @@ static int do_load_unload(Scsi_Tape *STp, struct file *filp, int load_code)
 
                if (!load_code)
                        STp->rew_at_close = 0;
-               else
+               else {
                        STp->rew_at_close = STp->autorew_dev;
-
-               retval = check_tape(STp, filp);
-               if (retval > 0)
-                       retval = 0;
+                       retval = check_tape(STp, filp);
+                       if (retval > 0)
+                               retval = 0;
+               }
        }
        else {
                STps = &(STp->ps[STp->partition]);
@@ -3286,7 +3377,6 @@ static ST_buffer *
  new_tape_buffer(int from_initialization, int need_dma, int in_use)
 {
        int i, priority, b_size, order, got = 0, segs = 0;
-       unsigned long flags;
        ST_buffer *tb;
 
        read_lock(&st_dev_arr_lock);
@@ -3381,9 +3471,9 @@ static ST_buffer *
        tb->buffer_size = got;
        tb->writing = 0;
 
-       write_lock_irqsave(&st_dev_arr_lock, flags);
+       write_lock(&st_dev_arr_lock);
        st_buffers[st_nbr_buffers++] = tb;
-       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+       write_unlock(&st_dev_arr_lock);
 
        return tb;
 }
@@ -3611,7 +3701,6 @@ static int st_attach(Scsi_Device * SDp)
        ST_mode *STm;
        ST_partstat *STps;
        int i, mode, target_nbr, dev_num;
-       unsigned long flags = 0;
        char *stp;
 
        if (SDp->type != TYPE_TAPE)
@@ -3624,7 +3713,7 @@ static int st_attach(Scsi_Device * SDp)
                return 1;
        }
 
-       write_lock_irqsave(&st_dev_arr_lock, flags);
+       write_lock(&st_dev_arr_lock);
        if (st_template.nr_dev >= st_template.dev_max) {
                Scsi_Tape **tmp_da;
                ST_buffer **tmp_ba;
@@ -3635,7 +3724,7 @@ static int st_attach(Scsi_Device * SDp)
                        tmp_dev_max = ST_MAX_TAPES;
                if (tmp_dev_max <= st_template.nr_dev) {
                        SDp->attached--;
-                       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+                       write_unlock(&st_dev_arr_lock);
                        printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
                               ST_MAX_TAPES);
                        return 1;
@@ -3649,7 +3738,7 @@ static int st_attach(Scsi_Device * SDp)
                        if (tmp_ba != NULL)
                                kfree(tmp_ba);
                        SDp->attached--;
-                       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+                       write_unlock(&st_dev_arr_lock);
                        printk(KERN_ERR "st: Can't extend device array.\n");
                        return 1;
                }
@@ -3682,7 +3771,7 @@ static int st_attach(Scsi_Device * SDp)
        tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
        if (tpnt == NULL) {
                SDp->attached--;
-               write_unlock_irqrestore(&st_dev_arr_lock, flags);
+               write_unlock(&st_dev_arr_lock);
                printk(KERN_ERR "st: Can't allocate device descriptor.\n");
                return 1;
        }
@@ -3770,7 +3859,7 @@ static int st_attach(Scsi_Device * SDp)
        init_MUTEX(&tpnt->lock);
 
        st_template.nr_dev++;
-       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+       write_unlock(&st_dev_arr_lock);
        printk(KERN_WARNING
        "Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
               dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
@@ -3798,45 +3887,12 @@ static int st_detect(Scsi_Device * SDp)
        return 1;
 }
 
-static int st_registered = 0;
-
-/* Driver initialization (not __init because may be called later) */
-static int st_init()
-{
-       unsigned long flags;
-
-       if (st_template.dev_noticed == 0 || st_registered)
-               return 0;
-
-       printk(KERN_INFO
-              "st: Version %s, bufsize %d, wrt %d, max init. bufs %d, s/g segs %d\n",
-              verstr, st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
-
-       write_lock_irqsave(&st_dev_arr_lock, flags);
-       if (!st_registered) {
-               if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
-                       write_unlock_irqrestore(&st_dev_arr_lock, flags);
-                       printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
-                               MAJOR_NR);
-                       return 1;
-               }
-               st_registered++;
-       }
-
-       st_template.dev_max = 0;
-       st_nbr_buffers = 0;
-       write_unlock_irqrestore(&st_dev_arr_lock, flags);
-
-       return 0;
-}
-
 static void st_detach(Scsi_Device * SDp)
 {
        Scsi_Tape *tpnt;
        int i, mode;
-       unsigned long flags;
 
-       write_lock_irqsave(&st_dev_arr_lock, flags);
+       write_lock(&st_dev_arr_lock);
        for (i = 0; i < st_template.dev_max; i++) {
                tpnt = scsi_tapes[i];
                if (tpnt != NULL && tpnt->device == SDp) {
@@ -3852,22 +3908,30 @@ static void st_detach(Scsi_Device * SDp)
                        SDp->attached--;
                        st_template.nr_dev--;
                        st_template.dev_noticed--;
-                       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+                       write_unlock(&st_dev_arr_lock);
                        return;
                }
        }
 
-       write_unlock_irqrestore(&st_dev_arr_lock, flags);
+       write_unlock(&st_dev_arr_lock);
        return;
 }
 
-
 static int __init init_st(void)
 {
        validate_options();
 
-       st_template.module = THIS_MODULE;
-        return scsi_register_device(&st_template);
+       printk(KERN_INFO
+               "st: Version %s, bufsize %d, wrt %d, "
+               "max init. bufs %d, s/g segs %d\n",
+               verstr, st_buffer_size, st_write_threshold,
+               st_max_buffers, st_max_sg_segs);
+
+       if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
+               return scsi_register_device(&st_template);
+
+       printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
+       return 1;
 }
 
 static void __exit exit_st(void)
@@ -3876,7 +3940,6 @@ static void __exit exit_st(void)
 
        scsi_unregister_device(&st_template);
        devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-       st_registered--;
        if (scsi_tapes != NULL) {
                for (i=0; i < st_template.dev_max; ++i)
                        if (scsi_tapes[i])
index 2ffb381fcb08498910496050ee3dd28e3c22c771..7fcd055b598103f4038036610de0adc2ffc8173e 100644 (file)
@@ -83,6 +83,7 @@ typedef struct {
        unsigned char cln_sense_value;
        unsigned char cln_sense_mask;
        unsigned char use_pf;                   /* Set Page Format bit in all mode selects? */
+       unsigned char c_algo;                   /* compression algorithm */
        int tape_type;
        int write_threshold;
        int timeout;            /* timeout for normal commands */
index 846e299178597b6148566a4d5a78fcea70d35421..325bd3cb5c1efcb0975b09d09b7eb0978da0df27 100644 (file)
@@ -3,7 +3,7 @@
 
    Copyright 1995-2000 Kai Makisara.
 
-   Last modified: Sat Apr 22 14:47:02 2000 by makisara@kai.makisara.local
+   Last modified: Tue Jan 22 21:52:34 2002 by makisara
 */
 
 #ifndef _ST_OPTIONS_H
@@ -99,5 +99,7 @@
    The default is BSD semantics. */
 #define ST_SYSV 0
 
+/* Time to wait for the drive to become ready if blocking open */
+#define ST_BLOCK_SECONDS     120
 
 #endif
index 35574d752c55415ad66483bd2f3162e012d96d44..0b7fefb3694390c1b001b6aea23b9e2999d011a8 100644 (file)
@@ -1440,7 +1440,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
 
 static int cm_open_mixdev(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        struct cm_state *s = devs;
 
        while (s && s->dev_mixer != minor)
@@ -2190,7 +2190,7 @@ static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
 
 static int cm_open(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        struct cm_state *s = devs;
        unsigned char fmtm = ~0, fmts = 0;
 
@@ -2445,7 +2445,7 @@ static unsigned int cm_midi_poll(struct file *file, struct poll_table_struct *wa
 
 static int cm_midi_open(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        struct cm_state *s = devs;
        unsigned long flags;
 
@@ -2662,7 +2662,7 @@ static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cm
 
 static int cm_dmfm_open(struct inode *inode, struct file *file)
 {
-       int minor = MINOR(inode->i_rdev);
+       int minor = minor(inode->i_rdev);
        struct cm_state *s = devs;
 
        while (s && s->dev_dmfm != minor)
@@ -2861,7 +2861,9 @@ void initialize_chip(struct pci_dev *pcidev)
        struct cm_state *s;
        mm_segment_t fs;
        int i, val;
+#if defined(CONFIG_SOUND_CMPCI_MIDI) || defined(CONFIG_SOUND_CMPCI_FM)
        unsigned char reg_mask = 0;
+#endif
        struct {
                unsigned short  deviceid;
                char            *devicename;
index 209c40f612f30a5de6b099771f5396be35b83c7a..0b372c81047f003fddc3fc13cdd3d816b6bcc037 100644 (file)
@@ -832,7 +832,14 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
        u32 lpfK = ymfpci_calc_lpfK(rate);
        ymfpci_playback_bank_t *bank;
        int nbank;
-       unsigned le_0x40000000 = cpu_to_le32(0x40000000);
+
+       /*
+        * The gain is a floating point number. According to the manual,
+        * bit 31 indicates a sign bit, bit 30 indicates an integer part,
+        * and bits [29:15] indicate a decimal fraction part. Thus,
+        * for a gain of 1.0 the constant of 0x40000000 is loaded.
+        */
+       unsigned default_gain = cpu_to_le32(0x40000000);
 
        format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
        if (stereo)
@@ -847,7 +854,7 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
                bank->loop_start = 0;
                bank->loop_end = cpu_to_le32(end);
                bank->loop_frac = 0;
-               bank->eg_gain_end = le_0x40000000;
+               bank->eg_gain_end = default_gain;
                bank->lpfQ = cpu_to_le32(lpfQ);
                bank->status = 0;
                bank->num_of_frames = 0;
@@ -858,7 +865,7 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
                bank->delta_end = cpu_to_le32(delta);
                bank->lpfK =
                bank->lpfK_end = cpu_to_le32(lpfK);
-               bank->eg_gain = le_0x40000000;
+               bank->eg_gain = default_gain;
                bank->lpfD1 =
                bank->lpfD2 = 0;
 
@@ -878,31 +885,31 @@ static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
                                bank->left_gain = 
                                bank->right_gain =
                                bank->left_gain_end =
-                               bank->right_gain_end = le_0x40000000;
+                               bank->right_gain_end = default_gain;
                        } else {
                                bank->eff2_gain =
                                bank->eff2_gain_end =
                                bank->eff3_gain =
-                               bank->eff3_gain_end = le_0x40000000;
+                               bank->eff3_gain_end = default_gain;
                        }
                } else {
                        if (!spdif) {
                                if ((voice->number & 1) == 0) {
                                        bank->left_gain =
-                                       bank->left_gain_end = le_0x40000000;
+                                       bank->left_gain_end = default_gain;
                                } else {
                                        bank->format |= cpu_to_le32(1);
                                        bank->right_gain =
-                                       bank->right_gain_end = le_0x40000000;
+                                       bank->right_gain_end = default_gain;
                                }
                        } else {
                                if ((voice->number & 1) == 0) {
                                        bank->eff2_gain =
-                                       bank->eff2_gain_end = le_0x40000000;
+                                       bank->eff2_gain_end = default_gain;
                                } else {
                                        bank->format |= cpu_to_le32(1);
                                        bank->eff3_gain =
-                                       bank->eff3_gain_end = le_0x40000000;
+                                       bank->eff3_gain_end = default_gain;
                                }
                        }
                }
index 36965ed83710ef03a02c3b25335515e6ac73686c..066170aabe2e37c63b983c6efb0b82ec96d52fde 100644 (file)
@@ -236,6 +236,8 @@ void __init tc_init(void)
        }
 }
 
+subsys_initcall(tc_init);
+
 EXPORT_SYMBOL(search_tc_card);
 EXPORT_SYMBOL(claim_tc_card);
 EXPORT_SYMBOL(release_tc_card);
index f8eda80f0d45153b91772253e8ecf077d645f9cf..defae1cd4a724c67d85814bd6d73f689284a6280 100644 (file)
@@ -125,14 +125,14 @@ static void read_bulk_callback( struct urb *urb )
 
 goon:
        // Prep the USB to wait for another frame
-       FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+       FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
                        usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
                        ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
                        read_bulk_callback, ether_dev );
                        
        // Give this to the USB subsystem so it can tell us 
        // when more data arrives.
-       if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {
+       if ( (res = usb_submit_urb(ether_dev->rx_urb)) ) {
                warn( __FUNCTION__ " failed submint rx_urb %d", res);
        }
        
@@ -259,8 +259,8 @@ static void CDCEther_tx_timeout( struct net_device *net )
        warn("%s: Tx timed out.", net->name);
        
        // Tear the waiting frame off the list
-       ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-       usb_unlink_urb( &ether_dev->tx_urb );
+       ether_dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+       usb_unlink_urb( ether_dev->tx_urb );
        
        // Update statistics
        ether_dev->stats.tx_errors++;
@@ -293,16 +293,16 @@ static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net )
        memcpy(ether_dev->tx_buff, skb->data, skb->len);
 
        // Fill in the URB for shipping it out.
-       FILL_BULK_URB( &ether_dev->tx_urb, ether_dev->usb,
+       FILL_BULK_URB( ether_dev->tx_urb, ether_dev->usb,
                        usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out),
                        ether_dev->tx_buff, ether_dev->wMaxSegmentSize, 
                        write_bulk_callback, ether_dev );
 
        // Tell the URB how much it will be transporting today
-       ether_dev->tx_urb.transfer_buffer_length = count;
+       ether_dev->tx_urb->transfer_buffer_length = count;
        
        // Send the URB on its merry way.
-       if ((res = usb_submit_urb(&ether_dev->tx_urb)))  {
+       if ((res = usb_submit_urb(ether_dev->tx_urb)))  {
                // Hmm...  It didn't go. Tell someone...
                warn("failed tx_urb %d", res);
                // update some stats...
@@ -344,13 +344,13 @@ static int CDCEther_open(struct net_device *net)
        }
 
        // Prep a receive URB
-       FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+       FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
                        usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
                        ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
                        read_bulk_callback, ether_dev );
 
        // Put it out there so the device can send us stuff
-       if ( (res = usb_submit_urb(&ether_dev->rx_urb)) )
+       if ( (res = usb_submit_urb(ether_dev->rx_urb)) )
        {
                // Hmm...  Okay...
                warn( __FUNCTION__ " failed rx_urb %d", res );
@@ -383,9 +383,9 @@ static int CDCEther_close( struct net_device *net )
        }
 
        // We don't need the URBs anymore.
-       usb_unlink_urb( &ether_dev->rx_urb );
-       usb_unlink_urb( &ether_dev->tx_urb );
-       usb_unlink_urb( &ether_dev->intr_urb );
+       usb_unlink_urb( ether_dev->rx_urb );
+       usb_unlink_urb( ether_dev->tx_urb );
+       usb_unlink_urb( ether_dev->intr_urb );
        
        // That's it.  I'm done.
        return 0;
@@ -1144,6 +1144,25 @@ static void * CDCEther_probe( struct usb_device *usb, unsigned int ifnum,
        // Zero everything out.
        memset(ether_dev, 0, sizeof(ether_dev_t));
 
+       ether_dev->rx_urb = usb_alloc_urb(0);
+       if (!ether_dev->rx_urb) {
+               kfree(ether_dev);
+               return NULL;
+       }
+       ether_dev->tx_urb = usb_alloc_urb(0);
+       if (!ether_dev->tx_urb) {
+               usb_free_urb(ether_dev->rx_urb);
+               kfree(ether_dev);
+               return NULL;
+       }
+       ether_dev->intr_urb = usb_alloc_urb(0);
+       if (!ether_dev->intr_urb) {
+               usb_free_urb(ether_dev->tx_urb);
+               usb_free_urb(ether_dev->rx_urb);
+               kfree(ether_dev);
+               return NULL;
+       }
+
        // Let's see if we can find a configuration we can use.
        rc = find_valid_configuration( usb, ether_dev );
        if (rc) {
@@ -1290,6 +1309,9 @@ static void CDCEther_disconnect( struct usb_device *usb, void *ptr )
                                      &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) );
 
        // No more tied up kernel memory
+       usb_free_urb(ether_dev->intr_urb);
+       usb_free_urb(ether_dev->rx_urb);
+       usb_free_urb(ether_dev->rx_urb);
        kfree( ether_dev );
        
        // This does no good, but it looks nice!
index 068a0147b635988301724cbcc23b7f9f10b345f1..e91c2115ac3a9c4af4d1f56193a1d20bf4257189 100644 (file)
@@ -83,7 +83,7 @@ typedef struct _ether_dev_t {
        __u16                   wNumberMCFilters;
        __u8                    bNumberPowerFilters;
        int                     intr_interval;
-       struct urb              rx_urb, tx_urb, intr_urb;
+       struct urb              *rx_urb, *tx_urb, *intr_urb;
        unsigned char           ALIGN(rx_buff[CDC_ETHER_MAX_MTU]);
        unsigned char           ALIGN(tx_buff[CDC_ETHER_MAX_MTU]);
        unsigned char           ALIGN(intr_buff[8]);
index 281b769fddf11343491c301ec085f5b1e8307aac..a1d11494233ec3edd79c23796c01163c58f31a8d 100644 (file)
@@ -297,12 +297,12 @@ struct usb_audio_state;
 #define FLG_CONNECTED    32
 
 struct my_data_urb {
-       struct urb urb;
+       struct urb *urb;
        struct usb_iso_packet_descriptor isoframe[DESCFRAMES];
 };
 
 struct my_sync_urb {
-       struct urb urb;
+       struct urb *urb;
        struct usb_iso_packet_descriptor isoframe[SYNCFRAMES];
 };
 
@@ -648,27 +648,27 @@ static void usbin_stop(struct usb_audiodev *as)
                spin_unlock_irqrestore(&as->lock, flags);
                if (notkilled && signal_pending(current)) {
                        if (i & FLG_URB0RUNNING)
-                               usb_unlink_urb(&u->durb[0].urb);
+                               usb_unlink_urb(u->durb[0].urb);
                        if (i & FLG_URB1RUNNING)
-                               usb_unlink_urb(&u->durb[1].urb);
+                               usb_unlink_urb(u->durb[1].urb);
                        if (i & FLG_SYNC0RUNNING)
-                               usb_unlink_urb(&u->surb[0].urb);
+                               usb_unlink_urb(u->surb[0].urb);
                        if (i & FLG_SYNC1RUNNING)
-                               usb_unlink_urb(&u->surb[1].urb);
+                               usb_unlink_urb(u->surb[1].urb);
                        notkilled = 0;
                }
        }
        set_current_state(TASK_RUNNING);
-       if (u->durb[0].urb.transfer_buffer)
-               kfree(u->durb[0].urb.transfer_buffer);
-       if (u->durb[1].urb.transfer_buffer)
-               kfree(u->durb[1].urb.transfer_buffer);
-       if (u->surb[0].urb.transfer_buffer)
-               kfree(u->surb[0].urb.transfer_buffer);
-       if (u->surb[1].urb.transfer_buffer)
-               kfree(u->surb[1].urb.transfer_buffer);
-       u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
-               u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+       if (u->durb[0].urb->transfer_buffer)
+               kfree(u->durb[0].urb->transfer_buffer);
+       if (u->durb[1].urb->transfer_buffer)
+               kfree(u->durb[1].urb->transfer_buffer);
+       if (u->surb[0].urb->transfer_buffer)
+               kfree(u->surb[0].urb->transfer_buffer);
+       if (u->surb[1].urb->transfer_buffer)
+               kfree(u->surb[1].urb->transfer_buffer);
+       u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
+               u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
 
 static inline void usbin_release(struct usb_audiodev *as)
@@ -904,9 +904,9 @@ static void usbin_completed(struct urb *urb)
 #if 0
        printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-       if (urb == &u->durb[0].urb)
+       if (urb == u->durb[0].urb)
                mask = FLG_URB0RUNNING;
-       else if (urb == &u->durb[1].urb)
+       else if (urb == u->durb[1].urb)
                mask = FLG_URB1RUNNING;
        else {
                mask = 0;
@@ -969,9 +969,9 @@ static void usbin_sync_completed(struct urb *urb)
 #if 0
        printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-       if (urb == &u->surb[0].urb)
+       if (urb == u->surb[0].urb)
                mask = FLG_SYNC0RUNNING;
-       else if (urb == &u->surb[1].urb)
+       else if (urb == u->surb[1].urb)
                mask = FLG_SYNC1RUNNING;
        else {
                mask = 0;
@@ -1017,26 +1017,26 @@ static int usbin_start(struct usb_audiodev *as)
                u->phase = 0;
                maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
                bufsz = DESCFRAMES * maxsze;
-               if (u->durb[0].urb.transfer_buffer)
-                       kfree(u->durb[0].urb.transfer_buffer);
-               u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[0].urb.transfer_buffer_length = bufsz;
-               if (u->durb[1].urb.transfer_buffer)
-                       kfree(u->durb[1].urb.transfer_buffer);
-               u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[1].urb.transfer_buffer_length = bufsz;
+               if (u->durb[0].urb->transfer_buffer)
+                       kfree(u->durb[0].urb->transfer_buffer);
+               u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+               u->durb[0].urb->transfer_buffer_length = bufsz;
+               if (u->durb[1].urb->transfer_buffer)
+                       kfree(u->durb[1].urb->transfer_buffer);
+               u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+               u->durb[1].urb->transfer_buffer_length = bufsz;
                if (u->syncpipe) {
-                       if (u->surb[0].urb.transfer_buffer)
-                               kfree(u->surb[0].urb.transfer_buffer);
-                       u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
-                       if (u->surb[1].urb.transfer_buffer)
-                               kfree(u->surb[1].urb.transfer_buffer);
-                       u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
-               }
-               if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
-                   (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+                       if (u->surb[0].urb->transfer_buffer)
+                               kfree(u->surb[0].urb->transfer_buffer);
+                       u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+                       u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+                       if (u->surb[1].urb->transfer_buffer)
+                               kfree(u->surb[1].urb->transfer_buffer);
+                       u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+                       u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
+               }
+               if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
+                   (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
                        printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
                        return 0;
                }
@@ -1048,7 +1048,7 @@ static int usbin_start(struct usb_audiodev *as)
        }
        u->flags |= FLG_RUNNING;
        if (!(u->flags & FLG_URB0RUNNING)) {
-               urb = &u->durb[0].urb;
+               urb = u->durb[0].urb;
                urb->dev = dev;
                urb->pipe = u->datapipe;
                urb->transfer_flags = USB_ISO_ASAP;
@@ -1061,7 +1061,7 @@ static int usbin_start(struct usb_audiodev *as)
                        u->flags &= ~FLG_RUNNING;
        }
        if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-               urb = &u->durb[1].urb;
+               urb = u->durb[1].urb;
                urb->dev = dev;
                urb->pipe = u->datapipe;
                urb->transfer_flags = USB_ISO_ASAP;
@@ -1075,7 +1075,7 @@ static int usbin_start(struct usb_audiodev *as)
        }
        if (u->syncpipe) {
                if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-                       urb = &u->surb[0].urb;
+                       urb = u->surb[0].urb;
                        urb->dev = dev;
                        urb->pipe = u->syncpipe;
                        urb->transfer_flags = USB_ISO_ASAP;
@@ -1089,7 +1089,7 @@ static int usbin_start(struct usb_audiodev *as)
                                u->flags &= ~FLG_RUNNING;
                }
                if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-                       urb = &u->surb[1].urb;
+                       urb = u->surb[1].urb;
                        urb->dev = dev;
                        urb->pipe = u->syncpipe;
                        urb->transfer_flags = USB_ISO_ASAP;
@@ -1125,27 +1125,27 @@ static void usbout_stop(struct usb_audiodev *as)
                spin_unlock_irqrestore(&as->lock, flags);
                if (notkilled && signal_pending(current)) {
                        if (i & FLG_URB0RUNNING)
-                               usb_unlink_urb(&u->durb[0].urb);
+                               usb_unlink_urb(u->durb[0].urb);
                        if (i & FLG_URB1RUNNING)
-                               usb_unlink_urb(&u->durb[1].urb);
+                               usb_unlink_urb(u->durb[1].urb);
                        if (i & FLG_SYNC0RUNNING)
-                               usb_unlink_urb(&u->surb[0].urb);
+                               usb_unlink_urb(u->surb[0].urb);
                        if (i & FLG_SYNC1RUNNING)
-                               usb_unlink_urb(&u->surb[1].urb);
+                               usb_unlink_urb(u->surb[1].urb);
                        notkilled = 0;
                }
        }
        set_current_state(TASK_RUNNING);
-       if (u->durb[0].urb.transfer_buffer)
-               kfree(u->durb[0].urb.transfer_buffer);
-       if (u->durb[1].urb.transfer_buffer)
-               kfree(u->durb[1].urb.transfer_buffer);
-       if (u->surb[0].urb.transfer_buffer)
-               kfree(u->surb[0].urb.transfer_buffer);
-       if (u->surb[1].urb.transfer_buffer)
-               kfree(u->surb[1].urb.transfer_buffer);
-       u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
-               u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+       if (u->durb[0].urb->transfer_buffer)
+               kfree(u->durb[0].urb->transfer_buffer);
+       if (u->durb[1].urb->transfer_buffer)
+               kfree(u->durb[1].urb->transfer_buffer);
+       if (u->surb[0].urb->transfer_buffer)
+               kfree(u->surb[0].urb->transfer_buffer);
+       if (u->surb[1].urb->transfer_buffer)
+               kfree(u->surb[1].urb->transfer_buffer);
+       u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
+               u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
 
 static inline void usbout_release(struct usb_audiodev *as)
@@ -1262,9 +1262,9 @@ static void usbout_completed(struct urb *urb)
 #if 0
        printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-       if (urb == &u->durb[0].urb)
+       if (urb == u->durb[0].urb)
                mask = FLG_URB0RUNNING;
-       else if (urb == &u->durb[1].urb)
+       else if (urb == u->durb[1].urb)
                mask = FLG_URB1RUNNING;
        else {
                mask = 0;
@@ -1334,9 +1334,9 @@ static void usbout_sync_completed(struct urb *urb)
 #if 0
        printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-       if (urb == &u->surb[0].urb)
+       if (urb == u->surb[0].urb)
                mask = FLG_SYNC0RUNNING;
-       else if (urb == &u->surb[1].urb)
+       else if (urb == u->surb[1].urb)
                mask = FLG_SYNC1RUNNING;
        else {
                mask = 0;
@@ -1382,26 +1382,26 @@ static int usbout_start(struct usb_audiodev *as)
                u->phase = 0;
                maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
                bufsz = DESCFRAMES * maxsze;
-               if (u->durb[0].urb.transfer_buffer)
-                       kfree(u->durb[0].urb.transfer_buffer);
-               u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[0].urb.transfer_buffer_length = bufsz;
-               if (u->durb[1].urb.transfer_buffer)
-                       kfree(u->durb[1].urb.transfer_buffer);
-               u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-               u->durb[1].urb.transfer_buffer_length = bufsz;
+               if (u->durb[0].urb->transfer_buffer)
+                       kfree(u->durb[0].urb->transfer_buffer);
+               u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+               u->durb[0].urb->transfer_buffer_length = bufsz;
+               if (u->durb[1].urb->transfer_buffer)
+                       kfree(u->durb[1].urb->transfer_buffer);
+               u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+               u->durb[1].urb->transfer_buffer_length = bufsz;
                if (u->syncpipe) {
-                       if (u->surb[0].urb.transfer_buffer)
-                               kfree(u->surb[0].urb.transfer_buffer);
-                       u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
-                       if (u->surb[1].urb.transfer_buffer)
-                               kfree(u->surb[1].urb.transfer_buffer);
-                       u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-                       u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
-               }
-               if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
-                   (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+                       if (u->surb[0].urb->transfer_buffer)
+                               kfree(u->surb[0].urb->transfer_buffer);
+                       u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+                       u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+                       if (u->surb[1].urb->transfer_buffer)
+                               kfree(u->surb[1].urb->transfer_buffer);
+                       u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+                       u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
+               }
+               if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
+                   (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
                        printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
                        return 0;
                }
@@ -1413,7 +1413,7 @@ static int usbout_start(struct usb_audiodev *as)
        }
                u->flags |= FLG_RUNNING;
        if (!(u->flags & FLG_URB0RUNNING)) {
-               urb = &u->durb[0].urb;
+               urb = u->durb[0].urb;
                urb->dev = dev;
                urb->pipe = u->datapipe;
                urb->transfer_flags = USB_ISO_ASAP;
@@ -1426,7 +1426,7 @@ static int usbout_start(struct usb_audiodev *as)
                        u->flags &= ~FLG_RUNNING;
        }
        if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-               urb = &u->durb[1].urb;
+               urb = u->durb[1].urb;
                urb->dev = dev;
                urb->pipe = u->datapipe;
                urb->transfer_flags = USB_ISO_ASAP;
@@ -1440,7 +1440,7 @@ static int usbout_start(struct usb_audiodev *as)
        }
        if (u->syncpipe) {
                if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-                       urb = &u->surb[0].urb;
+                       urb = u->surb[0].urb;
                        urb->dev = dev;
                        urb->pipe = u->syncpipe;
                        urb->transfer_flags = USB_ISO_ASAP;
@@ -1454,7 +1454,7 @@ static int usbout_start(struct usb_audiodev *as)
                                u->flags &= ~FLG_RUNNING;
                }
                if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-                       urb = &u->surb[1].urb;
+                       urb = u->surb[1].urb;
                        urb->dev = dev;
                        urb->pipe = u->syncpipe;
                        urb->transfer_flags = USB_ISO_ASAP;
@@ -1921,6 +1921,14 @@ static void release(struct usb_audio_state *s)
                usbout_release(as);
                dmabuf_release(&as->usbin.dma);
                dmabuf_release(&as->usbout.dma);
+               usb_free_urb(as->usbin.durb[0].urb);
+               usb_free_urb(as->usbin.durb[1].urb);
+               usb_free_urb(as->usbin.surb[0].urb);
+               usb_free_urb(as->usbin.surb[1].urb);
+               usb_free_urb(as->usbout.durb[0].urb);
+               usb_free_urb(as->usbout.durb[1].urb);
+               usb_free_urb(as->usbout.surb[0].urb);
+               usb_free_urb(as->usbout.surb[1].urb);
                kfree(as);
        }
        while (!list_empty(&s->mixerlist)) {
@@ -2821,14 +2829,33 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b
        init_waitqueue_head(&as->usbin.dma.wait);
        init_waitqueue_head(&as->usbout.dma.wait);
        spin_lock_init(&as->lock);
-       spin_lock_init(&as->usbin.durb[0].urb.lock);
-       spin_lock_init(&as->usbin.durb[1].urb.lock);
-       spin_lock_init(&as->usbin.surb[0].urb.lock);
-       spin_lock_init(&as->usbin.surb[1].urb.lock);
-       spin_lock_init(&as->usbout.durb[0].urb.lock);
-       spin_lock_init(&as->usbout.durb[1].urb.lock);
-       spin_lock_init(&as->usbout.surb[0].urb.lock);
-       spin_lock_init(&as->usbout.surb[1].urb.lock);
+       as->usbin.durb[0].urb = usb_alloc_urb(0);
+       as->usbin.durb[1].urb = usb_alloc_urb(0);
+       as->usbin.surb[0].urb = usb_alloc_urb(0);
+       as->usbin.surb[1].urb = usb_alloc_urb(0);
+       as->usbout.durb[0].urb = usb_alloc_urb(0);
+       as->usbout.durb[1].urb = usb_alloc_urb(0);
+       as->usbout.surb[0].urb = usb_alloc_urb(0);
+       as->usbout.surb[1].urb = usb_alloc_urb(0);
+       if ((!as->usbin.durb[0].urb) ||
+           (!as->usbin.durb[1].urb) ||
+           (!as->usbin.surb[0].urb) ||
+           (!as->usbin.surb[1].urb) ||
+           (!as->usbout.durb[0].urb) ||
+           (!as->usbout.durb[1].urb) ||
+           (!as->usbout.surb[0].urb) ||
+           (!as->usbout.surb[1].urb)) {
+               usb_free_urb(as->usbin.durb[0].urb);
+               usb_free_urb(as->usbin.durb[1].urb);
+               usb_free_urb(as->usbin.surb[0].urb);
+               usb_free_urb(as->usbin.surb[1].urb);
+               usb_free_urb(as->usbout.durb[0].urb);
+               usb_free_urb(as->usbout.durb[1].urb);
+               usb_free_urb(as->usbout.surb[0].urb);
+               usb_free_urb(as->usbout.surb[1].urb);
+               kfree(as);
+               return;
+       }
        as->state = s;
        as->usbin.interface = asifin;
        as->usbout.interface = asifout;
@@ -2997,11 +3024,27 @@ static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *b
                }
        }
        if (as->numfmtin == 0 && as->numfmtout == 0) {
+               usb_free_urb(as->usbin.durb[0].urb);
+               usb_free_urb(as->usbin.durb[1].urb);
+               usb_free_urb(as->usbin.surb[0].urb);
+               usb_free_urb(as->usbin.surb[1].urb);
+               usb_free_urb(as->usbout.durb[0].urb);
+               usb_free_urb(as->usbout.durb[1].urb);
+               usb_free_urb(as->usbout.surb[0].urb);
+               usb_free_urb(as->usbout.surb[1].urb);
                kfree(as);
                return;
        }
        if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
                printk(KERN_ERR "usbaudio: cannot register dsp\n");
+               usb_free_urb(as->usbin.durb[0].urb);
+               usb_free_urb(as->usbin.durb[1].urb);
+               usb_free_urb(as->usbin.surb[0].urb);
+               usb_free_urb(as->usbin.surb[1].urb);
+               usb_free_urb(as->usbout.durb[0].urb);
+               usb_free_urb(as->usbout.durb[1].urb);
+               usb_free_urb(as->usbout.surb[0].urb);
+               usb_free_urb(as->usbout.surb[1].urb);
                kfree(as);
                return;
        }
index cc14861706dbe704f797100d08d713c25b2ed1c0..0667997ff89a08fe28ec1036ce757ae0e519f40b 100644 (file)
@@ -179,7 +179,7 @@ struct catc {
                void (*callback)(struct catc *catc, struct ctrl_queue *q);
        } ctrl_queue[CTRL_QUEUE];
 
-       struct urb tx_urb, rx_urb, irq_urb, ctrl_urb;
+       struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb;
 };
 
 /*
@@ -256,8 +256,8 @@ static void catc_irq_done(struct urb *urb)
        }
 
        if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) {
-               catc->rx_urb.dev = catc->usbdev;
-               if ((status = usb_submit_urb(&catc->rx_urb)) < 0) {
+               catc->rx_urb->dev = catc->usbdev;
+               if ((status = usb_submit_urb(catc->rx_urb)) < 0) {
                        err("submit(rx_urb) status %d", status);
                        return;
                } 
@@ -282,11 +282,11 @@ static void catc_tx_run(struct catc *catc)
 {
        int status;
 
-       catc->tx_urb.transfer_buffer_length = catc->tx_ptr;
-       catc->tx_urb.transfer_buffer = catc->tx_buf[catc->tx_idx];
-       catc->tx_urb.dev = catc->usbdev;
+       catc->tx_urb->transfer_buffer_length = catc->tx_ptr;
+       catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
+       catc->tx_urb->dev = catc->usbdev;
 
-       if ((status = usb_submit_urb(&catc->tx_urb)) < 0)
+       if ((status = usb_submit_urb(catc->tx_urb)) < 0)
                err("submit(tx_urb), status %d", status);
 
        catc->tx_idx = !catc->tx_idx;
@@ -363,8 +363,8 @@ static void catc_tx_timeout(struct net_device *netdev)
        struct catc *catc = netdev->priv;
 
        warn("Transmit timed out.");
-       catc->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-       usb_unlink_urb(&catc->tx_urb);
+       catc->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+       usb_unlink_urb(catc->tx_urb);
 }
 
 /*
@@ -383,7 +383,7 @@ static void catc_ctrl_run(struct catc *catc)
 {
        struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
        struct usb_device *usbdev = catc->usbdev;
-       struct urb *urb = &catc->ctrl_urb;
+       struct urb *urb = catc->ctrl_urb;
        struct usb_ctrlrequest *dr = &catc->ctrl_dr;
        int status;
 
@@ -402,7 +402,7 @@ static void catc_ctrl_run(struct catc *catc)
        if (!q->dir && q->buf && q->len)
                memcpy(catc->ctrl_buf, q->buf, q->len);
 
-       if ((status = usb_submit_urb(&catc->ctrl_urb)))
+       if ((status = usb_submit_urb(catc->ctrl_urb)))
                err("submit(ctrl_urb) status %d", status);
 }
 
@@ -624,8 +624,8 @@ static int catc_open(struct net_device *netdev)
        struct catc *catc = netdev->priv;
        int status;
 
-       catc->irq_urb.dev = catc->usbdev;
-       if ((status = usb_submit_urb(&catc->irq_urb)) < 0) {
+       catc->irq_urb->dev = catc->usbdev;
+       if ((status = usb_submit_urb(catc->irq_urb)) < 0) {
                err("submit(irq_urb) status %d", status);
                return -1;
        }
@@ -645,10 +645,10 @@ static int catc_stop(struct net_device *netdev)
 
        del_timer_sync(&catc->timer);
 
-       usb_unlink_urb(&catc->rx_urb);
-       usb_unlink_urb(&catc->tx_urb);
-       usb_unlink_urb(&catc->irq_urb);
-       usb_unlink_urb(&catc->ctrl_urb);
+       usb_unlink_urb(catc->rx_urb);
+       usb_unlink_urb(catc->tx_urb);
+       usb_unlink_urb(catc->irq_urb);
+       usb_unlink_urb(catc->ctrl_urb);
 
        return 0;
 }
@@ -694,16 +694,26 @@ static void *catc_probe(struct usb_device *usbdev, unsigned int ifnum, const str
        catc->timer.data = (long) catc;
        catc->timer.function = catc_stats_timer;
 
-       FILL_CONTROL_URB(&catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
+       catc->ctrl_urb = usb_alloc_urb(0);
+       catc->tx_urb = usb_alloc_urb(0);
+       catc->rx_urb = usb_alloc_urb(0);
+       catc->irq_urb = usb_alloc_urb(0);
+       if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
+           (!catc->rx_urb) || (!catc->irq_urb)) {
+               err("No free urbs available.");
+               return NULL;
+       }
+
+       FILL_CONTROL_URB(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
                NULL, NULL, 0, catc_ctrl_done, catc);
 
-       FILL_BULK_URB(&catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
+       FILL_BULK_URB(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
                NULL, 0, catc_tx_done, catc);
 
-       FILL_BULK_URB(&catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
+       FILL_BULK_URB(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
                catc->rx_buf, RX_MAX_BURST * (PKT_SZ + 2), catc_rx_done, catc);
 
-       FILL_INT_URB(&catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
+       FILL_INT_URB(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
                 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
        dbg("Checking memory size\n");
@@ -772,6 +782,10 @@ static void catc_disconnect(struct usb_device *usbdev, void *dev_ptr)
 {
        struct catc *catc = dev_ptr;
        unregister_netdev(catc->netdev);
+       usb_free_urb(catc->ctrl_urb);
+       usb_free_urb(catc->tx_urb);
+       usb_free_urb(catc->rx_urb);
+       usb_free_urb(catc->irq_urb);
        kfree(catc->netdev);
        kfree(catc);
 }
index d75364cff6fa8e7d3e159c7422eaec541a844958..c7883b37613969a6cbf32d8db78fa904646f87f1 100644 (file)
@@ -53,7 +53,7 @@ struct async {
        unsigned int signr;
        void *userbuffer;
         void *userurb;
-        struct urb urb;
+        struct urb *urb;
 };
 
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -175,17 +175,21 @@ static struct async *alloc_async(unsigned int numisoframes)
         if (!as)
                 return NULL;
         memset(as, 0, assize);
-        as->urb.number_of_packets = numisoframes;
-        spin_lock_init(&as->urb.lock);
+       as->urb = usb_alloc_urb(numisoframes);
+       if (!as->urb) {
+               kfree(as);
+               return NULL;
+       }
         return as;
 }
 
 static void free_async(struct async *as)
 {
-        if (as->urb.transfer_buffer)
-                kfree(as->urb.transfer_buffer);
-        if (as->urb.setup_packet)
-                kfree(as->urb.setup_packet);
+        if (as->urb->transfer_buffer)
+                kfree(as->urb->transfer_buffer);
+        if (as->urb->setup_packet)
+                kfree(as->urb->setup_packet);
+       usb_free_urb(as->urb);
         kfree(as);
 }
 
@@ -259,7 +263,7 @@ static void async_completed(struct urb *urb)
         wake_up(&ps->wait);
        if (as->signr) {
                sinfo.si_signo = as->signr;
-               sinfo.si_errno = as->urb.status;
+               sinfo.si_errno = as->urb->status;
                sinfo.si_code = SI_ASYNCIO;
                sinfo.si_addr = as->userurb;
                send_sig_info(as->signr, &sinfo, as->task);
@@ -278,7 +282,7 @@ static void destroy_all_async(struct dev_state *ps)
                 INIT_LIST_HEAD(&as->asynclist);
                 spin_unlock_irqrestore(&ps->lock, flags);
                 /* usb_unlink_urb calls the completion handler with status == -ENOENT */
-                usb_unlink_urb(&as->urb);
+                usb_unlink_urb(as->urb);
                 spin_lock_irqsave(&ps->lock, flags);
         }
         spin_unlock_irqrestore(&ps->lock, flags);
@@ -862,7 +866,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg)
                        kfree(dr);
                return -ENOMEM;
        }
-       if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+       if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
                if (isopkt)
                        kfree(isopkt);
                if (dr)
@@ -870,19 +874,19 @@ static int proc_submiturb(struct dev_state *ps, void *arg)
                free_async(as);
                return -ENOMEM;
        }
-        as->urb.next = NULL;
-        as->urb.dev = ps->dev;
-        as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
-        as->urb.transfer_flags = uurb.flags;
-       as->urb.transfer_buffer_length = uurb.buffer_length;
-       as->urb.setup_packet = (unsigned char*)dr;
-       as->urb.start_frame = uurb.start_frame;
-       as->urb.number_of_packets = uurb.number_of_packets;
-        as->urb.context = as;
-        as->urb.complete = async_completed;
+        as->urb->next = NULL;
+        as->urb->dev = ps->dev;
+        as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb.flags;
+       as->urb->transfer_buffer_length = uurb.buffer_length;
+       as->urb->setup_packet = (unsigned char*)dr;
+       as->urb->start_frame = uurb.start_frame;
+       as->urb->number_of_packets = uurb.number_of_packets;
+        as->urb->context = as;
+        as->urb->complete = async_completed;
        for (totlen = u = 0; u < uurb.number_of_packets; u++) {
-               as->urb.iso_frame_desc[u].offset = totlen;
-               as->urb.iso_frame_desc[u].length = isopkt[u].length;
+               as->urb->iso_frame_desc[u].offset = totlen;
+               as->urb->iso_frame_desc[u].length = isopkt[u].length;
                totlen += isopkt[u].length;
        }
        if (isopkt)
@@ -896,13 +900,13 @@ static int proc_submiturb(struct dev_state *ps, void *arg)
        as->signr = uurb.signr;
        as->task = current;
        if (!(uurb.endpoint & USB_DIR_IN)) {
-               if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
+               if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
                        free_async(as);
                        return -EFAULT;
                }
        }
         async_newpending(as);
-        if ((ret = usb_submit_urb(&as->urb))) {
+        if ((ret = usb_submit_urb(as->urb))) {
                printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
                 async_removepending(as);
                 free_async(as);
@@ -918,34 +922,35 @@ static int proc_unlinkurb(struct dev_state *ps, void *arg)
        as = async_getpending(ps, arg);
        if (!as)
                return -EINVAL;
-       usb_unlink_urb(&as->urb);
+       usb_unlink_urb(as->urb);
        return 0;
 }
 
 static int processcompl(struct async *as)
 {
+       struct urb *urb = as->urb;
        unsigned int i;
 
        if (as->userbuffer)
-               if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
+               if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
                        return -EFAULT;
-       if (put_user(as->urb.status,
+       if (put_user(urb->status,
                     &((struct usbdevfs_urb *)as->userurb)->status))
                return -EFAULT;
-       if (put_user(as->urb.actual_length,
+       if (put_user(urb->actual_length,
                     &((struct usbdevfs_urb *)as->userurb)->actual_length))
                return -EFAULT;
-       if (put_user(as->urb.error_count,
+       if (put_user(urb->error_count,
                     &((struct usbdevfs_urb *)as->userurb)->error_count))
                return -EFAULT;
 
-       if (!(usb_pipeisoc(as->urb.pipe)))
+       if (!(usb_pipeisoc(urb->pipe)))
                return 0;
-       for (i = 0; i < as->urb.number_of_packets; i++) {
-               if (put_user(as->urb.iso_frame_desc[i].actual_length, 
+       for (i = 0; i < urb->number_of_packets; i++) {
+               if (put_user(urb->iso_frame_desc[i].actual_length, 
                             &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
                        return -EFAULT;
-               if (put_user(as->urb.iso_frame_desc[i].status, 
+               if (put_user(urb->iso_frame_desc[i].status, 
                             &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
                        return -EFAULT;
        }
index 406249ea1a428696bb5bba9c2b27d98c7de4e0ee..0a5a98173e894641f440d34b3fd865be6f88bab2 100644 (file)
@@ -90,7 +90,7 @@ static int radio_nr = -1;
 MODULE_PARM(radio_nr, "i");
 
 typedef struct
-{      struct urb readurb,writeurb;
+{
        struct usb_device *dev;
        unsigned char transfer_buffer[TB_LEN];
        int curfreq;
index e771ff6d0d4e31a6aff7e68df1ab660a70a52718..37cae7f9ce4251b5430a0f58bbdacbabfd4b8613 100644 (file)
@@ -56,8 +56,17 @@ hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
                return NULL;
        DEBUG ("Allocated memory\n");
        memset (new, 0, sizeof (struct hpusbscsi));
-       spin_lock_init (&new->dataurb.lock);
-       spin_lock_init (&new->controlurb.lock);
+       new->dataurb = usb_alloc_urb(0);
+       if (!new->dataurb) {
+               kfree (new);
+               return NULL;
+       }
+       new->controlurb = usb_alloc_urb(0);
+       if (!new->controlurb) {
+               usb_free_urb (new->dataurb);
+               kfree (new);
+               return NULL;
+       }
        new->dev = dev;
        init_waitqueue_head (&new->pending);
        init_waitqueue_head (&new->deathrow);
@@ -126,6 +135,8 @@ hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
        return new;
 
       err_out:
+       usb_free_urb (new->controlurb);
+       usb_free_urb (new->dataurb);
        kfree (new);
        return NULL;
 }
@@ -133,7 +144,7 @@ hpusbscsi_usb_probe (struct usb_device *dev, unsigned int interface,
 static void
 hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
 {
-                 usb_unlink_urb(&(((struct hpusbscsi *) ptr)->controlurb));
+                 usb_unlink_urb((((struct hpusbscsi *) ptr)->controlurb));
        ((struct hpusbscsi *) ptr)->dev = NULL;
 }
 
@@ -184,8 +195,10 @@ hpusbscsi_exit (void)
                old = tmp;
                tmp = tmp->next;
                o = (struct hpusbscsi *)old;
-               usb_unlink_urb(&o->controlurb);
+               usb_unlink_urb(o->controlurb);
                scsi_unregister_host(&o->ctempl);
+               usb_free_urb(o->controlurb);
+               usb_free_urb(o->dataurb);
                kfree(old);
        }
 
@@ -222,7 +235,7 @@ hpusbscsi_scsi_detect (struct SHT *sht)
        sht->proc_dir = NULL;
 
        /* build and submit an interrupt URB for status byte handling */
-       FILL_INT_URB(&desc->controlurb,
+       FILL_INT_URB(desc->controlurb,
                        desc->dev,
                        usb_rcvintpipe(desc->dev,desc->ep_int),
                        &desc->scsi_state_byte,
@@ -232,7 +245,7 @@ hpusbscsi_scsi_detect (struct SHT *sht)
                        desc->interrupt_interval
        );
 
-       if ( 0  >  usb_submit_urb(&desc->controlurb)) {
+       if ( 0  >  usb_submit_urb(desc->controlurb)) {
                kfree(sht->proc_name);
                return 0;
        }
@@ -241,7 +254,7 @@ hpusbscsi_scsi_detect (struct SHT *sht)
        desc->host = scsi_register (sht, sizeof (desc));
        if (desc->host == NULL) {
                kfree (sht->proc_name);
-               usb_unlink_urb(&desc->controlurb);
+               usb_unlink_urb(desc->controlurb);
                return 0;
        }
        desc->host->hostdata[0] = (unsigned long) desc;
@@ -297,7 +310,7 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
 
        /* We prepare the urb for writing out the scsi command */
        FILL_BULK_URB(
-               &hpusbscsi->dataurb,
+               hpusbscsi->dataurb,
                hpusbscsi->dev,
                usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
                srb->cmnd,
@@ -308,7 +321,7 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
        hpusbscsi->scallback = callback;
        hpusbscsi->srb = srb;
 
-       res = usb_submit_urb(&hpusbscsi->dataurb);
+       res = usb_submit_urb(hpusbscsi->dataurb);
        if (unlikely(res)) {
                hpusbscsi->state = HP_STATE_FREE;
                TRACE_STATE;
@@ -340,8 +353,8 @@ static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
        struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
        printk(KERN_DEBUG"Requested is canceled.\n");
 
-       usb_unlink_urb(&hpusbscsi->dataurb);
-       usb_unlink_urb(&hpusbscsi->controlurb);
+       usb_unlink_urb(hpusbscsi->dataurb);
+       usb_unlink_urb(hpusbscsi->controlurb);
        hpusbscsi->state = HP_STATE_FREE;
 
        return SCSI_ABORT_PENDING;
index 0daa39708437c5aa4565b6f91a5c8102ece5f72f..30d0524a788ed7367d7411daa3fe3be75d47d1bd 100644 (file)
@@ -26,8 +26,8 @@ struct hpusbscsi
         wait_queue_head_t pending;
         wait_queue_head_t deathrow;
 
-        struct urb dataurb;
-        struct urb controlurb;
+        struct urb *dataurb;
+        struct urb *controlurb;
         int fragment;
 
         int state;
index a73a209dc971384fcbb8deee56991bb5bd3b5725..53716ae850e5143cb52eecab740cc02d1fb37e3a 100644 (file)
@@ -678,6 +678,8 @@ void usbfs_remove_bus(struct usb_bus *bus)
 void usbfs_add_device(struct usb_device *dev)
 {
        char name[8];
+       int i;
+       int i_size;
 
        sprintf (name, "%03d", dev->devnum);
        dev->dentry = fs_create_file (name,
@@ -688,6 +690,17 @@ void usbfs_add_device(struct usb_device *dev)
        if (dev->dentry == NULL)
                return;
 
+       /* Set the size of the device's file to be
+        * equal to the size of the device descriptors. */
+       i_size = sizeof (struct usb_device_descriptor);
+       for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
+               struct usb_config_descriptor *config =
+                       (struct usb_config_descriptor *)dev->rawdescriptors[i];
+               i_size += le16_to_cpu (config->wTotalLength);
+       }
+       if (dev->dentry->d_inode)
+               dev->dentry->d_inode->i_size = i_size;
+
        usbfs_update_special();
        usbdevfs_conn_disc_event();
 }
index ba056f1ed6b24976011e4f9578e70e95d10d70d6..83d325608f57f55908619e9c1ddc1949d5cb7e05 100644 (file)
@@ -324,7 +324,7 @@ static inline void mts_urb_abort(struct mts_desc* desc) {
        MTS_DEBUG_GOT_HERE();
        mts_debug_dump(desc);
 
-       usb_unlink_urb( &desc->urb );
+       usb_unlink_urb( desc->urb );
 }
 
 static struct mts_desc * mts_list; /* list of active scanners */
@@ -365,6 +365,7 @@ void mts_remove_nolock( struct mts_desc* to_remove )
        scsi_unregister_host(&to_remove->ctempl);
        unlock_kernel();
 
+       usb_free_urb(to_remove->urb);
        kfree( to_remove );
 }
 
@@ -705,7 +706,7 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
        }
 
        
-       FILL_BULK_URB(&desc->urb,
+       FILL_BULK_URB(desc->urb,
                      desc->usb_dev,
                      usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
                      srb->cmnd,
@@ -718,7 +719,7 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
        mts_build_transfer_context( srb, desc );
        desc->context.final_callback = callback;
        
-       res=usb_submit_urb(&desc->urb);
+       res=usb_submit_urb(desc->urb);
 
        if(unlikely(res)){
                MTS_ERROR("error %d submitting URB\n",(int)res);
@@ -932,10 +933,12 @@ static void * mts_usb_probe (struct usb_device *dev, unsigned int interface,
                return NULL;
        }
 
-       /* As done by usb_alloc_urb */
        memset( new_desc, 0, sizeof(*new_desc) );
-       spin_lock_init(&new_desc->urb.lock);
-       
+       new_desc->urb = usb_alloc_urb(0);
+       if (!new_desc->urb) {
+               kfree(new_desc);
+               return NULL;
+       }
                
        /* initialising that descriptor */
        new_desc->usb_dev = dev;
index c5d3f174bf1a4a6d977dc7c3a2ace432c6a9f1f5..7ab7cb3f206285ce16e2dda73c4eaef1d37610b6 100644 (file)
@@ -46,7 +46,7 @@ struct mts_desc {
 
        struct semaphore lock;
 
-       struct urb urb;
+       struct urb *urb;
        struct mts_transfer_context context;
 };
 
index ce187fb485bdf0cde2679802311e6dcd72354ec4..ef89fc6a8fa7e6c6c92301ccb87d2747c6322990 100644 (file)
@@ -147,9 +147,9 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
        pegasus->dr.wValue = cpu_to_le16 (0);
        pegasus->dr.wIndex = cpu_to_le16p(&indx);
        pegasus->dr.wLength = cpu_to_le16p(&size);
-       pegasus->ctrl_urb.transfer_buffer_length = size;
+       pegasus->ctrl_urb->transfer_buffer_length = size;
 
-       FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+       FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
                          usb_rcvctrlpipe(pegasus->usb,0),
                          (char *)&pegasus->dr,
                          buffer, size, ctrl_callback, pegasus );
@@ -157,7 +157,7 @@ static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
        add_wait_queue( &pegasus->ctrl_wait, &wait );
        set_current_state( TASK_UNINTERRUPTIBLE );
 
-       if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+       if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
                err( __FUNCTION__ " BAD CTRLs %d", ret);
                goto out;
        }
@@ -197,9 +197,9 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
        pegasus->dr.wValue = cpu_to_le16 (0);
        pegasus->dr.wIndex = cpu_to_le16p( &indx );
        pegasus->dr.wLength = cpu_to_le16p( &size );
-       pegasus->ctrl_urb.transfer_buffer_length = size;
+       pegasus->ctrl_urb->transfer_buffer_length = size;
 
-       FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+       FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
                          usb_sndctrlpipe(pegasus->usb,0),
                          (char *)&pegasus->dr,
                          buffer, size, ctrl_callback, pegasus );
@@ -207,7 +207,7 @@ static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
        add_wait_queue( &pegasus->ctrl_wait, &wait );
        set_current_state( TASK_UNINTERRUPTIBLE );
 
-       if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+       if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
                err( __FUNCTION__ " BAD CTRL %d", ret);
                goto out;
        }
@@ -247,9 +247,9 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
        pegasus->dr.wValue = cpu_to_le16p( &dat);
        pegasus->dr.wIndex = cpu_to_le16p( &indx );
        pegasus->dr.wLength = cpu_to_le16( 1 );
-       pegasus->ctrl_urb.transfer_buffer_length = 1;
+       pegasus->ctrl_urb->transfer_buffer_length = 1;
 
-       FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+       FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
                          usb_sndctrlpipe(pegasus->usb,0),
                          (char *)&pegasus->dr,
                          buffer, 1, ctrl_callback, pegasus );
@@ -257,7 +257,7 @@ static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
        add_wait_queue( &pegasus->ctrl_wait, &wait );
        set_current_state( TASK_UNINTERRUPTIBLE );
 
-       if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+       if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
                err( __FUNCTION__ " BAD CTRL %d", ret);
                goto out;
        }
@@ -280,14 +280,14 @@ static int update_eth_regs_async( pegasus_t *pegasus )
        pegasus->dr.wValue = 0;
        pegasus->dr.wIndex =  cpu_to_le16(EthCtrl0);
        pegasus->dr.wLength = cpu_to_le16(3);
-       pegasus->ctrl_urb.transfer_buffer_length = 3;
+       pegasus->ctrl_urb->transfer_buffer_length = 3;
 
-       FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+       FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
                          usb_sndctrlpipe(pegasus->usb,0),
                          (char *)&pegasus->dr,
                          pegasus->eth_regs, 3, ctrl_callback, pegasus );
 
-       if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
+       if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
                err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags );
 
        return  ret;
@@ -569,11 +569,11 @@ static void read_bulk_callback( struct urb *urb )
        pegasus->stats.rx_bytes += pkt_len;
 
 goon:
-       FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+       FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
                        usb_rcvbulkpipe(pegasus->usb, 1),
                        pegasus->rx_buff, PEGASUS_MAX_MTU, 
                        read_bulk_callback, pegasus );
-       if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+       if ( (res = usb_submit_urb(pegasus->rx_urb)) )
                warn( __FUNCTION__ " failed submint rx_urb %d", res);
        pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
@@ -639,8 +639,8 @@ static void pegasus_tx_timeout( struct net_device *net )
                return;
                
        warn("%s: Tx timed out.", net->name);
-       pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-       usb_unlink_urb( &pegasus->tx_urb );
+       pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+       usb_unlink_urb( pegasus->tx_urb );
        pegasus->stats.tx_errors++;
 }
 
@@ -656,12 +656,12 @@ static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
                
        ((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
        memcpy(pegasus->tx_buff+2, skb->data, skb->len);
-       FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb,
+       FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
                        usb_sndbulkpipe(pegasus->usb, 2),
                        pegasus->tx_buff, PEGASUS_MAX_MTU, 
                        write_bulk_callback, pegasus );
-       pegasus->tx_urb.transfer_buffer_length = count;
-       if ((res = usb_submit_urb(&pegasus->tx_urb))) {
+       pegasus->tx_urb->transfer_buffer_length = count;
+       if ((res = usb_submit_urb(pegasus->tx_urb))) {
                warn("failed tx_urb %d", res);
                pegasus->stats.tx_errors++;
                netif_start_queue( net );
@@ -717,18 +717,18 @@ static int pegasus_open(struct net_device *net)
                err("can't enable_net_traffic() - %d", res);
                return -EIO;
        }
-       FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+       FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
                        usb_rcvbulkpipe(pegasus->usb, 1),
                        pegasus->rx_buff, PEGASUS_MAX_MTU, 
                        read_bulk_callback, pegasus );
-       if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+       if ( (res = usb_submit_urb(pegasus->rx_urb)) )
                warn( __FUNCTION__ " failed rx_urb %d", res );
 #ifdef PEGASUS_USE_INTR
-       FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
+       FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
                        usb_rcvintpipe(pegasus->usb, 3),
                        pegasus->intr_buff, sizeof(pegasus->intr_buff),
                        intr_callback, pegasus, pegasus->intr_interval );
-       if ( (res = usb_submit_urb(&pegasus->intr_urb)) )
+       if ( (res = usb_submit_urb(pegasus->intr_urb)) )
                warn( __FUNCTION__ " failed intr_urb %d", res);
 #endif
        netif_start_queue( net );
@@ -747,11 +747,11 @@ static int pegasus_close( struct net_device *net )
        if ( !(pegasus->flags & PEGASUS_UNPLUG) )
                disable_net_traffic( pegasus );
 
-       usb_unlink_urb( &pegasus->rx_urb );
-       usb_unlink_urb( &pegasus->tx_urb );
-       usb_unlink_urb( &pegasus->ctrl_urb );
+       usb_unlink_urb( pegasus->rx_urb );
+       usb_unlink_urb( pegasus->tx_urb );
+       usb_unlink_urb( pegasus->ctrl_urb );
 #ifdef PEGASUS_USE_INTR
-       usb_unlink_urb( &pegasus->intr_urb );
+       usb_unlink_urb( pegasus->intr_urb );
 #endif
 
        return 0;
@@ -800,7 +800,7 @@ static void pegasus_set_multicast( struct net_device *net )
        }
 
        pegasus->flags |= ETH_REGS_CHANGE;
-       ctrl_callback( &pegasus->ctrl_urb );
+       ctrl_callback( pegasus->ctrl_urb );
 
        netif_wake_queue(net);
 }
@@ -856,6 +856,33 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
        pegasus->dev_index = dev_index;
        init_waitqueue_head( &pegasus->ctrl_wait );
 
+       pegasus->ctrl_urb = usb_alloc_urb(0);
+       if (!pegasus->ctrl_urb) {
+               kfree (pegasus);
+               return NULL;
+       }
+       pegasus->rx_urb = usb_alloc_urb(0);
+       if (!pegasus->rx_urb) {
+               usb_free_urb (pegasus->ctrl_urb);
+               kfree (pegasus);
+               return NULL;
+       }
+       pegasus->tx_urb = usb_alloc_urb(0);
+       if (!pegasus->tx_urb) {
+               usb_free_urb (pegasus->rx_urb);
+               usb_free_urb (pegasus->ctrl_urb);
+               kfree (pegasus);
+               return NULL;
+       }
+       pegasus->intr_urb = usb_alloc_urb(0);
+       if (!pegasus->intr_urb) {
+               usb_free_urb (pegasus->tx_urb);
+               usb_free_urb (pegasus->rx_urb);
+               usb_free_urb (pegasus->ctrl_urb);
+               kfree (pegasus);
+               return NULL;
+       }
+
        net = init_etherdev( NULL, 0 );
        if ( !net ) {
                kfree( pegasus );
@@ -883,6 +910,7 @@ static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,
        if ( reset_mac(pegasus) ) {
                err("can't reset MAC");
                unregister_netdev( pegasus->net );
+               kfree(pegasus->net);
                kfree(pegasus);
                pegasus = NULL;
                return NULL;
@@ -919,6 +947,11 @@ static void pegasus_disconnect( struct usb_device *dev, void *ptr )
        pegasus->flags |= PEGASUS_UNPLUG;
        unregister_netdev( pegasus->net );
        usb_dec_dev_use( dev );
+       usb_free_urb (pegasus->intr_urb);
+       usb_free_urb (pegasus->tx_urb);
+       usb_free_urb (pegasus->rx_urb);
+       usb_free_urb (pegasus->ctrl_urb);
+       kfree( pegasus->net );
        kfree( pegasus );
        pegasus = NULL;
 }
index ccb80c2d3075719b0c7f715b62844f12f35e8c52..0b4f8231943f3374e5ddaa6af935d80125d2d63e 100644 (file)
@@ -107,7 +107,7 @@ typedef struct pegasus {
        unsigned                features;
        int                     dev_index;
        int                     intr_interval;
-       struct urb              ctrl_urb, rx_urb, tx_urb, intr_urb;
+       struct urb              *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
        struct usb_ctrlrequest  dr;
        wait_queue_head_t       ctrl_wait;
        struct semaphore        ctrl_sem;
@@ -145,6 +145,7 @@ struct usb_eth_dev {
 #define        VENDOR_SMARTBRIDGES     0x08d1
 #define        VENDOR_SMC              0x0707
 #define        VENDOR_SOHOWARE         0x15e8
+#define        VENDOR_SIEMENS          0x067c
 
 
 #else  /* PEGASUS_DEV */
@@ -173,6 +174,8 @@ PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
                DEFAULT_GPIO_RESET | PEGASUS_II )       
 PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
                DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
+               DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
                VENDOR_ADMTEK, 0x8511,
                DEFAULT_GPIO_RESET | PEGASUS_II )
@@ -245,6 +248,8 @@ PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
                DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
                DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
+               DEFAULT_GPIO_RESET )
 
 
 #endif /* PEGASUS_DEV */
index 4c147cf50ad0e56f51463f635297428a7dd35d9e..8dac42ff26c5551f3ef32b08484eb030417e7e5e 100644 (file)
@@ -972,6 +972,13 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
        }
        memset (scn, 0, sizeof(struct scn_usb_data));
 
+       scn->scn_irq = usb_alloc_urb(0);
+       if (!scn->scn_irq) {
+               kfree(scn);
+               up(&scn_mutex);
+               return NULL;
+       }
+
        init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
 
        dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
@@ -979,13 +986,13 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
 /* Ok, if we detected an interrupt EP, setup a handler for it */
        if (have_intr) {
                dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
-               FILL_INT_URB(&scn->scn_irq, dev,
+               FILL_INT_URB(scn->scn_irq, dev,
                             usb_rcvintpipe(dev, have_intr),
                             &scn->button, 1, irq_scanner, scn,
                             // endpoint[(int)have_intr].bInterval);
                             250);
 
-               if (usb_submit_urb(&scn->scn_irq)) {
+               if (usb_submit_urb(scn->scn_irq)) {
                        err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
                        kfree(scn);
                        up(&scn_mutex);
@@ -1067,7 +1074,7 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
 
        if(scn->intr_ep) {
                dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
-               usb_unlink_urb(&scn->scn_irq);
+               usb_unlink_urb(scn->scn_irq);
        }
         usb_driver_release_interface(&scanner_driver,
                 &scn->scn_dev->actconfig->interface[scn->ifnum]);
@@ -1078,6 +1085,7 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
        dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
        devfs_unregister(scn->devfs);
        p_scn_table[scn->scn_minor] = NULL;
+       usb_free_urb(scn->scn_irq);
        up (&(scn->sem));
        kfree (scn);
        up (&scn_mutex);
index eb899bb4d36156503e9813904e5965f26ded3058..be6c26ac1f9c9b966b4e3f57c138c9842d3c112b 100644 (file)
@@ -241,7 +241,7 @@ static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
 struct scn_usb_data {
        struct usb_device *scn_dev;
        devfs_handle_t devfs;   /* devfs device */
-       struct urb scn_irq;
+       struct urb *scn_irq;
        unsigned int ifnum;     /* Interface number of the USB device */
        int scn_minor;          /* Scanner minor - used in disconnect() */
        unsigned char button;   /* Front panel buffer */
index e7acef2f275031ea1084d37eca30f97dc59a7b55..85921f1ee7bc4ba44d5e3e62bb4e3794fb8c4068 100644 (file)
@@ -16,7 +16,7 @@
  * (C) Copyright 1999 Randy Dunlap
  * (C) Copyright 1999 Gregory P. Smith
  *
- * $Id: usb-uhci.c,v 1.268 2001/08/29 14:08:43 acher Exp $
+ * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
  */
 
 #include <linux/config.h>
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/pm.h>
+#include <linux/timer.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -52,7 +53,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.268 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -61,7 +62,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.268"
+#define DRIVER_VERSION "v1.275"
 #define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
@@ -71,6 +72,9 @@
 #define DEBUG_SYMBOLS
 #ifdef DEBUG_SYMBOLS
        #define _static
+       #ifndef EXPORT_SYMTAB
+               #define EXPORT_SYMTAB
+       #endif
 #else
        #define _static static
 #endif
@@ -1182,6 +1186,7 @@ _static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
                // cleanup the rest
                switch (usb_pipetype (urb->pipe)) {
 
+               case PIPE_INTERRUPT:
                case PIPE_ISOCHRONOUS:
                        uhci_wait_ms(1);
                        uhci_clean_iso_step2(s, urb_priv);
@@ -1779,17 +1784,15 @@ _static void uhci_check_timeouts(uhci_t *s)
                type = usb_pipetype (urb->pipe);
 
                hcpriv = (urb_priv_t*)urb->hcpriv;
-                               
-               if ( urb->timeout && 
-                       ((hcpriv->started + urb->timeout) < jiffies)) {
+               
+               if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
                        urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
                        async_dbg("uhci_check_timeout: timeout for %p",urb);
                        uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
                }
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
                else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-                    (hcpriv->use_loop) &&
-                    ((hcpriv->started + IDLE_TIMEOUT) < jiffies))
+                        (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
                        disable_desc_loop(s, urb);
 #endif
 
@@ -2445,7 +2448,7 @@ _static int process_interrupt (uhci_t *s, struct urb *urb)
                        break;
                }
 
-               if (!desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC)) {
+               if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
                        // do not process one-shot TDs, no recycling
                        break;
                }
@@ -2509,6 +2512,8 @@ _static int process_interrupt (uhci_t *s, struct urb *urb)
                        }
                        else {
                                uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+                               // correct toggle after unlink
+                               usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
                                clr_td_ioc(desc); // inactivate TD
                        }
                }
@@ -2738,7 +2743,7 @@ _static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
 
        if (status != 1) {
                // Avoid too much error messages at a time
-               if ((jiffies - s->last_error_time > ERROR_SUPPRESSION_TIME)) {
+               if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
                        warn("interrupt, status %x, frame# %i", status, 
                             UHCI_GET_CURRENT_FRAME(s));
                        s->last_error_time = jiffies;
@@ -2786,7 +2791,7 @@ restart:
                                break;
                }
        }
-       if ((jiffies - s->timeout_check) > (HZ/30)) 
+       if (time_after(jiffies, s->timeout_check + (HZ/30)))
                uhci_check_timeouts(s);
 
        clean_descs(s, CLEAN_NOT_FORCED);
@@ -2815,7 +2820,7 @@ _static void reset_hc (uhci_t *s)
 _static void start_hc (uhci_t *s)
 {
        unsigned int io_addr = s->io_addr;
-       int timeout = 1000;
+       int timeout = 10;
 
        /*
         * Reset the HC - this will force us to get a
@@ -2830,6 +2835,7 @@ _static void start_hc (uhci_t *s)
                        err("USBCMD_HCRESET timed out!");
                        break;
                }
+               udelay(1);
        }
 
        /* Turn on all interrupts */
@@ -2845,7 +2851,8 @@ _static void start_hc (uhci_t *s)
        s->running = 1;
 }
 
-_static void __devexit
+/* No  __devexit, since it maybe called from alloc_uhci() */
+_static void
 uhci_pci_remove (struct pci_dev *dev)
 {
        uhci_t *s = pci_get_drvdata(dev);
@@ -3130,4 +3137,3 @@ module_exit (uhci_hcd_cleanup);
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
-
index 5085dab3bb05f3b92f7b337d3ff7e800f2dec9bb..9d57df368e357c25a1029ea3e06b4ab01e3587e0 100644 (file)
@@ -73,7 +73,7 @@ struct usb_kbd {
        struct usb_device *usbdev;
        unsigned char new[8];
        unsigned char old[8];
-       struct urb irq, led;
+       struct urb *irq, *led;
        struct usb_ctrlrequest dr;
        unsigned char leds, newleds;
        char name[128];
@@ -121,15 +121,15 @@ int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, i
                       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
                       (!!test_bit(LED_NUML,    dev->led));
 
-       if (kbd->led.status == -EINPROGRESS)
+       if (kbd->led->status == -EINPROGRESS)
                return 0;
 
        if (kbd->leds == kbd->newleds)
                return 0;
 
        kbd->leds = kbd->newleds;
-       kbd->led.dev = kbd->usbdev;
-       if (usb_submit_urb(&kbd->led))
+       kbd->led->dev = kbd->usbdev;
+       if (usb_submit_urb(kbd->led))
                err("usb_submit_urb(leds) failed");
 
        return 0;
@@ -146,8 +146,8 @@ static void usb_kbd_led(struct urb *urb)
                return;
 
        kbd->leds = kbd->newleds;
-       kbd->led.dev = kbd->usbdev;
-       if (usb_submit_urb(&kbd->led))
+       kbd->led->dev = kbd->usbdev;
+       if (usb_submit_urb(kbd->led))
                err("usb_submit_urb(leds) failed");
 }
 
@@ -158,8 +158,8 @@ static int usb_kbd_open(struct input_dev *dev)
        if (kbd->open++)
                return 0;
 
-       kbd->irq.dev = kbd->usbdev;
-       if (usb_submit_urb(&kbd->irq))
+       kbd->irq->dev = kbd->usbdev;
+       if (usb_submit_urb(kbd->irq))
                return -EIO;
 
        return 0;
@@ -170,7 +170,7 @@ static void usb_kbd_close(struct input_dev *dev)
        struct usb_kbd *kbd = dev->private;
 
        if (!--kbd->open)
-               usb_unlink_urb(&kbd->irq);
+               usb_unlink_urb(kbd->irq);
 }
 
 static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
@@ -201,6 +201,18 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
        if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
        memset(kbd, 0, sizeof(struct usb_kbd));
 
+       kbd->irq = usb_alloc_urb(0);
+       if (!kbd->irq) {
+               kfree(kbd);
+               return NULL;
+       }
+       kbd->led = usb_alloc_urb(0);
+       if (!kbd->led) {
+               usb_free_urb(kbd->irq);
+               kfree(kbd);
+               return NULL;
+       }
+
        kbd->usbdev = dev;
 
        kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
@@ -215,7 +227,7 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
        kbd->dev.open = usb_kbd_open;
        kbd->dev.close = usb_kbd_close;
 
-       FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
+       FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
                usb_kbd_irq, kbd, endpoint->bInterval);
 
        kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
@@ -248,7 +260,7 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
 
        kfree(buf);
 
-       FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0),
+       FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0),
                (void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
                        
        input_register_device(&kbd->dev);
@@ -262,8 +274,10 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
 static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
 {
        struct usb_kbd *kbd = ptr;
-       usb_unlink_urb(&kbd->irq);
+       usb_unlink_urb(kbd->irq);
        input_unregister_device(&kbd->dev);
+       usb_free_urb(kbd->irq);
+       usb_free_urb(kbd->led);
        kfree(kbd);
 }
 
index ff4ee6676420025ae660c222e1cfccba16fa2605..db2e61f8290b4ee972dcdd9a30d0aea604f23b43 100644 (file)
@@ -54,7 +54,7 @@ struct usb_mouse {
        char name[128];
        struct usb_device *usbdev;
        struct input_dev dev;
-       struct urb irq;
+       struct urb *irq;
        int open;
 };
 
@@ -84,8 +84,8 @@ static int usb_mouse_open(struct input_dev *dev)
        if (mouse->open++)
                return 0;
 
-       mouse->irq.dev = mouse->usbdev;
-       if (usb_submit_urb(&mouse->irq))
+       mouse->irq->dev = mouse->usbdev;
+       if (usb_submit_urb(mouse->irq))
                return -EIO;
 
        return 0;
@@ -96,7 +96,7 @@ static void usb_mouse_close(struct input_dev *dev)
        struct usb_mouse *mouse = dev->private;
 
        if (!--mouse->open)
-               usb_unlink_urb(&mouse->irq);
+               usb_unlink_urb(mouse->irq);
 }
 
 static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
@@ -126,6 +126,12 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
        if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
        memset(mouse, 0, sizeof(struct usb_mouse));
 
+       mouse->irq = usb_alloc_urb(0);
+       if (!mouse->irq) {
+               kfree(mouse);
+               return NULL;
+       }
+
        mouse->usbdev = dev;
 
        mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
@@ -162,7 +168,7 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
 
        kfree(buf);
 
-       FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
+       FILL_INT_URB(mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
                usb_mouse_irq, mouse, endpoint->bInterval);
 
        input_register_device(&mouse->dev);
@@ -176,8 +182,9 @@ static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
 static void usb_mouse_disconnect(struct usb_device *dev, void *ptr)
 {
        struct usb_mouse *mouse = ptr;
-       usb_unlink_urb(&mouse->irq);
+       usb_unlink_urb(mouse->irq);
        input_unregister_device(&mouse->dev);
+       usb_free_urb(mouse->irq);
        kfree(mouse);
 }
 
index 82eef90a5929303bcb7fa2a81437ec39798118f5..069383fac14f0e0bb7a29a6b86d2dd30bb2f356d 100644 (file)
@@ -344,7 +344,7 @@ static void params_changed(struct usb_vicam *vicam)
        synchronize(vicam);
        mdelay(10);
        vicam_parameters(vicam);
-       printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+       printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
 #endif
 }
 
@@ -841,9 +841,9 @@ static int vicam_init(struct usb_vicam *vicam)
 
        vicam_parameters(vicam);
 
-       FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
+       FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
                      buf, 0x1e480, vicam_bulk, vicam);
-       printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+       printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
 
        return 0;
 error:
@@ -877,7 +877,13 @@ static void * __devinit vicam_probe(struct usb_device *udev, unsigned int ifnum,
                return NULL;
        }
        memset(vicam, 0, sizeof(*vicam));
-       
+
+       vicam->readurb = usb_alloc_urb(0);
+       if (!vicam->readurb) {
+               kfree(vicam);
+               return NULL;
+       }
+
        vicam->udev = udev;
        vicam->camera_name = camera_name;
        vicam->win.brightness = 128;
@@ -925,6 +931,7 @@ static void vicam_disconnect(struct usb_device *udev, void *ptr)
 
        if (!vicam->open_count) {
                /* Other random junk */
+               usb_free_urb(vicam->readurb);
                kfree(vicam);
                vicam = NULL;
        }
index b483befbfdaef4125ae87602630644e0c49f333a..4527d8e644f7a8ce2e2d97b8cbb78f5de32b8f9d 100644 (file)
@@ -75,7 +75,7 @@ struct usb_vicam
        int maxframesize;
        struct picture_parm win;
        struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
-       struct urb readurb;
+       struct urb *readurb;
 };
 
 #endif
index 0ed344eff4b7afd3f36144c6adcdffa8caa11de2..9f3433a8aa64045c734fcdf5db984a7139ca84b8 100644 (file)
@@ -100,7 +100,7 @@ struct wacom {
        signed char data[10];
        struct input_dev dev;
        struct usb_device *usbdev;
-       struct urb irq;
+       struct urb *irq;
        struct wacom_features *features;
        int tool[2];
        int open;
@@ -335,8 +335,8 @@ static int wacom_open(struct input_dev *dev)
        if (wacom->open++)
                return 0;
 
-       wacom->irq.dev = wacom->usbdev;
-       if (usb_submit_urb(&wacom->irq))
+       wacom->irq->dev = wacom->usbdev;
+       if (usb_submit_urb(wacom->irq))
                return -EIO;
 
        return 0;
@@ -347,7 +347,7 @@ static void wacom_close(struct input_dev *dev)
        struct wacom *wacom = dev->private;
 
        if (!--wacom->open)
-               usb_unlink_urb(&wacom->irq);
+               usb_unlink_urb(wacom->irq);
 }
 
 static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
@@ -358,6 +358,12 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
        if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
        memset(wacom, 0, sizeof(struct wacom));
 
+       wacom->irq = usb_alloc_urb(0);
+       if (!wacom->irq) {
+               kfree(wacom);
+               return NULL;
+       }
+
        wacom->features = wacom_features + id->driver_info;
 
        wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) | wacom->features->evbit;
@@ -397,7 +403,7 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
 
        endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
 
-       FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+       FILL_INT_URB(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
                     wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
 
        input_register_device(&wacom->dev);
@@ -411,8 +417,9 @@ static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struc
 static void wacom_disconnect(struct usb_device *dev, void *ptr)
 {
        struct wacom *wacom = ptr;
-       usb_unlink_urb(&wacom->irq);
+       usb_unlink_urb(wacom->irq);
        input_unregister_device(&wacom->dev);
+       usb_free_urb(wacom->irq);
        kfree(wacom);
 }
 
index ffb3a7160ab1d792f29043459f1662a65cd46b79..1d92c99c25052c0b582f5e6d7d2c0d7f4d217db5 100644 (file)
@@ -143,6 +143,7 @@ if [ "$CONFIG_FB" = "y" ]; then
            bool '    SIS 630/540/730 support' CONFIG_FB_SIS_300
            bool '    SIS 315H/315 support' CONFIG_FB_SIS_315
         fi
+        tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
         tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
         tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
       fi
@@ -268,7 +269,7 @@ if [ "$CONFIG_FB" = "y" ]; then
           "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
           "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
           "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-          "$CONFIG_FB_SIS" = "y" ]; then
+          "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
         define_tristate CONFIG_FBCON_CFB8 y
       else
         if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -288,7 +289,7 @@ if [ "$CONFIG_FB" = "y" ]; then
              "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
              "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
              "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-             "$CONFIG_FB_TX3912" = "m" ]; then
+             "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
            define_tristate CONFIG_FBCON_CFB8 m
         fi
       fi
@@ -304,7 +305,8 @@ if [ "$CONFIG_FB" = "y" ]; then
           "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
           "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
           "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
-          "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
+          "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+          "$CONFIG_FB_NEOMAGIC" = "y" ]; then
         define_tristate CONFIG_FBCON_CFB16 y
       else
         if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -319,7 +321,8 @@ if [ "$CONFIG_FB" = "y" ]; then
              "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
              "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
              "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-             "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+             "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+             "$CONFIG_FB_NEOMAGIC" = "m" ]; then
            define_tristate CONFIG_FBCON_CFB16 m
         fi
       fi
@@ -328,7 +331,7 @@ if [ "$CONFIG_FB" = "y" ]; then
           "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
            "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
           "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
-          "$CONFIG_FB_VOODOO1" = "y" ]; then
+          "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
         define_tristate CONFIG_FBCON_CFB24 y
       else
         if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
@@ -336,7 +339,7 @@ if [ "$CONFIG_FB" = "y" ]; then
              "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
              "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
              "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
-             "$CONFIG_FB_VOODOO1" = "m" ]; then
+             "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
            define_tristate CONFIG_FBCON_CFB24 m
         fi
       fi
index f3d69708bf6445ab649a71ee8bc9d276b686a8c2..c08b4ea7593caf13b7c8af597ba99f590d35de01 100644 (file)
@@ -49,6 +49,7 @@ obj-$(CONFIG_FB_Q40)              += q40fb.o
 obj-$(CONFIG_FB_ATARI)            += atafb.o
 obj-$(CONFIG_FB_ATY128)           += aty128fb.o
 obj-$(CONFIG_FB_RADEON)                  += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
 obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
 obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
index 7bb2b512291c8fad8aa3979ebcc04c4b73e7e038..39d964687c2653405cb6ad6f18ee42592dc6e109 100644 (file)
@@ -554,7 +554,7 @@ static void __init s3triofb_of_init(struct device_node *dp)
 
     strcpy(fb_info.modename, "Trio64 ");
     strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &s3trio_ops;
 #if 0
     fb_info.fbvar_num = 1;
index 8a9a1a88966ef10193df86ae104a2f6747e2e4f6..332e5286378c0010fb28bff5345f1554431560af 100644 (file)
@@ -1318,7 +1318,7 @@ acornfb_init_fbinfo(void)
        strcpy(fb_info.modename, "Acorn");
        strcpy(fb_info.fontname, "Acorn8x8");
 
-       fb_info.node               = -1;
+       fb_info.node               = NODEV;
        fb_info.fbops              = &acornfb_ops;
        fb_info.disp               = &global_disp;
        fb_info.changevar          = NULL;
index cab58a763256b96b0cab712522e35253436d7f79..fadb7f0a8719d4fb60fca4a10e11f556a16256db 100644 (file)
@@ -1730,7 +1730,7 @@ default_chipset:
 
        strcpy(fb_info.modename, amifb_name);
        fb_info.changevar = NULL;
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &amifb_ops;
        fb_info.disp = &disp;
        fb_info.switch_con = &amifbcon_switch;
index 8db29f44aadee5237332f26eae42b53e479b120e..73339ab4cba0dce1e2ebb93ba27716162b7d9a1e 100644 (file)
@@ -2828,7 +2828,7 @@ int __init atafb_init(void)
 
        strcpy(fb_info.modename, "Atari Builtin ");
        fb_info.changevar = NULL;
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &atafb_ops;
        fb_info.disp = &disp;
        fb_info.switch_con = &atafb_switch;
index 7168d0dff1f1e591758c08fae277536dc9e3d4b4..77ebcf9e6e008c992bfc628e3f22f51083ed96c1 100644 (file)
@@ -1704,7 +1704,7 @@ aty128_init(struct fb_info_aty128 *info, const char *name)
 
     /* fill in info */
     strcpy(info->fb_info.modename, aty128fb_name);
-    info->fb_info.node  = -1;
+    info->fb_info.node  = NODEV;
     info->fb_info.fbops = &aty128fb_ops;
     info->fb_info.disp  = &info->disp;
     strcpy(info->fb_info.fontname, fontname);
index d1db4fb29b849e24eff797c4597aa60ad6130e75..fedcdc15e375f670dd4d815b9ddc6f719ecf7af5 100644 (file)
@@ -578,7 +578,7 @@ static void __init init_chips(struct fb_info_chips *p)
        p->disp.scrollmode = SCROLL_YREDRAW;
 
        strcpy(p->info.modename, p->fix.id);
-       p->info.node = -1;
+       p->info.node = NODEV;
        p->info.fbops = &chipsfb_ops;
        p->info.disp = &p->disp;
        p->info.fontname[0] = 0;
index 46808a55981c0dc103b444f5897f5dc526a72d4a..5a48f270a5682dfe3bc61d72a1a8c7a53dec6278 100644 (file)
@@ -2758,7 +2758,7 @@ int __init clgenfb_init(void)
                 sizeof (fb_info->gen.info.modename));
        fb_info->gen.info.modename [sizeof (fb_info->gen.info.modename) - 1] = 0;
 
-       fb_info->gen.info.node = -1;
+       fb_info->gen.info.node = NODEV;
        fb_info->gen.info.fbops = &clgenfb_ops;
        fb_info->gen.info.disp = &disp;
        fb_info->gen.info.changevar = NULL;
index 3b42d082a02990a51bb1721c5ba2237bd735a0e4..0193fff5ab8e94b64cb949ec7853d99469e3e295 100644 (file)
@@ -1376,7 +1376,7 @@ static void control_set_dispsw(struct display *disp, int cmode, struct fb_info_c
 static void __init control_init_info(struct fb_info *info, struct fb_info_control *p)
 {
        strcpy(info->modename, "control");
-       info->node = -1;        /* ??? danj */
+       info->node = NODEV;
        info->fbops = &controlfb_ops;
        info->disp = &p->display;
        strcpy(info->fontname, fontname);
index f7925485b7ece62c55793ebfb92e041cf06155c1..d0133f694073553a055bb57a94cb74be0eead11b 100644 (file)
@@ -1085,7 +1085,7 @@ int __init cyberfb_init(void)
 
            strcpy(fb_info.modename, cyberfb_name);
            fb_info.changevar = NULL;
-           fb_info.node = -1;
+           fb_info.node = NODEV;
            fb_info.fbops = &cyberfb_ops;
            fb_info.disp = &disp;
            fb_info.switch_con = &Cyberfb_switch;
index 3d1f98b41091c85d815ff5a00aaa5795737ab691..f4b18798edbacfc861b3f69b170c60e077f515bf 100644 (file)
@@ -305,7 +305,7 @@ printk("dn_fb_init\n");
        fb_info.switch_con=&dnfbcon_switch;
        fb_info.updatevar=&dnfbcon_updatevar;
        fb_info.blank=&dnfbcon_blank;   
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &dn_fb_ops;
        fb_info.flags = FBINFO_FLAG_DEFAULT;    
 
index 6b51230a8c8f3be027334f2673150478c1d69798..b0601ea39eb6931133438cee4f64c1e4e92cf7f6 100644 (file)
@@ -292,7 +292,7 @@ printk("dn_fb_init\n");
        fb_info.switch_con=&dnfbcon_switch;
        fb_info.updatevar=&dnfbcon_updatevar;
        fb_info.blank=&dnfbcon_blank;   
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &dn_fb_ops;
        
 printk("dn_fb_init: register\n");
index 27c3807070bf65d55a17b6a9ebc3a9aaa45f6e40..8da6c0a0e6f583e8898361aa7a14a71c58156c45 100644 (file)
@@ -307,7 +307,7 @@ unsigned long __init dnfb_init(unsigned long mem_start) {
        fb_info.switch_con=&dnfbcon_switch;
        fb_info.updatevar=&dnfbcon_updatevar;
        fb_info.blank=&dnfbcon_blank;   
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &dn_fb_ops;
        
         dn_fb_get_var(&disp[0].var,0, &fb_info);
index 059389c2321a91ff5006a7784ac4c2732e7198bb..2da7098c12498f77ec16f35aca90c07f4f229ffb 100644 (file)
@@ -500,7 +500,7 @@ int __init e1355fb_init(void)
        fb_info.gen.fbhw->detect();
        strcpy(fb_info.gen.info.modename, "SED1355");
        fb_info.gen.info.changevar = NULL;
-       fb_info.gen.info.node = -1;
+       fb_info.gen.info.node = NODEV;
        fb_info.gen.info.fbops = &e1355fb_ops;
        fb_info.gen.info.disp = &disp;
        fb_info.gen.parsize = sizeof(struct e1355_par);
index 0caef8f0d4d7a53e155f6a52759561dab2207a7a..2fa7894752c4f5aff9d8edb1a3bd68dd31417bf0 100644 (file)
@@ -73,6 +73,8 @@ extern int atyfb_init(void);
 extern int atyfb_setup(char*);
 extern int aty128fb_init(void);
 extern int aty128fb_setup(char*);
+extern int neofb_init(void);
+extern int neofb_setup(char*);
 extern int igafb_init(void);
 extern int igafb_setup(char*);
 extern int imsttfb_init(void);
@@ -173,6 +175,9 @@ static struct {
 #ifdef CONFIG_FB_ATY128
        { "aty128fb", aty128fb_init, aty128fb_setup },
 #endif
+#ifdef CONFIG_FB_NEOMAGIC
+       { "neo", neofb_init, neofb_setup },
+#endif
 #ifdef CONFIG_FB_VIRGE
        { "virge", virgefb_init, virgefb_setup },
 #endif
index 1f4883c786cfda41a7bab2a9d27fe2042c0264bf..c8f31e2c4236b654556924eb05442ba75af25a85 100644 (file)
@@ -401,7 +401,7 @@ int __init fm2fb_init(void)
        disp.scrollmode = SCROLL_YREDRAW;
 
        strcpy(fb_info.modename, fb_fix.id);
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &fm2fb_ops;
        fb_info.disp = &disp;
        fb_info.fontname[0] = '\0';
index 0ea7aa5f5e939fc606aee0f7008900796069cd7e..87e55ed5313aeb6b312520ba27e507909ab89fe1 100644 (file)
@@ -378,7 +378,7 @@ int __init g364fb_init(void)
     disp.dispsw = &fbcon_g364cfb8;
 
     strcpy(fb_info.modename, fb_fix.id);
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &g364fb_ops;
     fb_info.disp = &disp;
     fb_info.fontname[0] = '\0';
index 61b6ce730d372deba15c9e877d839163e6cdb371..34d66213503efe946a5547621864b2ef03fb7991 100644 (file)
@@ -742,7 +742,7 @@ int __init hgafb_init(void)
        disp.scrollmode = SCROLL_YREDRAW;
        
        strcpy (fb_info.modename, hga_fix.id);
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.flags = FBINFO_FLAG_DEFAULT;
 /*     fb_info.open = ??? */
        fb_info.var = hga_default_var;
index 2f0dbf0f139fe5b7cef0153655717bceaeb5a7ff..2ce31c83675e905d8ba8a2e2753fb1288f177dc1 100644 (file)
@@ -344,7 +344,7 @@ static struct fb_ops hitfb_ops = {
 int __init hitfb_init(void)
 {
     strcpy(fb_info.gen.info.modename, "Hitachi HD64461");
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     fb_info.gen.info.fbops = &hitfb_ops;
     fb_info.gen.info.disp = &fb_info.disp;
index bddf068ab6ecfa79584720a4752c1314e5f303de..e39cd246620bd3a400a4ec69d9627e8f08b40917 100644 (file)
@@ -328,7 +328,7 @@ int __init hpfb_init_one(unsigned long base)
         */
        strcpy(fb_info.modename, "Topcat");
        fb_info.changevar = NULL;
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &hpfb_ops;
        fb_info.disp = &disp;
        fb_info.switch_con = &hpfb_switch;
index 8daf363642addcf52f5d1b8d56a8365fa2f95852..ec14056ac4e4116a88f9732def59a2a03da8e8bc 100644 (file)
@@ -568,7 +568,7 @@ static int __init iga_init(struct fb_info_iga *info)
        }
 
        strcpy(info->fb_info.modename, igafb_name);
-       info->fb_info.node = -1;
+       info->fb_info.node = NODEV;
        info->fb_info.fbops = &igafb_ops;
        info->fb_info.disp = &info->disp;
        strcpy(info->fb_info.fontname, fontname);
index 2030ab5967a8605248cadde40532235dcc24ee50..b3ef1541d3fa146dae61adf470a51777bca969b8 100644 (file)
@@ -1866,7 +1866,7 @@ init_imstt(struct fb_info_imstt *p)
 
        strcpy(p->info.modename, p->fix.id);
        strcpy(p->info.fontname, fontname);
-       p->info.node = -1;
+       p->info.node = NODEV;
        p->info.fbops = &imsttfb_ops;
        p->info.disp = &p->disp;
        p->info.changevar = 0;
index df9602d538e4d36823b62c5294a143afb133a261..b80f26565597a4fa194f0b7605e5e49f53c3da8e 100644 (file)
@@ -1221,7 +1221,7 @@ void __init macfb_init(void)
                }
        
        fb_info.changevar  = NULL;
-       fb_info.node       = -1;
+       fb_info.node       = NODEV;
        fb_info.fbops      = &macfb_ops;
        fb_info.disp       = &disp;
        fb_info.switch_con = &macfb_switch;
index 099ac0cdaa28c0316eddd2b25283384b6c6da672..614d051c650054f4c38277eb8e07dad1829be62a 100644 (file)
@@ -358,7 +358,7 @@ int __init maxinefb_init(void)
        strcpy(fb_info.modename, "Maxine onboard graphics 1024x768x8");
        /* fb_info.modename: maximum of 39 characters + trailing nullbyte, KM */
        fb_info.changevar = NULL;
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &maxinefb_ops;
        fb_info.disp = &disp;
        fb_info.switch_con = &maxinefb_switch;
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
new file mode 100644 (file)
index 0000000..43a48ca
--- /dev/null
@@ -0,0 +1,2421 @@
+/*
+ * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ *
+ * Card specific code is based on XFree86's neomagic driver.
+ * Framebuffer framework code is based on code of cyber2000fb.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ *
+ * 0.3.1
+ *  - added module license (dok)
+ *
+ * 0.3
+ *  - hardware accelerated clear and move for 2200 and above (dok)
+ *  - maximum allowed dotclock is handled now (dok)
+ *
+ * 0.2.1
+ *  - correct panning after X usage (dok)
+ *  - added module and kernel parameters (dok)
+ *  - no stretching if external display is enabled (dok)
+ *
+ * 0.2
+ *  - initial version (dok)
+ *
+ *
+ * TODO
+ * - ioctl for internal/external switching
+ * - blanking
+ * - 32bit depth support, maybe impossible
+ * - disable pan-on-sync, need specs
+ *
+ * BUGS
+ * - white margin on bootup like with tdfxfb (colormap problem?)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "neofb.h"
+
+
+#define NEOFB_VERSION "0.3.1"
+
+/* --------------------------------------------------------------------- */
+
+static int disabled   = 0;
+static int internal   = 0;
+static int external   = 0;
+static int nostretch  = 0;
+static int nopciburst = 0;
+
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
+MODULE_PARM(internal, "i");
+MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
+MODULE_PARM(external, "i");
+MODULE_PARM_DESC(external, "Enable output on external CRT.");
+MODULE_PARM(nostretch, "i");
+MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
+MODULE_PARM(nopciburst, "i");
+MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static biosMode bios8[] = {    
+    { 320, 240, 0x40 },
+    { 300, 400, 0x42 },    
+    { 640, 400, 0x20 },
+    { 640, 480, 0x21 },
+    { 800, 600, 0x23 },
+    { 1024, 768, 0x25 },
+};
+
+static biosMode bios16[] = {
+    { 320, 200, 0x2e },
+    { 320, 240, 0x41 },
+    { 300, 400, 0x43 },
+    { 640, 480, 0x31 },
+    { 800, 600, 0x34 },
+    { 1024, 768, 0x37 },
+};
+
+static biosMode bios24[] = {
+    { 640, 480, 0x32 },
+    { 800, 600, 0x35 },
+    { 1024, 768, 0x38 }
+};
+
+#ifdef NO_32BIT_SUPPORT_YET
+/* FIXME: guessed values, wrong */
+static biosMode bios32[] = {
+    { 640, 480, 0x33 },
+    { 800, 600, 0x36 },
+    { 1024, 768, 0x39 }
+    };
+#endif
+
+static int neoFindMode (int xres, int yres, int depth)
+{
+  int xres_s;
+  int i, size;
+  biosMode *mode;
+
+  switch (depth)
+    {
+    case 8:
+      size = sizeof(bios8) / sizeof(biosMode);
+      mode = bios8;
+      break;
+    case 16:
+      size = sizeof(bios16) / sizeof(biosMode);
+      mode = bios16;
+      break;
+    case 24:
+      size = sizeof(bios24) / sizeof(biosMode);
+      mode = bios24;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+      size = sizeof(bios32) / sizeof(biosMode);
+      mode = bios32;
+      break;
+#endif
+    default:
+      return 0;
+    }
+
+  for (i = 0; i < size; i++)
+    {
+      if (xres <= mode[i].x_res)
+       {
+         xres_s = mode[i].x_res;
+         for (; i < size; i++)
+           {
+             if (mode[i].x_res != xres_s)
+               return mode[i-1].mode;
+             if (yres <= mode[i].y_res)
+               return mode[i].mode;
+           }
+       }
+    }
+  return mode[size - 1].mode;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for Neo2200+
+ */
+static inline void neo2200_wait_idle (struct neofb_info *fb)
+{
+  int waitcycles;
+
+  while (fb->neo2200->bltStat & 1)
+    waitcycles++;
+}
+
+static inline void neo2200_wait_fifo (struct neofb_info *fb,
+                                      int requested_fifo_space)
+{
+  //  ndev->neo.waitfifo_calls++;
+  //  ndev->neo.waitfifo_sum += requested_fifo_space;
+
+  /* FIXME: does not work
+  if (neo_fifo_space < requested_fifo_space)
+    {
+      neo_fifo_waitcycles++;
+
+      while (1)
+        {
+          neo_fifo_space = (neo2200->bltStat >> 8);
+          if (neo_fifo_space >= requested_fifo_space)
+            break;
+        }
+    }
+  else
+    {
+      neo_fifo_cache_hits++;
+    }
+
+  neo_fifo_space -= requested_fifo_space;
+  */
+
+  neo2200_wait_idle (fb);
+}
+
+static inline void neo2200_accel_init (struct neofb_info        *fb,
+                                      struct fb_var_screeninfo *var)
+{
+  Neo2200 *neo2200 = fb->neo2200;
+  u32 bltMod, pitch;
+
+  neo2200_wait_idle (fb);
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      bltMod = NEO_MODE1_DEPTH8;
+      pitch  = var->xres_virtual;
+      break;
+    case 15:
+    case 16:
+      bltMod = NEO_MODE1_DEPTH16;
+      pitch  = var->xres_virtual * 2;
+      break;
+    default:
+      printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
+      return;
+    }
+
+  neo2200->bltStat = bltMod << 16;
+  neo2200->pitch   = (pitch << 16) | pitch;
+}
+
+static void neo2200_accel_setup (struct display *p)
+{
+  struct neofb_info        *fb  = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+
+  fb->dispsw->setup(p);
+
+  neo2200_accel_init (fb, var);
+}
+
+static void
+neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
+                    int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long src, dst;
+  int bpp, pitch, inc_y;
+  u_int fh, fw;
+
+  /* setting blitting direction does not work, so this case is unaccelerated */
+  if (sx != dx)
+    {
+      neo2200_wait_idle (fb);
+      fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
+      return;
+    }
+
+  bpp    = (var->bits_per_pixel+7) / 8;
+  pitch  = var->xres_virtual * bpp;
+
+  fw     = fontwidth(p);
+  sx    *= fw * bpp;
+  dx    *= fw * bpp;
+  width *= fw;
+
+  fh     = fontheight(p);
+  sy    *= fh;
+  dy    *= fh;
+
+  if (sy > dy)
+    inc_y = fh;
+  else
+    {
+      inc_y  = -fh;
+      sy    += (height - 1) * fh;
+      dy    += (height - 1) * fh;
+    }
+
+  neo2200_wait_fifo (fb, 1);
+
+  /* set blt control */
+  neo2200->bltCntl = NEO_BC3_FIFO_EN      |
+                     NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  /* looks silly, but setting the blitting direction did not work */
+  while (height--)
+    {
+      src = sx + sy * pitch;
+      dst = dx + dy * pitch;
+
+      neo2200_wait_fifo (fb, 3);
+
+      neo2200->srcStart = src;
+      neo2200->dstStart = dst;
+      neo2200->xyExt = (fh << 16) | (width & 0xffff);
+
+      sy += inc_y;
+      dy += inc_y;
+    }
+}
+
+static void
+neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
+                    int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long dst;
+  u_int fw, fh;
+  u32 bgx = attr_bgcol_ec(p, conp);
+
+  fw = fontwidth(p);
+  fh = fontheight(p);
+
+  dst    = sx * fw + sy * var->xres_virtual * fh;
+  width  = width * fw;
+  height = height * fh;
+
+  neo2200_wait_fifo (fb, 4);
+
+  /* set blt control */
+  neo2200->bltCntl  = NEO_BC3_FIFO_EN      |
+                      NEO_BC0_SRC_IS_FG    |
+                      NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      neo2200->fgColor = bgx;
+      break;
+    case 16:
+      neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
+      break;
+    }
+
+  neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
+
+  neo2200->xyExt    = (height << 16) | (width & 0xffff);
+}
+
+static void
+neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
+                   int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putc(conp, p, c, yy, xx);
+}
+
+static void
+neo2200_accel_putcs (struct vc_data *conp, struct display *p,
+                    const unsigned short *s, int count, int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putcs(conp, p, s, count, yy, xx);
+}
+
+static void neo2200_accel_revc (struct display *p, int xx, int yy)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+       
+  neo2200_wait_idle (fb);
+  fb->dispsw->revc (p, xx, yy);
+}
+
+static void
+neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
+                            int bottom_only)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  fb->dispsw->clear_margins (conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_neo2200_accel = {
+  setup:               neo2200_accel_setup,
+  bmove:               neo2200_accel_bmove,
+  clear:               neo2200_accel_clear,
+  putc:                        neo2200_accel_putc,
+  putcs:               neo2200_accel_putcs,
+  revc:                        neo2200_accel_revc,
+  clear_margins:       neo2200_accel_clear_margins,
+  fontwidthmask:       FONTWIDTH(8)|FONTWIDTH(16)
+};
+
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int neo_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                        u_int transp, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  if (regno >= NR_PALETTE)
+    return -EINVAL;
+
+  info->palette[regno].red    = red;
+  info->palette[regno].green  = green;
+  info->palette[regno].blue   = blue;
+  info->palette[regno].transp = transp;
+
+  switch (fb->var.bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      outb(regno, 0x3c8);
+
+      outb(red   >> 10, 0x3c9);
+      outb(green >> 10, 0x3c9);
+      outb(blue  >> 10, 0x3c9);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      if (regno < 16)
+       ((u16 *)fb->pseudo_palette)[regno] = ((red   & 0xf800)      ) |
+                                            ((green & 0xfc00) >>  5) |
+                                             ((blue  & 0xf800) >> 11);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      if (regno < 16)
+       ((u32 *)fb->pseudo_palette)[regno] = ((red   & 0xff00) << 8) |
+                                             ((green & 0xff00)     ) |
+                                            ((blue  & 0xff00) >> 8);
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+#ifdef FBCON_HAS_CFB32
+    case 32:
+      if (regno < 16)
+       ((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
+                                            ((red    & 0xff00) <<  8) |
+                                             ((green  & 0xff00)      ) |
+                                            ((blue   & 0xff00) >>  8);
+      break;
+#endif
+#endif
+
+    default:
+      return 1;
+    }
+
+  return 0;
+}
+
+static void vgaHWLock (void)
+{
+  /* Protect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) | 0x80);
+}
+
+static void vgaHWUnlock (void)
+{
+  /* Unprotect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) & ~0x80);
+}
+
+static void neoLock (void)
+{
+  VGAwGR (0x09, 0x00);
+  vgaHWLock();
+}
+
+static void neoUnlock (void)
+{
+  vgaHWUnlock();
+  VGAwGR (0x09, 0x26);
+}
+
+/*
+ * vgaHWSeqReset
+ *      perform a sequencer reset.
+ */
+void
+vgaHWSeqReset(int start)
+{
+  if (start)
+    VGAwSEQ (0x00, 0x01);              /* Synchronous Reset */
+  else
+    VGAwSEQ (0x00, 0x03);              /* End Reset */
+}
+
+void
+vgaHWProtect(int on)
+{
+  unsigned char tmp;
+  
+  if (on)
+    {
+      /*
+       * Turn off screen and disable sequencer.
+       */
+      tmp = VGArSEQ (0x01);
+
+      vgaHWSeqReset (1);                       /* start synchronous reset */
+      VGAwSEQ (0x01, tmp | 0x20);      /* disable the display */
+
+      VGAenablePalette();
+    }
+  else
+    {
+      /*
+       * Reenable sequencer, then turn on screen.
+       */
+  
+      tmp = VGArSEQ (0x01);
+
+      VGAwSEQ (0x01, tmp & ~0x20);     /* reenable display */
+      vgaHWSeqReset (0);               /* clear synchronousreset */
+
+      VGAdisablePalette();
+    }
+}
+
+static void vgaHWRestore (const struct neofb_info *info,
+                         const struct neofb_par  *par)
+{
+  int i;
+
+  VGAwMISC (par->MiscOutReg);
+
+  for (i = 1; i < 5; i++)
+    VGAwSEQ (i, par->Sequencer[i]);
+  
+  /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+  VGAwCR (17, par->CRTC[17] & ~0x80);
+
+  for (i = 0; i < 25; i++)
+    VGAwCR (i, par->CRTC[i]);
+
+  for (i = 0; i < 9; i++)
+    VGAwGR (i, par->Graphics[i]);
+
+  VGAenablePalette();
+
+  for (i = 0; i < 21; i++)
+    VGAwATTR (i, par->Attribute[i]);
+
+  VGAdisablePalette();
+}
+
+static void neofb_set_par (struct neofb_info       *info,
+                          const struct neofb_par  *par)
+{
+  unsigned char temp;
+  int i;
+  int clock_hi = 0;
+    
+  DBG("neofb_set_par");
+
+  neoUnlock();
+
+  vgaHWProtect (1);            /* Blank the screen */
+
+  /* linear colormap for non palettized modes */
+  switch (par->depth)
+    {
+    case 8:
+      break;
+    case 16:
+      for (i=0; i<64; i++)
+       {
+         outb(i, 0x3c8);
+         
+         outb(i << 1, 0x3c9);
+         outb(i, 0x3c9);
+         outb(i << 1, 0x3c9);
+       }
+      break;
+    case 24:
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+#endif
+      for (i=0; i<256; i++)
+       {
+         outb(i, 0x3c8);
+         
+         outb(i, 0x3c9);
+         outb(i, 0x3c9);
+         outb(i, 0x3c9);
+       }
+      break;
+    }
+    
+  /* alread unlocked above */
+  /* BOGUS  VGAwGR (0x09, 0x26);*/
+    
+  /* don't know what this is, but it's 0 from bootup anyway */
+  VGAwGR (0x15, 0x00);
+
+  /* was set to 0x01 by my bios in text and vesa modes */
+  VGAwGR (0x0A, par->GeneralLockReg);
+
+  /*
+   * The color mode needs to be set before calling vgaHWRestore
+   * to ensure the DAC is initialized properly.
+   *
+   * NOTE: Make sure we don't change bits make sure we don't change
+   * any reserved bits.
+   */
+  temp = VGArGR(0x90);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xF0; /* Save bits 7:4 */
+      temp |= (par->ExtColorModeSelect & ~0xF0);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x70; /* Save bits 6:4 */
+      temp |= (par->ExtColorModeSelect & ~0x70);
+      break;
+    }
+
+  VGAwGR(0x90,temp);
+
+  /*
+   * In some rare cases a lockup might occur if we don't delay
+   * here. (Reported by Miles Lane)
+   */
+  //mdelay(200);
+
+  /*
+   * Disable horizontal and vertical graphics and text expansions so
+   * that vgaHWRestore works properly.
+   */
+  temp = VGArGR(0x25);
+  temp &= 0x39;
+  VGAwGR (0x25, temp);
+
+  /*
+   * Sleep for 200ms to make sure that the two operations above have
+   * had time to take effect.
+   */
+  mdelay(200);
+
+  /*
+   * This function handles restoring the generic VGA registers.  */
+  vgaHWRestore (info, par);
+
+
+  VGAwGR(0x0E, par->ExtCRTDispAddr);
+  VGAwGR(0x0F, par->ExtCRTOffset);
+  temp = VGArGR(0x10);
+  temp &= 0x0F; /* Save bits 3:0 */
+  temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
+  VGAwGR(0x10, temp);
+
+  VGAwGR(0x11, par->SysIfaceCntl2);
+  VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
+  VGAwGR(0x16, 0 /*par->DualAddrPage*/);
+
+  temp = VGArGR(0x20);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xFC; /* Save bits 7:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xFC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      temp &= 0xDC; /* Save bits 7:6,4:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xDC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x98; /* Save bits 7,4:3 */
+      temp |= (par->PanelDispCntlReg1 & ~0x98);
+      break;
+    }
+  VGAwGR(0x20, temp);
+
+  temp = VGArGR(0x25);
+  temp &= 0x38; /* Save bits 5:3 */
+  temp |= (par->PanelDispCntlReg2 & ~0x38);
+  VGAwGR(0x25, temp);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      temp = VGArGR(0x30);
+      temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
+      temp |= (par->PanelDispCntlReg3 & ~0xEF);
+      VGAwGR(0x30, temp);
+    }
+
+  VGAwGR(0x28, par->PanelVertCenterReg1);
+  VGAwGR(0x29, par->PanelVertCenterReg2);
+  VGAwGR(0x2a, par->PanelVertCenterReg3);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      VGAwGR(0x32, par->PanelVertCenterReg4);
+      VGAwGR(0x33, par->PanelHorizCenterReg1);
+      VGAwGR(0x34, par->PanelHorizCenterReg2);
+      VGAwGR(0x35, par->PanelHorizCenterReg3);
+    }
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
+    VGAwGR(0x36, par->PanelHorizCenterReg4);
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwGR(0x36, par->PanelHorizCenterReg4);
+      VGAwGR(0x37, par->PanelVertCenterReg5);
+      VGAwGR(0x38, par->PanelHorizCenterReg5);
+
+      clock_hi = 1;
+    }
+
+  /* Program VCLK3 if needed. */
+  if (par->ProgramVCLK
+      && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
+         || (VGArGR(0x9F) !=  par->VCLK3Denominator)
+         || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
+                          != (par->VCLK3NumeratorHigh & ~0x0F)))))
+    {
+      VGAwGR(0x9B, par->VCLK3NumeratorLow);
+      if (clock_hi)
+       {
+         temp = VGArGR(0x8F);
+         temp &= 0x0F; /* Save bits 3:0 */
+         temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+         VGAwGR(0x8F, temp);
+       }
+      VGAwGR(0x9F, par->VCLK3Denominator);
+    }
+
+  if (par->biosMode)
+    VGAwCR(0x23, par->biosMode);
+    
+  VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
+
+  /* Program vertical extension register */
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwCR(0x70, par->VerticalExt);
+    }
+
+
+  vgaHWProtect (0);            /* Turn on screen */
+
+  /* Calling this also locks offset registers required in update_start */
+  neoLock();
+}
+
+static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
+{
+  int oldExtCRTDispAddr;
+  int Base; 
+
+  DBG("neofb_update_start");
+
+  Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
+  Base *= (var->bits_per_pixel + 7) / 8;
+
+  neoUnlock();
+
+  /*
+   * These are the generic starting address registers.
+   */
+  VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
+  VGAwCR(0x0D, (Base & 0x00FF));
+
+  /*
+   * Make sure we don't clobber some other bits that might already
+   * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+   * be needed.
+   */
+  oldExtCRTDispAddr = VGArGR(0x0E);
+  VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
+
+  neoLock();
+}
+
+/*
+ * Set the Colormap
+ */
+static int neofb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+                         struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display* disp = (con < 0) ? fb->disp : (fb_display + con);
+  struct fb_cmap *dcmap = &disp->cmap;
+  int err = 0;
+
+  /* no colormap allocated? */
+  if (!dcmap->len)
+    {
+      int size;
+
+      if (fb->var.bits_per_pixel == 8)
+       size = NR_PALETTE;
+      else
+       size = 32;
+
+      err = fb_alloc_cmap (dcmap, size, 0);
+    }
+
+  /*
+   * we should be able to remove this test once fbcon has been
+   * "improved" --rmk
+   */
+  if (!err && con == info->currcon)
+    {
+      err = fb_set_cmap (cmap, kspc, neo_setcolreg, fb);
+      dcmap = &fb->cmap;
+    }
+
+  if (!err)
+    fb_copy_cmap (cmap, dcmap, kspc ? 0 : 1);
+
+  return err;
+}
+
+/*
+ * neoCalcVCLK --
+ *
+ * Determine the closest clock frequency to the one requested.
+ */
+#define REF_FREQ 14.31818
+#define MAX_N 127
+#define MAX_D 31
+#define MAX_F 1
+
+static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
+{
+  int n, d, f;
+  double f_out;
+  double f_diff;
+  int n_best = 0, d_best = 0, f_best = 0;
+  double f_best_diff = 999999.0;
+  double f_target = freq/1000.0;
+
+  for (f = 0; f <= MAX_F; f++)
+    for (n = 0; n <= MAX_N; n++)
+      for (d = 0; d <= MAX_D; d++)
+       {
+         f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
+         f_diff = abs(f_out-f_target);
+         if (f_diff < f_best_diff)
+           {
+             f_best_diff = f_diff;
+             n_best = n;
+             d_best = d;
+             f_best = f;
+           }
+       }
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      /* NOT_DONE:  We are trying the full range of the 2200 clock.
+        We should be able to try n up to 2047 */
+      par->VCLK3NumeratorLow  = n_best;
+      par->VCLK3NumeratorHigh = (f_best << 7);
+    }
+  else
+    par->VCLK3NumeratorLow  = n_best | (f_best << 7);
+
+  par->VCLK3Denominator = d_best;
+
+#ifdef NEOFB_DEBUG
+  printk ("neoVCLK: f:%f NumLow=%d NumHi=%d Den=%d Df=%f\n",
+         f_target,
+         par->VCLK3NumeratorLow,
+         par->VCLK3NumeratorHigh,
+         par->VCLK3Denominator,
+         f_best_diff);
+#endif
+}
+
+/*
+ * vgaHWInit --
+ *      Handle the initialization, etc. of a screen.
+ *      Return FALSE on failure.
+ */
+
+static int vgaHWInit (const struct fb_var_screeninfo *var,
+                     const struct neofb_info        *info,
+                     struct neofb_par               *par,
+                     struct xtimings                *timings)
+{
+  par->MiscOutReg = 0x23;
+
+  if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+    par->MiscOutReg |= 0x40;
+
+  if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+    par->MiscOutReg |= 0x80;
+    
+  /*
+   * Time Sequencer
+   */
+  par->Sequencer[0] = 0x00;
+  par->Sequencer[1] = 0x01;
+  par->Sequencer[2] = 0x0F;
+  par->Sequencer[3] = 0x00;                             /* Font select */
+  par->Sequencer[4] = 0x0E;                             /* Misc */
+
+  /*
+   * CRTC Controller
+   */
+  par->CRTC[0]  = (timings->HTotal >> 3) - 5;
+  par->CRTC[1]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[2]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[3]  = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
+  par->CRTC[4]  = (timings->HSyncStart >> 3);
+  par->CRTC[5]  = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
+    | (((timings->HSyncEnd >> 3)) & 0x1F);
+  par->CRTC[6]  = (timings->VTotal - 2) & 0xFF;
+  par->CRTC[7]  = (((timings->VTotal - 2) & 0x100) >> 8)
+    | (((timings->VDisplay - 1) & 0x100) >> 7)
+    | ((timings->VSyncStart & 0x100) >> 6)
+    | (((timings->VDisplay - 1) & 0x100) >> 5)
+    | 0x10
+    | (((timings->VTotal - 2) & 0x200)   >> 4)
+    | (((timings->VDisplay - 1) & 0x200) >> 3)
+    | ((timings->VSyncStart & 0x200) >> 2);
+  par->CRTC[8]  = 0x00;
+  par->CRTC[9]  = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+
+  if (timings->dblscan)
+    par->CRTC[9] |= 0x80;
+
+  par->CRTC[10] = 0x00;
+  par->CRTC[11] = 0x00;
+  par->CRTC[12] = 0x00;
+  par->CRTC[13] = 0x00;
+  par->CRTC[14] = 0x00;
+  par->CRTC[15] = 0x00;
+  par->CRTC[16] = timings->VSyncStart & 0xFF;
+  par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
+  par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+  par->CRTC[19] = var->xres_virtual >> 4;
+  par->CRTC[20] = 0x00;
+  par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; 
+  par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+  par->CRTC[23] = 0xC3;
+  par->CRTC[24] = 0xFF;
+
+  /*
+   * are these unnecessary?
+   * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   */
+
+  /*
+   * Graphics Display Controller
+   */
+  par->Graphics[0] = 0x00;
+  par->Graphics[1] = 0x00;
+  par->Graphics[2] = 0x00;
+  par->Graphics[3] = 0x00;
+  par->Graphics[4] = 0x00;
+  par->Graphics[5] = 0x40;
+  par->Graphics[6] = 0x05;   /* only map 64k VGA memory !!!! */
+  par->Graphics[7] = 0x0F;
+  par->Graphics[8] = 0xFF;
+  
+
+  par->Attribute[0]  = 0x00; /* standard colormap translation */
+  par->Attribute[1]  = 0x01;
+  par->Attribute[2]  = 0x02;
+  par->Attribute[3]  = 0x03;
+  par->Attribute[4]  = 0x04;
+  par->Attribute[5]  = 0x05;
+  par->Attribute[6]  = 0x06;
+  par->Attribute[7]  = 0x07;
+  par->Attribute[8]  = 0x08;
+  par->Attribute[9]  = 0x09;
+  par->Attribute[10] = 0x0A;
+  par->Attribute[11] = 0x0B;
+  par->Attribute[12] = 0x0C;
+  par->Attribute[13] = 0x0D;
+  par->Attribute[14] = 0x0E;
+  par->Attribute[15] = 0x0F;
+  par->Attribute[16] = 0x41;
+  par->Attribute[17] = 0xFF;
+  par->Attribute[18] = 0x0F;
+  par->Attribute[19] = 0x00;
+  par->Attribute[20] = 0x00;
+
+  return 0;
+}
+
+static int neofb_decode_var (struct fb_var_screeninfo        *var,
+                             const struct neofb_info         *info,
+                             struct neofb_par                *par)
+{
+  struct xtimings timings;
+  int lcd_stretch;
+  int hoffset, voffset;
+  int memlen, vramlen;
+  int mode_ok = 0;
+  unsigned int pixclock = var->pixclock;
+
+  DBG("neofb_decode_var");
+
+  if (!pixclock) pixclock = 10000;     /* 10ns = 100MHz */
+  timings.pixclock = 1000000000 / pixclock;
+  if (timings.pixclock < 1) timings.pixclock = 1;
+  timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+  timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+  timings.HDisplay = var->xres;
+  timings.HSyncStart = timings.HDisplay + var->right_margin;
+  timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+  timings.HTotal = timings.HSyncEnd + var->left_margin;
+  timings.VDisplay = var->yres;
+  timings.VSyncStart = timings.VDisplay + var->lower_margin;
+  timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+  timings.VTotal = timings.VSyncEnd + var->upper_margin;
+  timings.sync = var->sync;
+
+  if (timings.pixclock > info->maxClock)
+    return -EINVAL;
+
+  /* Is the mode larger than the LCD panel? */
+  if ((var->xres > info->NeoPanelWidth) ||
+      (var->yres > info->NeoPanelHeight))
+    {
+      printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
+             var->xres,
+             var->yres,
+             info->NeoPanelWidth,
+             info->NeoPanelHeight);
+      return -EINVAL;
+    }
+
+  /* Is the mode one of the acceptable sizes? */
+  switch (var->xres)
+    {
+    case 1280:
+      if (var->yres == 1024)
+       mode_ok = 1;
+      break;
+    case 1024:
+      if (var->yres == 768)
+       mode_ok = 1;
+      break;
+    case  800:
+      if (var->yres == 600)
+       mode_ok = 1;
+      break;
+    case  640:
+      if (var->yres == 480)
+       mode_ok = 1;
+      break;
+    }
+
+  if (!mode_ok)
+    {
+      printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
+             var->xres, var->yres);
+      return -EINVAL;
+    }
+
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32:
+      break;
+# endif
+#endif
+
+    default:
+      return -EINVAL;
+    }
+
+  par->depth = var->bits_per_pixel;
+
+  vramlen = info->video.len;
+  if (vramlen > 4*1024*1024)
+    vramlen = 4*1024*1024;
+
+  if (var->yres_virtual < var->yres)
+    var->yres_virtual = var->yres;
+  if (var->xres_virtual < var->xres)
+    var->xres_virtual = var->xres;
+
+  memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+  if (memlen > vramlen)
+    {
+      var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
+      memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+    }
+
+  /* we must round yres/xres down, we already rounded y/xres_virtual up
+     if it was possible. We should return -EINVAL, but I disagree */
+  if (var->yres_virtual < var->yres)
+    var->yres = var->yres_virtual;
+  if (var->xres_virtual < var->xres)
+    var->xres = var->xres_virtual;
+  if (var->xoffset + var->xres > var->xres_virtual)
+    var->xoffset = var->xres_virtual - var->xres;
+  if (var->yoffset + var->yres > var->yres_virtual)
+    var->yoffset = var->yres_virtual - var->yres;
+
+
+  /*
+   * This will allocate the datastructure and initialize all of the
+   * generic VGA registers.
+   */
+
+  if (vgaHWInit (var, info, par, &timings))
+    return -EINVAL;
+
+  /*
+   * The default value assigned by vgaHW.c is 0x41, but this does
+   * not work for NeoMagic.
+   */
+  par->Attribute[16] = 0x01;
+
+  switch (var->bits_per_pixel)
+    {
+    case  8:
+      par->CRTC[0x13]   = var->xres_virtual >> 3;
+      par->ExtCRTOffset = var->xres_virtual >> 11;
+      par->ExtColorModeSelect = 0x11;
+      break;
+    case 16:
+      par->CRTC[0x13]   = var->xres_virtual >> 2;
+      par->ExtCRTOffset = var->xres_virtual >> 10;
+      par->ExtColorModeSelect = 0x13;
+      break;
+    case 24:
+      par->CRTC[0x13]   = (var->xres_virtual * 3) >> 3;
+      par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
+      par->ExtColorModeSelect = 0x14;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32: /* FIXME: guessed values */
+      par->CRTC[0x13]   = var->xres_virtual >> 1;
+      par->ExtCRTOffset = var->xres_virtual >> 9;
+      par->ExtColorModeSelect = 0x15;
+      break;
+#endif
+    default:
+      break;
+    }
+       
+  par->ExtCRTDispAddr = 0x10;
+
+  /* Vertical Extension */
+  par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
+    | (((timings.VDisplay -1) & 0x400) >> 9 )
+    | (((timings.VSyncStart) & 0x400) >> 8 )
+    | (((timings.VSyncStart) & 0x400) >> 7 );
+
+  /* Fast write bursts on unless disabled. */
+  if (info->pci_burst)
+    par->SysIfaceCntl1 = 0x30; 
+  else
+    par->SysIfaceCntl1 = 0x00; 
+
+  par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
+
+  /* Enable any user specified display devices. */
+  par->PanelDispCntlReg1 = 0x00;
+  if (info->internal_display)
+    par->PanelDispCntlReg1 |= 0x02;
+  if (info->external_display)
+    par->PanelDispCntlReg1 |= 0x01;
+
+  /* If the user did not specify any display devices, then... */
+  if (par->PanelDispCntlReg1 == 0x00) {
+    /* Default to internal (i.e., LCD) only. */
+    par->PanelDispCntlReg1 |= 0x02;
+  }
+
+  /* If we are using a fixed mode, then tell the chip we are. */
+  switch (var->xres)
+    {
+    case 1280:
+      par->PanelDispCntlReg1 |= 0x60;
+      break;
+    case 1024:
+      par->PanelDispCntlReg1 |= 0x40;
+      break;
+    case 800:
+      par->PanelDispCntlReg1 |= 0x20;
+      break;
+    case 640:
+    default:
+      break;
+    }
+  
+  /* Setup shadow register locking. */
+  switch (par->PanelDispCntlReg1 & 0x03)
+    {
+    case 0x01: /* External CRT only mode: */
+      par->GeneralLockReg = 0x00;
+      /* We need to program the VCLK for external display only mode. */
+      par->ProgramVCLK = 1;
+      break;
+    case 0x02: /* Internal LCD only mode: */
+    case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
+      par->GeneralLockReg = 0x01;
+      /* Don't program the VCLK when using the LCD. */
+      par->ProgramVCLK = 0;
+      break;
+    }
+
+  /*
+   * If the screen is to be stretched, turn on stretching for the
+   * various modes.
+   *
+   * OPTION_LCD_STRETCH means stretching should be turned off!
+   */
+  par->PanelDispCntlReg2 = 0x00;
+  par->PanelDispCntlReg3 = 0x00;
+
+  if (info->lcd_stretch &&
+      (par->PanelDispCntlReg1 == 0x02) &&  /* LCD only */
+      (var->xres != info->NeoPanelWidth))
+    {
+      switch (var->xres)
+       {
+       case  320: /* Needs testing.  KEM -- 24 May 98 */
+       case  400: /* Needs testing.  KEM -- 24 May 98 */
+       case  640:
+       case  800:
+       case 1024:
+         lcd_stretch = 1;
+         par->PanelDispCntlReg2 |= 0xC6;
+         break;
+       default:
+         lcd_stretch = 0;
+         /* No stretching in these modes. */
+       }
+    }
+  else
+    lcd_stretch = 0;
+
+  /*
+   * If the screen is to be centerd, turn on the centering for the
+   * various modes.
+   */
+  par->PanelVertCenterReg1  = 0x00;
+  par->PanelVertCenterReg2  = 0x00;
+  par->PanelVertCenterReg3  = 0x00;
+  par->PanelVertCenterReg4  = 0x00;
+  par->PanelVertCenterReg5  = 0x00;
+  par->PanelHorizCenterReg1 = 0x00;
+  par->PanelHorizCenterReg2 = 0x00;
+  par->PanelHorizCenterReg3 = 0x00;
+  par->PanelHorizCenterReg4 = 0x00;
+  par->PanelHorizCenterReg5 = 0x00;
+
+
+  if (par->PanelDispCntlReg1 & 0x02)
+    {
+      if (var->xres == info->NeoPanelWidth)
+       {
+         /*
+          * No centering required when the requested display width
+          * equals the panel width.
+          */
+       }
+      else
+       {
+         par->PanelDispCntlReg2 |= 0x01;
+         par->PanelDispCntlReg3 |= 0x10;
+
+         /* Calculate the horizontal and vertical offsets. */
+         if (!lcd_stretch)
+           {
+             hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
+             voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
+           }
+         else
+           {
+             /* Stretched modes cannot be centered. */
+             hoffset = 0;
+             voffset = 0;
+           }
+
+         switch (var->xres)
+           {
+           case  320: /* Needs testing.  KEM -- 24 May 98 */
+             par->PanelHorizCenterReg3 = hoffset;
+             par->PanelVertCenterReg2  = voffset;
+             break;
+           case  400: /* Needs testing.  KEM -- 24 May 98 */
+             par->PanelHorizCenterReg4 = hoffset;
+             par->PanelVertCenterReg1  = voffset;
+             break;
+           case  640:
+             par->PanelHorizCenterReg1 = hoffset;
+             par->PanelVertCenterReg3  = voffset;
+             break;
+           case  800:
+             par->PanelHorizCenterReg2 = hoffset;
+             par->PanelVertCenterReg4  = voffset;
+             break;
+           case 1024:
+             par->PanelHorizCenterReg5 = hoffset;
+             par->PanelVertCenterReg5  = voffset;
+             break;
+           case 1280:
+           default:
+             /* No centering in these modes. */
+             break;
+           }
+       }
+    }
+
+  par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
+    
+  /*
+   * Calculate the VCLK that most closely matches the requested dot
+   * clock.
+   */
+  neoCalcVCLK (info, par, timings.pixclock);
+
+  /* Since we program the clocks ourselves, always use VCLK3. */
+  par->MiscOutReg |= 0x0C;
+
+  return 0;
+}
+
+static int neofb_set_var (struct fb_var_screeninfo *var, int con,
+                          struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *display;
+  struct neofb_par par;
+  int err, chgvar = 0;
+
+  DBG("neofb_set_var");
+
+  err = neofb_decode_var (var, info, &par);
+  if (err)
+    return err;
+
+  if (var->activate & FB_ACTIVATE_TEST)
+    return 0;
+
+  if (con < 0)
+    {
+      display = fb->disp;
+      chgvar = 0;
+    }
+  else
+    {
+      display = fb_display + con;
+
+      if (fb->var.xres != var->xres)
+       chgvar = 1;
+      if (fb->var.yres != var->yres)
+       chgvar = 1;
+      if (fb->var.xres_virtual != var->xres_virtual)
+       chgvar = 1;
+      if (fb->var.yres_virtual != var->yres_virtual)
+       chgvar = 1;
+      if (fb->var.bits_per_pixel != var->bits_per_pixel)
+       chgvar = 1;
+    }
+
+  if (!info->neo2200)
+    var->accel_flags &= ~FB_ACCELF_TEXT;
+
+  var->red.msb_right   = 0;
+  var->green.msb_right = 0;
+  var->blue.msb_right  = 0;
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:    /* PSEUDOCOLOUR, 256 */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 0;
+      var->red.length      = 8;
+      var->green.offset           = 0;
+      var->green.length           = 8;
+      var->blue.offset    = 0;
+      var->blue.length    = 8;
+      
+      fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
+      info->dispsw         = &fbcon_cfb8;
+      display->dispsw_data = NULL;
+      display->next_line   = var->xres_virtual;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16: /* DIRECTCOLOUR, 64k */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 11;
+      var->red.length      = 5;
+      var->green.offset    = 5;
+      var->green.length    = 6;
+      var->blue.offset     = 0;
+      var->blue.length     = 5;
+
+      fb->fix.visual       = FB_VISUAL_DIRECTCOLOR;
+      info->dispsw         = &fbcon_cfb16;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 2;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb24;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 3;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 24;
+      var->transp.length   = 8;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb32;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 4;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+# endif
+#endif
+
+    default:
+      printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
+      info->dispsw      = &fbcon_dummy;
+      var->accel_flags &= ~FB_ACCELF_TEXT;
+      break;
+    }
+
+  if (var->accel_flags & FB_ACCELF_TEXT)
+    display->dispsw = &fbcon_neo2200_accel;
+  else
+    display->dispsw = info->dispsw;
+
+  fb->fix.line_length = display->next_line;
+
+  display->screen_base    = fb->screen_base;
+  display->line_length    = fb->fix.line_length;
+  display->visual         = fb->fix.visual;
+  display->type                  = fb->fix.type;
+  display->type_aux       = fb->fix.type_aux;
+  display->ypanstep       = fb->fix.ypanstep;
+  display->ywrapstep      = fb->fix.ywrapstep;
+  display->can_soft_blank = 1;
+  display->inverse        = 0;
+
+  fb->var = *var;
+  fb->var.activate &= ~FB_ACTIVATE_ALL;
+
+  /*
+   * Update the old var.  The fbcon drivers still use this.
+   * Once they are using cfb->fb.var, this can be dropped.
+   *                                   --rmk
+   */
+  display->var = fb->var;
+
+  /*
+   * If we are setting all the virtual consoles, also set the
+   * defaults used to create new consoles.
+   */
+  if (var->activate & FB_ACTIVATE_ALL)
+    fb->disp->var = fb->var;
+
+  if (chgvar && fb && fb->changevar)
+    fb->changevar (con);
+
+  if (con == info->currcon)
+    {
+      if (chgvar || con < 0)
+        neofb_set_par (info, &par);
+
+      neofb_update_start (info, var);
+      fb_set_cmap (&fb->cmap, 1, neo_setcolreg, fb);
+
+      if (var->accel_flags & FB_ACCELF_TEXT)
+       neo2200_accel_init (info, var);
+    }
+
+  return 0;
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
+                             struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  u_int y_bottom;
+
+  y_bottom = var->yoffset;
+
+  if (!(var->vmode & FB_VMODE_YWRAP))
+    y_bottom += var->yres;
+
+  if (var->xoffset > (var->xres_virtual - var->xres))
+    return -EINVAL;
+  if (y_bottom > fb->var.yres_virtual)
+    return -EINVAL;
+
+  neofb_update_start (info, var);
+
+  fb->var.xoffset = var->xoffset;
+  fb->var.yoffset = var->yoffset;
+
+  if (var->vmode & FB_VMODE_YWRAP)
+    fb->var.vmode |= FB_VMODE_YWRAP;
+  else
+    fb->var.vmode &= ~FB_VMODE_YWRAP;
+
+  return 0;
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+static int neofb_updatevar (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  neofb_update_start (info, &fb_display[con].var);
+
+  return 0;
+}
+
+static int neofb_switch (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *disp;
+  struct fb_cmap *cmap;
+
+  if (info->currcon >= 0)
+    {
+      disp = fb_display + info->currcon;
+
+      /*
+       * Save the old colormap and video mode.
+       */
+      disp->var = fb->var;
+      if (disp->cmap.len)
+       fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
+    }
+
+  info->currcon = con;
+  disp = fb_display + con;
+
+  /*
+   * Install the new colormap and change the video mode.  By default,
+   * fbcon sets all the colormaps and video modes to the default
+   * values at bootup.
+   *
+   * Really, we want to set the colourmap size depending on the
+   * depth of the new video mode.  For now, we leave it at its
+   * default 256 entry.
+   */
+  if (disp->cmap.len)
+    cmap = &disp->cmap;
+  else
+    cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+
+  fb_copy_cmap(cmap, &fb->cmap, 0);
+
+  disp->var.activate = FB_ACTIVATE_NOW;
+  neofb_set_var(&disp->var, con, fb);
+
+  return 0;
+}
+
+/*
+ *    (Un)Blank the display.
+ */
+static void neofb_blank (int blank, struct fb_info *fb)
+{
+  //  struct neofb_info *info = (struct neofb_info *)fb;
+
+  /*
+   *  Blank the screen if blank_mode != 0, else unblank. If
+   *  blank == NULL then the caller blanks by setting the CLUT
+   *  (Color Look Up Table) to all black. Return 0 if blanking
+   *  succeeded, != 0 if un-/blanking failed due to e.g. a
+   *  video mode which doesn't support it. Implements VESA
+   *  suspend and powerdown modes on hardware that supports
+   *  disabling hsync/vsync:
+   *    blank_mode == 2: suspend vsync
+   *    blank_mode == 3: suspend hsync
+   *    blank_mode == 4: powerdown
+   *
+   *  wms...Enable VESA DMPS compatible powerdown mode
+   *  run "setterm -powersave powerdown" to take advantage
+   */
+     
+  switch (blank)
+    {
+    case 4:    /* powerdown - both sync lines down */
+      break;   
+    case 3:    /* hsync off */
+      break;   
+    case 2:    /* vsync off */
+      break;   
+    case 1:    /* just software blanking of screen */
+      break;
+    default: /* case 0, or anything else: unblank */
+      break;
+    }
+}
+
+/*
+ * Get the currently displayed virtual consoles colormap.
+ */
+static int gen_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb)
+{
+  fb_copy_cmap (&fb->cmap, cmap, kspc ? 0 : 2);
+  return 0;
+}
+
+/*
+ * Get the currently displayed virtual consoles fixed part of the display.
+ */
+static int gen_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
+{
+  *fix = fb->fix;
+  return 0;
+}
+
+/*
+ * Get the current user defined part of the display.
+ */
+static int gen_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+  *var = fb->var;
+  return 0;
+}
+
+static struct fb_ops neofb_ops = {
+  owner:          THIS_MODULE,
+  fb_set_var:     neofb_set_var,
+  fb_set_cmap:    neofb_set_cmap,
+  fb_pan_display: neofb_pan_display,
+  fb_get_fix:     gen_get_fix,
+  fb_get_var:     gen_get_var,
+  fb_get_cmap:    gen_get_cmap,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
+       accel_flags:    FB_ACCELF_TEXT,
+       xres:           640,
+       yres:           480,
+       xres_virtual:   640,
+       yres_virtual:   30000,
+       bits_per_pixel: 8,
+       pixclock:       39722,
+       left_margin:    48,
+       right_margin:   16,
+       upper_margin:   33,
+       lower_margin:   10,
+       hsync_len:      96,
+       vsync_len:      2,
+       sync:           0,
+       vmode:          FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var800x600x8 = {
+       accel_flags:    FB_ACCELF_TEXT,
+       xres:           800,
+       yres:           600,
+       xres_virtual:   800,
+       yres_virtual:   30000,
+       bits_per_pixel: 8,
+       pixclock:       25000,
+       left_margin:    88,
+       right_margin:   40,
+       upper_margin:   23,
+       lower_margin:   1,
+       hsync_len:      128,
+       vsync_len:      4,
+       sync:           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       vmode:          FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var1024x768x8 = {
+       accel_flags:    FB_ACCELF_TEXT,
+       xres:           1024,
+       yres:           768,
+       xres_virtual:   1024,
+       yres_virtual:   30000,
+       bits_per_pixel: 8,
+       pixclock:       15385,
+       left_margin:    160,
+       right_margin:   24,
+       upper_margin:   29,
+       lower_margin:   3,
+       hsync_len:      136,
+       vsync_len:      6,
+       sync:           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       vmode:          FB_VMODE_NONINTERLACED
+};
+
+#ifdef NOT_DONE
+static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
+       accel_flags:    FB_ACCELF_TEXT,
+       xres:           1280,
+       yres:           1024,
+       xres_virtual:   1280,
+       yres_virtual:   30000,
+       bits_per_pixel: 8,
+       pixclock:       9260,
+       left_margin:    248,
+       right_margin:   48,
+       upper_margin:   38,
+       lower_margin:   1,
+       hsync_len:      112,
+       vsync_len:      3,
+       sync:           FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       vmode:          FB_VMODE_NONINTERLACED
+};
+#endif
+
+static struct fb_var_screeninfo *neofb_var = NULL;
+
+
+static int __devinit neo_map_mmio (struct neofb_info *info)
+{
+  DBG("neo_map_mmio");
+
+  info->mmio.pbase = pci_resource_start (info->pcidev, 1);
+  info->mmio.len   = MMIO_SIZE;
+
+  if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
+    {
+      printk ("neofb: memory mapped IO in use\n");
+      return -EBUSY;
+    }
+
+  info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
+  if (!info->mmio.vbase)
+    {
+      printk ("neofb: unable to map memory mapped IO\n");
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
+
+  info->fb.fix.mmio_start = info->mmio.pbase;
+  info->fb.fix.mmio_len   = info->mmio.len;
+
+  return 0;
+}
+
+static void __devinit neo_unmap_mmio (struct neofb_info *info)
+{
+  DBG("neo_unmap_mmio");
+
+  if (info->mmio.vbase)
+    {
+      iounmap (info->mmio.vbase);
+      info->mmio.vbase = NULL;
+
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+    }
+}
+
+static int __devinit neo_map_video (struct neofb_info *info, int video_len)
+{
+  DBG("neo_map_video");
+
+  info->video.pbase = pci_resource_start (info->pcidev, 0);
+  info->video.len   = video_len;
+
+  if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
+    {
+      printk ("neofb: frame buffer in use\n");
+      return -EBUSY;
+    }
+
+  info->video.vbase = ioremap (info->video.pbase, info->video.len);
+  if (!info->video.vbase)
+    {
+      printk ("neofb: unable to map screen memory\n");
+      release_mem_region (info->video.pbase, info->video.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
+
+  info->fb.fix.smem_start = info->video.pbase;
+  info->fb.fix.smem_len   = info->video.len;
+  info->fb.screen_base    = info->video.vbase;
+
+#ifdef CONFIG_MTRR
+  info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
+#endif
+
+  /* Clear framebuffer, it's all white in memory after boot */
+  memset (info->video.vbase, 0, info->video.len);
+
+  return 0;
+}
+
+static void __devinit neo_unmap_video (struct neofb_info *info)
+{
+  DBG("neo_unmap_video");
+
+  if (info->video.vbase)
+    {
+#ifdef CONFIG_MTRR
+      mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
+#endif
+
+      iounmap (info->video.vbase);
+      info->video.vbase = NULL;
+      info->fb.screen_base = NULL;
+
+      release_mem_region (info->video.pbase, info->video.len);
+    }
+}
+
+static int __devinit neo_init_hw (struct neofb_info *info)
+{
+  int videoRam = 896;
+  int maxClock = 65000;
+  int CursorMem = 1024;
+  int CursorOff = 0x100;
+  int linearSize = 1024;
+  int maxWidth = 1024;
+  int maxHeight = 1024;
+  unsigned char type, display;
+  int w;
+    
+  DBG("neo_init_hw");
+
+  neoUnlock();
+
+#if 0
+  printk (KERN_DEBUG "--- Neo extended register dump ---\n");
+  for (w=0; w<0x85; w++)
+    printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
+  for (w=0; w<0xC7; w++)
+    printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
+#endif
+
+  /* Determine the panel type */
+  VGAwGR(0x09,0x26);
+  type = VGArGR(0x21);
+  display = VGArGR(0x20);
+    
+  /* Determine panel width -- used in NeoValidMode. */
+  w = VGArGR(0x20);
+  VGAwGR(0x09,0x00);
+  switch ((w & 0x18) >> 3)
+    {
+    case 0x00:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    case 0x01:
+      info->NeoPanelWidth  = 800;
+      info->NeoPanelHeight = 600;
+      neofb_var = &neofb_var800x600x8;
+      break;
+    case 0x02:
+      info->NeoPanelWidth  = 1024;
+      info->NeoPanelHeight = 768;
+      neofb_var = &neofb_var1024x768x8;
+      break;
+    case 0x03:
+      /* 1280x1024 panel support needs to be added */
+#ifdef NOT_DONE
+      info->NeoPanelWidth  = 1280;
+      info->NeoPanelHeight = 1024;
+      neofb_var = &neofb_var1280x1024x8;
+      break;
+#else
+      printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
+      return -1;
+#endif
+    default:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    }
+
+  printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
+         info->NeoPanelWidth,
+         info->NeoPanelHeight,
+         (type & 0x02) ? "color" : "monochrome",
+         (type & 0x10) ? "TFT" : "dual scan");
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      videoRam   = 896;
+      maxClock   = 65000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 1024;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      videoRam   = 2048;
+      maxClock   = 90000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      videoRam   = 2560;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      videoRam   = 3008;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      videoRam   = 4096;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      videoRam   = 6144;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 8192;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    }
+
+  info->maxClock = maxClock;
+
+  return videoRam * 1024;
+}
+
+
+static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
+                                                       const struct pci_device_id *id)
+{
+  struct neofb_info *info;
+
+  info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
+                 sizeof(u32) * 16, GFP_KERNEL);
+
+  if (!info)
+    return NULL;
+
+  memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
+
+  info->currcon = -1;
+  info->pcidev  = dev;
+  info->accel   = id->driver_data;
+
+  info->pci_burst   = !nopciburst;
+  info->lcd_stretch = !nostretch;
+
+  if (!internal && !external)
+    {
+      info->internal_display = 1;
+      info->external_display = 0;
+    }
+  else
+    {
+      info->internal_display = internal;
+      info->external_display = external;
+    }
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      sprintf (info->fb.fix.id, "MagicGraph 128");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+      sprintf (info->fb.fix.id, "MagicGraph 128V");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      sprintf (info->fb.fix.id, "MagicGraph 128XD");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      sprintf (info->fb.fix.id, "MagicGraph 256ZX");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      sprintf (info->fb.fix.id, "MagicGraph 256XL+");
+      break;
+    }
+
+  info->fb.fix.type       = FB_TYPE_PACKED_PIXELS;
+  info->fb.fix.type_aux           = 0;
+  info->fb.fix.xpanstep           = 0;
+  info->fb.fix.ypanstep           = 4;
+  info->fb.fix.ywrapstep   = 0;
+  info->fb.fix.accel       = id->driver_data;
+
+  info->fb.var.nonstd      = 0;
+  info->fb.var.activate    = FB_ACTIVATE_NOW;
+  info->fb.var.height      = -1;
+  info->fb.var.width       = -1;
+  info->fb.var.accel_flags = 0;
+
+  strcpy (info->fb.modename, info->fb.fix.id);
+
+  info->fb.fbops          = &neofb_ops;
+  info->fb.changevar      = NULL;
+  info->fb.switch_con     = neofb_switch;
+  info->fb.updatevar      = neofb_updatevar;
+  info->fb.blank          = neofb_blank;
+  info->fb.flags          = FBINFO_FLAG_DEFAULT;
+  info->fb.disp           = (struct display *)(info + 1);
+  info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
+
+  fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
+
+  return info;
+}
+
+static void __devinit neo_free_fb_info (struct neofb_info *info)
+{
+  if (info)
+    {
+      /*
+       * Free the colourmap
+       */
+      fb_alloc_cmap (&info->fb.cmap, 0, 0);
+
+      kfree (info);
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
+{
+  struct neofb_info *info;
+  u_int h_sync, v_sync;
+  int err;
+  int video_len;
+
+  DBG("neofb_probe");
+
+  err = pci_enable_device (dev);
+  if (err)
+    return err;
+
+  err = -ENOMEM;
+  info = neo_alloc_fb_info (dev, id);
+  if (!info)
+    goto failed;
+
+  err = neo_map_mmio (info);
+  if (err)
+    goto failed;
+
+  video_len = neo_init_hw (info);
+  if (video_len < 0)
+    {
+      err = video_len;
+      goto failed;
+    }
+
+  err = neo_map_video (info, video_len);
+  if (err)
+    goto failed;
+
+  neofb_set_var (neofb_var, -1, &info->fb);
+
+  /*
+   * Calculate the hsync and vsync frequencies.  Note that
+   * we split the 1e12 constant up so that we can preserve
+   * the precision and fit the results into 32-bit registers.
+   *  (1953125000 * 512 = 1e12)
+   */
+  h_sync = 1953125000 / info->fb.var.pixclock;
+  h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
+                          info->fb.var.right_margin + info->fb.var.hsync_len);
+  v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
+                    info->fb.var.lower_margin + info->fb.var.vsync_len);
+
+  printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+        info->fb.fix.smem_len >> 10,
+        info->fb.var.xres, info->fb.var.yres,
+        h_sync / 1000, h_sync % 1000, v_sync);
+
+
+  err = register_framebuffer (&info->fb);
+  if (err < 0)
+    goto failed;
+
+  printk (KERN_INFO "fb%d: %s frame buffer device\n",
+         GET_FB_IDX(info->fb.node), info->fb.modename);
+
+  /*
+   * Our driver data
+   */
+  dev->driver_data = info;
+
+  return 0;
+
+failed:
+  neo_unmap_video (info);
+  neo_unmap_mmio (info);
+  neo_free_fb_info (info);
+
+  return err;
+}
+
+static void __devexit neofb_remove (struct pci_dev *dev)
+{
+  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
+
+  DBG("neofb_remove");
+
+  if (info)
+    {
+      /*
+       * If unregister_framebuffer fails, then
+       * we will be leaving hooks that could cause
+       * oopsen laying around.
+       */
+      if (unregister_framebuffer (&info->fb))
+       printk (KERN_WARNING "neofb: danger danger!  Oopsen imminent!\n");
+
+      neo_unmap_video (info);
+      neo_unmap_mmio (info);
+      neo_free_fb_info (info);
+
+      /*
+       * Ensure that the driver data is no longer
+       * valid.
+       */
+      dev->driver_data = NULL;
+    }
+}
+
+static struct pci_device_id neofb_devices[] __devinitdata = {
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
+
+  {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, neofb_devices);
+
+static struct pci_driver neofb_driver = {
+  name:      "neofb",
+  id_table:  neofb_devices,
+  probe:     neofb_probe,
+  remove:    neofb_remove
+};
+
+/* **************************** init-time only **************************** */
+
+static void __init neo_init (void)
+{
+  DBG("neo_init");
+  pci_register_driver (&neofb_driver);
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit neo_done (void)
+{
+  DBG("neo_done");
+  pci_unregister_driver (&neofb_driver);
+}
+
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+int __init neofb_setup (char *options)
+{
+  char *this_opt;
+
+  DBG("neofb_setup");
+
+  if (!options || !*options)
+    return 0;
+
+  for (this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,","))
+    {
+      if (!*this_opt) continue;
+
+      if (!strncmp(this_opt, "disabled", 8))
+       disabled = 1;
+      if (!strncmp(this_opt, "internal", 8))
+       internal = 1;
+      if (!strncmp(this_opt, "external", 8))
+       external = 1;
+      if (!strncmp(this_opt, "nostretch", 9))
+       nostretch = 1;
+      if (!strncmp(this_opt, "nopciburst", 10))
+       nopciburst = 1;
+    }
+
+  return 0;
+}
+
+static int __init initialized = 0;
+
+int __init neofb_init(void)
+{
+  DBG("neofb_init");
+
+  if (disabled)
+    return -ENXIO;
+
+  if (!initialized)
+    {
+      initialized = 1;
+      neo_init();
+    }
+
+  /* never return failure, user can hotplug card later... */
+  return 0;
+}
+
+#else
+
+/* *************************** init module code **************************** */
+
+int __init init_module(void)
+{
+  DBG("init_module");
+
+  if (disabled)
+    return -ENXIO;
+
+  neo_init();
+
+  /* never return failure; user can hotplug card later... */
+  return 0;
+}
+
+#endif /* MODULE */
+
+module_exit(neo_done);
diff --git a/drivers/video/neofb.h b/drivers/video/neofb.h
new file mode 100644 (file)
index 0000000..1034311
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+
+#ifdef NEOFB_DEBUG
+# define DBG(x)                printk (KERN_DEBUG "neofb: %s\n", (x));
+#else
+# define DBG(x)
+#endif
+
+
+#define PCI_CHIP_NM2070 0x0001
+#define PCI_CHIP_NM2090 0x0002
+#define PCI_CHIP_NM2093 0x0003
+#define PCI_CHIP_NM2097 0x0083
+#define PCI_CHIP_NM2160 0x0004
+#define PCI_CHIP_NM2200 0x0005
+#define PCI_CHIP_NM2230 0x0025
+#define PCI_CHIP_NM2360 0x0006
+#define PCI_CHIP_NM2380 0x0016
+
+
+struct xtimings {
+  unsigned int pixclock;
+  unsigned int HDisplay;
+  unsigned int HSyncStart;
+  unsigned int HSyncEnd;
+  unsigned int HTotal;
+  unsigned int VDisplay;
+  unsigned int VSyncStart;
+  unsigned int VSyncEnd;
+  unsigned int VTotal;
+  unsigned int sync;
+  int         dblscan;
+  int         interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+typedef volatile struct {
+  __u32 bltStat;
+  __u32 bltCntl;
+  __u32 xpColor;
+  __u32 fgColor;
+  __u32 bgColor;
+  __u32 pitch;
+  __u32 clipLT;
+  __u32 clipRB;
+  __u32 srcBitOffset;
+  __u32 srcStart;
+  __u32 reserved0;
+  __u32 dstStart;
+  __u32 xyExt;
+
+  __u32 reserved1[19];
+
+  __u32 pageCntl;
+  __u32 pageBase;
+  __u32 postBase;
+  __u32 postPtr;
+  __u32 dataPtr;
+} Neo2200;
+
+#define NR_PALETTE     256
+
+#define MMIO_SIZE 0x200000
+
+#define NEO_EXT_CR_MAX 0x85
+#define NEO_EXT_GR_MAX 0xC7
+
+struct neofb_par {
+
+  int depth;
+
+  unsigned char MiscOutReg;     /* Misc */
+  unsigned char CRTC[25];       /* Crtc Controller */
+  unsigned char Sequencer[5];   /* Video Sequencer */
+  unsigned char Graphics[9];    /* Video Graphics */
+  unsigned char Attribute[21];  /* Video Atribute */
+
+  unsigned char GeneralLockReg;
+  unsigned char ExtCRTDispAddr;
+  unsigned char ExtCRTOffset;
+  unsigned char SysIfaceCntl1;
+  unsigned char SysIfaceCntl2;
+  unsigned char ExtColorModeSelect;
+  unsigned char biosMode;
+
+  unsigned char PanelDispCntlReg1;
+  unsigned char PanelDispCntlReg2;
+  unsigned char PanelDispCntlReg3;
+  unsigned char PanelVertCenterReg1;
+  unsigned char PanelVertCenterReg2;
+  unsigned char PanelVertCenterReg3;
+  unsigned char PanelVertCenterReg4;
+  unsigned char PanelVertCenterReg5;
+  unsigned char PanelHorizCenterReg1;
+  unsigned char PanelHorizCenterReg2;
+  unsigned char PanelHorizCenterReg3;
+  unsigned char PanelHorizCenterReg4;
+  unsigned char PanelHorizCenterReg5;
+
+  int           ProgramVCLK;
+  unsigned char VCLK3NumeratorLow;
+  unsigned char VCLK3NumeratorHigh;
+  unsigned char VCLK3Denominator;
+  unsigned char VerticalExt;
+};
+
+struct neofb_info {
+
+  struct fb_info  fb;
+  struct display_switch        *dispsw;
+
+  struct pci_dev *pcidev;
+
+  int   currcon;
+
+  int   accel;
+  char *name;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+#ifdef CONFIG_MTRR
+    int    mtrr;
+#endif
+  } video;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+  } mmio;
+
+  Neo2200 *neo2200;
+
+  /* Panels size */
+  int NeoPanelWidth;
+  int NeoPanelHeight;
+
+  int maxClock;
+
+  int pci_burst;
+  int lcd_stretch;
+  int internal_display;
+  int external_display;
+
+  struct {
+    u16 red, green, blue, transp;
+  } palette[NR_PALETTE];
+};
+
+
+typedef struct {
+    int x_res;
+    int y_res;
+    int mode;
+} biosMode;
+
+
+/* vga IO functions */
+static inline u8 VGArCR (u8 index)
+{
+  outb (index, 0x3d4);
+  return inb (0x3d5);
+}
+
+static inline void VGAwCR (u8 index, u8 val)
+{
+  outb (index, 0x3d4);
+  outb (val, 0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+  outb (index, 0x3ce);
+  return inb (0x3cf);
+}
+
+static inline void VGAwGR (u8 index, u8 val)
+{
+  outb (index, 0x3ce);
+  outb (val, 0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+  outb (index, 0x3c4);
+  return inb (0x3c5);
+}
+
+static inline void VGAwSEQ (u8 index, u8 val)
+{
+  outb (index, 0x3c4);
+  outb (val, 0x3c5);
+}
+
+
+static int paletteEnabled = 0;
+
+static inline void VGAenablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x00, 0x3c0);
+  paletteEnabled = 1;
+}
+
+static inline void VGAdisablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x20, 0x3c0);
+  paletteEnabled = 0;
+}
+
+static inline void VGAwATTR (u8 index, u8 value)
+{
+  u8 tmp;
+
+  if (paletteEnabled)
+    index &= ~0x20;
+  else
+    index |= 0x20;
+
+  tmp = inb (0x3da);
+  outb (index, 0x3c0);
+  outb (value, 0x3c0);
+}
+
+static inline void VGAwMISC (u8 value)
+{
+  outb (value, 0x3c2);
+}
+
+
+#define NEO_BS0_BLT_BUSY        0x00000001
+#define NEO_BS0_FIFO_AVAIL      0x00000002
+#define NEO_BS0_FIFO_PEND       0x00000004
+
+#define NEO_BC0_DST_Y_DEC       0x00000001
+#define NEO_BC0_X_DEC           0x00000002
+#define NEO_BC0_SRC_TRANS       0x00000004
+#define NEO_BC0_SRC_IS_FG       0x00000008
+#define NEO_BC0_SRC_Y_DEC       0x00000010
+#define NEO_BC0_FILL_PAT        0x00000020
+#define NEO_BC0_SRC_MONO        0x00000040
+#define NEO_BC0_SYS_TO_VID      0x00000080
+
+#define NEO_BC1_DEPTH8          0x00000100
+#define NEO_BC1_DEPTH16         0x00000200
+#define NEO_BC1_X_320           0x00000400
+#define NEO_BC1_X_640           0x00000800
+#define NEO_BC1_X_800           0x00000c00
+#define NEO_BC1_X_1024          0x00001000
+#define NEO_BC1_X_1152          0x00001400
+#define NEO_BC1_X_1280          0x00001800
+#define NEO_BC1_X_1600          0x00001c00
+#define NEO_BC1_DST_TRANS       0x00002000
+#define NEO_BC1_MSTR_BLT        0x00004000
+#define NEO_BC1_FILTER_Z        0x00008000
+
+#define NEO_BC2_WR_TR_DST       0x00800000
+
+#define NEO_BC3_SRC_XY_ADDR     0x01000000
+#define NEO_BC3_DST_XY_ADDR     0x02000000
+#define NEO_BC3_CLIP_ON         0x04000000
+#define NEO_BC3_FIFO_EN         0x08000000
+#define NEO_BC3_BLT_ON_ADDR     0x10000000
+#define NEO_BC3_SKIP_MAPPING    0x80000000
+
+#define NEO_MODE1_DEPTH8        0x0100
+#define NEO_MODE1_DEPTH16       0x0200
+#define NEO_MODE1_DEPTH24       0x0300
+#define NEO_MODE1_X_320         0x0400
+#define NEO_MODE1_X_640         0x0800
+#define NEO_MODE1_X_800         0x0c00
+#define NEO_MODE1_X_1024        0x1000
+#define NEO_MODE1_X_1152        0x1400
+#define NEO_MODE1_X_1280        0x1800
+#define NEO_MODE1_X_1600        0x1c00
+#define NEO_MODE1_BLT_ON_ADDR   0x2000
index 80621868bd1cca4ece3a7c0ad288af9b0e14f08e..3188c54251905b9e7794eeacf25a74c4491127b7 100644 (file)
@@ -566,7 +566,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
 
     strcpy(info->info.modename, "OFfb ");
     strncat(info->info.modename, full_name, sizeof(info->info.modename));
-    info->info.node = -1;
+    info->info.node = NODEV;
     info->info.fbops = &offb_ops;
     info->info.disp = disp;
     info->info.fontname[0] = '\0';
index b558e0d42f0d5dbf7775e91c8b8ba3b416f50f08..af6aad704219ac468ab4d936e567881481b10239 100644 (file)
@@ -591,7 +591,7 @@ static int __init init_platinum(struct fb_info_platinum *info)
        disp = &info->disp;
 
        strcpy(info->fb_info.modename, "platinum");
-       info->fb_info.node = -1;
+       info->fb_info.node = NODEV;
        info->fb_info.fbops = &platinumfb_ops;
        info->fb_info.disp = disp;
        strcpy(info->fb_info.fontname, fontname);
index 6a42bec215697db1e6f08d995788b1122693673b..368b07c28d59abb149ad1a46f70560f87d911ccf 100644 (file)
@@ -386,7 +386,7 @@ int __init pmagbafb_init_one(int slot)
         */
        strcpy(ip->info.modename, "PMAG-BA");
        ip->info.changevar = NULL;
-       ip->info.node = -1;
+       ip->info.node = NODEV;
        ip->info.fbops = &pmagbafb_ops;
        ip->info.disp = &disp;
        ip->info.switch_con = &pmagbafb_switch;
index 2c3f7e7b18705fcfef197e992c9a1295e70c2172..7e531eb6bca37cb1157d91333351bb0479766de7 100644 (file)
@@ -389,7 +389,7 @@ int __init pmagbbfb_init_one(int slot)
         */
        strcpy(ip->info.modename, "PMAGB-BA");
        ip->info.changevar = NULL;
-       ip->info.node = -1;
+       ip->info.node = NODEV;
        ip->info.fbops = &pmagbbfb_ops;
        ip->info.disp = &disp;
        ip->info.switch_con = &pmagbbfb_switch;
index 9fd9f0cc230717d227a1eca5f5b04c85d082e5d6..ea328df69050cfb73299a6fb667474b658a496ae 100644 (file)
@@ -1034,7 +1034,7 @@ int __init pvr2fb_init(void)
        
        strcpy(fb_info.modename, pvr2fb_name);
        fb_info.changevar = NULL;
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &pvr2fb_ops;
        fb_info.disp = &disp;
        fb_info.switch_con = &pvr2fbcon_switch;
index 458ff5d5a40eaf8ab858abb599736e3ecaab326f..43fde5bc52dee425e0c42c5c4f2ff2c6c6908bf0 100644 (file)
@@ -331,7 +331,7 @@ int __init q40fb_init(void)
        fb_info.switch_con=&q40con_switch;
        fb_info.updatevar=&q40con_updatevar;
        fb_info.blank=&q40con_blank;    
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &q40fb_ops;
        fb_info.flags = FBINFO_FLAG_DEFAULT;  /* not as module for now */
        
index 30db837cb97ca4dd7ae51d2ab323d99a94eaca65..d89cdb282c45890dac922d0da997005f7b6b633e 100644 (file)
@@ -1305,7 +1305,7 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
        info = &rinfo->info;
 
        strcpy (info->modename, rinfo->name);
-        info->node = -1;
+        info->node = NODEV;
         info->flags = FBINFO_FLAG_DEFAULT;
         info->fbops = &radeon_fb_ops;
         info->display_fg = NULL;
index 335015cdce29dd611c9851a0a8e882fe1f53211e..e893c6504afb1d51653053437144749c0be6502b 100644 (file)
@@ -1422,7 +1422,7 @@ int __init retz3fb_init(void)
 
                strcpy(fb_info->modename, retz3fb_name);
                fb_info->changevar = NULL;
-               fb_info->node = -1;
+               fb_info->node = NODEV;
                fb_info->fbops = &retz3fb_ops;
                fb_info->disp = &zinfo->disp;
                fb_info->switch_con = &z3fb_switch;
index 89f8a67f598c103c2d048993a85242b74ead3a6e..8dc9c920c15cfd3d9b4f37d70bc0f48b2054452c 100644 (file)
@@ -890,7 +890,7 @@ int __init sgivwfb_init(void)
 
   strcpy(fb_info.modename, sgivwfb_name);
   fb_info.changevar = NULL;
-  fb_info.node = -1;
+  fb_info.node = NODEV;
   fb_info.fbops = &sgivwfb_ops;
   fb_info.disp = &disp;
   fb_info.switch_con = &sgivwfbcon_switch;
index 74d3c1634084fe694a9b6119f1c268bde1d48ad8..a15f462c49ec3c39c7a9ef88f2a3610fda082ac5 100644 (file)
@@ -306,7 +306,7 @@ int __init xxxfb_init(void)
     fb_info.gen.fbhw->detect();
     strcpy(fb_info.gen.info.modename, "XXX");
     fb_info.gen.info.changevar = NULL;
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.fbops = &xxxfb_ops;
     fb_info.gen.info.disp = &disp;
     fb_info.gen.info.switch_con = &xxxfb_switch;
index 843b0b15c6f1b04cd163f8db31ecf688007d92a2..8d02da31dae785593dfa9dbff9f155001619d79b 100644 (file)
@@ -1797,7 +1797,7 @@ int __init sstfb_init(void)
                f_ddprintk("membase_phys: %#lx\n", fb_info.video.base);
                f_ddprintk("fbbase_virt: %#lx\n", fb_info.video.vbase);
 
-               fb_info.info.node       = -1 ;
+               fb_info.info.node       = NODEV;
                fb_info.info.flags      = FBINFO_FLAG_DEFAULT;
                fb_info.info.fbops      = &sstfb_ops;
                fb_info.info.disp       = &disp;
index 27a28f10c9b909dbff2fe32656076b651a9de783..d4280cf27fe54e2596a67df10566b16e9424b36f 100644 (file)
@@ -166,7 +166,7 @@ stifb_init(void)
        if ((fb_info.sti = sti_init_roms()) == NULL)
                return -ENXIO;
 
-       fb_info.gen.info.node = -1;
+       fb_info.gen.info.node = NODEV;
        fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
        fb_info.gen.info.fbops = &stifb_ops;
        fb_info.gen.info.disp = &disp;
index 9ed344b43779f31836eef49130df4ae8da811066..59e08a433cefa8eb4da03cca7548c2456059186b 100644 (file)
@@ -573,7 +573,7 @@ sizechange:
        fix->type = FB_TYPE_PACKED_PIXELS;
        fix->visual = FB_VISUAL_PSEUDOCOLOR;
        
-       fb->info.node = -1;
+       fb->info.node = NODEV;
        fb->info.fbops = &sun3fb_ops;
        fb->info.disp = disp;
        strcpy(fb->info.fontname, fontname);
index 11c93e7373a023e040197fb1d200f00f35cf4431..68b8ed57a7c3ea25ea5afba8c29e48aa10a3b157 100644 (file)
@@ -1975,7 +1975,7 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
        strcpy(fb_info.fb_info.modename, "3Dfx "); 
        strcat(fb_info.fb_info.modename, name);
        fb_info.fb_info.changevar  = NULL;
-       fb_info.fb_info.node       = -1;
+       fb_info.fb_info.node       = NODEV;
        fb_info.fb_info.fbops      = &tdfxfb_ops;
        fb_info.fb_info.disp       = &fb_info.disp;
        strcpy(fb_info.fb_info.fontname, fontname);
index a98c62c7e7dcbee531628c0dc144e41b5dde2296..3c7b0ed6d4619fb96a322475b7ab2fea08768104 100644 (file)
@@ -937,7 +937,7 @@ int __init tgafb_init(void)
 
     /* setup framebuffer */
 
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     fb_info.gen.info.fbops = &tgafb_ops;
     fb_info.gen.info.disp = &disp;
index 8f102a833ef8d47cd510da3fc33074c8f5d83b76..b7b7ff514ef83eeb33294d76515fbded9caeba80 100644 (file)
@@ -397,7 +397,7 @@ int __init tx3912fb_init(void)
 
        strcpy(fb_info.modename, TX3912FB_NAME);
        fb_info.changevar = NULL;
-       fb_info.node = -1;
+       fb_info.node = NODEV;
        fb_info.fbops = &tx3912fb_ops;
        fb_info.disp = &global_disp;
        fb_info.switch_con = &tx3912fbcon_switch;
index 1af28c8afe73d1cc5b52541150aec80aff668ad3..295d62606b7db717aa85f3a4e4b4abcdce6f664b 100644 (file)
@@ -779,7 +779,7 @@ static void valkyrie_par_to_display(struct fb_par_valkyrie *par,
 static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
 {
        strcpy(info->modename, p->fix.id);
-       info->node = -1;        /* ??? danj */
+       info->node = NODEV;
        info->fbops = &valkyriefb_ops;
        info->disp = &p->disp;
        strcpy(info->fontname, fontname);
index a8ef9a54a45685f56eebaa2c87740f11f9f511b8..3462fb93563baaae9b8cdd913f3cc36a920e6b7d 100644 (file)
@@ -404,7 +404,7 @@ int __init vfb_init(void)
 
     strcpy(fb_info.modename, vfb_name);
     fb_info.changevar = NULL;
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &vfb_ops;
     fb_info.disp = &disp;
     fb_info.switch_con = &vfbcon_switch;
index 3a6572c6af69c5f7d1545d5ba27ba4c9014ae524..a69a7f846a8cc995575cb0b252de91f2b6a0db13 100644 (file)
@@ -926,7 +926,7 @@ int __init vga16fb_init(void)
        /* name should not depend on EGA/VGA */
        strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
        vga16fb.fb_info.changevar = NULL;
-       vga16fb.fb_info.node = -1;
+       vga16fb.fb_info.node = NODEV;
        vga16fb.fb_info.fbops = &vga16fb_ops;
        vga16fb.fb_info.disp=&disp;
        vga16fb.fb_info.switch_con=&vga16fb_switch;
index 9a0a69dd7165847397ecb1f2bc12606d09b66d06..4128cab5e0d9ddbdefe6b13ca347f8d64abfaf3c 100644 (file)
@@ -1168,7 +1168,7 @@ int __init virgefb_init(void)
 
            strcpy(fb_info.modename, virgefb_name);
            fb_info.changevar = NULL;
-           fb_info.node = -1;
+           fb_info.node = NODEV;
            fb_info.fbops = &virgefb_ops;
            fb_info.disp = &disp;
            fb_info.switch_con = &Cyberfb_switch;
index ec77dc7e926130b24ae634b27698393aa32b2214..1c4d618aa77c3ff5fde089bd4c7b88c61ac46126 100644 (file)
@@ -170,6 +170,7 @@ void __init zorro_init(void)
                        m68k_memory[i].addr+m68k_memory[i].size, 0);
 }
 
+subsys_initcall(zorro_init);
 
 EXPORT_SYMBOL(zorro_find_device);
 EXPORT_SYMBOL(zorro_unused_z2ram);
index cf54dfdc907650436568869ac103c3d37b0d4c7b..e39a91ca1b6013dc3243958ad5e3559f381f2880 100644 (file)
@@ -31,7 +31,10 @@ dep_mbool '  JBD (ext3) debugging support' CONFIG_JBD_DEBUG $CONFIG_JBD
 # msdos file systems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
 dep_tristate '  MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+#dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+# UMSDOS is temprory broken
+define_bool CONFIG_UMSDOS_FS n
+
 dep_tristate '  VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
 dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
 dep_tristate 'Journalling Flash File System (JFFS) support' CONFIG_JFFS_FS $CONFIG_MTD
index 365fb633e88f06218783950c67fb8221d8153df5..350a648ee38400db22c11a8ab467718593433518 100644 (file)
@@ -45,6 +45,8 @@ static struct inode *coda_alloc_inode(struct super_block *sb)
 {
        struct coda_inode_info *ei;
        ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, SLAB_KERNEL);
+       if (!ei)
+               return NULL;
        memset(&ei->c_fid, 0, sizeof(struct ViceFid));
        ei->c_flags = 0;
        INIT_LIST_HEAD(&ei->c_cilist);
@@ -52,8 +54,6 @@ static struct inode *coda_alloc_inode(struct super_block *sb)
        ei->c_contcount = 0;
        memset(&ei->c_cached_cred, 0, sizeof(struct coda_cred));
        ei->c_cached_perm = 0;
-       if (!ei)
-               return NULL;
        return &ei->vfs_inode;
 }
 
index c8d9f41439dd32db5eec27a8bd9bd931a6d55cc6..1658a0580c6866e134475c9a6bc456ecc9ca767d 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/dcache.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/driverfs_fs.h>
+#include <linux/device.h>
 
 #include <asm/uaccess.h>
 
@@ -232,6 +232,7 @@ driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
        struct driver_file_entry * entry;
        unsigned char *page;
        ssize_t retval = 0;
+       struct device * dev;
 
        entry = (struct driver_file_entry *)file->private_data;
        if (!entry) {
@@ -239,10 +240,13 @@ driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
                return -ENOENT;
        }
 
-       if (!entry->ops || !entry->ops->read) {
-               DBG("%s: no read callback\n",__FUNCTION__);
-               return -ENOENT;
-       }
+       dev = list_entry(entry->parent,struct device, dir);
+
+       if (!valid_device(dev))
+               return -EFAULT;
+
+       if (!entry->show)
+               goto done;
 
        page = (unsigned char*)__get_free_page(GFP_KERNEL);
        if (!page) {
@@ -253,7 +257,7 @@ driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
        while (count > 0) {
                ssize_t len;
 
-               len = entry->ops->read(page,count,*ppos,entry->data);
+               len = entry->show(dev,page,count,*ppos);
 
                if (len <= 0) {
                        if (len < 0)
@@ -274,6 +278,7 @@ driverfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
        free_page((unsigned long)page);
 
  done:
+       put_device(dev);
        return retval;
 }
 
@@ -294,6 +299,7 @@ static ssize_t
 driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
        struct driver_file_entry * entry;
+       struct device * dev;
        ssize_t retval = 0;
 
        entry = (struct driver_file_entry *)file->private_data;
@@ -302,16 +308,18 @@ driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *pp
                return -ENOENT;
        }
 
-       if (!entry->ops || !entry->ops->write) {
-               DBG("%s: no write callback\n",__FUNCTION__);
-               retval = -ENOENT;
+       dev = list_entry(entry->parent,struct device, dir);
+
+       if (!valid_device(dev))
+               return -EFAULT;
+
+       if (!entry->store)
                goto done;
-       }
 
        while (count > 0) {
                ssize_t len;
 
-               len = entry->ops->write(buf,count,*ppos,entry->data);
+               len = entry->store(dev,buf,count,*ppos);
 
                if (len <= 0) {
                        if (len < 0)
@@ -323,8 +331,8 @@ driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *pp
                *ppos += len;
                buf += len;
        }
-
  done:
+       put_device(dev);
        return retval;
 }
 
@@ -378,18 +386,6 @@ static int driverfs_d_delete_file (struct dentry * dentry)
        return 0;
 }
 
-/* Similar to above - if this dentry goes away, free the
- * driver_dir_entry associated with it..
- */
-static int driverfs_d_delete_dir (struct dentry * dentry)
-{
-       struct driver_dir_entry * entry;
-       entry = (struct driver_dir_entry *)dentry->d_fsdata;
-       if (entry)
-               kfree(entry);
-       return 0;
-}
-
 static struct address_space_operations driverfs_aops = {
 
 };
@@ -425,10 +421,6 @@ static struct dentry_operations driverfs_dentry_file_ops = {
        d_delete:       driverfs_d_delete_file,
 };
 
-static struct dentry_operations driverfs_dentry_dir_ops = {
-       d_delete:       driverfs_d_delete_dir,
-};
-
 static struct super_operations driverfs_ops = {
        statfs:         driverfs_statfs,
        put_inode:      force_delete,
@@ -545,33 +537,6 @@ EXPORT_SYMBOL(driverfs_remove_dir);
 MODULE_DESCRIPTION("The device driver filesystem");
 MODULE_LICENSE("GPL");
 
-/**
- * driverfs_create_dir_entry - allocate and initialise directory entry
- * @name:      name of the directory
- * @mode:      permissions of the dir
- */
-struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode)
-{
-       struct driver_dir_entry * entry;
-       int size = sizeof(struct driver_dir_entry) + strlen(name) + 1;
-
-
-       entry = kmalloc(size, GFP_KERNEL);
-       if (!entry)
-               return NULL;
-
-       memset(entry, 0, size);
-       strcpy((char *)entry + sizeof(struct driver_dir_entry), name);
-
-       entry->name = (char *)entry + sizeof(struct driver_dir_entry);
-
-       INIT_LIST_HEAD(&entry->files);
-       entry->mode = mode;
-
-       return entry;
-}
-
 /**
  * driverfs_create_dir - create a directory in the filesystem
  * @entry:     directory entry
@@ -672,6 +637,7 @@ driverfs_create_file(struct driver_file_entry * entry,
                dentry->d_inode->u.generic_ip = (void *)entry;
 
                entry->dentry = dentry;
+               entry->parent = parent;
 
                list_add_tail(&entry->node,&parent->files);
        }
@@ -784,39 +750,3 @@ void driverfs_remove_dir(struct driver_dir_entry * dir)
  done:
        put_mount();
 }
-
-/**
- * driverfs_create_entry - allocate and initialise a struct driver_file_entry
- * @name:      name of the file
- * @mode:      permissions of the file
- * @ops:       Operations for the file
- * @data:      data that will be passed back to the callback
- *
- */
-struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
-                      struct driverfs_operations * ops, void * data)
-{
-       struct driver_file_entry * entry;
-       int size;
-
-       size = sizeof(struct driver_file_entry) + strlen(name) + 1;
-
-       entry = kmalloc(size,GFP_KERNEL);
-       if (!entry)
-               return NULL;
-
-       memset(entry, 0, size);
-       strcpy((char *)entry + sizeof(struct driver_file_entry), name);
-
-       entry->name = (char *)entry + sizeof(struct driver_file_entry);
-
-       INIT_LIST_HEAD(&entry->node);
-
-       entry->mode = mode;
-       entry->ops = ops;
-       entry->data = data;
-
-       return entry;
-}
-
index 9d273604a2f80b214b439d9ff03a8060546798fe..f58731211154cdf8431e787b708a3378a3b028d1 100644 (file)
@@ -261,6 +261,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
        inode->i_ino = j;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_blocks = inode->i_blksize = 0;
+       memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
 
index 7cd92b2d6ec6fe040ce4d4634b1ac85d9d20f370..1b4886e416396e98ca149c506c5f9be0df9074c9 100644 (file)
@@ -75,7 +75,51 @@ static void minix_put_super(struct super_block *sb)
        return;
 }
 
+static kmem_cache_t * minix_inode_cachep;
+
+static struct inode *minix_alloc_inode(struct super_block *sb)
+{
+       struct minix_inode_info *ei;
+       ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, SLAB_KERNEL);
+       if (!ei)
+               return NULL;
+       return &ei->vfs_inode;
+}
+
+static void minix_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(minix_inode_cachep, minix_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+       struct minix_inode_info *ei = (struct minix_inode_info *) foo;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+           SLAB_CTOR_CONSTRUCTOR)
+               inode_init_once(&ei->vfs_inode);
+}
+static int init_inodecache(void)
+{
+       minix_inode_cachep = kmem_cache_create("minix_inode_cache",
+                                            sizeof(struct minix_inode_info),
+                                            0, SLAB_HWCACHE_ALIGN,
+                                            init_once, NULL);
+       if (minix_inode_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void destroy_inodecache(void)
+{
+       if (kmem_cache_destroy(minix_inode_cachep))
+               printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations minix_sops = {
+       alloc_inode:    minix_alloc_inode,
+       destroy_inode:  minix_destroy_inode,
        read_inode:     minix_read_inode,
        write_inode:    minix_write_inode,
        delete_inode:   minix_delete_inode,
@@ -344,6 +388,7 @@ static void V1_minix_read_inode(struct inode * inode)
 {
        struct buffer_head * bh;
        struct minix_inode * raw_inode;
+       struct minix_inode_info *minix_inode = minix_i(inode);
        int i;
 
        raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -359,7 +404,7 @@ static void V1_minix_read_inode(struct inode * inode)
        inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
        inode->i_blocks = inode->i_blksize = 0;
        for (i = 0; i < 9; i++)
-               inode->u.minix_i.u.i1_data[i] = raw_inode->i_zone[i];
+               minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
        minix_set_inode(inode, raw_inode->i_zone[0]);
        brelse(bh);
 }
@@ -371,6 +416,7 @@ static void V2_minix_read_inode(struct inode * inode)
 {
        struct buffer_head * bh;
        struct minix2_inode * raw_inode;
+       struct minix_inode_info *minix_inode = minix_i(inode);
        int i;
 
        raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -388,7 +434,7 @@ static void V2_minix_read_inode(struct inode * inode)
        inode->i_ctime = raw_inode->i_ctime;
        inode->i_blocks = inode->i_blksize = 0;
        for (i = 0; i < 10; i++)
-               inode->u.minix_i.u.i2_data[i] = raw_inode->i_zone[i];
+               minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
        minix_set_inode(inode, raw_inode->i_zone[0]);
        brelse(bh);
 }
@@ -411,6 +457,7 @@ static struct buffer_head * V1_minix_update_inode(struct inode * inode)
 {
        struct buffer_head * bh;
        struct minix_inode * raw_inode;
+       struct minix_inode_info *minix_inode = minix_i(inode);
        int i;
 
        raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -425,7 +472,7 @@ static struct buffer_head * V1_minix_update_inode(struct inode * inode)
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
                raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
        else for (i = 0; i < 9; i++)
-               raw_inode->i_zone[i] = inode->u.minix_i.u.i1_data[i];
+               raw_inode->i_zone[i] = minix_inode->u.i1_data[i];
        mark_buffer_dirty(bh);
        return bh;
 }
@@ -437,6 +484,7 @@ static struct buffer_head * V2_minix_update_inode(struct inode * inode)
 {
        struct buffer_head * bh;
        struct minix2_inode * raw_inode;
+       struct minix_inode_info *minix_inode = minix_i(inode);
        int i;
 
        raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -453,7 +501,7 @@ static struct buffer_head * V2_minix_update_inode(struct inode * inode)
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
                raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
        else for (i = 0; i < 10; i++)
-               raw_inode->i_zone[i] = inode->u.minix_i.u.i2_data[i];
+               raw_inode->i_zone[i] = minix_inode->u.i2_data[i];
        mark_buffer_dirty(bh);
        return bh;
 }
@@ -514,12 +562,23 @@ static DECLARE_FSTYPE_DEV(minix_fs_type,"minix",minix_read_super);
 
 static int __init init_minix_fs(void)
 {
-        return register_filesystem(&minix_fs_type);
+       int err = init_inodecache();
+       if (err)
+               goto out1;
+       err = register_filesystem(&minix_fs_type);
+       if (err)
+               goto out;
+       return 0;
+out:
+       destroy_inodecache();
+out1:
+       return err;
 }
 
 static void __exit exit_minix_fs(void)
 {
         unregister_filesystem(&minix_fs_type);
+       destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
index 990dddd0d73e25d153ba0595d1611c83d2a33dc5..31d85c1093f606b615e860620c44a536d3161ab0 100644 (file)
@@ -19,7 +19,7 @@ static inline block_t cpu_to_block(unsigned long n)
 
 static inline block_t *i_data(struct inode *inode)
 {
-       return (block_t *)inode->u.minix_i.u.i1_data;
+       return (block_t *)minix_i(inode)->u.i1_data;
 }
 
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
index bbff60d850fc8c04621fc71cf8e41543a369cbf9..5a3c8192ac25270e50a35b88e2dcbf76e171b221 100644 (file)
@@ -19,7 +19,7 @@ static inline block_t cpu_to_block(unsigned long n)
 
 static inline block_t *i_data(struct inode *inode)
 {
-       return (block_t *)inode->u.minix_i.u.i2_data;
+       return (block_t *)minix_i(inode)->u.i2_data;
 }
 
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
index 093ed8ef6dcfd9086255775fd4266fb1637a2774..fdcc369fbe38fdbfc320a14cbac221b29aaf7f85 100644 (file)
@@ -38,7 +38,7 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
        return tmp & hash_mask;
 }
 
-struct vfsmount *alloc_vfsmnt(void)
+struct vfsmount *alloc_vfsmnt(char *name)
 {
        struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); 
        if (mnt) {
@@ -48,6 +48,14 @@ struct vfsmount *alloc_vfsmnt(void)
                INIT_LIST_HEAD(&mnt->mnt_child);
                INIT_LIST_HEAD(&mnt->mnt_mounts);
                INIT_LIST_HEAD(&mnt->mnt_list);
+               if (name) {
+                       int size = strlen(name)+1;
+                       char * newname = kmalloc(size, GFP_KERNEL);
+                       if (newname) {
+                               memcpy(newname, name, size);
+                               mnt->mnt_devname = newname;
+                       }
+               }
        }
        return mnt;
 }
@@ -59,18 +67,6 @@ void free_vfsmnt(struct vfsmount *mnt)
        kmem_cache_free(mnt_cache, mnt);
 }
 
-void set_devname(struct vfsmount *mnt, const char *name)
-{
-       if (name) {
-               int size = strlen(name)+1;
-               char * newname = kmalloc(size, GFP_KERNEL);
-               if (newname) {
-                       memcpy(newname, name, size);
-                       mnt->mnt_devname = newname;
-               }
-       }
-}
-
 struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
 {
        struct list_head * head = mount_hashtable + hash(mnt, dentry);
@@ -138,11 +134,10 @@ static struct vfsmount *
 clone_mnt(struct vfsmount *old, struct dentry *root)
 {
        struct super_block *sb = old->mnt_sb;
-       struct vfsmount *mnt = alloc_vfsmnt();
+       struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
 
        if (mnt) {
                mnt->mnt_flags = old->mnt_flags;
-               set_devname(mnt, old->mnt_devname);
                atomic_inc(&sb->s_active);
                mnt->mnt_sb = sb;
                mnt->mnt_root = dget(root);
index 4054697f6c93f95af906d18b2fb2a47c8bd3b02d..32e089bd5ec0351481d59f6f1cf2b26bf066b695 100644 (file)
@@ -36,8 +36,54 @@ static void ncp_delete_inode(struct inode *);
 static void ncp_put_super(struct super_block *);
 static int  ncp_statfs(struct super_block *, struct statfs *);
 
+static kmem_cache_t * ncp_inode_cachep;
+
+static struct inode *ncp_alloc_inode(struct super_block *sb)
+{
+       struct ncp_inode_info *ei;
+       ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL);
+       if (!ei)
+               return NULL;
+       return &ei->vfs_inode;
+}
+
+static void ncp_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+       struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+           SLAB_CTOR_CONSTRUCTOR) {
+               init_MUTEX(&ei->open_sem);
+               inode_init_once(&ei->vfs_inode);
+       }
+}
+static int init_inodecache(void)
+{
+       ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
+                                            sizeof(struct ncp_inode_info),
+                                            0, SLAB_HWCACHE_ALIGN,
+                                            init_once, NULL);
+       if (ncp_inode_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void destroy_inodecache(void)
+{
+       if (kmem_cache_destroy(ncp_inode_cachep))
+               printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations ncp_sops =
 {
+       alloc_inode:    ncp_alloc_inode,
+       destroy_inode:  ncp_destroy_inode,
        put_inode:      force_delete,
        delete_inode:   ncp_delete_inode,
        put_super:      ncp_put_super,
@@ -61,6 +107,8 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
 
 #ifdef CONFIG_NCPFS_STRONG
        NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
+#else
+       NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
 #endif
        NCP_FINFO(inode)->access = nwinfo->access;
        NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
@@ -216,7 +264,6 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
 
        inode = new_inode(sb);
        if (inode) {
-               init_MUTEX(&NCP_FINFO(inode)->open_sem);
                atomic_set(&NCP_FINFO(inode)->opened, info->opened);
 
                inode->i_ino = info->ino;
@@ -707,19 +754,31 @@ static DECLARE_FSTYPE(ncp_fs_type, "ncpfs", ncp_read_super, 0);
 
 static int __init init_ncp_fs(void)
 {
+       int err;
        DPRINTK("ncpfs: init_module called\n");
 
 #ifdef DEBUG_NCP_MALLOC
        ncp_malloced = 0;
        ncp_current_malloced = 0;
 #endif
-       return register_filesystem(&ncp_fs_type);
+       err = init_inodecache();
+       if (err)
+               goto out1;
+       err = register_filesystem(&ncp_fs_type);
+       if (err)
+               goto out;
+       return 0;
+out:
+       destroy_inodecache();
+out1:
+       return err;
 }
 
 static void __exit exit_ncp_fs(void)
 {
        DPRINTK("ncpfs: cleanup_module called\n");
        unregister_filesystem(&ncp_fs_type);
+       destroy_inodecache();
 #ifdef DEBUG_NCP_MALLOC
        PRINTK("ncp_malloced: %d\n", ncp_malloced);
        PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
index 6cc44031e4e00bbf631083e7b7cc0500f64a0126..a4d9a98185801fb2fbdf18703a0e5cfb995235c5 100644 (file)
@@ -99,7 +99,7 @@ nfsd_svc(unsigned short port, int nrservs)
                if (error < 0)
                        goto failure;
 #endif
-               get_fast_time(&nfssvc_boot);            /* record boot time */
+               do_gettimeofday(&nfssvc_boot);          /* record boot time */
        } else
                nfsd_serv->sv_nrthreads++;
        nrservs -= (nfsd_serv->sv_nrthreads-1);
index a426e4f84584bfb1b35b534e02a7866469f24567..9b19cc7ddbbfcd14e96733ec283b2368baf91484 100644 (file)
@@ -466,6 +466,7 @@ int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th,
                                unsigned long      * free_blocknrs,
                                unsigned long        search_start)
 {
+  struct reiserfs_inode_info *ei = REISERFS_I(p_s_inode);
   int ret=0, blks_gotten=0;
   unsigned long border = 0;
   unsigned long bstart = 0;
@@ -550,13 +551,13 @@ int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th,
     }
 
   /* take a block off the prealloc list and return it -Hans */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) {
-    p_s_inode->u.reiserfs_i.i_prealloc_count--;
-    *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++;
+  if (ei->i_prealloc_count > 0) {
+    ei->i_prealloc_count--;
+    *free_blocknrs = ei->i_prealloc_block++;
 
     /* if no more preallocated blocks, remove inode from list */
-    if (! p_s_inode->u.reiserfs_i.i_prealloc_count) {
-      list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list);
+    if (! ei->i_prealloc_count) {
+      list_del_init(&ei->i_prealloc_list);
     }
     
     return ret;
@@ -567,8 +568,8 @@ int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th,
   /* this uses the last preallocated block as the search_start.  discard
   ** prealloc does not zero out this number.
   */
-  if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) {
-    search_start = p_s_inode->u.reiserfs_i.i_prealloc_block;
+  if (search_start <= ei->i_prealloc_block) {
+    search_start = ei->i_prealloc_block;
   }
   
   /* doing the compare again forces search_start to be >= the border,
@@ -611,18 +612,18 @@ int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th,
     }
 #endif
     if (blks_gotten==0) {
-      p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs;
+      ei->i_prealloc_block = *free_blocknrs;
     }
     search_start = *free_blocknrs; 
     *free_blocknrs = 0;
   }
-  p_s_inode->u.reiserfs_i.i_prealloc_count = blks;
-  *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block;
-  p_s_inode->u.reiserfs_i.i_prealloc_block++;
+  ei->i_prealloc_count = blks;
+  *free_blocknrs = ei->i_prealloc_block;
+  ei->i_prealloc_block++;
 
   /* if inode has preallocated blocks, link him to list */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count) {
-    list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list,
+  if (ei->i_prealloc_count) {
+    list_add(&ei->i_prealloc_list,
             &SB_JOURNAL(th->t_super)->j_prealloc_list);
   } 
   /* we did actually manage to get 1 block */
@@ -657,42 +658,43 @@ int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th,
 // analog. You should be able to tell which portion by looking at the
 // ext2 code and comparing. 
 static void __discard_prealloc (struct reiserfs_transaction_handle * th,
-                               struct inode * inode)
+                               struct reiserfs_inode_info *ei)
 {
-  while (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    reiserfs_free_block(th,inode->u.reiserfs_i.i_prealloc_block);
-    inode->u.reiserfs_i.i_prealloc_block++;
-    inode->u.reiserfs_i.i_prealloc_count --;
+  while (ei->i_prealloc_count > 0) {
+    reiserfs_free_block(th,ei->i_prealloc_block);
+    ei->i_prealloc_block++;
+    ei->i_prealloc_count --;
   }
-  list_del (&(inode->u.reiserfs_i.i_prealloc_list));
+  list_del_init(&(ei->i_prealloc_list));
 }
 
 
 void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
                                struct inode * inode)
 {
+  struct reiserfs_inode_info *ei = REISERFS_I(inode);
 #ifdef CONFIG_REISERFS_CHECK
-  if (inode->u.reiserfs_i.i_prealloc_count < 0)
+  if (ei->i_prealloc_count < 0)
      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");
 #endif  
-    if (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    __discard_prealloc(th, inode);
+    if (ei->i_prealloc_count > 0) {
+    __discard_prealloc(th, ei);
   }
       }
 
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
 {
   struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
-  struct inode * inode;
   
   while (!list_empty(plist)) {
-    inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
+       struct reiserfs_inode_info *ei;
+       ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
 #ifdef CONFIG_REISERFS_CHECK
-    if (!inode->u.reiserfs_i.i_prealloc_count) {
-      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
-    }
-#endif    
-    __discard_prealloc(th, inode);
+       if (!ei->i_prealloc_count) {
+               reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
+       }
+#endif
+       __discard_prealloc(th, ei);
     }
 }
 #endif
index 7e854531edfa3dad8022ea1b148d49d16f1a9bac..c940340928da0af0c84f5ed71566fda96ac2662c 100644 (file)
@@ -186,7 +186,7 @@ inline int get_last_unformatted_node_blocknr_of_file(  struct key * p_s_key_to_s
 
       copy_key(&unf_key_to_search,p_s_key_to_search);
       unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
-      unf_key_to_search.k_offset = p_s_inode->u.reiserfs_i.i_first_direct_byte - 1;
+      unf_key_to_search.k_offset = REISERFS_I(p_s_inode)->i_first_direct_byte - 1;
 
         /* p_s_key_to_search->k_offset -  MAX_ITEM_LEN(p_s_sb->s_blocksize); */
       if (search_for_position_by_key (p_s_sb, &unf_key_to_search, p_unf_search_path, &n_pos_in_item) == POSITION_FOUND)
@@ -218,16 +218,16 @@ static int get_buffer_near_last_unf ( struct super_block * p_s_sb, struct key *
   unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
   
   if (
-      (p_s_inode->u.reiserfs_i.i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of
+      (REISERFS_I(p_s_inode)->i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of
                                                               crap other than what the name indicates, thus
                                                               testing to see if it is 0 is not enough */
-      && (p_s_inode->u.reiserfs_i.i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then
+      && (REISERFS_I(p_s_inode)->i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then
                                                                            i_first_direct_byte = MAX_KEY_OFFSET */
       )
     {
                                 /* actually, we don't want the last unformatted node, we want the last unformatted node
                                    which is before the current file offset */
-      unf_key_to_search.k_offset = ((p_s_inode->u.reiserfs_i.i_first_direct_byte -1) < unf_key_to_search.k_offset) ? p_s_inode->u.reiserfs_i.i_first_direct_byte -1 :  unf_key_to_search.k_offset;
+      unf_key_to_search.k_offset = ((REISERFS_I(p_s_inode)->i_first_direct_byte -1) < unf_key_to_search.k_offset) ? REISERFS_I(p_s_inode)->i_first_direct_byte -1 :  unf_key_to_search.k_offset;
 
       while (unf_key_to_search.k_offset > -1)
         {
index 3a41dc5f44389b4e2ca353fbe78a4a4047b140a4..d68564b045a039c502e98c69ef908bfcfb393eb0 100644 (file)
@@ -33,9 +33,9 @@ static int reiserfs_file_release (struct inode * inode, struct file * filp)
 
     /* fast out for when nothing needs to be done */
     if ((atomic_read(&inode->i_count) > 1 ||
-         !inode->u.reiserfs_i.i_pack_on_close || 
+         REISERFS_I(inode)->i_pack_on_close || 
          !tail_has_to_be_packed(inode))       && 
-       inode->u.reiserfs_i.i_prealloc_count <= 0) {
+       REISERFS_I(inode)->i_prealloc_count <= 0) {
        return 0;
     }    
     
@@ -50,7 +50,7 @@ static int reiserfs_file_release (struct inode * inode, struct file * filp)
     journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
 
     if (atomic_read(&inode->i_count) <= 1 &&
-       inode->u.reiserfs_i.i_pack_on_close &&
+       REISERFS_I(inode)->i_pack_on_close &&
         tail_has_to_be_packed (inode)) {
        /* if regular file is released by last holder and it has been
           appended (we append by unformatted node only) or its direct
index f9748aac81cf4d783f104081e45b48678ca070b2..7b760ac02bcea541e307fa7b99d17a4fb771d336 100644 (file)
@@ -69,7 +69,7 @@ static void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32
 
 /* take base of inode_key (it comes from inode always) (dirid, objectid) and version from an inode, set
    offset and type of key */
-void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset,
+void make_cpu_key (struct cpu_key * key, struct inode * inode, loff_t offset,
              int type, int length )
 {
   _make_cpu_key (key, inode_items_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
@@ -559,7 +559,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
        return ret;
     }
 
-    inode->u.reiserfs_i.i_pack_on_close = 1 ;
+    REISERFS_I(inode)->i_pack_on_close = 1 ;
 
     windex = push_journal_writer("reiserfs_get_block") ;
   
@@ -868,8 +868,6 @@ static void init_inode (struct inode * inode, struct path * path)
     copy_key (INODE_PKEY (inode), &(ih->ih_key));
     inode->i_blksize = PAGE_SIZE;
 
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
-
     if (stat_data_v1 (ih)) {
        struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
        unsigned long blocks;
@@ -898,7 +896,7 @@ static void init_inode (struct inode * inode, struct path * path)
        }
 
         rdev = sd_v1_rdev(sd);
-       inode->u.reiserfs_i.i_first_direct_byte = sd_v1_first_direct_byte(sd);
+       REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
     } else {
        // new stat data found, but object may have old items
        // (directories and symlinks)
@@ -926,10 +924,15 @@ static void init_inode (struct inode * inode, struct path * path)
            inode_items_version (inode) = ITEM_VERSION_1;
        else
            inode_items_version (inode) = ITEM_VERSION_2;
+       REISERFS_I(inode)->i_first_direct_byte = 0;
     }
-
+    REISERFS_I(inode)->i_pack_on_close = 0;
+    REISERFS_I(inode)->i_prealloc_block = 0;
+    REISERFS_I(inode)->i_prealloc_count = 0;
+    REISERFS_I(inode)->i_trans_id = 0;
+    REISERFS_I(inode)->i_trans_index = 0;
     /* nopack = 0, by default */
-    inode->u.reiserfs_i.nopack = 0;
+    REISERFS_I(inode)->nopack = 0;
 
     pathrelse (path);
     if (S_ISREG (inode->i_mode)) {
@@ -993,7 +996,7 @@ static void inode2sd_v1 (void * sd, struct inode * inode)
         set_sd_v1_blocks(sd_v1, inode->i_blocks );
 
     // Sigh. i_first_direct_byte is back
-    set_sd_v1_first_direct_byte(sd_v1, inode->u.reiserfs_i.i_first_direct_byte);
+    set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
 }
 
 
@@ -1331,7 +1334,7 @@ int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode *
    containing "." and ".." entries */
 static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, 
                                   struct item_head * ih, struct path * path,
-                                  const struct inode * dir)
+                                  struct inode * dir)
 {
     struct super_block * sb = th->t_super;
     char empty_dir [EMPTY_DIR_SIZE];
@@ -1419,7 +1422,7 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th,
    directory) or reiserfs_new_symlink (to insert symlink body if new
    object is symlink) or nothing (if new object is regular file) */
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-                                  const struct inode * dir, int mode, 
+                                  struct inode * dir, int mode, 
                                   const char * symname, 
                                   int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
                                                  strlen (symname) for symlinks)*/
@@ -1501,10 +1504,15 @@ struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
     inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
     inode->i_size = i_size;
     inode->i_blocks = (inode->i_size + 511) >> 9;
-    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
+    REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : 
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+    REISERFS_I(inode)->i_pack_on_close = 0;
+    REISERFS_I(inode)->i_prealloc_block = 0;
+    REISERFS_I(inode)->i_prealloc_count = 0;
+    REISERFS_I(inode)->nopack = 0;
+    REISERFS_I(inode)->i_trans_id = 0;
+    REISERFS_I(inode)->i_trans_index = 0;
 
     if (old_format_only (sb))
        inode2sd_v1 (&sd, inode);
index d142a322c397efe02c70e27be0adf9ffc5f79d52..2d0f172dc6054d542f975ba701a2f7cb84cc18a7 100644 (file)
@@ -46,7 +46,7 @@ int reiserfs_unpack (struct inode * inode, struct file * filp)
         return -EINVAL ;
     }
     /* ioctl already done */
-    if (inode->u.reiserfs_i.nopack) {
+    if (REISERFS_I(inode)->nopack) {
         return 0 ;
     }
     lock_kernel();
@@ -59,7 +59,7 @@ int reiserfs_unpack (struct inode * inode, struct file * filp)
     write_from = inode->i_size & (blocksize - 1) ;
     /* if we are on a block boundary, we are already unpacked.  */
     if ( write_from == 0) {
-       inode->u.reiserfs_i.nopack = 1;
+       REISERFS_I(inode)->nopack = 1;
        goto out ;
     }
 
@@ -79,7 +79,7 @@ int reiserfs_unpack (struct inode * inode, struct file * filp)
 
     /* conversion can change page contents, must flush */
     flush_dcache_page(page) ;
-    inode->u.reiserfs_i.nopack = 1;
+    REISERFS_I(inode)->nopack = 1;
     kunmap(page) ; /* mapped by prepare_write */
 
 out_unlock:
index 1c9dc427c8a8e46de725edf79b87da59b0093c82..fe718c7cd7e636e27437eefa19971da084788cc9 100644 (file)
@@ -2613,14 +2613,14 @@ int journal_mark_freed(struct reiserfs_transaction_handle *th, struct super_bloc
 
 void reiserfs_update_inode_transaction(struct inode *inode) {
   
-  inode->u.reiserfs_i.i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
+  REISERFS_I(inode)->i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
 
-  inode->u.reiserfs_i.i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
+  REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
 }
 
 static int reiserfs_inode_in_this_transaction(struct inode *inode) {
-  if (inode->u.reiserfs_i.i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id || 
-      inode->u.reiserfs_i.i_trans_id == 0) {
+  if (REISERFS_I(inode)->i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id || 
+      REISERFS_I(inode)->i_trans_id == 0) {
     return 1; 
   } 
   return 0 ;
@@ -2631,14 +2631,14 @@ void reiserfs_commit_for_inode(struct inode *inode) {
   struct reiserfs_transaction_handle th ;
   struct super_block *sb = inode->i_sb ;
 
-  jl = SB_JOURNAL_LIST(sb) + inode->u.reiserfs_i.i_trans_index ;
+  jl = SB_JOURNAL_LIST(sb) + REISERFS_I(inode)->i_trans_index ;
 
   /* is it from the current transaction, or from an unknown transaction? */
   if (reiserfs_inode_in_this_transaction(inode)) {
     journal_join(&th, sb, 1) ;
     reiserfs_update_inode_transaction(inode) ;
     journal_end_sync(&th, sb, 1) ;
-  } else if (jl->j_trans_id == inode->u.reiserfs_i.i_trans_id) {
+  } else if (jl->j_trans_id == REISERFS_I(inode)->i_trans_id) {
     flush_commit_list(sb, jl, 1) ;
   }
   /* if the transaction id does not match, this list is long since flushed
index 482b03d94872a6dbb46fb09dfc9efbb124c11d60..defc862b779a785e5e64debca86d9f55b5c13848 100644 (file)
@@ -1489,7 +1489,7 @@ static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th,
     */
     if (atomic_read(&p_s_inode->i_count) > 1 || 
         !tail_has_to_be_packed (p_s_inode) || 
-       !page || p_s_inode->u.reiserfs_i.nopack) {
+       !page || REISERFS_I(p_s_inode)->nopack) {
        // leave tail in an unformatted node    
        *p_c_mode = M_SKIP_BALANCING;
        cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1));
@@ -1654,7 +1654,7 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
            /* we delete first part of tail which was stored in direct
                item(s) */
            // FIXME: this is to keep 3.5 happy
-           p_s_inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+           REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
            p_s_inode->i_blocks -= p_s_sb->s_blocksize / 512;
        }
     }
@@ -1691,7 +1691,7 @@ int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
        ** be flushed before the transaction commits, so we don't need to 
        ** deal with it here.
        */
-       p_s_inode->u.reiserfs_i.i_pack_on_close = 0 ;
+       REISERFS_I(p_s_inode)->i_pack_on_close = 0 ;
     }
     return n_ret_value;
 }
index 4281c39ee0b0b5d42d0b10e04361943b13f9d862..65d6d90d8d22b3d6313a4c273b5c4af402f5dcd2 100644 (file)
@@ -124,8 +124,54 @@ void reiserfs_put_super (struct super_block * s)
   return;
 }
 
+static kmem_cache_t * reiserfs_inode_cachep;
+
+static struct inode *reiserfs_alloc_inode(struct super_block *sb)
+{
+       struct reiserfs_inode_info *ei;
+       ei = (struct reiserfs_inode_info *)kmem_cache_alloc(reiserfs_inode_cachep, SLAB_KERNEL);
+       if (!ei)
+               return NULL;
+       return &ei->vfs_inode;
+}
+
+static void reiserfs_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+       struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *) foo;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+           SLAB_CTOR_CONSTRUCTOR) {
+               INIT_LIST_HEAD(&ei->i_prealloc_list) ;
+               inode_init_once(&ei->vfs_inode);
+       }
+}
+static int init_inodecache(void)
+{
+       reiserfs_inode_cachep = kmem_cache_create("reiserfs_inode_cache",
+                                            sizeof(struct reiserfs_inode_info),
+                                            0, SLAB_HWCACHE_ALIGN,
+                                            init_once, NULL);
+       if (reiserfs_inode_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void destroy_inodecache(void)
+{
+       if (kmem_cache_destroy(reiserfs_inode_cachep))
+               printk(KERN_INFO "reiserfs_inode_cache: not all structures were freed\n");
+}
+
 struct super_operations reiserfs_sops = 
 {
+  alloc_inode: reiserfs_alloc_inode,
+  destroy_inode: reiserfs_destroy_inode,
   read_inode: reiserfs_read_inode,
   read_inode2: reiserfs_read_inode2,
   write_inode: reiserfs_write_inode,
@@ -365,7 +411,7 @@ static int read_super_block (struct super_block * s, int offset)
     bh = sb_bread (s, offset / s->s_blocksize);
     if (!bh) {
       printk ("read_super_block: "
-              "bread failed (dev %s, block %d, size %d)\n",
+              "bread failed (dev %s, block %ld, size %ld)\n",
               s->s_id, offset / s->s_blocksize, s->s_blocksize);
       return 1;
     }
@@ -373,7 +419,7 @@ static int read_super_block (struct super_block * s, int offset)
     rs = (struct reiserfs_super_block *)bh->b_data;
     if (!is_reiserfs_magic_string (rs)) {
       printk ("read_super_block: "
-              "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+              "can't find a reiserfs filesystem on (dev %s, block %lu, size %ld)\n",
               s->s_id, bh->b_blocknr, s->s_blocksize);
       brelse (bh);
       return 1;
@@ -389,7 +435,7 @@ static int read_super_block (struct super_block * s, int offset)
     bh = reiserfs_bread (s, offset / s->s_blocksize);
     if (!bh) {
        printk("read_super_block: "
-                "bread failed (dev %s, block %d, size %d)\n",
+                "bread failed (dev %s, block %ld, size %ld)\n",
                 s->s_id, offset / s->s_blocksize, s->s_blocksize);
        return 1;
     }
@@ -397,7 +443,7 @@ static int read_super_block (struct super_block * s, int offset)
     rs = (struct reiserfs_super_block *)bh->b_data;
     if (!is_reiserfs_magic_string (rs) || sb_blocksize(rs) != s->s_blocksize) {
        printk ("read_super_block: "
-               "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+               "can't find a reiserfs filesystem on (dev %s, block %lu, size %ld)\n",
                s->s_id, bh->b_blocknr, s->s_blocksize);
        brelse (bh);
        printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", s->s_id);
@@ -803,10 +849,22 @@ static DECLARE_FSTYPE_DEV(reiserfs_fs_type,"reiserfs",reiserfs_read_super);
 //
 static int __init init_reiserfs_fs (void)
 {
+       int err = init_inodecache();
+       if (err)
+               goto out1;
        reiserfs_proc_info_global_init();
        reiserfs_proc_register_global( "version", 
                                       reiserfs_global_version_in_proc );
-        return register_filesystem(&reiserfs_fs_type);
+        err = register_filesystem(&reiserfs_fs_type);
+       if (err)
+               goto out;
+       return 0;
+out:
+       reiserfs_proc_unregister_global( "version" );
+       reiserfs_proc_info_global_done();
+       destroy_inodecache();
+out1:
+       return err;
 }
 
 MODULE_DESCRIPTION("ReiserFS journaled filesystem");
@@ -822,6 +880,7 @@ static void __exit exit_reiserfs_fs(void)
        reiserfs_proc_unregister_global( "version" );
        reiserfs_proc_info_global_done();
         unregister_filesystem(&reiserfs_fs_type);
+       destroy_inodecache();
 }
 
 module_init(init_reiserfs_fs) ;
index 5648d09857a63360bff1d5ed7237e16371b98895..8f433ebce87d5b044281210e960dbe98c0101aaa 100644 (file)
@@ -125,7 +125,7 @@ int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inod
        memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ;
     }
 
-    inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+    REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
 
     return 0;
 }
@@ -285,7 +285,7 @@ int indirect2direct (struct reiserfs_transaction_handle *th,
 
     /* we store position of first direct item in the in-core inode */
     //mark_file_with_tail (p_s_inode, pos1 + 1);
-    p_s_inode->u.reiserfs_i.i_first_direct_byte = pos1 + 1;
+    REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
 
     return n_block_size - round_tail_len;
 }
index 14f9a9a9a70efb35fff608e15a379f74e78574c8..fb70602790ae0c6e997a49d13984f924cad1bedd 100644 (file)
@@ -408,9 +408,8 @@ static void remove_super(struct super_block *s)
                put_anon_dev(dev);
 }
 
-struct vfsmount *alloc_vfsmnt(void);
+struct vfsmount *alloc_vfsmnt(char *name);
 void free_vfsmnt(struct vfsmount *mnt);
-void set_devname(struct vfsmount *mnt, const char *name);
 
 static inline struct super_block * find_super(kdev_t dev)
 {
@@ -790,10 +789,9 @@ do_kern_mount(const char *fstype, int flags, char *name, void *data)
        if (!type)
                return ERR_PTR(-ENODEV);
 
-       mnt = alloc_vfsmnt();
+       mnt = alloc_vfsmnt(name);
        if (!mnt)
                goto out;
-       set_devname(mnt, name);
        if (type->fs_flags & FS_REQUIRES_DEV)
                sb = get_sb_bdev(type, flags, name, data);
        else if (type->fs_flags & FS_SINGLE)
index 38525d6ce6e291cf2937580fa4f08d896ea89c44..f379adc79dfd460f58bad70ca208e33d5090253f 100644 (file)
@@ -1,3 +1,33 @@
+Mon Jan 21 2001  Alexander Viro  <viro@math.psu.edu>
+       * ialloc.c (sysv_new_inode): zero SYSV_I(inode)->i_data out.
+       * i_vnode renamed to vfs_inode.  Sorry, but let's keep that
+         consistent.
+
+Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+
+       * include/linux/sysv_fs.h (SYSV_I): Get fs-private inode data using
+               list_entry() instead of inode->u.
+       * include/linux/sysv_fs_i.h: Add 'struct inode  i_vnode' field to
+               sysv_inode_info structure.
+       * inode.c: Include <linux/slab.h>, implement alloc_inode/destroy_inode
+               sop methods, add infrastructure for per-fs inode slab cache.
+       * super.c (init_sysv_fs): Initialize inode cache, recover properly
+               in the case of failed register_filesystem for V7.
+       (exit_sysv_fs): Destroy inode cache.
+
+Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+
+       * include/linux/sysv_fs.h: Include <linux/sysv_fs_i.h>, declare SYSV_I().
+       * dir.c (sysv_find_entry): Use SYSV_I() instead of ->u.sysv_i to
+               access fs-private inode data.
+       * ialloc.c (sysv_new_inode): Likewise.
+       * inode.c (sysv_read_inode): Likewise.
+       (sysv_update_inode): Likewise.
+       * itree.c (get_branch): Likewise.
+       (sysv_truncate): Likewise.
+       * symlink.c (sysv_readlink): Likewise.
+       (sysv_follow_link): Likewise.
+
 Fri Jan  4 2001  Alexander Viro  <viro@math.psu.edu>
 
        * ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname().
index db0b233541fbef5486f9dd2cf3d1b8d535933942..99cd284659afd4ce8cdd9d39a50fe459106a0b8b 100644 (file)
@@ -145,7 +145,7 @@ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_
 
        *res_page = NULL;
 
-       start = dir->u.sysv_i.i_dir_start_lookup;
+       start = SYSV_I(dir)->i_dir_start_lookup;
        if (start >= npages)
                start = 0;
        n = start;
@@ -174,7 +174,7 @@ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_
        return NULL;
 
 found:
-       dir->u.sysv_i.i_dir_start_lookup = n;
+       SYSV_I(dir)->i_dir_start_lookup = n;
        *res_page = page;
        return de;
 }
index 4e20e5e9844c930621c05a1c3bd9148b8314965a..361e8965be3a1266fbe5e79b7e5caf6173cd64e5 100644 (file)
@@ -165,7 +165,8 @@ struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
        inode->i_ino = fs16_to_cpu(sb, ino);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_blocks = inode->i_blksize = 0;
-       inode->u.sysv_i.i_dir_start_lookup = 0;
+       memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
+       SYSV_I(inode)->i_dir_start_lookup = 0;
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
 
index 15b8b321bde4c6685409fb4aadf2dec33e214238..c554f1d46a7ff82b3c3467873dced294334e277c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <linux/highuid.h>
+#include <linux/slab.h>
 #include <asm/byteorder.h>
 
 /* This is only called on sync() and umount(), when s_dirt=1. */
@@ -144,6 +145,7 @@ static void sysv_read_inode(struct inode *inode)
        struct super_block * sb = inode->i_sb;
        struct buffer_head * bh;
        struct sysv_inode * raw_inode;
+       struct sysv_inode_info * si;
        unsigned int block, ino;
        dev_t rdev = 0;
 
@@ -169,13 +171,15 @@ static void sysv_read_inode(struct inode *inode)
        inode->i_mtime = fs32_to_cpu(sb, raw_inode->i_mtime);
        inode->i_ctime = fs32_to_cpu(sb, raw_inode->i_ctime);
        inode->i_blocks = inode->i_blksize = 0;
+
+       si = SYSV_I(inode);
        for (block = 0; block < 10+1+1+1; block++)
                read3byte(sb, &raw_inode->i_a.i_addb[3*block],
-                       (unsigned char*)&inode->u.sysv_i.i_data[block]);
+                       (unsigned char*)&si->i_data[block]);
        brelse(bh);
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-               rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]);
-       inode->u.sysv_i.i_dir_start_lookup = 0;
+               rdev = (u16)fs32_to_cpu(sb, si->i_data[0]);
+       si->i_dir_start_lookup = 0;
        sysv_set_inode(inode, rdev);
        return;
 
@@ -189,6 +193,7 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
        struct super_block * sb = inode->i_sb;
        struct buffer_head * bh;
        struct sysv_inode * raw_inode;
+       struct sysv_inode_info * si;
        unsigned int ino, block;
 
        ino = inode->i_ino;
@@ -211,11 +216,12 @@ static struct buffer_head * sysv_update_inode(struct inode * inode)
        raw_inode->i_atime = cpu_to_fs32(sb, inode->i_atime);
        raw_inode->i_mtime = cpu_to_fs32(sb, inode->i_mtime);
        raw_inode->i_ctime = cpu_to_fs32(sb, inode->i_ctime);
+
+       si = SYSV_I(inode);
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-               inode->u.sysv_i.i_data[0] = 
-                       cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
+               si->i_data[0] = cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
        for (block = 0; block < 10+1+1+1; block++)
-               write3byte(sb, (unsigned char*)&inode->u.sysv_i.i_data[block],
+               write3byte(sb, (unsigned char*)&si->i_data[block],
                        &raw_inode->i_a.i_addb[3*block]);
        mark_buffer_dirty(bh);
        return bh;
@@ -260,7 +266,35 @@ static void sysv_delete_inode(struct inode *inode)
        unlock_kernel();
 }
 
+static kmem_cache_t *sysv_inode_cachep;
+
+static struct inode *sysv_alloc_inode(struct super_block *sb)
+{
+       struct sysv_inode_info *si;
+
+       si = kmem_cache_alloc(sysv_inode_cachep, SLAB_KERNEL);
+       if (!si)
+               return NULL;
+       return &si->vfs_inode;
+}
+
+static void sysv_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
+}
+
+static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+       struct sysv_inode_info *si = (struct sysv_inode_info *)p;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+                       SLAB_CTOR_CONSTRUCTOR)
+               inode_init_once(&si->vfs_inode);
+}
+
 struct super_operations sysv_sops = {
+       alloc_inode:    sysv_alloc_inode,
+       destroy_inode:  sysv_destroy_inode,
        read_inode:     sysv_read_inode,
        write_inode:    sysv_write_inode,
        delete_inode:   sysv_delete_inode,
@@ -268,3 +302,18 @@ struct super_operations sysv_sops = {
        write_super:    sysv_write_super,
        statfs:         sysv_statfs,
 };
+
+int __init sysv_init_icache(void)
+{
+       sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
+                       sizeof(struct sysv_inode_info), 0,
+                       SLAB_HWCACHE_ALIGN, init_once, NULL);
+       if (!sysv_inode_cachep)
+               return -ENOMEM;
+       return 0;
+}
+
+void sysv_destroy_icache(void)
+{
+       kmem_cache_destroy(sysv_inode_cachep);
+}
index b88cc432536a9b259ab9fdafd9c700d8cb7afec1..4ff94df7a3a2a8a294f124a9a7c6f96869b5c61b 100644 (file)
@@ -91,7 +91,7 @@ static Indirect *get_branch(struct inode *inode,
        struct buffer_head *bh;
 
        *err = 0;
-       add_chain (chain, NULL, inode->u.sysv_i.i_data + *offsets);
+       add_chain (chain, NULL, SYSV_I(inode)->i_data + *offsets);
        if (!p->key)
                goto no_block;
        while (--depth) {
@@ -348,7 +348,7 @@ static void free_branches(struct inode *inode, u32 *p, u32 *q, int depth)
 
 void sysv_truncate (struct inode * inode)
 {
-       u32 *i_data = inode->u.sysv_i.i_data;
+       u32 *i_data = SYSV_I(inode)->i_data;
        int offsets[DEPTH];
        Indirect chain[DEPTH];
        Indirect *partial;
index 7c9c82932e7b4317f60e36d87fae78b47e33fa10..1e853dd27a9aafad06b299520843a4c2c70cf75d 100644 (file)
@@ -479,18 +479,37 @@ failed:
 static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super);
 static DECLARE_FSTYPE_DEV(v7_fs_type, "v7", v7_read_super);
 
+extern int sysv_init_icache(void) __init;
+extern void sysv_destroy_icache(void);
+
 static int __init init_sysv_fs(void)
 {
-       int err = register_filesystem(&sysv_fs_type);
-       if (!err)
-               err = register_filesystem(&v7_fs_type);
-       return err;
+       int error;
+
+       error = sysv_init_icache();
+       if (error)
+               goto out;
+       error = register_filesystem(&sysv_fs_type);
+       if (error)
+               goto destroy_icache;
+       error = register_filesystem(&v7_fs_type);
+       if (error)
+               goto unregister;
+       return 0;
+
+unregister:
+       unregister_filesystem(&sysv_fs_type);
+destroy_icache:
+       sysv_destroy_icache();
+out:
+       return error;
 }
 
 static void __exit exit_sysv_fs(void)
 {
        unregister_filesystem(&sysv_fs_type);
        unregister_filesystem(&v7_fs_type);
+       sysv_destroy_icache();
 }
 
 EXPORT_NO_SYMBOLS;
index d6840317762c27aaf7d61ee749746a38c7a02947..3335bb130bc27b01d15b392f91a20944fc92e1ce 100644 (file)
@@ -6,16 +6,17 @@
  */
 
 #include <linux/fs.h>
+#include <linux/sysv_fs.h>
 
 static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-       char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+       char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
        return vfs_readlink(dentry, buffer, buflen, s);
 }
 
 static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-       char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+       char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
        return vfs_follow_link(nd, s);
 }
 
index 7d44903b1c1acfd50d12905b2e7bcf42e8f157a3..e560827b02ee67d11f6b3872a3f27c003e8e3b9f 100644 (file)
@@ -95,6 +95,11 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
        }
        lock_super(sb);
 
+       UDF_I_UNIQUE(inode) = 0;
+       UDF_I_LENEXTENTS(inode) = 0;
+       UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+       UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
+       UDF_I_STRAT4096(inode) = 0;
        if (UDF_SB_LVIDBH(sb))
        {
                struct LogicalVolHeaderDesc *lvhd;
index edd94ec5b74ee5d13684a161312d5d855b350bcd..2f573745139dca229828f0460570b39280afca9b 100644 (file)
@@ -945,7 +945,6 @@ __udf_read_inode(struct inode *inode)
         *      i_nlink = 1
         *      i_op = NULL;
         */
-
        inode->i_blksize = PAGE_SIZE;
 
        bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
@@ -1042,6 +1041,16 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                UDF_I_STRAT4096(inode) = 1;
 
        UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
+       UDF_I_UMTIME(inode) = 0;
+       UDF_I_UCTIME(inode) = 0;
+       UDF_I_CRTIME(inode) = 0;
+       UDF_I_UCRTIME(inode) = 0;
+       UDF_I_UNIQUE(inode) = 0;
+       UDF_I_LENEATTR(inode) = 0;
+       UDF_I_LENEXTENTS(inode) = 0;
+       UDF_I_LENALLOC(inode) = 0;
+       UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+       UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
        if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
                UDF_I_EXTENDED_FE(inode) = 1;
        else if (fe->descTag.tagIdent == TID_FILE_ENTRY)
@@ -1070,9 +1079,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        inode->i_mode = udf_convert_permissions(fe);
        inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
 
-       UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
-       UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
-
        if (UDF_I_EXTENDED_FE(inode) == 0)
        {
                inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
index 7a06f1d276b5efa117c35878b02ae0749c9f43b4..a4984734a38426803c050b5d37ad88ed54f80c41 100644 (file)
@@ -98,8 +98,52 @@ static int udf_statfs(struct super_block *, struct statfs *);
 /* UDF filesystem type */
 static DECLARE_FSTYPE_DEV(udf_fstype, "udf", udf_read_super);
 
+static kmem_cache_t * udf_inode_cachep;
+
+static struct inode *udf_alloc_inode(struct super_block *sb)
+{
+       struct udf_inode_info *ei;
+       ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL);
+       if (!ei)
+               return NULL;
+       return &ei->vfs_inode;
+}
+
+static void udf_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(udf_inode_cachep, UDF_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+       struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+
+       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+           SLAB_CTOR_CONSTRUCTOR)
+               inode_init_once(&ei->vfs_inode);
+}
+static int init_inodecache(void)
+{
+       udf_inode_cachep = kmem_cache_create("udf_inode_cache",
+                                            sizeof(struct udf_inode_info),
+                                            0, SLAB_HWCACHE_ALIGN,
+                                            init_once, NULL);
+       if (udf_inode_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void destroy_inodecache(void)
+{
+       if (kmem_cache_destroy(udf_inode_cachep))
+               printk(KERN_INFO "udf_inode_cache: not all structures were freed\n");
+}
+
 /* Superblock operations */
 static struct super_operations udf_sb_ops = {
+       alloc_inode:            udf_alloc_inode,
+       destroy_inode:          udf_destroy_inode,
        read_inode:             udf_read_inode,
        write_inode:            udf_write_inode,
        put_inode:              udf_put_inode,
@@ -130,14 +174,26 @@ struct udf_options
 
 static int __init init_udf_fs(void)
 {
+       int err;
        printk(KERN_NOTICE "udf: registering filesystem\n");
-       return register_filesystem(&udf_fstype);
+       err = init_inodecache();
+       if (err)
+               goto out1;
+       err = register_filesystem(&udf_fstype);
+       if (err)
+               goto out;
+       return 0;
+out:
+       destroy_inodecache();
+out1:
+       return err;
 }
 
 static void __exit exit_udf_fs(void)
 {
        printk(KERN_NOTICE "udf: unregistering filesystem\n");
        unregister_filesystem(&udf_fstype);
+       destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
index 8ffa2f316adcf65ad8189bb7e9c1b3b238f71a7c..7f627543683d7980c284f53daf4d3e491cd0aa61 100644 (file)
@@ -1,7 +1,11 @@
 #ifndef __LINUX_UDF_I_H
 #define __LINUX_UDF_I_H
 
-#define UDF_I(X)                       (&((X)->u.udf_i))
+#include <linux/udf_fs_i.h>
+static inline struct udf_inode_info *UDF_I(struct inode *inode)
+{
+       return list_entry(inode, struct udf_inode_info, vfs_inode);
+}
 
 #define UDF_I_LOCATION(X)      ( UDF_I(X)->i_location )
 #define UDF_I_LENEATTR(X)      ( UDF_I(X)->i_lenEAttr )
index fe8e6751999e8cde5b0768528b6ac2bc966b93fb..abf7713a4150d1f40bc0fe52169dda5780a3568b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.6 2000/05/27 00:49:37 davem Exp $
+/* $Id: ide.h,v 1.7 2002/01/16 20:58:40 davem Exp $
  * ide.h: SPARC PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -91,7 +91,7 @@ typedef union {
                unsigned int reserved456: 3;
                unsigned bit3           : 1;    /* ATA-2 thingy */
                unsigned int SRST       : 1;    /* host soft reset bit */
-               unsigned int nIEN       : 1;    /* device INTRQ to host *
+               unsigned int nIEN       : 1;    /* device INTRQ to host */
                unsigned int bit0       : 1;
        } b;
 } control_t;
index 913ada4e1553b67cb4563793abbbe3d6f7b522f4..3c7285db0918313f40107f601962d81cac99a0de 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.21 2001/09/25 20:21:48 kanoj Exp $
+/* $Id: ide.h,v 1.22 2002/01/16 20:58:40 davem Exp $
  * ide.h: Ultra/PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -87,7 +87,7 @@ typedef union {
                unsigned int reserved456: 3;
                unsigned bit3           : 1;    /* ATA-2 thingy */
                unsigned int SRST       : 1;    /* host soft reset bit */
-               unsigned int nIEN       : 1;    /* device INTRQ to host *
+               unsigned int nIEN       : 1;    /* device INTRQ to host */
                unsigned int bit0       : 1;
        } b;
 } control_t;
index a56a9daa3fbacdb40bf7ec4999ebd1f485620447..dde76b787f413499d8a1555ea95c1d19725b796e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.20 2001/03/09 01:31:40 davem Exp $
+/* $Id: irq.h,v 1.21 2002/01/23 11:27:36 davem Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/kernel.h>
-
-struct devid_cookie {
-       int dummy;
-};
+#include <asm/pil.h>
 
 /* You should not mess with this directly. That's the job of irq.c.
  *
diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h
new file mode 100644 (file)
index 0000000..75ee614
--- /dev/null
@@ -0,0 +1,21 @@
+/* $Id: pil.h,v 1.1 2002/01/23 11:27:36 davem Exp $ */
+#ifndef _SPARC64_PIL_H
+#define _SPARC64_PIL_H
+
+/* To avoid some locking problems, we hard allocate certain PILs
+ * for SMP cross call messages.  cli() does not block the cross
+ * call delivery, so when SMP locking is an issue we reschedule
+ * the event into a PIL interrupt which is blocked by cli().
+ *
+ * XXX In fact the whole set of PILs used for hardware interrupts
+ * XXX may be allocated in this manner.  All of the devices can
+ * XXX happily sit at the same PIL.  We would then need only two
+ * XXX PILs, one for devices and one for the CPU local timer tick.
+ */
+#define PIL_MIGRATE    1
+
+#ifndef __ASSEMBLY__
+#define PIL_RESERVED(PIL)      ((PIL) == PIL_MIGRATE)
+#endif
+
+#endif /* !(_SPARC64_PIL_H) */
index 32a2fed4dddddcf56e9b769e682275dce81d873e..e0c55821fc16fecccf05bd42285628c0a71a0a08 100644 (file)
@@ -80,7 +80,7 @@ struct device {
        atomic_t        refcount;       /* refcount to make sure the device
                                         * persists for the right amount of time */
 
-       struct driver_dir_entry dir;
+       struct driver_dir_entry dir;
 
        struct device_driver *driver;   /* which driver has allocated this
                                           device */
@@ -123,7 +123,7 @@ struct iobus {
        struct list_head devices;       /* children devices */
 
        struct device *self;            /* pointer to controlling device */
-       struct driver_dir_entry * dir;  /* driverfs directory */
+       struct driver_dir_entry dir;    /* driverfs directory */
 
        char    name[DEVICE_NAME_SIZE];
        char    bus_id[BUS_ID_SIZE];
@@ -154,15 +154,9 @@ extern int iobus_register(struct iobus * iobus);
 extern struct iobus * iobus_alloc(void);
 extern void iobus_init(struct iobus * iobus);
 
-extern int device_create_file(struct device *device, const char * name, mode_t mode,
-                             struct driverfs_operations * ops, void * data);
+extern int device_create_file(struct device *device, struct driver_file_entry * entry);
 extern void device_remove_file(struct device * dev, const char * name);
 
-extern int iobus_create_file(struct iobus *bus, const char * name, mode_t mode,
-                            struct driverfs_operations * ops, void * data);
-extern void iobus_remove_file(struct iobus * iobus, const char * name);
-
-
 /*
  * Platform "fixup" functions - allow the platform to have their say
  * about devices and actions that the general device layer doesn't
index 90a6034304a6a7db1ffed55778ab5ed81e7aee11..8141302ef67d8cfae5ddad4d40d904bcab2505f1 100644 (file)
 #ifndef _DRIVER_FS_H_
 #define _DRIVER_FS_H_
 
-struct driverfs_operations {
-       ssize_t (*read) (char *, size_t, loff_t, void *);
-       ssize_t (*write)(const char *, size_t, loff_t, void*);
-};
-
 struct driver_dir_entry {
        char                    * name;
        struct dentry           * dentry;
@@ -38,6 +33,8 @@ struct driver_dir_entry {
        struct list_head        files;
 };
 
+struct device;
+
 struct driver_file_entry {
        struct driver_dir_entry * parent;
        struct list_head        node;
@@ -45,11 +42,10 @@ struct driver_file_entry {
        mode_t                  mode;
        struct dentry           * dentry;
        void                    * data;
-       struct driverfs_operations      * ops;
-};
 
-extern struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode);
+       ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
+       ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
+};
 
 extern int
 driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);
@@ -57,10 +53,6 @@ driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);
 extern void
 driverfs_remove_dir(struct driver_dir_entry * entry);
 
-extern struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
-                      struct driverfs_operations * ops, void * data);
-
 extern int
 driverfs_create_file(struct driver_file_entry * entry,
                     struct driver_dir_entry * parent);
index 357878b650490ef606a14e4994a85d383f0b2d8f..2fffbbfae7df6aea658c2f468343d2a34bf1afe7 100644 (file)
 #define FB_ACCEL_IGS_CYBER5000 35      /* CyberPro 5000                */
 #define FB_ACCEL_SIS_GLAMOUR    36     /* SiS 300/630/540              */
 
+
+#define FB_ACCEL_NEOMAGIC_NM2070 90    /* NeoMagic NM2070              */
+#define FB_ACCEL_NEOMAGIC_NM2090 91    /* NeoMagic NM2090              */
+#define FB_ACCEL_NEOMAGIC_NM2093 92    /* NeoMagic NM2093              */
+#define FB_ACCEL_NEOMAGIC_NM2097 93    /* NeoMagic NM2097              */
+#define FB_ACCEL_NEOMAGIC_NM2160 94    /* NeoMagic NM2160              */
+#define FB_ACCEL_NEOMAGIC_NM2200 95    /* NeoMagic NM2200              */
+#define FB_ACCEL_NEOMAGIC_NM2230 96    /* NeoMagic NM2230              */
+#define FB_ACCEL_NEOMAGIC_NM2360 97    /* NeoMagic NM2360              */
+#define FB_ACCEL_NEOMAGIC_NM2380 98    /* NeoMagic NM2380              */
+
+
 struct fb_fix_screeninfo {
        char id[16];                    /* identification string eg "TT Builtin" */
        unsigned long smem_start;       /* Start of frame buffer mem */
index 6bda17aed79ac146466c42bd2355c246e4814d0e..c4d6123672fa140a998a13262317ba2b6a4f0104 100644 (file)
@@ -287,20 +287,15 @@ extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long
 
 
 #include <linux/pipe_fs_i.h>
-#include <linux/minix_fs_i.h>
 #include <linux/ntfs_fs_i.h>
 #include <linux/msdos_fs_i.h>
-#include <linux/umsdos_fs_i.h>
+/* #include <linux/umsdos_fs_i.h> */
 #include <linux/iso_fs_i.h>
-#include <linux/sysv_fs_i.h>
 #include <linux/romfs_fs_i.h>
 #include <linux/smb_fs_i.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/adfs_fs_i.h>
-#include <linux/reiserfs_fs_i.h>
 #include <linux/bfs_fs_i.h>
-#include <linux/udf_fs_i.h>
-#include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
@@ -466,20 +461,15 @@ struct inode {
        unsigned int            i_attr_flags;
        __u32                   i_generation;
        union {
-               struct minix_inode_info         minix_i;
                struct ntfs_inode_info          ntfs_i;
                struct msdos_inode_info         msdos_i;
-               struct umsdos_inode_info        umsdos_i;
+               /* struct umsdos_inode_info     umsdos_i; */
                struct iso_inode_info           isofs_i;
-               struct sysv_inode_info          sysv_i;
                struct romfs_inode_info         romfs_i;
                struct smb_inode_info           smbfs_i;
                struct hfs_inode_info           hfs_i;
                struct adfs_inode_info          adfs_i;
-               struct reiserfs_inode_info      reiserfs_i;
                struct bfs_inode_info           bfs_i;
-               struct udf_inode_info           udf_i;
-               struct ncp_inode_info           ncpfs_i;
                struct proc_inode_info          proc_i;
                struct socket                   socket_i;
                struct jffs2_inode_info         jffs2_i;
index f0644ca302e8863bdcbfb628134c0687f89729bf..0a9c2eba880ee2f86c1529c7dbb031f16201d083 100644 (file)
@@ -50,8 +50,26 @@ typedef void (*exitcall_t)(void);
 
 extern initcall_t __initcall_start, __initcall_end;
 
-#define __initcall(fn)                                                         \
-       static initcall_t __initcall_##fn __init_call = fn
+/* initcalls are now grouped by functionality into separate 
+ * subsections. Ordering inside the subsections is determined
+ * by link order. 
+ * For backwards compatability, initcall() puts the call in 
+ * the device init subsection.
+ */
+
+#define __define_initcall(level,fn) \
+       static initcall_t __initcall_##fn __attribute__ ((unused,__section__ (".initcall" level ".init"))) = fn
+
+#define early_arch_initcall(fn)                __define_initcall("1",fn)
+#define mem_initcall(fn)               __define_initcall("2",fn)
+#define subsys_initcall(fn)            __define_initcall("3",fn)
+#define arch_initcall(fn)              __define_initcall("4",fn)
+#define fs_initcall(fn)                        __define_initcall("5",fn)
+#define device_initcall(fn)            __define_initcall("6",fn)
+#define late_initcall(fn)              __define_initcall("7",fn)
+
+#define __initcall(fn) device_initcall(fn)
+
 #define __exitcall(fn)                                                         \
        static exitcall_t __exitcall_##fn __exit_call = fn
 
@@ -80,7 +98,7 @@ extern struct kernel_param __setup_start, __setup_end;
 #define __initdata     __attribute__ ((__section__ (".data.init")))
 #define __exitdata     __attribute__ ((unused, __section__ (".data.exit")))
 #define __initsetup    __attribute__ ((unused,__section__ (".setup.init")))
-#define __init_call    __attribute__ ((unused,__section__ (".initcall.init")))
+#define __init_call(level)  __attribute__ ((unused,__section__ (".initcall" level ".init")))
 #define __exit_call    __attribute__ ((unused,__section__ (".exitcall.exit")))
 
 /* For assembly routines */
@@ -141,6 +159,14 @@ typedef void (*__cleanup_module_func_t)(void);
 
 #define __setup(str,func) /* nothing */
 
+#define early_arch_initcall(fn)                module_init(fn)
+#define mem_initcall(fn)               module_init(fn)
+#define subsys_initcall(fn)            module_init(fn)
+#define arch_initcall(fn)              module_init(fn)
+#define fs_initcall(fn)                        module_init(fn)
+#define device_initcall(fn)            module_init(fn)
+#define late_initcall(fn)              module_init(fn)
+
 #endif
 
 #ifdef CONFIG_HOTPLUG
index cfa7eab9c32279e8c0a051685d110b1e2dc31464..c767d1ff8752ff0a1c4d4b4e6929b207f9161849 100644 (file)
@@ -89,6 +89,8 @@ struct minix_dir_entry {
 
 #ifdef __KERNEL__
 
+#include <linux/minix_fs_i.h>
+
 /*
  * change the define below to 0 if you want names > info->s_namelen chars to be
  * truncated. Else they will be disallowed (ENAMETOOLONG).
@@ -129,6 +131,11 @@ extern struct file_operations minix_file_operations;
 extern struct file_operations minix_dir_operations;
 extern struct dentry_operations minix_dentry_operations;
 
+static inline struct minix_inode_info *minix_i(struct inode *inode)
+{
+       return list_entry(inode, struct minix_inode_info, vfs_inode);
+}
+
 #endif /* __KERNEL__ */
 
 #endif
index c3711e52292b1ebefd8eb99851e65de570bbf498..1ffd85ed4070d51ba9fb091637ba897ec03161a0 100644 (file)
@@ -9,6 +9,7 @@ struct minix_inode_info {
                __u16 i1_data[16];
                __u32 i2_data[16];
        } u;
+       struct inode vfs_inode;
 };
 
 #endif
index 919fc654a155d251a3350f6f965c3525eb80cafa..0f285d5170686f72f1f29d4282cf3e8e51ccf3eb 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/in.h>
 #include <linux/types.h>
 
+#include <linux/ncp_fs_i.h>
 #include <linux/ipx.h>
 #include <linux/ncp_no.h>
 
@@ -192,7 +193,10 @@ struct ncp_entry_info {
 #define NCP_SBP(sb)            (&((sb)->u.ncpfs_sb))
 
 #define NCP_SERVER(inode)      NCP_SBP((inode)->i_sb)
-#define NCP_FINFO(inode)       (&((inode)->u.ncpfs_i))
+static inline struct ncp_inode_info *NCP_FINFO(struct inode *inode)
+{
+       return list_entry(inode, struct ncp_inode_info, vfs_inode);
+}
 
 #ifdef DEBUG_NCP_MALLOC
 
index ffdf49f4c53f948bef1e695a2aaca7bbac4fee0b..528fc633a27b71aaf2b343b35a576502f5c22129 100644 (file)
  * all the information we need to work with an inode after creation.
  */
 struct ncp_inode_info {
-       __u32   dirEntNum __attribute__((packed));
-       __u32   DosDirNum __attribute__((packed));
-       __u32   volNumber __attribute__((packed));
+       __u32   dirEntNum;
+       __u32   DosDirNum;
+       __u32   volNumber;
        __u32   nwattr;
        struct semaphore open_sem;
        atomic_t        opened;
        int     access;
-       __u32   server_file_handle __attribute__((packed));
-       __u8    open_create_action __attribute__((packed));
-       __u8    file_handle[6] __attribute__((packed));
+       __u32   server_file_handle;
+       __u8    file_handle[6];
+       struct inode vfs_inode;
 };
 
 #endif /* __KERNEL__ */
index 88ecbad9dd6b99b7780ef6b758c724e2efa771af..d2a7f4b40ccd04ff56ed47d7df1b9f21835f2a45 100644 (file)
@@ -428,6 +428,9 @@ struct ipt_table
 
        /* Man behind the curtain... */
        struct ipt_table_info *private;
+
+       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+       struct module *me;
 };
 
 extern int ipt_register_table(struct ipt_table *table);
diff --git a/include/linux/netfilter_ipv4/ipt_ULOG.h b/include/linux/netfilter_ipv4/ipt_ULOG.h
new file mode 100644 (file)
index 0000000..dd8379a
--- /dev/null
@@ -0,0 +1,46 @@
+/* Header file for IP tables userspace logging, Version 1.8
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ * 
+ * Distributed under the terms of GNU GPL */
+
+#ifndef _IPT_ULOG_H
+#define _IPT_ULOG_H
+
+#ifndef NETLINK_NFLOG
+#define NETLINK_NFLOG  5
+#endif
+
+#define ULOG_MAC_LEN   80
+#define ULOG_PREFIX_LEN        32
+
+#define ULOG_MAX_QLEN  50
+/* Why 50? Well... there is a limit imposed by the slab cache 131000
+ * bytes. So the multipart netlink-message has to be < 131000 bytes.
+ * Assuming a standard ethernet-mtu of 1500, we could define this up
+ * to 80... but even 50 seems to be big enough. */
+
+/* private data structure for each rule with a ULOG target */
+struct ipt_ulog_info {
+       unsigned int nl_group;
+       size_t copy_range;
+       size_t qthreshold;
+       char prefix[ULOG_PREFIX_LEN];
+};
+
+/* Format of the ULOG packets passed through netlink */
+typedef struct ulog_packet_msg {
+       unsigned long mark;
+       long timestamp_sec;
+       long timestamp_usec;
+       unsigned int hook;
+       char indev_name[IFNAMSIZ];
+       char outdev_name[IFNAMSIZ];
+       size_t data_len;
+       char prefix[ULOG_PREFIX_LEN];
+       unsigned char mac_len;
+       unsigned char mac[ULOG_MAC_LEN];
+       unsigned char payload[0];
+} ulog_packet_msg_t;
+
+#endif /*_IPT_ULOG_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_ah.h b/include/linux/netfilter_ipv4/ipt_ah.h
new file mode 100644 (file)
index 0000000..7b9a2ac
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _IPT_AH_H
+#define _IPT_AH_H
+
+struct ipt_ah
+{
+       u_int32_t spis[2];                      /* Security Parameter Index */
+       u_int8_t  invflags;                     /* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_ah. */
+#define IPT_AH_INV_SPI         0x01    /* Invert the sense of spi. */
+#define IPT_AH_INV_MASK        0x01    /* All possible flags. */
+
+#endif /*_IPT_AH_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_esp.h b/include/linux/netfilter_ipv4/ipt_esp.h
new file mode 100644 (file)
index 0000000..c782a83
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _IPT_ESP_H
+#define _IPT_ESP_H
+
+struct ipt_esp
+{
+       u_int32_t spis[2];                      /* Security Parameter Index */
+       u_int8_t  invflags;                     /* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_esp. */
+#define IPT_ESP_INV_SPI                0x01    /* Invert the sense of spi. */
+#define IPT_ESP_INV_MASK       0x01    /* All possible flags. */
+
+#endif /*_IPT_ESP_H*/
index 76fba12faa87d5cfdc5ed4a0e63e2824b497882f..99ad017569c78b1b0d6f464a68666e94255e54fd 100644 (file)
@@ -435,6 +435,9 @@ struct ip6t_table
 
        /* Man behind the curtain... */
        struct ip6t_table_info *private;
+
+       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+       struct module *me;
 };
 
 extern int ip6t_register_table(struct ip6t_table *table);
index 226767fbbfb299ea1150ad0060773ec9e3e6e2aa..b3a7c5770c45302240500b8b33e1055fa94eda1f 100644 (file)
@@ -6,6 +6,7 @@
 #define NETLINK_USERSOCK       2       /* Reserved for user mode socket protocols      */
 #define NETLINK_FIREWALL       3       /* Firewalling hook                             */
 #define NETLINK_TCPDIAG                4       /* TCP socket monitoring                        */
+#define NETLINK_NFLOG          5       /* netfilter/iptables ULOG */
 #define NETLINK_ARPD           8
 #define NETLINK_ROUTE6         11      /* af_inet6 route comm channel */
 #define NETLINK_IP6_FW         13
index 4971fa3c3586394b70244e8bb34675d91c0fdc32..6c9bd9e3f99acecf7c797623cd93dbe11e18be2b 100644 (file)
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 
 /* File state for mmap()s on /proc/bus/pci/X/Y */
 enum pci_mmap_state {
@@ -363,6 +364,8 @@ struct pci_dev {
                                           this is D0-D3, D0 being fully functional,
                                           and D3 being off. */
 
+       struct  device  dev;            /* Generic device interface */
+
        /* device is compatible with these IDs */
        unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
        unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
@@ -429,6 +432,8 @@ struct pci_bus {
        unsigned char   productver;     /* product version */
        unsigned char   checksum;       /* if zero - checksum passed */
        unsigned char   pad1;
+
+       struct iobus    iobus;          /* Generic device interface */
 };
 
 #define pci_bus_b(n) list_entry(n, struct pci_bus, node)
@@ -525,7 +530,6 @@ int pcibios_find_device (unsigned short vendor, unsigned short dev_id,
 
 /* Generic PCI functions used internally */
 
-void pci_init(void);
 int pci_bus_exists(const struct list_head *list, int nr);
 struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_alloc_primary_bus(int bus);
index 1c4cec479ba34381c5d90cfe64cbeb5b37545f08..f9f74b6d72129eda854eced8a0f9bad23ba88f39 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/unaligned.h>
 #include <linux/bitops.h>
 #include <linux/proc_fs.h>
+#include <linux/reiserfs_fs_i.h>
 #endif
 
 /*
@@ -204,9 +205,13 @@ struct unfm_nodeinfo {
 */
 #define MIN_PACK_ON_CLOSE              512
 
+static inline struct reiserfs_inode_info *REISERFS_I(struct inode *inode)
+{
+       return list_entry(inode, struct reiserfs_inode_info, vfs_inode);
+}
 // this says about version of all items (but stat data) the object
 // consists of
-#define inode_items_version(inode) ((inode)->u.reiserfs_i.i_version)
+#define inode_items_version(inode) (REISERFS_I(inode)->i_version)
 
 
   /* This is an aggressive tail suppression policy, I am hoping it
@@ -1257,10 +1262,10 @@ struct path var = {ILLEGAL_PATH_ELEMENT_OFFSET, }
 #define UNFM_P_SIZE (sizeof(unp_t))
 
 // in in-core inode key is stored on le form
-#define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
-//#define mark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted),1))
-//#define unmark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted), 0))
-//#define is_tail_converted(inode) (atomic_read(&((inode)->u.reiserfs_i.i_converted)))
+#define INODE_PKEY(inode) ((struct key *)(REISERFS_I(inode)->i_key))
+//#define mark_tail_converted(inode) (atomic_set(&(REISERFS_I(inode)->i_converted),1))
+//#define unmark_tail_converted(inode) (REISERFS_I(inode)->i_converted), 0))
+//#define is_tail_converted(inode) (REISERFS_I(inode)->i_converted)))
 
 
 
@@ -1272,7 +1277,7 @@ struct path var = {ILLEGAL_PATH_ELEMENT_OFFSET, }
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
 #define U32_MAX (~(__u32)0)
-static inline loff_t max_reiserfs_offset (const struct inode * inode)
+static inline loff_t max_reiserfs_offset (struct inode * inode)
 {
     if (inode_items_version (inode) == ITEM_VERSION_1)
        return (loff_t)U32_MAX;
@@ -1848,7 +1853,7 @@ void padd_item (char * item, int total_length, int length);
 
 int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ;
 void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
-void make_cpu_key (struct cpu_key * cpu_key, const struct inode * inode, loff_t offset,
+void make_cpu_key (struct cpu_key * cpu_key, struct inode * inode, loff_t offset,
                   int type, int key_length);
 void make_le_item_head (struct item_head * ih, const struct cpu_key * key, 
                        int version,
@@ -1873,7 +1878,7 @@ int reiserfs_dentry_to_fh(struct dentry *, __u32 *fh, int *lenp, int need_parent
 void reiserfs_dirty_inode (struct inode * inode) ;
 
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, 
-                                  const struct inode * dir, int mode, 
+                                  struct inode * dir, int mode, 
                                   const char * symname, int item_len,
                                   struct dentry *dentry, struct inode *inode, int * err);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
index 08445c12024c6a34a42842c970f3ec890e43c4d1..6b7a94ece6bc8a81374d60a3b01c334b0f886b98 100644 (file)
@@ -46,6 +46,7 @@ struct reiserfs_inode_info {
   */
   unsigned long i_trans_id ;
   unsigned long i_trans_index ;
+  struct inode vfs_inode;
 };
 
 
index 4f6105ff6667f4f7430c425fa246ea1bcf40c17b..43976035cfcd63fb50f5447e91d036ed8a8ff7b7 100644 (file)
@@ -586,9 +586,9 @@ extern void rtnl_unlock(void);
 extern void rtnetlink_init(void);
 
 #define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0)  { up(&rtnl_sem); \
-printk("RTNL: assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } \
+printk("RTNL: assertion failed at " __FILE__ "(%d)\n", __LINE__); } \
                   } while(0);
-#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
+#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d)\n", __LINE__); }
 
 
 #endif /* __KERNEL__ */
index 104de0a08e19e59ed695e102b2ed354d51bd5260..91e1e1e8689d2d9af05aa82aeb6bc8d36d87ec67 100644 (file)
 #include <linux/sched.h>       /* declares wake_up() */
 #include <linux/sysv_fs_sb.h>  /* defines the sv_... shortcuts */
 
+/* temporary hack. */
+#include <linux/sysv_fs_i.h>
+static inline struct sysv_inode_info *SYSV_I(struct inode *inode)
+{
+       /* I think list_entry should have a more descriptive name..  --hch */
+       return list_entry(inode, struct sysv_inode_info, vfs_inode);
+}
+/* end temporary hack. */
+
 
 /* Layout on disk */
 /* ============== */
index 084173ad891bb4f91e7370e2be1473f70b959bab..77679676a646a8f891f4e8a3bcc1f6c00755c1fb 100644 (file)
@@ -11,6 +11,7 @@ struct sysv_inode_info {
                                 * then 1 triple indirection block.
                                 */
        u32 i_dir_start_lookup;
+       struct inode  vfs_inode;
 };
 
 #endif
index 8d641efd8ec35f7dacd86ed566d05a289362659d..15ba838c26b91d54501008f770c8e6723b92c9d8 100644 (file)
@@ -100,8 +100,6 @@ struct timezone {
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
 extern void do_settimeofday(struct timeval *tv);
-extern void get_fast_time(struct timeval *tv);
-extern void (*do_get_fast_time)(struct timeval *);
 #endif
 
 #define FD_SETSIZE             __FD_SETSIZE
index 3d48fced7cc1613362630c3d27af397422cca725..8e26831b69420093edcd1b923b44906342f33423 100644 (file)
@@ -47,6 +47,7 @@ struct udf_inode_info
        unsigned i_strat_4096 : 1;
        unsigned i_new_inode : 1;
        unsigned reserved : 26;
+       struct inode vfs_inode;
 };
 
 #endif
index 0f5ea3ee4761d9115e2a2b1f23511dbbf71ed429..0a71a18bcf2dfe937dd45782f30ec737e2fe70fa 100644 (file)
 #include <asm/ccwcache.h>
 #endif
 
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#ifdef CONFIG_DIO
-#include <linux/dio.h>
-#endif
-
-#ifdef CONFIG_ZORRO
-#include <linux/zorro.h>
-#endif
-
 #ifdef CONFIG_MTRR
 #  include <asm/mtrr.h>
 #endif
 
-#ifdef CONFIG_NUBUS
-#include <linux/nubus.h>
-#endif
-
-#ifdef CONFIG_ISAPNP
-#include <linux/isapnp.h>
-#endif
-
-#ifdef CONFIG_IRDA
-extern int irda_proto_init(void);
-extern int irda_device_init(void);
-#endif
-
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
 #endif
@@ -92,10 +67,8 @@ extern void sock_init(void);
 extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
-extern void ppc_init(void);
 extern void sysctl_init(void);
 extern void signals_init(void);
-extern int init_pcmcia_ds(void);
 
 extern void free_initmem(void);
 
@@ -103,8 +76,6 @@ extern void free_initmem(void);
 extern void tc_init(void);
 #endif
 
-extern void ecard_init(void);
-
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
@@ -492,50 +463,11 @@ static void __init do_basic_setup(void)
        /* bring up the device tree */
        device_driver_init();
 
-#ifdef CONFIG_PCI
-       pci_init();
-#endif
-#ifdef CONFIG_SBUS
-       sbus_init();
-#endif
-#if defined(CONFIG_PPC)
-       ppc_init();
-#endif
-#ifdef CONFIG_MCA
-       mca_init();
-#endif
-#ifdef CONFIG_ARCH_ACORN
-       ecard_init();
-#endif
-#ifdef CONFIG_ZORRO
-       zorro_init();
-#endif
-#ifdef CONFIG_DIO
-       dio_init();
-#endif
-#ifdef CONFIG_NUBUS
-       nubus_init();
-#endif
-#ifdef CONFIG_ISAPNP
-       isapnp_init();
-#endif
-#ifdef CONFIG_TC
-       tc_init();
-#endif
-
        /* Networking initialization needs a process context */ 
        sock_init();
 
        start_context_thread();
        do_initcalls();
-
-#ifdef CONFIG_IRDA
-       irda_proto_init();
-       irda_device_init(); /* Must be done after protocol initialization */
-#endif
-#ifdef CONFIG_PCMCIA
-       init_pcmcia_ds();               /* Do this last */
-#endif
 }
 
 extern void prepare_namespace(void);
index 8b7c9e47e4045cb4d346ac569c1a2929132a2712..aac19836f4a3c15a02670eac5b52a1ae5942397c 100644 (file)
@@ -51,46 +51,37 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
 
 static spinlock_t device_lock;
 
-static ssize_t device_read_status(char *, size_t, loff_t, void *);
-static ssize_t device_write_status(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations device_status_ops = {
-       read:   device_read_status,
-       write:  device_write_status,
-};
-
-static ssize_t device_read_power(char *, size_t, loff_t, void *);
-static ssize_t device_write_power(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations device_power_ops = {
-       read:   device_read_power,
-       write:  device_write_power,
+static ssize_t device_read_status(struct device *, char *, size_t, loff_t);
+static ssize_t device_write_status(struct device *,const char *, size_t, loff_t);
+
+static struct driver_file_entry device_status_entry = {
+       name:           "status",
+       mode:           S_IWUSR | S_IRUGO,
+       show:           device_read_status,
+       store:          device_write_status,
 };
 
-static ssize_t iobus_read_status(char *, size_t, loff_t, void *);
-static ssize_t iobus_write_status(const char *, size_t, loff_t, void *);
+static ssize_t device_read_power(struct device *, char *, size_t, loff_t);
+static ssize_t device_write_power(struct device *, const char *, size_t, loff_t);
 
-static struct driverfs_operations iobus_status_ops = {
-       read:   iobus_read_status,
-       write:  iobus_write_status,
+static struct driver_file_entry device_power_entry = {
+       name:           "power",
+       mode:           S_IWUSR | S_IRUGO,
+       show:           device_read_power,
+       store:          device_write_power,
 };
 
-
 /**
  * device_create_file - create a driverfs file for a device
  * @dev:       device requesting file
- * @name:      name of file
- * @mode:      permissions of file
- * @ops:       operations for the file
- * @data:      private data for the file
+ * @entry:     entry describing file
  *
- * Create a driverfs entry, then create the actual file the entry describes.
+ * Allocate space for file entry, copy descriptor, and create.
  */
-int device_create_file(struct device * dev, const char * name, mode_t mode,
-                      struct driverfs_operations * ops, void * data)
+int device_create_file(struct device * dev, struct driver_file_entry * entry)
 {
-       int error = -EFAULT;
-       struct driver_file_entry * entry;
+       struct driver_file_entry * new_entry;
+       int error = -ENOMEM;
 
        if (!dev)
                return -EINVAL;
@@ -98,10 +89,15 @@ int device_create_file(struct device * dev, const char * name, mode_t mode,
        if (!valid_device(dev))
                return -EFAULT;
 
-       entry = driverfs_create_entry(name,mode,ops,data);
-       if (entry)
-               error = driverfs_create_file(entry,dev->dir);
+       new_entry = kmalloc(sizeof(*new_entry),GFP_KERNEL);
+       if (!new_entry)
+               goto done;
 
+       memcpy(new_entry,entry,sizeof(*entry));
+       error = driverfs_create_file(new_entry,&dev->dir);
+       if (error)
+               kfree(new_entry);
+ done:
        put_device(dev);
        return error;
 }
@@ -120,7 +116,7 @@ void device_remove_file(struct device * dev, const char * name)
        if (!valid_device(dev))
                return;
 
-       driverfs_remove_file(dev->dir,name);
+       driverfs_remove_file(&dev->dir,name);
 
        put_device(dev);
 }
@@ -131,18 +127,8 @@ void device_remove_file(struct device * dev, const char * name)
  */
 void device_remove_dir(struct device * dev)
 {
-       struct driver_dir_entry * dir;
-
-       if (!dev)
-               return;
-
-       lock_device(dev);
-       dir = dev->dir;
-       dev->dir = NULL;
-       unlock_device(dev);
-
-       if (dir)
-               driverfs_remove_dir(dir);
+       if (dev)
+               driverfs_remove_dir(&dev->dir);
 }
 
 /**
@@ -159,128 +145,52 @@ void device_remove_dir(struct device * dev)
  */
 static int device_make_dir(struct device * dev)
 {
-       struct driver_dir_entry * entry;
+       struct driver_dir_entry * parent = NULL;
        int error;
 
-       entry = driverfs_create_dir_entry(dev->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
-       if (!entry)
-               return -EFAULT;
+       INIT_LIST_HEAD(&dev->dir.files);
+       dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+       dev->dir.name = dev->bus_id;
 
-       error = driverfs_create_dir(entry,dev->parent->dir);
+       if (dev->parent)
+               parent = &dev->parent->dir;
 
-       if (error) {
-               kfree(entry);
-               return error;
-       }
+       error = driverfs_create_dir(&dev->dir,parent);
 
-       lock_device(dev);
-       dev->dir = entry;
-       unlock_device(dev);
+       if (error)
+               return error;
 
-       /* first the status file */
-       error = device_create_file(dev, "status", S_IRUGO | S_IWUSR,
-                                  &device_status_ops, (void *) dev);
+       error = device_create_file(dev,&device_status_entry);
        if (error) {
                device_remove_dir(dev);
                goto done;
        }
-
-       /* now the power file */
-       error = device_create_file(dev,"power",S_IRUGO | S_IWUSR,
-                                  &device_power_ops, (void *) dev);
-       if (error)
+       error = device_create_file(dev,&device_power_entry);
+       if (error) 
                device_remove_dir(dev);
-
  done:
        return error;
 }
 
-/* iobus interface.
- * For practical purposes, it's exactly the same as the device interface above.
- * Even below, the two are almost identical, only taking different pointer
- * types.
- * I have fantasized about removing struct iobus completely. It would reduce
- * this file by about 30%, and make life much easier. However, it will take some
- * time to really work everything out..
- */
-
-int iobus_create_file(struct iobus * iobus, const char * name, mode_t mode,
-                     struct driverfs_operations * ops, void * data)
-{
-       int error = -EFAULT;
-       struct driver_file_entry * entry;
-
-       if (!iobus)
-               return -EINVAL;
-
-       if (!valid_iobus(iobus))
-               return -EFAULT;
-
-       entry = driverfs_create_entry(name,mode,ops,data);
-       if (entry)
-               error = driverfs_create_file(entry,iobus->dir);
-
-       put_iobus(iobus);
-       return error;
-}
-
-void iobus_remove_file(struct iobus * iobus, const char * name)
-{
-       if (!iobus)
-               return;
-
-       if (!valid_iobus(iobus))
-               return;
-
-       driverfs_remove_file(iobus->dir,name);
-
-       put_iobus(iobus);
-}
-
 void iobus_remove_dir(struct iobus * iobus)
 {
-       struct driver_dir_entry * dir;
-
-       if (!iobus)
-               return;
-
-       lock_iobus(iobus);
-       dir = iobus->dir;
-       iobus->dir = NULL;
-       unlock_iobus(iobus);
-
-       if (dir)
-               driverfs_remove_dir(dir);
+       if (iobus)
+               driverfs_remove_dir(&iobus->dir);
 }
 
 static int iobus_make_dir(struct iobus * iobus)
 {
-       struct driver_dir_entry * entry;
        struct driver_dir_entry * parent = NULL;
        int error;
 
-       entry = driverfs_create_dir_entry(iobus->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
-       if (!entry)
-               return -EFAULT;
+       INIT_LIST_HEAD(&iobus->dir.files);
+       iobus->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+       iobus->dir.name = iobus->bus_id;
 
        if (iobus->parent)
-               parent = iobus->parent->dir;
-
-       error = driverfs_create_dir(entry,parent);
-       if (error) {
-               kfree(entry);
-               return error;
-       }
-
-       lock_iobus(iobus);
-       iobus->dir = entry;
-       unlock_iobus(iobus);
-
-       error = iobus_create_file(iobus, "status", S_IRUGO | S_IWUSR,
-                                 &iobus_status_ops, (void *)iobus);
-       if (error)
-               iobus_remove_dir(iobus);
+               parent = &iobus->parent->dir;
 
+       error = driverfs_create_dir(&iobus->dir,parent);
        return error;
 }
 
@@ -304,6 +214,9 @@ int device_register(struct device *dev)
                dev->parent = &device_root;
        parent = dev->parent;
 
+       DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
+           dev->bus_id, dev->name, parent->bus_id);
+
        if (valid_iobus(parent)) {
                if (!valid_device(dev)) {
                        put_iobus(parent);
@@ -327,15 +240,10 @@ int device_register(struct device *dev)
        list_add_tail(&dev->node, &parent->devices);
        unlock_iobus(parent);
 
-       DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
-           dev->bus_id, dev->name, parent->bus_id);
-
        /* notify platform of device entry */
        if (platform_notify)
                platform_notify(dev);
 
-       return 0;
-
  register_done:
        put_device(dev);
        put_iobus(parent);
@@ -430,8 +338,6 @@ int iobus_register(struct iobus *bus)
        list_add_tail(&bus->node,&parent->children);
        unlock_iobus(parent);
 
-       return 0;
-
  register_done_put:
        put_iobus(bus);
        put_iobus(parent);
@@ -533,45 +439,6 @@ struct iobus *iobus_alloc(void)
        return bus;
 }
 
-static int do_device_suspend(struct device * dev, u32 state)
-{
-       int error = 0;
-
-       if (!dev->driver->suspend)
-               return error;
-
-       error = dev->driver->suspend(dev,state,SUSPEND_NOTIFY);
-
-       if (error)
-               return error;
-
-       error = dev->driver->suspend(dev,state,SUSPEND_SAVE_STATE);
-       if (error) {
-               if (dev->driver->resume)
-                       dev->driver->resume(dev,RESUME_RESTORE_STATE);
-               return error;
-       }
-       error = dev->driver->suspend(dev,state,SUSPEND_POWER_DOWN);
-       if (error) {
-               if (dev->driver->resume)
-                       dev->driver->resume(dev,RESUME_RESTORE_STATE);
-       }
-       return error;
-}
-
-static int do_device_resume(struct device * dev)
-{
-       int error = 0;
-
-       if (!dev->driver->resume)
-               return 0;
-       error = dev->driver->resume(dev,RESUME_POWER_ON);
-       if (error)
-               return error;
-       error = dev->driver->resume(dev,RESUME_RESTORE_STATE);
-       return error;
-}
-
 /**
  * device_read_status - report some device information
  * @page:      page-sized buffer to write into
@@ -582,37 +449,17 @@ static int do_device_resume(struct device * dev)
  * Report some human-readable information about the device.
  * This includes the name, the bus id, and the current power state.
  */
-static ssize_t device_read_status(char * page, size_t count,
-                                 loff_t off, void * data)
+static ssize_t device_read_status(struct device * dev, char * page, size_t count, loff_t off)
 {
        char *str = page;
-       struct device *dev = (struct device*)data;
-       ssize_t len = 0;
-
-       if (!dev)
-               return -EINVAL;
-
-       if (!valid_device(dev))
-               return -EFAULT;
 
        if (off)
-               goto done;
+               return 0;
 
        str += sprintf(str,"Name:       %s\n",dev->name);
        str += sprintf(str,"Bus ID:     %s\n",dev->bus_id);
 
-       len = str - page;
-
-       if (len > count)
-               len = count;
-
-       if (len < 0)
-               len = 0;
-
- done:
-       put_device(dev);
-
-       return len;
+       return (str - page);
 }
 
 /**
@@ -631,31 +478,24 @@ static ssize_t device_read_status(char * page, size_t count,
  * (See Documentation/driver-model.txt for the theory of an n-stage
  * suspend sequence).
  */
-static ssize_t device_write_status(const char* buf, size_t count, loff_t off, void *data)
+static ssize_t device_write_status(struct device * dev, const char* buf, size_t count, loff_t off)
 {
        char command[20];
-       struct device *dev = (struct device *)data;
        int num;
        int arg = 0;
        int error = 0;
 
-       if (!dev)
-               return 0;
-
-       if (!valid_device(dev))
-               return -EFAULT;
-
        if (off)
-               goto done_put;
+               return 0;
 
        /* everything involves dealing with the driver. */
        if (!dev->driver)
-               goto done_put;
+               return 0;
 
        num = sscanf(buf,"%10s %d",command,&arg);
 
        if (!num)
-               goto done_put;
+               return 0;
 
        if (!strcmp(command,"probe")) {
                if (dev->driver->probe)
@@ -666,50 +506,25 @@ static ssize_t device_write_status(const char* buf, size_t count, loff_t off, vo
                        error = dev->driver->remove(dev,REMOVE_NOTIFY);
        } else
                error = -EFAULT;
-
- done_put:
-       put_device(dev);
        return error < 0 ? error : count;
 }
 
 static ssize_t
-device_read_power(char * page, size_t count, loff_t off, void * data)
+device_read_power(struct device * dev, char * page, size_t count, loff_t off)
 {
        char    * str = page;
-       struct  device * dev = (struct device *)data;
-       ssize_t len = 0;
-
-       if (!dev)
-               return 0;
 
-       if (!valid_device(dev))
+       if (off)
                return 0;
 
        str += sprintf(str,"State:      %d\n",dev->current_state);
 
-       len = str - page;
-
-       if (off) {
-               if (len < off) {
-                       len = 0;
-                       goto done;
-               }
-               str += off;
-               len -= off;
-       }
-
-       if (len > count)
-               len = count;
-
- done:
-       put_device(dev);
-       return len;
+       return (str - page);
 }
 
 static ssize_t
-device_write_power(const char * buf, size_t count, loff_t off, void * data)
+device_write_power(struct device * dev, const char * buf, size_t count, loff_t off)
 {
-       struct  device * dev = (struct device *)data;
        char    str_command[20];
        char    str_stage[20];
        int     num_args;
@@ -717,14 +532,9 @@ device_write_power(const char * buf, size_t count, loff_t off, void * data)
        u32     int_stage;
        int     error = 0;
 
-       if (!dev)
+       if (off)
                return 0;
 
-       if (!valid_device(dev))
-               return -EFAULT;
-
-       if (off)
-               goto done;
        if (!dev->driver)
                goto done;
 
@@ -772,107 +582,6 @@ device_write_power(const char * buf, size_t count, loff_t off, void * data)
                        error = 0;
        }
  done:
-       put_device(dev);
-
-       DBG("%s: returning %d\n",__FUNCTION__,error);
-
-       return error < 0 ? error : count;
-}
-
-/**
- * bus_read_status - report human readable information
- * @page:      page-sized buffer to write into
- * @count:     number of bytes requested
- * @off:       offset into buffer to start at
- * @data:      bus-specific data
- */
-static ssize_t iobus_read_status(char *page, size_t count,
-                                loff_t off, void *data)
-{
-       char *str = page;
-       struct iobus *bus = (struct iobus*)data;
-       ssize_t len = 0;
-
-       if (!bus)
-               return -EINVAL;
-
-       if (!valid_iobus(bus))
-               return -EFAULT;
-
-       if (off)
-               goto done;
-
-       str += sprintf(str,"Name:       %s\n",bus->name);
-       str += sprintf(str,"Bus ID:     %s\n",bus->bus_id);
-
-       if (bus->driver)
-               str += sprintf(str,"Type:       %s\n",bus->driver->name);
-
-       len = str - page;
-       if (len < off)
-               len = 0;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
-
- done:
-       put_iobus(bus);
-       return len;
-}
-
-/**
- * bus_write_status - forward a command to a bus
- * @buf:       string encoded command
- * @count:     number of bytes requested
- * @off:       offset into buffer to start at
- * @data:      bus-specific data
- *
- * Like device_write_status, this sends a command to a bus driver.
- * Supported actions are:
- * scan - scan a bus for devices
- * add_device <id> - add a child device
- */
-static ssize_t iobus_write_status(const char *buf, size_t count, loff_t off, void *data)
-{
-       char command[10];
-       char which[15];
-       char id[10];
-       struct iobus *bus = (struct iobus*)data;
-       int num;
-       int error = -EINVAL;
-
-       if (!bus)
-               return -EINVAL;
-
-       if (!valid_iobus(bus))
-               return -EFAULT;
-
-       if (!bus->driver)
-               goto done;
-
-       num = sscanf(buf,"%10s %15s %10s",command,which,id);
-
-       if (!num)
-               goto done;
-
-       if (!strnicmp(command,"scan",4)) {
-               if (bus->driver->scan)
-                       error = bus->driver->scan(bus);
-       } else if (!strnicmp(command,"add",3) && num == 2) {
-               error = bus->driver->add_device(bus,id);
-       } else if (!strnicmp(command, "suspend",7)) {
-               u32 state = simple_strtoul(which,NULL,0);
-               if (state > 0)
-                       error = do_device_suspend(bus->self,state);
-
-       } else if (!strnicmp(command,"resume",6)) {
-               error = do_device_resume(bus->self);
-
-       }
-
- done:
-       put_iobus(bus);
        return error < 0 ? error : count;
 }
 
@@ -885,9 +594,7 @@ static int __init device_init_root(void)
         * needs to do is create the root directory. Easier
         * to just do it here than special case it elsewhere..
         */
-       iobus_make_dir(&device_root);
-
-       return (device_root.dir ? 0 : -EFAULT);
+       return iobus_make_dir(&device_root);
 }
 
 int __init device_driver_init(void)
@@ -938,7 +645,4 @@ EXPORT_SYMBOL(iobus_register);
 EXPORT_SYMBOL(iobus_alloc);
 EXPORT_SYMBOL(iobus_init);
 
-EXPORT_SYMBOL(iobus_create_file);
-EXPORT_SYMBOL(iobus_remove_file);
-
 EXPORT_SYMBOL(device_driver_init);
index e51c417a72c1076a20367aa4a42a0bcb3dada4f7..cf0da799be7330ed81cb3a7223b39fef0f3243d3 100644 (file)
@@ -271,6 +271,8 @@ EXPORT_SYMBOL(lease_get_mtime);
 EXPORT_SYMBOL(lock_may_read);
 EXPORT_SYMBOL(lock_may_write);
 EXPORT_SYMBOL(dcache_readdir);
+EXPORT_SYMBOL(fd_install);
+EXPORT_SYMBOL(put_unused_fd);
 
 /* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
 EXPORT_SYMBOL(default_llseek);
@@ -534,9 +536,6 @@ EXPORT_SYMBOL(disk_name);   /* for md.c */
 /* binfmt_aout */
 EXPORT_SYMBOL(get_write_access);
 
-/* time */
-EXPORT_SYMBOL(get_fast_time);
-
 /* library functions */
 EXPORT_SYMBOL(strnicmp);
 EXPORT_SYMBOL(strspn);
index ffad77ad6203896bbcb5235ece1beda8748a3814..461a87de346dd191f4f9ec4696033269c5bca386 100644 (file)
  */
 struct timezone sys_tz;
 
-static void do_normal_gettime(struct timeval * tm)
-{
-        *tm=xtime;
-}
-
-void (*do_get_fast_time)(struct timeval *) = do_normal_gettime;
-
-/*
- * Generic way to access 'xtime' (the current time of day).
- * This can be changed if the platform provides a more accurate (and fast!) 
- * version.
- */
-
-void get_fast_time(struct timeval * t)
-{
-       do_get_fast_time(t);
-}
-
 /* The xtime_lock is not only serializing the xtime read/writes but it's also
    serializing all accesses to the global NTP variables now. */
 extern rwlock_t xtime_lock;
index f942bfd45cbd60cc682a037604447b736832bac5..f97669090983a9a3b094ad89ed49ed6a4219837d 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Lennert Buytenhek               <buytenh@gnu.org>
  *
- *     $Id: br_fdb.c,v 1.5 2000/11/08 05:16:40 davem Exp $
+ *     $Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -292,7 +292,8 @@ void br_fdb_insert(struct net_bridge *br,
        write_lock_bh(&br->hash_lock);
        fdb = br->hash[hash];
        while (fdb != NULL) {
-               if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
+               if (!fdb->is_local &&
+                   !memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
                        __fdb_possibly_replace(fdb, source, is_local);
                        write_unlock_bh(&br->hash_lock);
                        return;
index 04ce443e29fc35fd04a415a79e414386e48a17c1..d76a5ea24a77a55788f6db159e636346f248d45c 100644 (file)
@@ -239,7 +239,7 @@ void dev_add_pack(struct packet_type *pt)
 
 #ifdef CONFIG_NET_FASTROUTE
        /* Hack to detect packet socket */
-       if (pt->data) {
+       if ((pt->data) && ((int)(pt->data)!=1)) {
                netdev_fastroute_obstacles++;
                dev_clear_fastroute(pt->dev);
        }
@@ -876,7 +876,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 {
        struct packet_type *ptype;
-       get_fast_time(&skb->stamp);
+       do_gettimeofday(&skb->stamp);
 
        br_read_lock(BR_NETPROTO_LOCK);
        for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) 
@@ -1219,7 +1219,7 @@ int netif_rx(struct sk_buff *skb)
        unsigned long flags;
 
        if (skb->stamp.tv_sec == 0)
-               get_fast_time(&skb->stamp);
+               do_gettimeofday(&skb->stamp);
 
        /* The code is rearranged so that the path is the most
           short when CPU is congested, but is still operating.
index 4b823829b404208ee651bd16fd6310d936dc0c7b..ec3b4e0de22ff338fa5ab66fa10dcc7362ebdbdc 100644 (file)
@@ -21,6 +21,7 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
@@ -74,6 +75,9 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+  if [ "$CONFIG_NETLINK" != "n" ]; then
+     dep_tristate '  ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_NETLINK $CONFIG_IP_NF_IPTABLES
+  fi
   dep_tristate '  TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
 fi
 
index 3feca30e62f7618df02fc4fef830878150097411..a3d4e39fcac052445ba2fc24e08cc3d25a65da4c 100644 (file)
@@ -56,6 +56,7 @@ obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 
@@ -73,6 +74,7 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 
 # backwards compatibility 
index eb6215904403aca2b9f048de1c3bb367f140e286..1d462ac6d7a0302deef7f9d7341883e835d015c2 100644 (file)
@@ -157,7 +157,7 @@ check_for_demasq(struct sk_buff **pskb)
                /* Fall thru... */
        case IPPROTO_TCP:
        case IPPROTO_UDP:
-               IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
+               IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
                if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
                        if (net_ratelimit())
index d83562c292a102081132700f10390cafb1995edd..9a3248e68d64299b0790778addb9ceed2f09dbe8 100644 (file)
@@ -104,7 +104,7 @@ static struct
 
 static struct ipt_table nat_table
 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
-    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 LIST_HEAD(nat_expect_list);
 
index 22ab65a8d34b34329a565c4cf6a3f6d99a7a0a30..c7515da8dc2eeab4a5676d09917b7689d25deba2 100644 (file)
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2009-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ *     - increase module usage count as soon as we have rules inside
+ *       a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -84,6 +89,8 @@ struct ipt_table_info
        unsigned int size;
        /* Number of entries: FIXME. --RR */
        unsigned int number;
+       /* Initial number of entries. Needed for module usage count */
+       unsigned int initial_entries;
 
        /* Entry points and underflows */
        unsigned int hook_entry[NF_IP_NUMHOOKS];
@@ -902,6 +909,7 @@ replace_table(struct ipt_table *table,
        }
        oldinfo = table->private;
        table->private = newinfo;
+       newinfo->initial_entries = oldinfo->initial_entries;
        write_unlock_bh(&table->lock);
 
        return oldinfo;
@@ -1105,6 +1113,16 @@ do_replace(void *user, unsigned int len)
        if (!oldinfo)
                goto free_newinfo_counters_untrans_unlock;
 
+       /* Update module usage count based on number of rules */
+       duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+               oldinfo->number, oldinfo->initial_entries, newinfo->number);
+       if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+           (newinfo->number > oldinfo->initial_entries))
+               __MOD_INC_USE_COUNT(t->me);
+       else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+                (newinfo->number <= oldinfo->initial_entries))
+               __MOD_DEC_USE_COUNT(t->me);
+
        /* Get the old counters. */
        get_counters(oldinfo, counters);
        /* Decrease module usage counts and free resource */
@@ -1363,7 +1381,7 @@ int ipt_register_table(struct ipt_table *table)
        int ret;
        struct ipt_table_info *newinfo;
        static struct ipt_table_info bootstrap
-               = { 0, 0, { 0 }, { 0 }, { } };
+               = { 0, 0, 0, { 0 }, { 0 }, { } };
 
        MOD_INC_USE_COUNT;
        newinfo = vmalloc(sizeof(struct ipt_table_info)
@@ -1406,6 +1424,9 @@ int ipt_register_table(struct ipt_table *table)
 
        duprintf("table->private->number = %u\n",
                 table->private->number);
+       
+       /* save number of initial entries */
+       table->private->initial_entries = table->private->number;
 
        table->lock = RW_LOCK_UNLOCKED;
        list_prepend(&ipt_tables, table);
@@ -1746,7 +1767,7 @@ static int __init init(void)
        }
 #endif
 
-       printk("ip_tables: (c)2000 Netfilter core team\n");
+       printk("ip_tables: (C) 2000-2002 Netfilter core team\n");
        return 0;
 }
 
index bf320445cd10ee0761a2b5fa44b77faad7984880..18c4a29e2931340ccc1c8210d41595727fe80ca1 100644 (file)
@@ -838,6 +838,7 @@ static int clear_fw_chain(struct ip_chain *chainptr)
                        i->branch->refcount--;
                kfree(i);
                i = tmp;
+               MOD_DEC_USE_COUNT;
        }
        return 0;
 }
@@ -875,13 +876,16 @@ static int append_to_chain(struct ip_chain *chainptr, struct ip_fwkernel *rule)
                 * interrupts is not necessary. */
                chainptr->chain = rule;
                if (rule->branch) rule->branch->refcount++;
-               return 0;
+               goto append_successful;
        }
 
        /* Find the rule before the end of the chain */
        for (i = chainptr->chain; i->next; i = i->next);
        i->next = rule;
        if (rule->branch) rule->branch->refcount++;
+
+append_successful:
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -900,7 +904,7 @@ static int insert_in_chain(struct ip_chain *chainptr,
                frwl->next = chainptr->chain;
                if (frwl->branch) frwl->branch->refcount++;
                chainptr->chain = frwl;
-               return 0;
+               goto insert_successful;
        }
        position--;
        while (--position && f != NULL) f = f->next;
@@ -910,6 +914,9 @@ static int insert_in_chain(struct ip_chain *chainptr,
        frwl->next = f->next;
 
        f->next = frwl;
+
+insert_successful:
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
@@ -943,6 +950,8 @@ static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum)
                i->next = i->next->next;
                kfree(tmp);
        }
+
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1049,6 +1058,7 @@ static int del_rule_from_chain(struct ip_chain *chainptr,
                else
                        chainptr->chain = ftmp->next;
                kfree(ftmp);
+               MOD_DEC_USE_COUNT;
                break;
        }
 
@@ -1089,6 +1099,8 @@ static int del_chain(ip_chainlabel label)
 
        tmp->next = tmp2->next;
        kfree(tmp2);
+
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -1141,6 +1153,7 @@ static int create_chain(ip_chainlabel label)
                                              * user defined chain *
                                              * and therefore can be
                                              * deleted */
+       MOD_INC_USE_COUNT;
        return 0;
 }
 
index 6a7cab94b6b0ef6626fa005358bbb35faa6d24ca..cdcfa1cc6f9c6feb7977519f037ef9c6059f94fc 100644 (file)
@@ -20,7 +20,7 @@
  *     license in recognition of the original copyright.
  *                             -- Alan Cox.
  *
- *     $Id: ipfwadm_core.c,v 1.9 2001/09/18 22:29:10 davem Exp $
+ *     $Id: ipfwadm_core.c,v 1.10 2002/01/23 13:20:54 davem Exp $
  *
  *     Ported from BSD to Linux,
  *             Alan Cox 22/Nov/1994.
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/module.h>
 
 #include <linux/socket.h>
 #include <linux/sockios.h>
@@ -687,6 +688,7 @@ static void free_fw_chain(struct ip_fw *volatile* chainptr)
                ftmp = *chainptr;
                *chainptr = ftmp->fw_next;
                kfree(ftmp);
+               MOD_DEC_USE_COUNT();
        }
        restore_flags(flags);
 }
@@ -730,6 +732,7 @@ static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,
        ftmp->fw_next = *chainptr;
                *chainptr=ftmp;
        restore_flags(flags);
+       MOD_INC_USE_COUNT();
        return(0);
 }
 
@@ -780,6 +783,7 @@ static int append_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,
        else
                *chainptr=ftmp;
        restore_flags(flags);
+       MOD_INC_USE_COUNT();
        return(0);
 }
 
@@ -853,9 +857,10 @@ static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl)
                 }
        }
        restore_flags(flags);
-       if (was_found)
+       if (was_found) {
+               MOD_DEC_USE_COUNT();
                return 0;
-       else
+       else
                return(EINVAL);
 }
 
index 6a31ad3b081ccec423e866c59d033727a2582ce8..178ca0281155a2f9054fe7c37b15866fc4b35722 100644 (file)
@@ -217,7 +217,7 @@ static void dump_packet(const struct ipt_log_info *info,
                                printk("[");
                                dump_packet(info,
                                            (struct iphdr *)(icmph + 1),
-                                           datalen-sizeof(struct iphdr),
+                                           datalen-sizeof(struct icmphdr),
                                            0);
                                printk("] ");
                        }
index 82d1e8be6b4ca6020300df6cb6d229c744cd4c5f..2e3b4de377da018af6cf8b88d8cf2e982ccdc1ad 100644 (file)
@@ -74,10 +74,17 @@ redirect_target(struct sk_buff **pskb,
        /* Local packets: make them go to loopback */
        if (hooknum == NF_IP_LOCAL_OUT)
                newdst = htonl(0x7F000001);
-       else
+       else {
+               struct in_device *indev;
+
+               /* Device might not have an associated in_device. */
+               indev = (struct in_device *)(*pskb)->dev->ip_ptr;
+               if (indev == NULL)
+                       return NF_DROP;
+
                /* Grab first address on interface. */
-               newdst = (((struct in_device *)(*pskb)->dev->ip_ptr)
-                         ->ifa_list->ifa_local);
+               newdst = indev->ifa_list->ifa_local;
+       }
 
        /* Transfer from original range. */
        newrange = ((struct ip_nat_multi_range)
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
new file mode 100644 (file)
index 0000000..a978874
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * netfilter module for userspace packet logging daemons
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 2000/09/22 ulog-cprange feature added
+ * 2001/01/04 in-kernel queue as proposed by Sebastian Zander 
+ *                                             <zander@fokus.gmd.de>
+ * 2001/01/30 per-rule nlgroup conflicts with global queue. 
+ *            nlgroup now global (sysctl)
+ * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
+ *           module loadtime -HW
+ *
+ * Released under the terms of the GPL
+ *
+ * This module accepts two parameters: 
+ * 
+ * nlbufsiz:
+ *   The parameter specifies how big the buffer for each netlink multicast
+ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
+ * get accumulated in the kernel until they are sent to userspace. It is
+ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
+ * because atomically allocating 128kB inside the network rx softirq is not
+ * reliable. Please also keep in mind that this buffer size is allocated for
+ * each nlgroup you are using, so the total kernel memory usage increases
+ * by that factor.
+ *
+ * flushtimeout:
+ *   Specify, after how many clock ticks (intel: 100 per second) the queue
+ * should be flushed even if it is not full yet.
+ *
+ * ipt_ULOG.c,v 1.15 2002/01/18 21:33:19 laforge Exp
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+
+#define ULOG_NL_EVENT          111             /* Harald's favorite number */
+#define ULOG_MAXNLGROUPS       32              /* numer of nlgroups */
+
+#if 0
+#define DEBUGP(format, args...)        printk(__FILE__ ":" __FUNCTION__ ":" \
+                                      format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables userspace logging module");
+
+
+static unsigned int nlbufsiz = 4096;
+MODULE_PARM(nlbufsiz, "i");
+MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
+
+static unsigned int flushtimeout = 10 * HZ;
+MODULE_PARM(flushtimeout, "i");
+MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
+
+/* global data structures */
+
+typedef struct {
+       unsigned int qlen;              /* number of nlmsgs' in the skb */
+       struct nlmsghdr *lastnlh;       /* netlink header of last msg in skb */
+       struct sk_buff *skb;            /* the pre-allocated skb */
+       struct timer_list timer;        /* the timer function */
+} ulog_buff_t;
+
+static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS];     /* array of buffers */
+
+static struct sock *nflognl;   /* our socket */
+static size_t qlen;            /* current length of multipart-nlmsg */
+DECLARE_LOCK(ulog_lock);       /* spinlock */
+
+/* send one ulog_buff_t to userspace */
+static void ulog_send(unsigned int nlgroup)
+{
+       ulog_buff_t *ub = &ulog_buffers[nlgroup];
+
+       if (timer_pending(&ub->timer)) {
+               DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
+               del_timer(&ub->timer);
+       }
+
+       /* last nlmsg needs NLMSG_DONE */
+       if (ub->qlen > 1)
+               ub->lastnlh->nlmsg_type = NLMSG_DONE;
+
+       NETLINK_CB(ub->skb).dst_groups = nlgroup;
+       DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
+               ub->qlen, nlgroup);
+       netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
+
+       ub->qlen = 0;
+       ub->skb = NULL;
+       ub->lastnlh = NULL;
+
+}
+
+
+/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
+static void ulog_timer(unsigned long data)
+{
+       DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
+
+       /* lock to protect against somebody modifying our structure
+        * from ipt_ulog_target at the same time */
+       LOCK_BH(&ulog_lock);
+       ulog_send(data);
+       UNLOCK_BH(&ulog_lock);
+}
+
+static void nflog_rcv(struct sock *sk, int len)
+{
+       printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?\n");
+}
+
+struct sk_buff *ulog_alloc_skb(unsigned int size)
+{
+       struct sk_buff *skb;
+
+       /* alloc skb which should be big enough for a whole
+        * multipart message. WARNING: has to be <= 131000
+        * due to slab allocator restrictions */
+
+       skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+       if (!skb) {
+               PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
+                       nlbufsiz);
+
+               /* try to allocate only as much as we need for 
+                * current packet */
+
+               skb = alloc_skb(size, GFP_ATOMIC);
+               if (!skb)
+                       PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
+       }
+
+       return skb;
+}
+
+static unsigned int ipt_ulog_target(struct sk_buff **pskb,
+                                   unsigned int hooknum,
+                                   const struct net_device *in,
+                                   const struct net_device *out,
+                                   const void *targinfo, void *userinfo)
+{
+       ulog_buff_t *ub;
+       ulog_packet_msg_t *pm;
+       size_t size, copy_len;
+       struct nlmsghdr *nlh;
+       struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+       /* calculate the size of the skb needed */
+       if ((loginfo->copy_range == 0) ||
+           (loginfo->copy_range > (*pskb)->len)) {
+               copy_len = (*pskb)->len;
+       } else {
+               copy_len = loginfo->copy_range;
+       }
+
+       size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+
+       ub = &ulog_buffers[loginfo->nl_group];
+       
+       LOCK_BH(&ulog_lock);
+
+       if (!ub->skb) {
+               if (!(ub->skb = ulog_alloc_skb(size)))
+                       goto alloc_failure;
+       } else if (ub->qlen >= loginfo->qthreshold ||
+                  size > skb_tailroom(ub->skb)) {
+               /* either the queue len is too high or we don't have 
+                * enough room in nlskb left. send it to userspace. */
+
+               ulog_send(loginfo->nl_group);
+
+               if (!(ub->skb = ulog_alloc_skb(size)))
+                       goto alloc_failure;
+       }
+
+       DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
+               loginfo->qthreshold);
+
+       /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
+       nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
+                       size - sizeof(*nlh));
+       ub->qlen++;
+
+       pm = NLMSG_DATA(nlh);
+
+       /* copy hook, prefix, timestamp, payload, etc. */
+       pm->data_len = copy_len;
+       pm->timestamp_sec = (*pskb)->stamp.tv_sec;
+       pm->timestamp_usec = (*pskb)->stamp.tv_usec;
+       pm->mark = (*pskb)->nfmark;
+       pm->hook = hooknum;
+       if (loginfo->prefix[0] != '\0')
+               strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
+       else
+               *(pm->prefix) = '\0';
+
+       if (in && in->hard_header_len > 0
+           && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
+           && in->hard_header_len <= ULOG_MAC_LEN) {
+               memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
+               pm->mac_len = in->hard_header_len;
+       }
+
+       if (in)
+               strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+       else
+               pm->indev_name[0] = '\0';
+
+       if (out)
+               strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
+       else
+               pm->outdev_name[0] = '\0';
+
+       if (copy_len)
+               memcpy(pm->payload, (*pskb)->data, copy_len);
+       
+       /* check if we are building multi-part messages */
+       if (ub->qlen > 1) {
+               ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
+       }
+
+       /* if threshold is reached, send message to userspace */
+       if (qlen >= loginfo->qthreshold) {
+               if (loginfo->qthreshold > 1)
+                       nlh->nlmsg_type = NLMSG_DONE;
+       }
+
+       ub->lastnlh = nlh;
+
+       /* if timer isn't already running, start it */
+       if (!timer_pending(&ub->timer)) {
+               ub->timer.expires = jiffies + flushtimeout;
+               add_timer(&ub->timer);
+       }
+
+       UNLOCK_BH(&ulog_lock);
+
+       return IPT_CONTINUE;
+
+
+nlmsg_failure:
+       PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
+
+alloc_failure:
+       PRINTR("ipt_ULOG: Error building netlink message\n");
+
+       UNLOCK_BH(&ulog_lock);
+
+       return IPT_CONTINUE;
+}
+
+static int ipt_ulog_checkentry(const char *tablename,
+                              const struct ipt_entry *e,
+                              void *targinfo,
+                              unsigned int targinfosize,
+                              unsigned int hookmask)
+{
+       struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
+               DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
+               return 0;
+       }
+
+       if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
+               DEBUGP("ipt_ULOG: prefix term %i\n",
+                      loginfo->prefix[sizeof(loginfo->prefix) - 1]);
+               return 0;
+       }
+
+       if (loginfo->qthreshold > ULOG_MAX_QLEN) {
+               DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
+                       loginfo->qthreshold);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ipt_target ipt_ulog_reg =
+    { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
+THIS_MODULE
+};
+
+static int __init init(void)
+{
+       int i;
+
+       DEBUGP("ipt_ULOG: init module\n");
+
+       if (nlbufsiz >= 128*1024) {
+               printk("Netlink buffer has to be <= 128kB\n");
+               return -EINVAL;
+       }
+
+       /* initialize ulog_buffers */
+       for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
+               memset(&ulog_buffers[i], 0, sizeof(ulog_buff_t));
+               init_timer(&ulog_buffers[i].timer);
+               ulog_buffers[i].timer.function = ulog_timer;
+               ulog_buffers[i].timer.data = i;
+       }
+
+       nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
+       if (!nflognl)
+               return -ENOMEM;
+
+       if (ipt_register_target(&ipt_ulog_reg) != 0) {
+               sock_release(nflognl->socket);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       DEBUGP("ipt_ULOG: cleanup_module\n");
+
+       ipt_unregister_target(&ipt_ulog_reg);
+       sock_release(nflognl->socket);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
new file mode 100644 (file)
index 0000000..b027d4a
--- /dev/null
@@ -0,0 +1,105 @@
+/* Kernel module to match AH parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_ah.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct ahhdr {
+       __u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+       int r=0;
+        duprintf("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+               min,spi,max);
+       r=(spi >= min && spi <= max) ^ invert;
+       duprintf(" result %s\n",r? "PASS" : "FAILED");
+       return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       const struct ahhdr *ah = hdr;
+       const struct ipt_ah *ahinfo = matchinfo;
+
+       if (offset == 0 && datalen < sizeof(struct ahhdr)) {
+               /* We've been asked to examine this packet, and we
+                  can't.  Hence, no choice but to drop. */
+               duprintf("Dropping evil AH tinygram.\n");
+               *hotdrop = 1;
+               return 0;
+       }
+
+       /* Must not be a fragment. */
+       return !offset
+               && spi_match(ahinfo->spis[0], ahinfo->spis[1],
+                             ntohl(ah->spi),
+                             !!(ahinfo->invflags & IPT_AH_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ipt_ip *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ipt_ah *ahinfo = matchinfo;
+
+       /* Must specify proto == AH, and no unknown invflags */
+       if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
+               duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
+                        IPPROTO_AH);
+               return 0;
+       }
+       if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
+               duprintf("ipt_ah: matchsize %u != %u\n",
+                        matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
+               return 0;
+       }
+       if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
+               duprintf("ipt_ah: unknown flags %X\n",
+                        ahinfo->invflags);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ipt_match ah_match
+= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+
+int __init init(void)
+{
+       return ipt_register_match(&ah_match);
+}
+
+void __exit cleanup(void)
+{
+       ipt_unregister_match(&ah_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff --git a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c
new file mode 100644 (file)
index 0000000..e8305b6
--- /dev/null
@@ -0,0 +1,105 @@
+/* Kernel module to match ESP parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_esp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct esphdr {
+       __u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+       int r=0;
+        duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+               min,spi,max);
+       r=(spi >= min && spi <= max) ^ invert;
+       duprintf(" result %s\n",r? "PASS" : "FAILED");
+       return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       const struct esphdr *esp = hdr;
+       const struct ipt_esp *espinfo = matchinfo;
+
+       if (offset == 0 && datalen < sizeof(struct esphdr)) {
+               /* We've been asked to examine this packet, and we
+                  can't.  Hence, no choice but to drop. */
+               duprintf("Dropping evil ESP tinygram.\n");
+               *hotdrop = 1;
+               return 0;
+       }
+
+       /* Must not be a fragment. */
+       return !offset
+               && spi_match(espinfo->spis[0], espinfo->spis[1],
+                             ntohl(esp->spi),
+                             !!(espinfo->invflags & IPT_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ipt_ip *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ipt_esp *espinfo = matchinfo;
+
+       /* Must specify proto == ESP, and no unknown invflags */
+       if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
+               duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
+                        IPPROTO_ESP);
+               return 0;
+       }
+       if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
+               duprintf("ipt_esp: matchsize %u != %u\n",
+                        matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
+               return 0;
+       }
+       if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
+               duprintf("ipt_esp: unknown flags %X\n",
+                        espinfo->invflags);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct ipt_match esp_match
+= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+       return ipt_register_match(&esp_match);
+}
+
+static void __exit cleanup(void)
+{
+       ipt_unregister_match(&esp_match);
+}
+
+module_init(init);
+module_exit(cleanup);
index 38b5f0257acf1d2fcc89a2b1444c3b2ba82f139e..22ff7d92664a3f9e9132a5fb4cf099bf8f9f8e4e 100644 (file)
@@ -83,7 +83,7 @@ static struct
 
 static struct ipt_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
index 1c26b28f5013501cff7d99bddf8dc2b6e6d53e06..c00a5a84be3ee8d22b382c1e5505b9561b97e442 100644 (file)
@@ -2,6 +2,8 @@
  * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
  */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <net/route.h>
 #include <linux/ip.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | \
+                           (1 << NF_IP_LOCAL_IN) | \
+                           (1 << NF_IP_FORWARD) | \
+                           (1 << NF_IP_LOCAL_OUT) | \
+                           (1 << NF_IP_POST_ROUTING))
 
 /* Standard entry. */
 struct ipt_standard
@@ -33,18 +39,25 @@ struct ipt_error
        struct ipt_error_target target;
 };
 
+/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
 static struct
 {
        struct ipt_replace repl;
-       struct ipt_standard entries[2];
+       struct ipt_standard entries[5];
        struct ipt_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
-      { [NF_IP_PRE_ROUTING] 0,
-       [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
-      { [NF_IP_PRE_ROUTING] 0,
-       [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+      { [NF_IP_PRE_ROUTING]    0,
+       [NF_IP_LOCAL_IN]        sizeof(struct ipt_standard),
+       [NF_IP_FORWARD]         sizeof(struct ipt_standard) * 2,
+       [NF_IP_LOCAL_OUT]       sizeof(struct ipt_standard) * 3,
+       [NF_IP_POST_ROUTING]    sizeof(struct ipt_standard) * 4 },
+      { [NF_IP_PRE_ROUTING]    0,
+       [NF_IP_LOCAL_IN]        sizeof(struct ipt_standard),
+       [NF_IP_FORWARD]         sizeof(struct ipt_standard) * 2,
+       [NF_IP_LOCAL_OUT]       sizeof(struct ipt_standard) * 3,
+       [NF_IP_POST_ROUTING]    sizeof(struct ipt_standard) * 4 },
       0, NULL, { } },
     {
            /* PRE_ROUTING */
@@ -55,6 +68,22 @@ static struct
                0, { 0, 0 }, { } },
              { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
                -NF_ACCEPT - 1 } },
+           /* LOCAL_IN */
+           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+               0,
+               sizeof(struct ipt_entry),
+               sizeof(struct ipt_standard),
+               0, { 0, 0 }, { } },
+             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+               -NF_ACCEPT - 1 } },
+           /* FORWARD */
+           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+               0,
+               sizeof(struct ipt_entry),
+               sizeof(struct ipt_standard),
+               0, { 0, 0 }, { } },
+             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+               -NF_ACCEPT - 1 } },
            /* LOCAL_OUT */
            { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
                0,
@@ -62,7 +91,15 @@ static struct
                sizeof(struct ipt_standard),
                0, { 0, 0 }, { } },
              { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-               -NF_ACCEPT - 1 } }
+               -NF_ACCEPT - 1 } },
+           /* POST_ROUTING */
+           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+               0,
+               sizeof(struct ipt_entry),
+               sizeof(struct ipt_standard),
+               0, { 0, 0 }, { } },
+             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+               -NF_ACCEPT - 1 } },
     },
     /* ERROR */
     { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
@@ -79,11 +116,11 @@ static struct
 
 static struct ipt_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ipt_hook(unsigned int hook,
+ipt_route_hook(unsigned int hook,
         struct sk_buff **pskb,
         const struct net_device *in,
         const struct net_device *out,
@@ -121,7 +158,7 @@ route_me_harder(struct sk_buff *skb)
 }
 
 static unsigned int
-ipt_local_out_hook(unsigned int hook,
+ipt_local_hook(unsigned int hook,
                   struct sk_buff **pskb,
                   const struct net_device *in,
                   const struct net_device *out,
@@ -159,9 +196,16 @@ ipt_local_out_hook(unsigned int hook,
 }
 
 static struct nf_hook_ops ipt_ops[]
-= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_MANGLE },
-    { { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
-               NF_IP_PRI_MANGLE }
+= { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, 
+       NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN,
+       NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
+       NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT,
+       NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING,
+       NF_IP_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -182,8 +226,26 @@ static int __init init(void)
        if (ret < 0)
                goto cleanup_hook0;
 
+       ret = nf_register_hook(&ipt_ops[2]);
+       if (ret < 0)
+               goto cleanup_hook1;
+
+       ret = nf_register_hook(&ipt_ops[3]);
+       if (ret < 0)
+               goto cleanup_hook2;
+
+       ret = nf_register_hook(&ipt_ops[4]);
+       if (ret < 0)
+               goto cleanup_hook3;
+
        return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ipt_ops[3]);
+ cleanup_hook2:
+        nf_unregister_hook(&ipt_ops[2]);
+ cleanup_hook1:
+       nf_unregister_hook(&ipt_ops[1]);
  cleanup_hook0:
        nf_unregister_hook(&ipt_ops[0]);
  cleanup_table:
index 08d79394cbf6a0f26bf26d42e1270e0adcf1ef1c..838f7eebc396b46481f3687ac58bcb0847ccef26 100644 (file)
@@ -957,6 +957,7 @@ int ndisc_rcv(struct sk_buff *skb)
        struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
        struct neighbour *neigh;
        struct inet6_ifaddr *ifp;
+       unsigned int payload_len;
 
        __skb_push(skb, skb->data-skb->h.raw);
 
@@ -979,10 +980,11 @@ int ndisc_rcv(struct sk_buff *skb)
         *      (Some checking in ndisc_find_option)
         */
 
+       payload_len = ntohs(skb->nh.ipv6h->payload_len);
        switch (msg->icmph.icmp6_type) {
        case NDISC_NEIGHBOUR_SOLICITATION:
                /* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
-               if (skb->nh.ipv6h->payload_len < 8+16) {
+               if (payload_len < 8+16) {
                        if (net_ratelimit())
                                printk(KERN_WARNING "ICMP NS: packet too short\n");
                        return 0;
@@ -1112,7 +1114,7 @@ int ndisc_rcv(struct sk_buff *skb)
 
        case NDISC_NEIGHBOUR_ADVERTISEMENT:
                /* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
-               if (skb->nh.ipv6h->payload_len < 16+8 ) {
+               if (payload_len < 16+8 ) {
                        if (net_ratelimit())
                                printk(KERN_WARNING "ICMP NA: packet too short\n");
                        return 0;
@@ -1174,7 +1176,7 @@ int ndisc_rcv(struct sk_buff *skb)
 
        case NDISC_ROUTER_ADVERTISEMENT:
                /* XXX: import nd_router_advert from glibc netinet/icmp6.h */
-               if (skb->nh.ipv6h->payload_len < 8+4+4) {
+               if (payload_len < 8+4+4) {
                        if (net_ratelimit())
                                printk(KERN_WARNING "ICMP RA: packet too short\n");
                        return 0;
@@ -1184,7 +1186,7 @@ int ndisc_rcv(struct sk_buff *skb)
 
        case NDISC_REDIRECT:
                /* XXX: import nd_redirect from glibc netinet/icmp6.h */
-               if (skb->nh.ipv6h->payload_len < 8+16+16) {
+               if (payload_len < 8+16+16) {
                        if (net_ratelimit())
                                printk(KERN_WARNING "ICMP redirect: packet too short\n");
                        return 0;
@@ -1196,7 +1198,7 @@ int ndisc_rcv(struct sk_buff *skb)
                /* No RS support in the kernel, but we do some required checks */
 
                /* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
-               if (skb->nh.ipv6h->payload_len < 8) {
+               if (payload_len < 8) {
                        if (net_ratelimit())
                                printk(KERN_WARNING "ICMP RS: packet too short\n");
                        return 0;
index 5eae4fce40e930c3a34b3a2be0e79729939c4295..8177efd620b72e1432fe66439c98596628928118 100644 (file)
@@ -9,9 +9,10 @@ comment '  IPv6: Netfilter Configuration'
 #  dep_tristate '  FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
 #fi
 
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-#  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
-#fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
+fi
+
 tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES
 if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
 # The simple matches.
index 171703a3e7be473f59597b94ce7b38ef9bc96c2d..080b8068fed68ec5d1f922e2dbc8c412c6ed4d74 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 
 include $(TOPDIR)/Rules.make
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
new file mode 100644 (file)
index 0000000..235533a
--- /dev/null
@@ -0,0 +1,721 @@
+/*
+ * This is a module which is used for queueing IPv6 packets and
+ * communicating with userspace via netlink.
+ *
+ * (C) 2001 Fernando Anton, this code is GPL.
+ *     IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+ *     Universidad Carlos III de Madrid - Leganes (Madrid) - Spain
+ *     Universidad Politecnica de Alcala de Henares - Alcala de H. (Madrid) - Spain
+ *     email: fanton@it.uc3m.es
+ *
+ * 2001-11-06: First try. Working with ip_queue.c for IPv4 and trying
+ *             to adapt it to IPv6
+ *             HEAVILY based in ipqueue.c by James Morris. It's just
+ *             a little modified version of it, so he's nearly the
+ *             real coder of this.
+ *             Few changes needed, mainly the hard_routing code and
+ *             the netlink socket protocol (we're NETLINK_IP6_FW).
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ipv6.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+
+/* We're still usign the following structs. No need to change them: */
+/*   ipq_packet_msg                                                 */
+/*   ipq_mode_msg                                                   */
+/*   ipq_verdict_msg                                                */
+/*   ipq_peer_msg                                                   */
+#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#define IPQ_QMAX_DEFAULT 1024
+#define IPQ_PROC_FS_NAME "ip6_queue"
+#define NET_IPQ_QMAX 2088
+#define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
+
+typedef struct ip6q_rt_info {
+       struct in6_addr daddr;
+       struct in6_addr saddr;
+} ip6q_rt_info_t;
+
+typedef struct ip6q_queue_element {
+       struct list_head list;          /* Links element into queue */
+       int verdict;                    /* Current verdict */
+       struct nf_info *info;           /* Extra info from netfilter */
+       struct sk_buff *skb;            /* Packet inside */
+       ip6q_rt_info_t rt_info;         /* May need post-mangle routing */
+} ip6q_queue_element_t;
+
+typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
+
+typedef struct ip6q_peer {
+       pid_t pid;                      /* PID of userland peer */
+       unsigned char died;             /* We think the peer died */
+       unsigned char copy_mode;        /* Copy packet as well as metadata? */
+       size_t copy_range;              /* Range past metadata to copy */
+       ip6q_send_cb_t send;            /* Callback for sending data to peer */
+} ip6q_peer_t;
+
+typedef struct ip6q_queue {
+       int len;                        /* Current queue len */
+       int *maxlen;                    /* Maximum queue len, via sysctl */
+       unsigned char flushing;         /* If queue is being flushed */
+       unsigned char terminate;        /* If the queue is being terminated */
+       struct list_head list;          /* Head of packet queue */
+       spinlock_t lock;                /* Queue spinlock */
+       ip6q_peer_t peer;               /* Userland peer */
+} ip6q_queue_t;
+
+/****************************************************************************
+ *
+ * Packet queue
+ *
+ ****************************************************************************/
+/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
+static ip6q_queue_element_t *
+ip6q_dequeue(ip6q_queue_t *q,
+            int (*cmp)(ip6q_queue_element_t *, unsigned long),
+            unsigned long data)
+{
+       struct list_head *i;
+
+       spin_lock_bh(&q->lock);
+       for (i = q->list.prev; i != &q->list; i = i->prev) {
+               ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
+               
+               if (!cmp || cmp(e, data)) {
+                       list_del(&e->list);
+                       q->len--;
+                       spin_unlock_bh(&q->lock);
+                       return e;
+               }
+       }
+       spin_unlock_bh(&q->lock);
+       return NULL;
+}
+
+/* Flush all packets */
+static void ip6q_flush(ip6q_queue_t *q)
+{
+       ip6q_queue_element_t *e;
+       
+       spin_lock_bh(&q->lock);
+       q->flushing = 1;
+       spin_unlock_bh(&q->lock);
+       while ((e = ip6q_dequeue(q, NULL, 0))) {
+               e->verdict = NF_DROP;
+               nf_reinject(e->skb, e->info, e->verdict);
+               kfree(e);
+       }
+       spin_lock_bh(&q->lock);
+       q->flushing = 0;
+       spin_unlock_bh(&q->lock);
+}
+
+static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
+                                     ip6q_send_cb_t send_cb,
+                                     int *errp, int *sysctl_qmax)
+{
+       int status;
+       ip6q_queue_t *q;
+
+       *errp = 0;
+       q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
+       if (q == NULL) {
+               *errp = -ENOMEM;
+               return NULL;
+       }
+       q->peer.pid = 0;
+       q->peer.died = 0;
+       q->peer.copy_mode = IPQ_COPY_NONE;
+       q->peer.copy_range = 0;
+       q->peer.send = send_cb;
+       q->len = 0;
+       q->maxlen = sysctl_qmax;
+       q->flushing = 0;
+       q->terminate = 0;
+       INIT_LIST_HEAD(&q->list);
+       spin_lock_init(&q->lock);
+       status = nf_register_queue_handler(PF_INET6, outfn, q);
+       if (status < 0) {
+               *errp = -EBUSY;
+               kfree(q);
+               return NULL;
+       }
+       return q;
+}
+
+static int ip6q_enqueue(ip6q_queue_t *q,
+                       struct sk_buff *skb, struct nf_info *info)
+{
+       ip6q_queue_element_t *e;
+       int status;
+       
+       e = kmalloc(sizeof(*e), GFP_ATOMIC);
+       if (e == NULL) {
+               printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+               return -ENOMEM;
+       }
+
+       e->verdict = NF_DROP;
+       e->info = info;
+       e->skb = skb;
+
+       if (e->info->hook == NF_IP_LOCAL_OUT) {
+               struct ipv6hdr *iph = skb->nh.ipv6h;
+
+               e->rt_info.daddr = iph->daddr;
+               e->rt_info.saddr = iph->saddr;
+       }
+
+       spin_lock_bh(&q->lock);
+       if (q->len >= *q->maxlen) {
+               spin_unlock_bh(&q->lock);
+               if (net_ratelimit()) 
+                       printk(KERN_WARNING "ip6_queue: full at %d entries, "
+                              "dropping packet(s).\n", q->len);
+               goto free_drop;
+       }
+       if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
+           || q->peer.pid == 0 || q->peer.died || q->terminate) {
+               spin_unlock_bh(&q->lock);
+               goto free_drop;
+       }
+       status = q->peer.send(e);
+       if (status > 0) {
+               list_add(&e->list, &q->list);
+               q->len++;
+               spin_unlock_bh(&q->lock);
+               return status;
+       }
+       spin_unlock_bh(&q->lock);
+       if (status == -ECONNREFUSED) {
+               printk(KERN_INFO "ip6_queue: peer %d died, "
+                      "resetting state and flushing queue\n", q->peer.pid);
+                       q->peer.died = 1;
+                       q->peer.pid = 0;
+                       q->peer.copy_mode = IPQ_COPY_NONE;
+                       q->peer.copy_range = 0;
+                       ip6q_flush(q);
+       }
+free_drop:
+       kfree(e);
+       return -EBUSY;
+}
+
+static void ip6q_destroy_queue(ip6q_queue_t *q)
+{
+       nf_unregister_queue_handler(PF_INET6);
+       spin_lock_bh(&q->lock);
+       q->terminate = 1;
+       spin_unlock_bh(&q->lock);
+       ip6q_flush(q);
+       kfree(q);
+}
+
+/*
+ * Taken from net/ipv6/ip6_output.c
+ *
+ * We should use the one there, but is defined static
+ * so we put this just here and let the things as
+ * they are now.
+ *
+ * If that one is modified, this one should be modified too.
+ */
+static int route6_me_harder(struct sk_buff *skb)
+{
+       struct ipv6hdr *iph = skb->nh.ipv6h;
+       struct dst_entry *dst;
+       struct flowi fl;
+
+       fl.proto = iph->nexthdr;
+       fl.fl6_dst = &iph->daddr;
+       fl.fl6_src = &iph->saddr;
+       fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
+       fl.fl6_flowlabel = 0;
+       fl.uli_u.ports.dport = 0;
+       fl.uli_u.ports.sport = 0;
+
+       dst = ip6_route_output(skb->sk, &fl);
+
+       if (dst->error) {
+               if (net_ratelimit())
+                       printk(KERN_DEBUG "route6_me_harder: No more route.\n");
+               return -EINVAL;
+       }
+
+       /* Drop old route. */
+       dst_release(skb->dst);
+
+       skb->dst = dst;
+       return 0;
+}
+static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+{
+       int diff;
+       struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
+
+       if (v->data_len < sizeof(*user_iph))
+               return 0;
+       diff = v->data_len - e->skb->len;
+       if (diff < 0)
+               skb_trim(e->skb, v->data_len);
+       else if (diff > 0) {
+               if (v->data_len > 0xFFFF)
+                       return -EINVAL;
+               if (diff > skb_tailroom(e->skb)) {
+                       struct sk_buff *newskb;
+                       
+                       newskb = skb_copy_expand(e->skb,
+                                                skb_headroom(e->skb),
+                                                diff,
+                                                GFP_ATOMIC);
+                       if (newskb == NULL) {
+                               printk(KERN_WARNING "ip6_queue: OOM "
+                                     "in mangle, dropping packet\n");
+                               return -ENOMEM;
+                       }
+                       if (e->skb->sk)
+                               skb_set_owner_w(newskb, e->skb->sk);
+                       kfree_skb(e->skb);
+                       e->skb = newskb;
+               }
+               skb_put(e->skb, diff);
+       }
+       memcpy(e->skb->data, v->payload, v->data_len);
+       e->skb->nfcache |= NFC_ALTERED;
+
+       /*
+        * Extra routing may needed on local out, as the QUEUE target never
+        * returns control to the table.
+         * Not a nice way to cmp, but works
+        */
+       if (e->info->hook == NF_IP_LOCAL_OUT) {
+               struct ipv6hdr *iph = e->skb->nh.ipv6h;
+               if (!(   iph->daddr.in6_u.u6_addr32[0] == e->rt_info.daddr.in6_u.u6_addr32[0]
+                      && iph->daddr.in6_u.u6_addr32[1] == e->rt_info.daddr.in6_u.u6_addr32[1]
+                      && iph->daddr.in6_u.u6_addr32[2] == e->rt_info.daddr.in6_u.u6_addr32[2]
+                      && iph->daddr.in6_u.u6_addr32[3] == e->rt_info.daddr.in6_u.u6_addr32[3]
+                     && iph->saddr.in6_u.u6_addr32[0] == e->rt_info.saddr.in6_u.u6_addr32[0]
+                     && iph->saddr.in6_u.u6_addr32[1] == e->rt_info.saddr.in6_u.u6_addr32[1]
+                     && iph->saddr.in6_u.u6_addr32[2] == e->rt_info.saddr.in6_u.u6_addr32[2]
+                     && iph->saddr.in6_u.u6_addr32[3] == e->rt_info.saddr.in6_u.u6_addr32[3]))
+                       return route6_me_harder(e->skb);
+       }
+       return 0;
+}
+
+static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+{
+       return (id == (unsigned long )e);
+}
+
+static int ip6q_set_verdict(ip6q_queue_t *q,
+                           ipq_verdict_msg_t *v, unsigned int len)
+{
+       ip6q_queue_element_t *e;
+
+       if (v->value > NF_MAX_VERDICT)
+               return -EINVAL;
+       e = ip6q_dequeue(q, id_cmp, v->id);
+       if (e == NULL)
+               return -ENOENT;
+       else {
+               e->verdict = v->value;
+               if (v->data_len && v->data_len == len)
+                       if (ip6q_mangle_ipv6(v, e) < 0)
+                               e->verdict = NF_DROP;
+               nf_reinject(e->skb, e->info, e->verdict);
+               kfree(e);
+               return 0;
+       }
+}
+
+static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
+                            unsigned char type, unsigned int len)
+{
+
+       int status = 0;
+       int busy;
+               
+       spin_lock_bh(&q->lock);
+       busy = (q->terminate || q->flushing);
+       spin_unlock_bh(&q->lock);
+       if (busy)
+               return -EBUSY;
+       if (len < sizeof(ipq_peer_msg_t))
+               return -EINVAL;
+       switch (type) {
+               case IPQM_MODE:
+                       switch (m->msg.mode.value) {
+                               case IPQ_COPY_META:
+                                       q->peer.copy_mode = IPQ_COPY_META;
+                                       q->peer.copy_range = 0;
+                                       break;
+                               case IPQ_COPY_PACKET:
+                                       q->peer.copy_mode = IPQ_COPY_PACKET;
+                                       q->peer.copy_range = m->msg.mode.range;
+                                       if (q->peer.copy_range > 0xFFFF)
+                                               q->peer.copy_range = 0xFFFF;
+                                       break;
+                               default:
+                                       status = -EINVAL;
+                       }
+                       break;
+               case IPQM_VERDICT:
+                       if (m->msg.verdict.value > NF_MAX_VERDICT)
+                               status = -EINVAL;
+                       else
+                               status = ip6q_set_verdict(q,
+                                                        &m->msg.verdict,
+                                                        len - sizeof(*m));
+                       break;
+               default:
+                        status = -EINVAL;
+       }
+       return status;
+}
+
+static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+{
+       if (e->info->indev)
+               if (e->info->indev->ifindex == ifindex)
+                       return 1;
+       if (e->info->outdev)
+               if (e->info->outdev->ifindex == ifindex)
+                       return 1;
+       return 0;
+}
+
+/* Drop any queued packets associated with device ifindex */
+static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+{
+       ip6q_queue_element_t *e;
+       
+       while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
+               e->verdict = NF_DROP;
+               nf_reinject(e->skb, e->info, e->verdict);
+               kfree(e);
+       }
+}
+
+/****************************************************************************
+ *
+ * Netfilter interface
+ *
+ ****************************************************************************/
+
+/*
+ * Packets arrive here from netfilter for queuing to userspace.
+ * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
+ */
+static int netfilter6_receive(struct sk_buff *skb,
+                             struct nf_info *info, void *data)
+{
+       return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
+}
+
+/****************************************************************************
+ *
+ * Netlink interface.
+ *
+ ****************************************************************************/
+
+static struct sock *nfnl = NULL;
+/* This is not a static one, so we should not repeat its name */
+ip6q_queue_t *nlq6 = NULL;
+
+static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
+{
+       unsigned char *old_tail;
+       size_t size = 0;
+       size_t data_len = 0;
+       struct sk_buff *skb;
+       ipq_packet_msg_t *pm;
+       struct nlmsghdr *nlh;
+
+       switch (nlq6->peer.copy_mode) {
+               size_t copy_range;
+
+               case IPQ_COPY_META:
+                       size = NLMSG_SPACE(sizeof(*pm));
+                       data_len = 0;
+                       break;
+               case IPQ_COPY_PACKET:
+                       copy_range = nlq6->peer.copy_range;
+                       if (copy_range == 0 || copy_range > e->skb->len)
+                               data_len = e->skb->len;
+                       else
+                               data_len = copy_range;
+                       size = NLMSG_SPACE(sizeof(*pm) + data_len);
+                       
+                       break;
+               case IPQ_COPY_NONE:
+               default:
+                       *errp = -EINVAL;
+                       return NULL;
+       }
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (!skb)
+               goto nlmsg_failure;
+       old_tail = skb->tail;
+       nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+       pm = NLMSG_DATA(nlh);
+       memset(pm, 0, sizeof(*pm));
+       pm->packet_id = (unsigned long )e;
+       pm->data_len = data_len;
+       pm->timestamp_sec = e->skb->stamp.tv_sec;
+       pm->timestamp_usec = e->skb->stamp.tv_usec;
+       pm->mark = e->skb->nfmark;
+       pm->hook = e->info->hook;
+       if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
+       else pm->indev_name[0] = '\0';
+       if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
+       else pm->outdev_name[0] = '\0';
+       pm->hw_protocol = e->skb->protocol;
+       if (e->info->indev && e->skb->dev) {
+               pm->hw_type = e->skb->dev->type;
+               if (e->skb->dev->hard_header_parse)
+                       pm->hw_addrlen =
+                               e->skb->dev->hard_header_parse(e->skb,
+                                                              pm->hw_addr);
+       }
+       if (data_len)
+               memcpy(pm->payload, e->skb->data, data_len);
+       nlh->nlmsg_len = skb->tail - old_tail;
+       NETLINK_CB(skb).dst_groups = 0;
+       return skb;
+nlmsg_failure:
+       if (skb)
+               kfree_skb(skb);
+       *errp = 0;
+       printk(KERN_ERR "ip6_queue: error creating netlink message\n");
+       return NULL;
+}
+
+static int netlink_send_peer(ip6q_queue_element_t *e)
+{
+       int status = 0;
+       struct sk_buff *skb;
+
+       skb = netlink_build_message(e, &status);
+       if (skb == NULL)
+               return status;
+       return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+
+static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+{
+       int status, type;
+       struct nlmsghdr *nlh;
+
+       if (skb->len < sizeof(struct nlmsghdr))
+               return;
+
+       nlh = (struct nlmsghdr *)skb->data;
+       if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+           || skb->len < nlh->nlmsg_len)
+               return;
+
+       if(nlh->nlmsg_pid <= 0
+           || !(nlh->nlmsg_flags & NLM_F_REQUEST)
+           || nlh->nlmsg_flags & NLM_F_MULTI)
+               RCV_SKB_FAIL(-EINVAL);
+       if (nlh->nlmsg_flags & MSG_TRUNC)
+               RCV_SKB_FAIL(-ECOMM);
+       type = nlh->nlmsg_type;
+       if (type < NLMSG_NOOP || type >= IPQM_MAX)
+               RCV_SKB_FAIL(-EINVAL);
+       if (type <= IPQM_BASE)
+               return;
+       if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+               RCV_SKB_FAIL(-EPERM);
+       if (nlq6->peer.pid && !nlq6->peer.died
+           && (nlq6->peer.pid != nlh->nlmsg_pid)) {
+               printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
+                     "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
+               ip6q_flush(nlq6);
+       }       
+       nlq6->peer.pid = nlh->nlmsg_pid;
+       nlq6->peer.died = 0;
+       status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
+                                 type, skb->len - NLMSG_LENGTH(0));
+       if (status < 0)
+               RCV_SKB_FAIL(status);
+       if (nlh->nlmsg_flags & NLM_F_ACK)
+               netlink_ack(skb, nlh, 0);
+        return;
+}
+
+/* Note: we are only dealing with single part messages at the moment. */
+static void netlink_receive_user_sk(struct sock *sk, int len)
+{
+       do {
+               struct sk_buff *skb;
+
+               if (rtnl_shlock_nowait())
+                       return;
+               while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+                       netlink_receive_user_skb(skb);
+                       kfree_skb(skb);
+               }
+               up(&rtnl_sem);
+       } while (nfnl && nfnl->receive_queue.qlen);
+}
+
+/****************************************************************************
+ *
+ * System events
+ *
+ ****************************************************************************/
+
+static int receive_event(struct notifier_block *this,
+                         unsigned long event, void *ptr)
+{
+       struct net_device *dev = ptr;
+
+       /* Drop any packets associated with the downed device */
+       if (event == NETDEV_DOWN)
+               ip6q_dev_drop(nlq6, dev->ifindex);
+       return NOTIFY_DONE;
+}
+
+struct notifier_block ip6q_dev_notifier = {
+       receive_event,
+       NULL,
+       0
+};
+
+/****************************************************************************
+ *
+ * Sysctl - queue tuning.
+ *
+ ****************************************************************************/
+
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+
+static struct ctl_table_header *ip6q_sysctl_header;
+
+static ctl_table ip6q_table[] = {
+       { NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
+         sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
+       { 0 }
+};
+
+static ctl_table ip6q_dir_table[] = {
+       {NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+       { 0 }
+};
+
+static ctl_table ip6q_root_table[] = {
+       {CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+       { 0 }
+};
+
+/****************************************************************************
+ *
+ * Procfs - debugging info.
+ *
+ ****************************************************************************/
+
+static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+{
+       int len;
+
+       spin_lock_bh(&nlq6->lock);
+       len = sprintf(buffer,
+                     "Peer pid            : %d\n"
+                     "Peer died           : %d\n"
+                     "Peer copy mode      : %d\n"
+                     "Peer copy range     : %Zu\n"
+                     "Queue length        : %d\n"
+                     "Queue max. length   : %d\n"
+                     "Queue flushing      : %d\n"
+                     "Queue terminate     : %d\n",
+                     nlq6->peer.pid,
+                     nlq6->peer.died,
+                     nlq6->peer.copy_mode,
+                     nlq6->peer.copy_range,
+                     nlq6->len,
+                     *nlq6->maxlen,
+                     nlq6->flushing,
+                     nlq6->terminate);
+       spin_unlock_bh(&nlq6->lock);
+       *start = buffer + offset;
+       len -= offset;
+       if (len > length)
+               len = length;
+       else if (len < 0)
+               len = 0;
+       return len;
+}
+
+/****************************************************************************
+ *
+ * Module stuff.
+ *
+ ****************************************************************************/
+
+static int __init init(void)
+{
+       int status = 0;
+       struct proc_dir_entry *proc;
+       
+        /* We must create the NETLINK_IP6_FW protocol service */
+       nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
+       if (nfnl == NULL) {
+               printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+                      "create kernel netlink socket\n");
+               return -ENOMEM;
+       }
+       nlq6 = ip6q_create_queue(netfilter6_receive,
+                              netlink_send_peer, &status, &sysctl_maxlen);
+       if (nlq6 == NULL) {
+               printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+                      "create queue\n");
+               sock_release(nfnl->socket);
+               return status;
+       }
+        /* The file will be /proc/net/ip6_queue */
+       proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
+       if (proc) proc->owner = THIS_MODULE;
+       else {
+               ip6q_destroy_queue(nlq6);
+               sock_release(nfnl->socket);
+               return -ENOMEM;
+       }
+       register_netdevice_notifier(&ip6q_dev_notifier);
+       ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+       return status;
+}
+
+static void __exit fini(void)
+{
+       unregister_sysctl_table(ip6q_sysctl_header);
+       proc_net_remove(IPQ_PROC_FS_NAME);
+       unregister_netdevice_notifier(&ip6q_dev_notifier);
+       ip6q_destroy_queue(nlq6);
+       sock_release(nfnl->socket);
+}
+
+MODULE_DESCRIPTION("IPv6 packet queue handler");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
index 849b81f756615908684aac3f270e0aa1548fa431..8b962275c4b9c7b5069edf81de1b1832f559b363 100644 (file)
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ *     - increase module usage count as soon as we have rules inside
+ *       a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -86,6 +91,8 @@ struct ip6t_table_info
        unsigned int size;
        /* Number of entries: FIXME. --RR */
        unsigned int number;
+       /* Initial number of entries. Needed for module usage count */
+       unsigned int initial_entries;
 
        /* Entry points and underflows */
        unsigned int hook_entry[NF_IP6_NUMHOOKS];
@@ -949,6 +956,7 @@ replace_table(struct ip6t_table *table,
        }
        oldinfo = table->private;
        table->private = newinfo;
+       newinfo->initial_entries = oldinfo->initial_entries;
        write_unlock_bh(&table->lock);
 
        return oldinfo;
@@ -1148,6 +1156,16 @@ do_replace(void *user, unsigned int len)
        if (!oldinfo)
                goto free_newinfo_counters_untrans_unlock;
 
+       /* Update module usage count based on number of rules */
+       duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+               oldinfo->number, oldinfo->initial_entries, newinfo->number);
+       if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+           (newinfo->number > oldinfo->initial_entries))
+               __MOD_INC_USE_COUNT(t->me);
+       else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+                (newinfo->number <= oldinfo->initial_entries))
+               __MOD_DEC_USE_COUNT(t->me);
+
        /* Get the old counters. */
        get_counters(oldinfo, counters);
        /* Decrease module usage counts and free resource */
@@ -1406,7 +1424,7 @@ int ip6t_register_table(struct ip6t_table *table)
        int ret;
        struct ip6t_table_info *newinfo;
        static struct ip6t_table_info bootstrap
-               = { 0, 0, { 0 }, { 0 }, { }, { } };
+               = { 0, 0, 0, { 0 }, { 0 }, { }, { } };
 
        MOD_INC_USE_COUNT;
        newinfo = vmalloc(sizeof(struct ip6t_table_info)
@@ -1783,7 +1801,7 @@ static int __init init(void)
        }
 #endif
 
-       printk("ip6_tables: (c)2000 Netfilter core team\n");
+       printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
        return 0;
 }
 
index 1bd758fc3221db5899ef07aed347352e0d71adc9..88c12a44ad5ab2d49e02fbc3c5236a02a8559fb1 100644 (file)
@@ -51,7 +51,7 @@ static struct ip6t_target ip6t_mark_reg
 
 static int __init init(void)
 {
-       printk(KERN_DEBUG "registreing ipv6 mark target\n");
+       printk(KERN_DEBUG "registering ipv6 mark target\n");
        if (ip6t_register_target(&ip6t_mark_reg))
                return -EINVAL;
 
index 3d922ab365557ed0d4a4029f10f77cdf304ea5cb..34913a807d270e6dc1bca5978e4fdb085c4cd202 100644 (file)
@@ -83,7 +83,7 @@ static struct
 
 static struct ip6t_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
index da87bbb3e8a8d5496251db81277069a61521a008..3f5f1344e24923c41784697b7760d31e147526c1 100644 (file)
@@ -1,14 +1,18 @@
 /*
  * IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6
  *
- * Copyright (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
+                           (1 << NF_IP6_LOCAL_IN) | \
+                           (1 << NF_IP6_FORWARD) | \
+                           (1 << NF_IP6_LOCAL_OUT) | \
+                           (1 << NF_IP6_POST_ROUTING))
 
-#if 1
+#if 0
 #define DEBUGP(x, args...)     printk(KERN_DEBUG x, ## args)
 #else
 #define DEBUGP(x, args...)
@@ -36,19 +40,41 @@ struct ip6t_error
 static struct
 {
        struct ip6t_replace repl;
-       struct ip6t_standard entries[2];
+       struct ip6t_standard entries[5];
        struct ip6t_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
-      { [NF_IP6_PRE_ROUTING] 0,
-       [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
-      { [NF_IP6_PRE_ROUTING] 0,
-       [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+      { [NF_IP6_PRE_ROUTING]   0,
+       [NF_IP6_LOCAL_IN]       sizeof(struct ip6t_standard),
+       [NF_IP6_FORWARD]        sizeof(struct ip6t_standard) * 2,
+       [NF_IP6_LOCAL_OUT]      sizeof(struct ip6t_standard) * 3,
+       [NF_IP6_POST_ROUTING]   sizeof(struct ip6t_standard) * 4},
+      { [NF_IP6_PRE_ROUTING]   0,
+       [NF_IP6_LOCAL_IN]       sizeof(struct ip6t_standard),
+       [NF_IP6_FORWARD]        sizeof(struct ip6t_standard) * 2,
+       [NF_IP6_LOCAL_OUT]      sizeof(struct ip6t_standard) * 3,
+       [NF_IP6_POST_ROUTING]   sizeof(struct ip6t_standard) * 4},
       0, NULL, { } },
     {
            /* PRE_ROUTING */
-           { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+               0,
+               sizeof(struct ip6t_entry),
+               sizeof(struct ip6t_standard),
+               0, { 0, 0 }, { } },
+             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+               -NF_ACCEPT - 1 } },
+           /* LOCAL_IN */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+               0,
+               sizeof(struct ip6t_entry),
+               sizeof(struct ip6t_standard),
+               0, { 0, 0 }, { } },
+             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+               -NF_ACCEPT - 1 } },
+           /* FORWARD */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
                0,
                sizeof(struct ip6t_entry),
                sizeof(struct ip6t_standard),
@@ -56,6 +82,14 @@ static struct
              { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
                -NF_ACCEPT - 1 } },
            /* LOCAL_OUT */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+               0,
+               sizeof(struct ip6t_entry),
+               sizeof(struct ip6t_standard),
+               0, { 0, 0 }, { } },
+             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+               -NF_ACCEPT - 1 } },
+           /* POST_ROUTING */
            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
                0,
                sizeof(struct ip6t_entry),
@@ -79,11 +113,11 @@ static struct
 
 static struct ip6t_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ip6t_hook(unsigned int hook,
+ip6t_route_hook(unsigned int hook,
         struct sk_buff **pskb,
         const struct net_device *in,
         const struct net_device *out,
@@ -93,7 +127,7 @@ ip6t_hook(unsigned int hook,
 }
 
 static unsigned int
-ip6t_local_out_hook(unsigned int hook,
+ip6t_local_hook(unsigned int hook,
                   struct sk_buff **pskb,
                   const struct net_device *in,
                   const struct net_device *out,
@@ -142,9 +176,11 @@ ip6t_local_out_hook(unsigned int hook,
 }
 
 static struct nf_hook_ops ip6t_ops[]
-= { { { NULL, NULL }, ip6t_hook, PF_INET6, NF_IP6_PRE_ROUTING, NF_IP6_PRI_MANGLE },
-    { { NULL, NULL }, ip6t_local_out_hook, PF_INET6, NF_IP6_LOCAL_OUT,
-               NF_IP6_PRI_MANGLE }
+= { { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_PRE_ROUTING,  NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_IN,     NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_FORWARD,      NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_OUT,    NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_POST_ROUTING, NF_IP6_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -165,8 +201,26 @@ static int __init init(void)
        if (ret < 0)
                goto cleanup_hook0;
 
+       ret = nf_register_hook(&ip6t_ops[2]);
+       if (ret < 0)
+               goto cleanup_hook1;
+
+       ret = nf_register_hook(&ip6t_ops[3]);
+       if (ret < 0)
+               goto cleanup_hook2;
+
+       ret = nf_register_hook(&ip6t_ops[4]);
+       if (ret < 0)
+               goto cleanup_hook3;
+
        return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ip6t_ops[3]);
+ cleanup_hook2:
+       nf_unregister_hook(&ip6t_ops[2]);
+ cleanup_hook1:
+       nf_unregister_hook(&ip6t_ops[1]);
  cleanup_hook0:
        nf_unregister_hook(&ip6t_ops[0]);
  cleanup_table:
index da456b250deffeb21b126b958a16f343dc5b63e4..d4b7b21f5f84e91141b4396e0e352ad8eb217104 100644 (file)
@@ -2590,14 +2590,11 @@ int __init irda_proto_init(void)
        register_netdevice_notifier(&irda_dev_notifier);
 
        irda_init();
-#ifdef MODULE
-       irda_device_init();  /* Called by init/main.c when non-modular */
-#endif
+       irda_device_init();
        return 0;
 }
-#ifdef MODULE
-module_init(irda_proto_init);  /* If non-module, called from init/main.c */
-#endif
+
+late_initcall(irda_proto_init);
 
 /*
  * Function irda_proto_cleanup (void)
index 49843fa2d58b05e3a0ad74e1fa560f7fb0123823..6805ea3db988c3e8af31e0fdf2b2fcfd583257e0 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 #include <net/sock.h>
@@ -48,8 +48,6 @@
 #define NL_EMULATE_DEV
 #endif
 
-#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
-
 struct netlink_opt
 {
        u32                     pid;
index 4935c8992078de4f2f54b56a83d05311b5d9b4de..0ecce3fcc4a896fbf299f1bb0354c6b9dd6c197c 100644 (file)
@@ -292,6 +292,8 @@ EXPORT_SYMBOL(icmpv6_send);
 EXPORT_SYMBOL(ndisc_mc_map);
 EXPORT_SYMBOL(register_inet6addr_notifier);
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
+#include <net/ip6_route.h>
+EXPORT_SYMBOL(ip6_route_output);
 #endif
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
 /* inet functions common to v4 and v6 */
@@ -519,6 +521,10 @@ EXPORT_SYMBOL(if_port_text);
 EXPORT_SYMBOL(hippi_type_trans);
 #endif
 
+#ifdef CONFIG_NET_FASTROUTE
+EXPORT_SYMBOL(netdev_fastroute);
+#endif
+
 #ifdef CONFIG_SYSCTL
 EXPORT_SYMBOL(sysctl_wmem_max);
 EXPORT_SYMBOL(sysctl_rmem_max);