]> git.hungrycats.org Git - linux/commitdiff
v2.5.2.1 -> v2.5.2.1.1
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 08:13:46 +0000 (00:13 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 08:13:46 +0000 (00:13 -0800)
- David Howells: abtract out "current->need_resched" as "need_resched()"
- Frank Davis: ide-tape update for bio
- various: header file fixups
- Jens Axboe: fix up bio/ide/highmem issues
- Kai Germaschewski: ISDN update
- Tim Waugh: parport update
- Patrik Mochel: initcall update
- Greg KH: USB and Compaq PCI hotplug updates

150 files changed:
Documentation/DocBook/kernel-hacking.tmpl
Documentation/ioctl-number.txt
Makefile
arch/arm/kernel/ecard.c
arch/arm/kernel/process.c
arch/i386/kernel/apm.c
arch/i386/kernel/mca.c
arch/i386/kernel/process.c
arch/i386/math-emu/fpu_entry.c
arch/i386/vmlinux.lds
arch/ia64/kernel/process.c
arch/m68k/kernel/process.c
arch/mips/kernel/process.c
arch/mips/math-emu/cp1emu.c
arch/mips64/kernel/process.c
arch/mips64/math-emu/cp1emu.c
arch/parisc/kernel/process.c
arch/ppc/kernel/idle.c
arch/ppc/kernel/setup.c
arch/s390/kernel/process.c
arch/s390x/kernel/process.c
arch/sh/kernel/process.c
arch/sparc/kernel/process.c
arch/sparc64/kernel/process.c
drivers/block/ll_rw_blk.c
drivers/char/lp.c
drivers/char/mem.c
drivers/char/mwave/3780i.c
drivers/char/ppdev.c
drivers/char/random.c
drivers/char/tty_io.c
drivers/dio/dio.c
drivers/hotplug/cpqphp_core.c
drivers/i2c/i2c-algo-bit.c
drivers/i2c/i2c-algo-ite.c
drivers/ide/ide-disk.c
drivers/ide/ide-floppy.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide.c
drivers/isdn/avmb1/b1pci.c
drivers/isdn/avmb1/c4.c
drivers/isdn/avmb1/t1pci.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_ppp.h
drivers/md/md.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/video/c-qcam.c
drivers/media/video/cpia.c
drivers/media/video/cpia_pp.c
drivers/media/video/saa5249.c
drivers/mtd/chips/amd_flash.c
drivers/mtd/devices/doc2000.c
drivers/net/acenic.h
drivers/net/pcmcia/wavelan.h
drivers/net/pcmcia/wavelan_cs.c
drivers/net/pcmcia/wavelan_cs.h
drivers/nubus/nubus.c
drivers/parport/ChangeLog
drivers/parport/ieee1284.c
drivers/parport/ieee1284_ops.c
drivers/parport/parport_pc.c
drivers/pci/pci.c
drivers/pcmcia/ds.c
drivers/pnp/isapnp.c
drivers/sbus/sbus.c
drivers/scsi/advansys.c
drivers/scsi/aic7xxx/aic7xxx_linux.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_debug.h
drivers/scsi/sg.c
drivers/scsi/sr.c
drivers/sound/via82cxxx_audio.c
drivers/tc/tc.c
drivers/usb/hcd.c
drivers/usb/hcd/ehci-hcd.c
drivers/usb/hcd/ehci-hub.c
drivers/usb/hcd/ehci-q.c
drivers/usb/hcd/ehci-sched.c
drivers/usb/hpusbscsi.c
drivers/usb/hub.c
drivers/usb/microtek.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/storage/protocol.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/stv680.c
drivers/usb/stv680.h
drivers/usb/usb.c
drivers/video/vesafb.c
drivers/zorro/zorro.c
fs/Makefile.lib
fs/binfmt_misc.c
fs/buffer.c
fs/ext2/balloc.c
fs/fat/inode.c
fs/inode.c
fs/intermezzo/kml_reint.c
fs/jbd/commit.c
fs/jffs2/background.c
fs/jffs2/erase.c
fs/jffs2/nodemgmt.c
fs/msdos/msdosfs_syms.c
fs/msdos/namei.c
fs/namei.c
fs/reiserfs/inode.c
fs/reiserfs/journal.c
fs/umsdos/inode.c
fs/vfat/namei.c
include/asm-arm/arch-arc/system.h
include/asm-arm/arch-cl7500/system.h
include/asm-arm/arch-ebsa110/system.h
include/asm-arm/arch-ebsa285/system.h
include/asm-arm/arch-nexuspci/system.h
include/asm-arm/arch-rpc/system.h
include/asm-arm/arch-sa1100/system.h
include/asm-arm/arch-tbox/system.h
include/asm-i386/mmu_context.h
include/asm-i386/smplock.h
include/linux/blk.h
include/linux/file.h
include/linux/fs.h
include/linux/ide.h
include/linux/init.h
include/linux/init_task.h
include/linux/isdn.h
include/linux/mtd/cfi.h
include/linux/pci.h
include/linux/reiserfs_fs_sb.h
include/linux/sched.h
include/scsi/sg.h
init/main.c
kernel/fork.c
kernel/ksyms.c
kernel/printk.c
kernel/sched.c
kernel/softirq.c
kernel/timer.c
mm/filemap.c
mm/highmem.c
mm/swapfile.c
mm/vmscan.c
net/ipv4/netfilter/ip_fw_compat_redir.c
net/irda/af_irda.c
net/socket.c
net/sunrpc/sched.c

index b25aa1bf577bbfc33d1b9c8c4e0a95cb6cc1ce4d..bf5a8f6f8991b522d324dc1e476d035265c04a66 100644 (file)
@@ -371,8 +371,7 @@ if (signal_pending())
   </para>
 
   <programlisting>
-if (current-&gt;need_resched)
-        schedule(); /* Will sleep */ 
+cond_resched(); /* Will sleep */ 
   </programlisting>
 
   <para>
index 4b520113fbfff0c4189690c0ba840a28a754319f..711483a87c722f3292c76abd09dffe0de5e01ad2 100644 (file)
@@ -101,7 +101,8 @@ Code        Seq#    Include File            Comments
 'S'    82-FF   scsi/scsi.h             conflict!
 'T'    all     linux/soundcard.h       conflict!
 'T'    all     asm-i386/ioctls.h       conflict!
-'U'    all     linux/drivers/usb/usb.h
+'U'    00-EF   linux/drivers/usb/usb.h
+'U'    F0-FF   drivers/usb/auerswald.c
 'V'    all     linux/vt.h
 'W'    00-1F   linux/watchdog.h        conflict!
 'W'    00-1F   linux/wanrouter.h       conflict!
index dc774375b213c9ae58148dd9aa9e9abc99d0bbca..f168a156c07736883a719a8402be9800e97f87d8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 3
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
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 741984e0c6afd23cad24cb9ef024cad378b0f328..61b592b9747c03bd1ba788a6d8e7665b4e1382ac 100644 (file)
@@ -91,7 +91,7 @@ void cpu_idle(void)
                if (!idle)
                        idle = arch_idle;
                leds_event(led_idle_start);
-               while (!current->need_resched)
+               while (!need_resched())
                        idle();
                leds_event(led_idle_end);
                schedule();
index 02a1a5d093c4fea5ba52f819749afc69c4334f9b..c81844e10870b7903fd162faaeac6e33a8bfe1a1 100644 (file)
@@ -766,14 +766,14 @@ static void apm_cpu_idle(void)
 
        start_idle = jiffies;
        while (1) {
-               if (!current->need_resched) {
+               if (!need_resched()) {
                        if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
                                if (!current_cpu_data.hlt_works_ok)
                                        continue;
                                if (hlt_counter)
                                        continue;
                                __cli();
-                               if (!current->need_resched)
+                               if (!need_resched())
                                        safe_halt();
                                else
                                        __sti();
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 e17b07ecd69d515ace5f5409ad6f5f7260854054..0f0b20014bc2e0f0527b89f1c782930e4c280671 100644 (file)
@@ -42,7 +42,6 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/desc.h>
-#include <asm/mmu_context.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -81,7 +80,7 @@ static void default_idle(void)
 {
        if (current_cpu_data.hlt_works_ok && !hlt_counter) {
                __cli();
-               if (!current->need_resched)
+               if (!need_resched())
                        safe_halt();
                else
                        __sti();
@@ -127,7 +126,7 @@ void cpu_idle (void)
                void (*idle)(void) = pm_idle;
                if (!idle)
                        idle = default_idle;
-               while (!current->need_resched)
+               while (!need_resched())
                        idle();
                schedule();
                check_pgt_cache();
index 7d50e87b8f0d0b9be81524f1237c51376e6eed2f..c37a93bea50b4b6213d727e827d62ed0992c15a2 100644 (file)
@@ -559,7 +559,7 @@ FPU_fwait_done:
   RE_ENTRANT_CHECK_ON;
 #endif /* DEBUG */
 
-  if (FPU_lookahead && !current->need_resched)
+  if (FPU_lookahead && !need_resched())
     {
       FPU_ORIG_EIP = FPU_EIP - code_base;
       if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
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 82eb84428efa615de008ba3c9517281595d3bd7b..bfdb34b4352dc9c3d675961d72999a4725549da5 100644 (file)
@@ -117,10 +117,10 @@ cpu_idle (void *unused)
 
        while (1) {
 #ifdef CONFIG_SMP
-               if (!current->need_resched)
+               if (!need_resched())
                        min_xtp();
 #endif
-               while (!current->need_resched)
+               while (!need_resched())
                        continue;
 #ifdef CONFIG_SMP
                normal_xtp();
index 520a1ea26d4f1abbc1899983d1da984c9fa32cc8..ec9a7c0dcbbcc52c4294ad3886fee6943fc568d9 100644 (file)
@@ -56,7 +56,7 @@ asmlinkage void ret_from_fork(void);
 static void default_idle(void)
 {
        while(1) {
-               if (!current->need_resched)
+               if (!need_resched())
 #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
                        /* block out HSYNC on the atari (falcon) */
                        __asm__("stop #0x2200" : : : "cc");
index 248c51d9465fd2d0b4f446d58d3391e35a790a66..de4a3a1873cd8cfecf00378631374e0840ff265d 100644 (file)
@@ -39,7 +39,7 @@ void cpu_idle(void)
        init_idle();
 
        while (1) {
-               while (!current->need_resched)
+               while (!need_resched())
                        if (cpu_wait)
                                (*cpu_wait)();
                schedule();
index 9712dfc05eb0f398eb408a9fe89de57675a32c0e..4d3367c651b8cd5be9f8c8e74246a3a10c67d823 100644 (file)
@@ -1674,8 +1674,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp)
 
        oldepc = xcp->cp0_epc;
        do {
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
 
                prevepc = xcp->cp0_epc;
                insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
index 595b396700898a4b3e21e0b8ed3b283013be1c97..aad1e7834d915b38a036961d9dd1bd8e1c03f427 100644 (file)
@@ -35,7 +35,7 @@ asmlinkage int cpu_idle(void)
        init_idle();
        current->nice = 20;
        while (1) {
-               while (!current->need_resched)
+               while (!need_resched())
                        if (wait_available)
                                __asm__("wait");
                schedule();
index fbb8911b87ff390052cd66c0db8cec3f462f4fda..5acd218d218da79a2de13521377ed507f53a7247 100644 (file)
@@ -1707,8 +1707,7 @@ int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp)
 
        oldepc = xcp->cp0_epc;
        do {
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
 
                prevepc = xcp->cp0_epc;
                insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
index aae398f1e28984af2740131c4080fea887b27ba3..c49239b9502f92246672c8fd31ecc722009bdd14 100644 (file)
@@ -73,8 +73,8 @@ void cpu_idle(void)
        current->nice = 20;
 
        while (1) {
-               while (!current->need_resched) {
-               }
+               while (!need_resched())
+                       barrier();
                schedule();
                check_pgt_cache();
        }
index 3fff2ebb649f858dc93309d775e3bcc94aa5e475..2d93e549ccea74c78684f2acf387a7e1e688afc6 100644 (file)
@@ -66,15 +66,15 @@ int idled(void)
                        int oldval = xchg(&current->need_resched, -1);
 
                        if (!oldval) {
-                               while(current->need_resched == -1)
-                                       ; /* Do Nothing */
+                               while (need_resched())
+                                       barrier(); /* Do Nothing */
                        }
                }
 #endif
-               if (do_power_save && !current->need_resched)
+               if (do_power_save && !need_resched())
                        power_save();
 
-               if (current->need_resched) {
+               if (need_resched()) {
                        schedule();
                        check_pgt_cache();
                }
@@ -150,7 +150,7 @@ void zero_paged(void)
 
        if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
                return;
-       while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
+       while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && !need_resched() )
        {
                /*
                 * Mark a page as reserved so we can mess with it
@@ -161,8 +161,7 @@ void zero_paged(void)
                if ( !pageptr )
                        return;
                
-               if ( current->need_resched )
-                       schedule();
+               cond_resched();
                
                /*
                 * Make the page no cache so we don't blow our cache with 0's
@@ -181,8 +180,7 @@ void zero_paged(void)
                 */
                for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
                {
-                       if ( current->need_resched )
-                               schedule();
+                       cond_resched();
                        *(unsigned long *)(bytecount + pageptr) = 0;
                }
                
@@ -243,7 +241,7 @@ void power_save(void)
         *  -- Cort
         */
        _nmask_and_or_msr(MSR_EE, 0);
-       if (!current->need_resched)
+       if (!need_resched())
        {
                asm("mfspr %0,1008" : "=r" (hid0) :);
                hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
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 978c6647b87e91ba402fa61b6bc3a8145cd4612f..9ae8a6350ab99dd4328493c6903b6ad096de4a4e 100644 (file)
@@ -60,7 +60,7 @@ int cpu_idle(void *unused)
        wait_psw.mask = _WAIT_PSW_MASK;
        wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
        while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
index c54bb41e709fd441408cb66bdf1c021bdad08d5f..caa8b60164c153ce2bb30f848df09c831f983d92 100644 (file)
@@ -60,7 +60,7 @@ int cpu_idle(void *unused)
        wait_psw.mask = _WAIT_PSW_MASK;
        wait_psw.addr = (unsigned long) &&idle_wakeup;
        while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
index ae0dfa9b8631395e2c763b8fb3bda7968fd1a266..f991af5c788ac9ebba4afb2eb696db78f12631a9 100644 (file)
@@ -44,11 +44,11 @@ void cpu_idle(void *unused)
 
        while (1) {
                if (hlt_counter) {
-                       if (current->need_resched)
+                       if (need_resched())
                                break;
                } else {
                        __cli();
-                       while (!current->need_resched) {
+                       while (!need_resched()) {
                                __sti();
                                asm volatile("sleep" : : : "memory");
                                __cli();
index 2e477bfbc8ecc5b69ce5e89919cda270f5902368..00c1de5e877f7c4f674b103b98b2fdf2eae3479f 100644 (file)
@@ -106,7 +106,7 @@ int cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
        while(1) {
-               if(current->need_resched) {
+               if(need_resched()) {
                        schedule();
                        check_pgt_cache();
                }
index cedff9e3a975efbc626dc47ece9597d3ba43c52c..8c2cbcb5bc79912b3f374e8a9b4c39da8674b42f 100644 (file)
@@ -61,7 +61,7 @@ int cpu_idle(void)
                 * But this requires writing back the contents of the
                 * L2 cache etc. so implement this later. -DaveM
                 */
-               while (!current->need_resched)
+               while (!need_resched())
                        barrier();
 
                schedule();
@@ -80,7 +80,7 @@ int cpu_idle(void)
 int cpu_idle(void)
 {
        while(1) {
-               if (current->need_resched != 0) {
+               if (need_resched()) {
                        unidle_me();
                        schedule();
                        check_pgt_cache();
index 142b4a8e8391099fd73f68f6be1f1bc69d261234..ddb14e8f127834ef56bc324c4baa41a088382c96 100644 (file)
@@ -186,7 +186,8 @@ void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr)
         * full 4GB zone, so we have to resort to low memory for any bounces.
         * ISA has its own < 16MB zone.
         */
-       if (dma_addr == BLK_BOUNCE_ISA) {
+       if (bounce_pfn < blk_max_low_pfn) {
+               BUG_ON(dma_addr < BLK_BOUNCE_ISA);
                init_emergency_isa_pool();
                q->bounce_gfp = GFP_NOIO | GFP_DMA;
        } else
@@ -302,8 +303,8 @@ void blk_queue_assign_lock(request_queue_t *q, spinlock_t *lock)
 static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER",
                           "REQ_CMD", "REQ_NOMERGE", "REQ_STARTED",
                           "REQ_DONTPREP", "REQ_DRIVE_CMD", "REQ_DRIVE_TASK",
-                          "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE",
-                          "REQ_SPECIAL" };
+                          "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC",
+                          "REQ_SENSE", "REQ_SPECIAL" };
 
 void blk_dump_rq_flags(struct request *rq, char *msg)
 {
@@ -1708,7 +1709,11 @@ int __init blk_dev_init(void)
        printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests);
 
        blk_max_low_pfn = max_low_pfn;
+#ifdef CONFIG_HIGHMEM
        blk_max_pfn = max_pfn;
+#else
+       blk_max_pfn = max_low_pfn;
+#endif
 
 #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
        ide_init();             /* this MUST precede hd_init */
index 4c0acc344fbb2404991b140496eb82816ecd8af5..f71e3fa09312ba02a82a52f161b5964a976a576e 100644 (file)
@@ -367,7 +367,7 @@ static ssize_t lp_write(struct file * file, const char * buf,
                          = lp_negotiate (port, 
                                          lp_table[minor].best_mode);
 
-               } else if (current->need_resched)
+               } else if (need_resched())
                        schedule ();
 
                if (count) {
index 8b1f582a7168ae3f4d3233dcd923b48af571d645..90e1e9956054cd13de1ccb6e9694d6583142a674 100644 (file)
@@ -381,8 +381,7 @@ static inline size_t read_zero_pagealigned(char * buf, size_t size)
                unsigned long unwritten = clear_user(buf, PAGE_SIZE);
                if (unwritten)
                        return size + unwritten - PAGE_SIZE;
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
                buf += PAGE_SIZE;
                size -= PAGE_SIZE;
        } while (size);
index 54f2f46d9d518534488a92d1e69dcd7f6921e93d..b8f583ca3029a30e1fee4f3d6eccb3ed61976b82 100644 (file)
@@ -68,11 +68,9 @@ static unsigned long flags;
 
 static void PaceMsaAccess(unsigned short usDspBaseIO)
 {
-       if(current->need_resched)
-               schedule();
+       cond_resched();
        udelay(100);
-       if(current->need_resched)
-               schedule();
+       cond_resched();
 }
 
 unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
index 6e976f28c271ae3d1307ceb5f8f18cfa745210ec..bdebe0aee56387838083aa3be8e483e66d025795 100644 (file)
@@ -170,9 +170,7 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
                        break;
                }
 
-               if (current->need_resched) {
-                       schedule ();
-               }
+               cond_resched();
        }
 
        kfree (kbuffer);
@@ -242,9 +240,7 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
                        break;
                }
 
-               if (current->need_resched) {
-                       schedule ();
-               }
+               cond_resched();
        }
 
        kfree (kbuffer);
index ddd02651910034342d9c0d0c6e64af0fd881f1f0..656a38b22da75459dac89f71788a7134badce19b 100644 (file)
@@ -1313,7 +1313,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf,
                /*
                 * Check if we need to break out or reschedule....
                 */
-               if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) {
+               if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) {
                        if (signal_pending(current)) {
                                if (ret == 0)
                                        ret = -ERESTARTSYS;
index cea100d98184be5c072b2297b7391490fd8fd3a3..9fdd57eff81c48e7008cd0449763cf5bddfadeaf 100644 (file)
@@ -712,8 +712,7 @@ static inline ssize_t do_tty_write(
                        ret = -ERESTARTSYS;
                        if (signal_pending(current))
                                break;
-                       if (current->need_resched)
-                               schedule();
+                       cond_resched();
                }
        }
        if (written) {
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 5b4861915c72f9764281b1a8886bfa742acd7408..ddcd791f4f2711e15df562547baec58c46f9a37e 100644 (file)
@@ -404,6 +404,10 @@ static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *
                result = pci_hp_register (new_slot->hotplug_slot);
                if (result) {
                        err ("pci_hp_register failed with error %d\n", result);
+                       kfree (new_slot->hotplug_slot->info);
+                       kfree (new_slot->hotplug_slot->name);
+                       kfree (new_slot->hotplug_slot);
+                       kfree (new_slot);
                        return result;
                }
                
@@ -429,6 +433,8 @@ static int ctrl_slot_cleanup (struct controller * ctrl)
        while (old_slot) {
                next_slot = old_slot->next;
                pci_hp_deregister (old_slot->hotplug_slot);
+               kfree(old_slot->hotplug_slot->info);
+               kfree(old_slot->hotplug_slot->name);
                kfree(old_slot->hotplug_slot);
                kfree(old_slot);
                old_slot = next_slot;
index 7e968759a635975735718e71d07b72dea488421e..a576ffe4c239ee726166b6e023c79b41b9dea30f 100644 (file)
@@ -50,7 +50,7 @@
 /* might not like this, as they have an internal timeout of some mils  */
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
@@ -120,8 +120,7 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
                if (start+adap->timeout <= jiffies) {
                        return -ETIMEDOUT;
                }
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
        }
        DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
 #ifdef SLO_IO
index 59170078f0776d2e77e636153a6690efefbf959e..919a287fa7f3ea62194ea13c833be16d3800e6b3 100644 (file)
@@ -67,7 +67,7 @@
 /* might not like this, as they have an internal timeout of some mils  */
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
index cbc80707bed13adc3e0ac8f16ede0eaec50b72a8..baf50487df3175c8c97e6e9c16a534e95725dbd2 100644 (file)
@@ -123,12 +123,10 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-       if (rq_data_dir(rq) == READ)
-               goto good_command;
-       if (rq_data_dir(rq) == WRITE)
+       if (rq->flags & REQ_CMD)
                goto good_command;
 
-       printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
+       blk_dump_rq_flags(rq, "do_rw_disk, bad command");
        ide_end_request(0, HWGROUP(drive));
        return ide_stopped;
 
@@ -179,8 +177,10 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi
        struct hd_drive_task_hdr        taskfile;
        struct hd_drive_hob_hdr         hobfile;
        ide_task_t                      args;
+       int                             sectors;
 
        task_ioreg_t command    = get_command(drive, rq_data_dir(rq));
+
        unsigned int track      = (block / drive->sect);
        unsigned int sect       = (block % drive->sect) + 1;
        unsigned int head       = (track % drive->head);
@@ -189,7 +189,16 @@ static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsi
        memset(&taskfile, 0, sizeof(task_struct_t));
        memset(&hobfile, 0, sizeof(hob_struct_t));
 
-       taskfile.sector_count   = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+       sectors = rq->nr_sectors;
+       if (sectors == 256)
+               sectors = 0;
+       if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+               sectors = drive->mult_count;
+               if (sectors > rq->current_nr_sectors)
+                       sectors = rq->current_nr_sectors;
+       }
+
+       taskfile.sector_count   = sectors;
        taskfile.sector_number  = sect;
        taskfile.low_cylinder   = cyl;
        taskfile.high_cylinder  = (cyl>>8);
@@ -225,13 +234,23 @@ static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, u
        struct hd_drive_task_hdr        taskfile;
        struct hd_drive_hob_hdr         hobfile;
        ide_task_t                      args;
+       int                             sectors;
 
        task_ioreg_t command    = get_command(drive, rq_data_dir(rq));
 
+       sectors = rq->nr_sectors;
+       if (sectors == 256)
+               sectors = 0;
+       if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+               sectors = drive->mult_count;
+               if (sectors > rq->current_nr_sectors)
+                       sectors = rq->current_nr_sectors;
+       }
+
        memset(&taskfile, 0, sizeof(task_struct_t));
        memset(&hobfile, 0, sizeof(hob_struct_t));
 
-       taskfile.sector_count   = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+       taskfile.sector_count   = sectors;
        taskfile.sector_number  = block;
        taskfile.low_cylinder   = (block>>=8);
        taskfile.high_cylinder  = (block>>=8);
@@ -273,14 +292,24 @@ static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, u
        struct hd_drive_task_hdr        taskfile;
        struct hd_drive_hob_hdr         hobfile;
        ide_task_t                      args;
+       int                             sectors;
 
        task_ioreg_t command    = get_command(drive, rq_data_dir(rq));
 
        memset(&taskfile, 0, sizeof(task_struct_t));
        memset(&hobfile, 0, sizeof(hob_struct_t));
 
-       taskfile.sector_count   = rq->nr_sectors;
-       hobfile.sector_count    = (rq->nr_sectors>>8);
+       sectors = rq->nr_sectors;
+       if (sectors == 256)
+               sectors = 0;
+       if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+               sectors = drive->mult_count;
+               if (sectors > rq->current_nr_sectors)
+                       sectors = rq->current_nr_sectors;
+       }
+
+       taskfile.sector_count   = sectors;
+       hobfile.sector_count    = sectors >> 8;
 
        if (rq->nr_sectors == 65536) {
                taskfile.sector_count   = 0x00;
@@ -652,7 +681,7 @@ static ide_startstop_t idedisk_special (ide_drive_t *drive)
                        memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
                        taskfile.sector_count   = drive->mult_req;
                        taskfile.command        = WIN_SETMULT;
-                       do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+                       do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
                }
        } else if (s->all) {
                int special = s->all;
@@ -789,23 +818,12 @@ static ide_proc_entry_t idedisk_proc[] = {
 
 #endif /* CONFIG_PROC_FS */
 
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
-#if 1
-       struct hd_drive_task_hdr taskfile;
-       struct hd_drive_hob_hdr hobfile;
-
-       if (drive->special.b.set_multmode)
-               return -EBUSY;
-
-       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-       taskfile.sector_count   = drive->mult_req;
-       taskfile.command        = WIN_SETMULT;
-       drive->mult_req         = arg;
-       drive->special.b.set_multmode = 1;
-       ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else
        struct request rq;
 
        if (drive->special.b.set_multmode)
@@ -814,7 +832,6 @@ static int set_multcount(ide_drive_t *drive, int arg)
        drive->mult_req = arg;
        drive->special.b.set_multmode = 1;
        (void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif
        return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
index 07e5e8260a8e2a6440812ed8117d001718c168cb..7a66d61682f305fd31b355163cafecc2be3013e5 100644 (file)
@@ -688,7 +688,7 @@ static void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
        /* Why does this happen? */
        if (!rq)
                return;
-       if (rq->flags & IDEFLOPPY_RQ) {
+       if (!(rq->flags & IDEFLOPPY_RQ)) {
                ide_end_request (uptodate, hwgroup);
                return;
        }
index 4828e49f98854a1697937601f8e18d2f7b825aa7..c591729acc1499826314645adc6aaeeb72ca78ec 100644 (file)
@@ -721,7 +721,7 @@ typedef struct idetape_packet_command_s {
        int request_transfer;                   /* Bytes to transfer */
        int actually_transferred;               /* Bytes actually transferred */
        int buffer_size;                        /* Size of our data buffer */
-       struct buffer_head *bh;
+       struct bio *bio;
        char *b_data;
        int b_count;
        byte *buffer;                           /* Data buffer */
@@ -805,7 +805,7 @@ typedef struct {
  */
 typedef struct idetape_stage_s {
        struct request rq;                      /* The corresponding request */
-       struct buffer_head *bh;                 /* The data buffers */
+       struct bio *bio;                        /* The data buffers */
        struct idetape_stage_s *next;           /* Pointer to the next stage */
        os_aux_t *aux;                          /* OnStream aux ptr */
 } idetape_stage_t;
@@ -929,7 +929,7 @@ typedef struct {
        int stage_size;                         /* Data buffer size (chosen based on the tape's recommendation */
        idetape_stage_t *merge_stage;
        int merge_stage_size;
-       struct buffer_head *bh;
+       struct bio *bio;
        char *b_data;
        int b_count;
        
@@ -1013,7 +1013,7 @@ typedef struct {
         * Measures number of frames:
         *
         * 1. written/read to/from the driver pipeline (pipeline_head).
-        * 2. written/read to/from the tape buffers (buffer_head).
+        * 2. written/read to/from the tape buffers (bio).
         * 3. written/read by the tape to/from the media (tape_head).
         */
        int pipeline_head;
@@ -1493,52 +1493,52 @@ static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
 
 static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-       struct buffer_head *bh = pc->bh;
+       struct bio *bio = pc->bio;
        int count;
 
        while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-               if (bh == NULL) {
-                       printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
+               if (bio == NULL) {
+                       printk (KERN_ERR "ide-tape: bio == NULL in idetape_input_buffers\n");
                        idetape_discard_data (drive, bcount);
                        return;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
-               count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
-               atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+               count = IDE_MIN (bio->bi_size - pc->b_count, bcount);
+               atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
                bcount -= count;
-               atomic_add(count, &bh->b_count);
-               if (atomic_read(&bh->b_count) == bh->b_size) {
-                       bh = bh->b_reqnext;
-                       if (bh)
-                               atomic_set(&bh->b_count, 0);
+               pc->b_count += bio->bi_size;
+               if (pc->b_count == bio->bi_size) {
+                       bio = bio->bi_next;
+                       if (bio)
+                               pc->b_count = 0;
                }
        }
-       pc->bh = bh;
+       pc->bio = bio;
 }
 
 static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-       struct buffer_head *bh = pc->bh;
+       struct bio *bio = pc->bio;
        int count;
 
        while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-               if (bh == NULL) {
-                       printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+               if (bio == NULL) {
+                       printk (KERN_ERR "ide-tape: bio == NULL in idetape_output_buffers\n");
                        return;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
                count = IDE_MIN (pc->b_count, bcount);
-               atapi_output_bytes (drive, pc->b_data, count);
+               atapi_output_bytes (drive, bio_data(bio), count);
                bcount -= count;
                pc->b_data += count;
                pc->b_count -= count;
                if (!pc->b_count) {
-                       pc->bh = bh = bh->b_reqnext;
-                       if (bh) {
-                               pc->b_data = bh->b_data;
-                               pc->b_count = atomic_read(&bh->b_count);
+                       pc->bio = bio = bio->bi_next;
+                       if (bio) {
+                               pc->b_data = bio_data(bio);
+                               pc->b_count = bio->bi_size;
                        }
                }
        }
@@ -1547,25 +1547,25 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign
 #ifdef CONFIG_BLK_DEV_IDEDMA
 static void idetape_update_buffers (idetape_pc_t *pc)
 {
-       struct buffer_head *bh = pc->bh;
+       struct bio *bio = pc->bio;
        int count, bcount = pc->actually_transferred;
 
        if (test_bit (PC_WRITING, &pc->flags))
                return;
        while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-               if (bh == NULL) {
-                       printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+               if (bio == NULL) {
+                       printk (KERN_ERR "ide-tape: bio == NULL in idetape_update_buffers\n");
                        return;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
-               count = IDE_MIN (bh->b_size, bcount);
-               atomic_set(&bh->b_count, count);
-               if (atomic_read(&bh->b_count) == bh->b_size)
-                       bh = bh->b_reqnext;
+               count = IDE_MIN (bio->bi_size, bcount);
+               pc->b_count = count;
+               if (pc->b_count == bio->bi_size)
+                       bio = bio->bi_next;
                bcount -= count;
        }
-       pc->bh = bh;
+       pc->bio = bio;
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1625,7 +1625,7 @@ static void idetape_init_pc (idetape_pc_t *pc)
        pc->request_transfer = 0;
        pc->buffer = pc->pc_buffer;
        pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
-       pc->bh = NULL;
+       pc->bio = NULL;
        pc->b_data = NULL;
 }
 
@@ -1706,10 +1706,10 @@ static void idetape_abort_pipeline (ide_drive_t *drive)
                printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
 #endif
        while (stage) {
-               if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-                       stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-               else if (stage->rq.cmd == IDETAPE_READ_RQ)
-                       stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
+               if (stage->rq.flags == IDETAPE_WRITE_RQ)
+                       stage->rq.flags = IDETAPE_ABORTED_WRITE_RQ;
+               else if (stage->rq.flags == IDETAPE_READ_RQ)
+                       stage->rq.flags = IDETAPE_ABORTED_READ_RQ;
                stage = stage->next;
        }
 }
@@ -1735,7 +1735,7 @@ static void idetape_active_next_stage (ide_drive_t *drive)
 #endif /* IDETAPE_DEBUG_BUGS */        
 
        rq->buffer = NULL;
-       rq->bh = stage->bh;
+       rq->bio = stage->bio;
        tape->active_data_request = rq;
        tape->active_stage = stage;
        tape->next_stage = stage->next;
@@ -1769,21 +1769,21 @@ static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
  */
 static void __idetape_kfree_stage (idetape_stage_t *stage)
 {
-       struct buffer_head *prev_bh, *bh = stage->bh;
+       struct bio *prev_bio, *bio = stage->bio;
        int size;
 
-       while (bh != NULL) {
-               if (bh->b_data != NULL) {
-                       size = (int) bh->b_size;
+       while (bio != NULL) {
+               if (bio_data(bio) != NULL) {
+                       size = (int) bio->bi_size;
                        while (size > 0) {
-                               free_page ((unsigned long) bh->b_data);
+                               free_page ((unsigned long) bio_data(bio));
                                size -= PAGE_SIZE;
-                               bh->b_data += PAGE_SIZE;
+                               bio->bi_size += PAGE_SIZE;
                        }
                }
-               prev_bh = bh;
-               bh = bh->b_reqnext;
-               kfree (prev_bh);
+               prev_bio = bio;
+               bio = bio->bi_next;
+               kfree (prev_bio);
        }
        kfree (stage);
 }
@@ -1868,13 +1868,13 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
                tape->active_stage = NULL;
                tape->active_data_request = NULL;
                tape->nr_pending_stages--;
-               if (rq->cmd == IDETAPE_WRITE_RQ) {
+               if (rq->flags == IDETAPE_WRITE_RQ) {
 #if ONSTREAM_DEBUG
                        if (tape->debug_level >= 2) {
                                if (tape->onstream) {
                                        stage = tape->first_stage;
                                        aux = stage->aux;
-                                       p = stage->bh->b_data;
+                                       p = bio_data(stage->bio);
                                        if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
                                                printk(KERN_INFO "ide-tape: finished writing logical blk %u (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
                                }
@@ -1908,7 +1908,7 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
                                                complete(tape->waiting);
                                }
                        }
-               } else if (rq->cmd == IDETAPE_READ_RQ) {
+               } else if (rq->flags == IDETAPE_READ_RQ) {
                        if (error == IDETAPE_ERROR_EOD) {
                                set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
                                idetape_abort_pipeline(drive);
@@ -1984,7 +1984,7 @@ static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct re
 {
        ide_init_drive_cmd (rq);
        rq->buffer = (char *) pc;
-       rq->cmd = IDETAPE_PC_RQ1;
+       rq->flags = IDETAPE_PC_RQ1;
        (void) ide_do_drive_cmd (drive, rq, ide_preempt);
 }
 
@@ -2164,12 +2164,12 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
                }
        }
        if (test_bit (PC_WRITING, &pc->flags)) {
-               if (pc->bh != NULL)
+               if (pc->bio != NULL)
                        idetape_output_buffers (drive, pc, bcount.all);
                else
                        atapi_output_bytes (drive,pc->current_position,bcount.all);     /* Write the current buffer */
        } else {
-               if (pc->bh != NULL)
+               if (pc->bio != NULL)
                        idetape_input_buffers (drive, pc, bcount.all);
                else
                        atapi_input_bytes (drive,pc->current_position,bcount.all);      /* Read the current buffer */
@@ -2523,21 +2523,22 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
        return ide_stopped;
 }
 
-static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-       struct buffer_head *p = bh;
+       struct bio *p = bio;
+       struct bio_vec *bv = bio_iovec(p);
        idetape_init_pc (pc);
        pc->c[0] = IDETAPE_READ_CMD;
        put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
        pc->c[1] = 1;
        pc->callback = &idetape_rw_callback;
-       pc->bh = bh;
-       atomic_set(&bh->b_count, 0);
+       pc->bio = bio;
+       bv->bv_len = 0;
        pc->buffer = NULL;
        if (tape->onstream) {
                while (p) {
-                       atomic_set(&p->b_count, 0);
-                       p = p->b_reqnext;
+                       bv->bv_len = 0;
+                       p = p->bi_next;
                }
        }
        if (!tape->onstream) {
@@ -2553,30 +2554,31 @@ static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, uns
        }
 }
 
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
        int size = 32768;
 
-       struct buffer_head *p = bh;
+       struct bio *p = bio;
        idetape_init_pc (pc);
        pc->c[0] = IDETAPE_READ_BUFFER_CMD;
        pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
        pc->c[7] = size >> 8;
        pc->c[8] = size & 0xff;
        pc->callback = &idetape_pc_callback;
-       pc->bh = bh;
-       atomic_set(&bh->b_count, 0);
+       pc->bio = bio;
+       atomic_set(&bio->bi_cnt, 0);
        pc->buffer = NULL;
        while (p) {
-               atomic_set(&p->b_count, 0);
-               p = p->b_reqnext;
+               p->bi_size = 0;
+               p = p->bi_next;
        }
        pc->request_transfer = pc->buffer_size = size;
 }
 
-static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-       struct buffer_head *p = bh;
+       struct bio *p = bio;
+       struct bio_vec *bv= bio_iovec(p);
        idetape_init_pc (pc);
        pc->c[0] = IDETAPE_WRITE_CMD;
        put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
@@ -2585,13 +2587,13 @@ static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, un
        set_bit (PC_WRITING, &pc->flags);
        if (tape->onstream) {
                while (p) {
-                       atomic_set(&p->b_count, p->b_size);
-                       p = p->b_reqnext;
+                       bv->bv_len = p->bi_size;
+                       p = p->bi_next;
                }
        }
-       pc->bh = bh;
-       pc->b_data = bh->b_data;
-       pc->b_count = atomic_read(&bh->b_count);
+       pc->bio = bio;
+       pc->b_data = bio_data(bio);
+       pc->b_count = bio->bi_size;
        pc->buffer = NULL;
        if (!tape->onstream) {
                pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
@@ -2618,16 +2620,16 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
 
 #if IDETAPE_DEBUG_LOG
        if (tape->debug_level >= 5)
-               printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+/*             printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %ld, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); */
        if (tape->debug_level >= 2)
-               printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+               printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-       if (!IDETAPE_RQ_CMD (rq->cmd)) {
+       if (!IDETAPE_RQ_CMD (rq->flags)) {
                /*
                 *      We do not support buffer cache originated requests.
                 */
-               printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
+               printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
                ide_end_request (0, HWGROUP (drive));                   /* Let the common code handle it */
                return ide_stopped;
        }
@@ -2661,7 +2663,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
         */
        if (tape->onstream)
                status.b.dsc = 1;
-       if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
+       if (!drive->dsc_overlap && rq->flags != IDETAPE_PC_RQ2)
                set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
 
        /*
@@ -2674,7 +2676,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
         */
        if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
                tape->measure_insert_time = 1;
-       if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+       if (tape->req_buffer_fill && (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) {
                tape->req_buffer_fill = 0;
                tape->writes_since_buffer_fill = 0;
                tape->reads_since_buffer_fill = 0;
@@ -2688,19 +2690,19 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
                tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
        calculate_speeds(drive);
        if (tape->onstream && tape->max_frames &&
-           ((rq->cmd == IDETAPE_WRITE_RQ &&
+           ((rq->flags == IDETAPE_WRITE_RQ &&
               ( tape->cur_frames == tape->max_frames ||
                 ( tape->speed_control && tape->cur_frames > 5 &&
                        (tape->insert_speed > tape->max_insert_speed ||
                         (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) ||
-            (rq->cmd == IDETAPE_READ_RQ &&
+            (rq->flags == IDETAPE_READ_RQ &&
              ( tape->cur_frames == 0 ||
                ( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) &&
                        tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
                if (tape->debug_level >= 4)
-                       printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
-                               rq->cmd, tape->cur_frames, tape->max_frames);
+                       printk(KERN_INFO "ide-tape: postponing request, cmd %ld, cur %d, max %d\n",
+                               rq->flags, tape->cur_frames, tape->max_frames);
 #endif
                if (tape->postpone_cnt++ < 500) {
                        status.b.dsc = 0;
@@ -2718,7 +2720,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
                        tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
                } else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
                        printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-                       if (rq->cmd == IDETAPE_PC_RQ2) {
+                       if (rq->flags == IDETAPE_PC_RQ2) {
                                idetape_media_access_finished (drive);
                                return ide_stopped;
                        } else {
@@ -2729,7 +2731,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
                idetape_postpone_request (drive);
                return ide_stopped;
        }
-       switch (rq->cmd) {
+       switch (rq->flags) {
                case IDETAPE_READ_RQ:
                        tape->buffer_head++;
 #if USE_IOTRACE
@@ -2744,7 +2746,7 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
                                        tape->req_buffer_fill = 1;
                        }
                        pc = idetape_next_pc_storage (drive);
-                       idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+                       idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
                        break;
                case IDETAPE_WRITE_RQ:
                        tape->buffer_head++;
@@ -2761,15 +2763,15 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
                                calculate_speeds(drive);
                        }
                        pc = idetape_next_pc_storage (drive);
-                       idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+                       idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
                        break;
                case IDETAPE_READ_BUFFER_RQ:
                        tape->postpone_cnt = 0;
                        pc = idetape_next_pc_storage (drive);
-                       idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+                       idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
                        break;
                case IDETAPE_ABORTED_WRITE_RQ:
-                       rq->cmd = IDETAPE_WRITE_RQ;
+                       rq->flags = IDETAPE_WRITE_RQ;
                        idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
                        return ide_stopped;
                case IDETAPE_ABORTED_READ_RQ:
@@ -2777,12 +2779,12 @@ static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *r
                        if (tape->debug_level >= 2)
                                printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
 #endif
-                       rq->cmd = IDETAPE_READ_RQ;
+                       rq->flags = IDETAPE_READ_RQ;
                        idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
                        return ide_stopped;
                case IDETAPE_PC_RQ1:
                        pc = (idetape_pc_t *) rq->buffer;
-                       rq->cmd = IDETAPE_PC_RQ2;
+                       rq->flags = IDETAPE_PC_RQ2;
                        break;
                case IDETAPE_PC_RQ2:
                        idetape_media_access_finished (drive);
@@ -2822,61 +2824,65 @@ static inline int idetape_pipeline_active (idetape_tape_t *tape)
 static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
 {
        idetape_stage_t *stage;
-       struct buffer_head *prev_bh, *bh;
+       struct bio *prev_bio, *bio;
        int pages = tape->pages_per_stage;
-       char *b_data;
+       char *b_data = NULL;
+       struct bio_vec *bv; 
 
        if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
                return NULL;
        stage->next = NULL;
 
-       bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
-       if (bh == NULL)
+       bio = stage->bio = bio_alloc(GFP_KERNEL,1);
+       bv = bio_iovec(bio);    
+       bv->bv_len = 0;
+       if (bio == NULL)
                goto abort;
-       bh->b_reqnext = NULL;
-       if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+       bio->bi_next = NULL;
+       if ((bio->bi_io_vec[0].bv_page = alloc_page(GFP_KERNEL)) == NULL)
                goto abort;
        if (clear)
-               memset(bh->b_data, 0, PAGE_SIZE);
-       bh->b_size = PAGE_SIZE;
-       atomic_set(&bh->b_count, full ? bh->b_size : 0);
-       set_bit (BH_Lock, &bh->b_state);
+               memset(bio_data(bio), 0, PAGE_SIZE);
+       bio->bi_size = PAGE_SIZE;
+       if(bv->bv_len == full) bv->bv_len = bio->bi_size;
+       set_bit (BH_Lock, &bio->bi_flags);
 
        while (--pages) {
-               if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+               if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL)
                        goto abort;
                if (clear)
-                       memset(b_data, 0, PAGE_SIZE);
-               if (bh->b_data == b_data + PAGE_SIZE) {
-                       bh->b_size += PAGE_SIZE;
-                       bh->b_data -= PAGE_SIZE;
+                       memset(bio_data(bio), 0, PAGE_SIZE);
+               if (bio->bi_size == bv->bv_len + PAGE_SIZE) {
+                       bio->bi_size += PAGE_SIZE;
+                       bv->bv_len += PAGE_SIZE;
+                       bv->bv_offset -= PAGE_SIZE;
                        if (full)
-                               atomic_add(PAGE_SIZE, &bh->b_count);
+                               bio->bi_size += PAGE_SIZE;
                        continue;
                }
-               if (b_data == bh->b_data + bh->b_size) {
-                       bh->b_size += PAGE_SIZE;
+               if (b_data == bio_data(bio) + bio->bi_size) {
+                       bio->bi_size += PAGE_SIZE;
                        if (full)
-                               atomic_add(PAGE_SIZE, &bh->b_count);
+                               bio->bi_size += PAGE_SIZE;
                        continue;
                }
-               prev_bh = bh;
-               if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-                       free_page ((unsigned long) b_data);
+               prev_bio = bio;
+               if ((bio = bio_alloc(GFP_KERNEL,1)) == NULL) {
+                       free_page ((unsigned long) bio_data(bio));
                        goto abort;
                }
-               bh->b_reqnext = NULL;
-               bh->b_data = b_data;
-               bh->b_size = PAGE_SIZE;
-               atomic_set(&bh->b_count, full ? bh->b_size : 0);
-               set_bit (BH_Lock, &bh->b_state);
-               prev_bh->b_reqnext = bh;
-       }
-       bh->b_size -= tape->excess_bh_size;
+               bio->bi_next = NULL;
+               //bio->bi_io_vec[0].bv_offset = b_data;
+               bio->bi_size = PAGE_SIZE;
+               atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0);
+               set_bit (BH_Lock, &bio->bi_flags);
+               prev_bio->bi_next = bio;
+       }
+       bio->bi_size -= tape->excess_bh_size;
        if (full)
-               atomic_sub(tape->excess_bh_size, &bh->b_count);
+               atomic_sub(tape->excess_bh_size, &bio->bi_cnt);
        if (tape->onstream)
-               stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
+               stage->aux = (os_aux_t *) (bio_data(bio) + bio->bi_size - OS_AUX_SIZE);
        return stage;
 abort:
        __idetape_kfree_stage (stage);
@@ -2903,39 +2909,39 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
 {
-       struct buffer_head *bh = tape->bh;
+       struct bio *bio = tape->bio;
        int count;
 
        while (n) {
 #if IDETAPE_DEBUG_BUGS
-               if (bh == NULL) {
-                       printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+               if (bio == NULL) {
+                       printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_from_user\n");
                        return;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
-               count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
-               copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+               count = IDE_MIN (bio->bi_size - tape->b_count, n);
+               copy_from_user (bio_data(bio) + tape->b_count, buf, count);
                n -= count;
-               atomic_add(count, &bh->b_count);
+               bio->bi_size += count;
                buf += count;
-               if (atomic_read(&bh->b_count) == bh->b_size) {
-                       bh = bh->b_reqnext;
-                       if (bh)
-                               atomic_set(&bh->b_count, 0);
+               if (tape->b_count == bio->bi_size) {
+                       bio = bio->bi_next;
+                       if (bio)
+                               tape->b_count = 0;
                }
        }
-       tape->bh = bh;
+       tape->bio = bio;
 }
 
 static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
 {
-       struct buffer_head *bh = tape->bh;
+       struct bio *bio = tape->bio;
        int count;
 
        while (n) {
 #if IDETAPE_DEBUG_BUGS
-               if (bh == NULL) {
-                       printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+               if (bio == NULL) {
+                       printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_to_user\n");
                        return;
                }
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2946,10 +2952,10 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape
                tape->b_count -= count;
                buf += count;
                if (!tape->b_count) {
-                       tape->bh = bh = bh->b_reqnext;
-                       if (bh) {
-                               tape->b_data = bh->b_data;
-                               tape->b_count = atomic_read(&bh->b_count);
+                       tape->bio = bio = bio->bi_next;
+                       if (bio) {
+                               tape->b_data = bio_data(bio);
+                               tape->b_count = bio->bi_size;
                        }
                }
        }
@@ -2957,25 +2963,25 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape
 
 static void idetape_init_merge_stage (idetape_tape_t *tape)
 {
-       struct buffer_head *bh = tape->merge_stage->bh;
+       struct bio *bio = tape->merge_stage->bio;
        
-       tape->bh = bh;
+       tape->bio = bio;
        if (tape->chrdev_direction == idetape_direction_write)
-               atomic_set(&bh->b_count, 0);
+               atomic_set(&bio->bi_cnt, 0);
        else {
-               tape->b_data = bh->b_data;
-               tape->b_count = atomic_read(&bh->b_count);
+               tape->b_data = bio_data(bio);
+               tape->b_count = atomic_read(&bio->bi_cnt);
        }
 }
 
 static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-       struct buffer_head *tmp;
+       struct bio *tmp;
        os_aux_t *tmp_aux;
 
-       tmp = stage->bh; tmp_aux = stage->aux;
-       stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
-       tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+       tmp = stage->bio; tmp_aux = stage->aux;
+       stage->bio = tape->merge_stage->bio; stage->aux = tape->merge_stage->aux;
+       tape->merge_stage->bio = tmp; tape->merge_stage->aux = tmp_aux;
        idetape_init_merge_stage (tape);
 }
 
@@ -3077,7 +3083,7 @@ static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
        idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
-       if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
+       if (rq == NULL || !IDETAPE_RQ_CMD (rq->flags)) {
                printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
                return;
        }
@@ -3185,7 +3191,7 @@ static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
 
        ide_init_drive_cmd (&rq);
        rq.buffer = (char *) pc;
-       rq.cmd = IDETAPE_PC_RQ1;
+       rq.flags = IDETAPE_PC_RQ1;
        return ide_do_drive_cmd (drive, &rq, ide_wait);
 }
 
@@ -3430,7 +3436,7 @@ static void idetape_update_stats (ide_drive_t *drive)
  *     idetape_queue_rw_tail generates a read/write request for the block
  *     device interface and wait for it to be serviced.
  */
-static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh)
+static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct bio *bio)
 {
        idetape_tape_t *tape = drive->driver_data;
        struct request rq;
@@ -3447,8 +3453,8 @@ static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struc
 #endif /* IDETAPE_DEBUG_BUGS */        
 
        ide_init_drive_cmd (&rq);
-       rq.bh = bh;
-       rq.cmd = cmd;
+       rq.bio = bio;
+       rq.flags = cmd;
        rq.sector = tape->first_frame_position;
        rq.nr_sectors = rq.current_nr_sectors = blocks;
        if (tape->onstream)
@@ -3489,15 +3495,15 @@ static void idetape_onstream_read_back_buffer (ide_drive_t *drive)
                if (!first)
                        first = stage;
                aux = stage->aux;
-               p = stage->bh->b_data;
-               idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh);
+               p = bio_data(stage->bio);
+               idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bio);
 #if ONSTREAM_DEBUG
                if (tape->debug_level >= 2)
                        printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
 #endif
                rq = &stage->rq;
                ide_init_drive_cmd (rq);
-               rq->cmd = IDETAPE_WRITE_RQ;
+               rq->flags = IDETAPE_WRITE_RQ;
                rq->sector = tape->first_frame_position;
                rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
                idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++);
@@ -3646,18 +3652,18 @@ static int idetape_verify_stage (ide_drive_t *drive, idetape_stage_t *stage, int
        os_aux_t *aux = stage->aux;
        os_partition_t *par = &aux->partition;
        struct request *rq = &stage->rq;
-       struct buffer_head *bh;
+       struct bio *bio;
 
        if (!tape->onstream)
                return 1;
        if (tape->raw) {
                if (rq->errors) {
-                       bh = stage->bh;
-                       while (bh) {
-                               memset(bh->b_data, 0, bh->b_size);
-                               bh = bh->b_reqnext;
+                       bio = stage->bio;
+                       while (bio) {
+                               memset(bio_data(bio), 0, bio->bi_size);
+                               bio = bio->bi_next;
                        }
-                       strcpy(stage->bh->b_data, "READ ERROR ON FRAME");
+                       strcpy(bio_data(stage->bio), "READ ERROR ON FRAME");
                }
                return 1;
        }
@@ -3767,12 +3773,12 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
                         *      Linux is short on memory. Fallback to
                         *      non-pipelined operation mode for this request.
                         */
-                       return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+                       return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
                }
        }
        rq = &new_stage->rq;
        ide_init_drive_cmd (rq);
-       rq->cmd = IDETAPE_WRITE_RQ;
+       rq->flags = IDETAPE_WRITE_RQ;
        rq->sector = tape->first_frame_position;        /* Doesn't actually matter - We always assume sequential access */
        rq->nr_sectors = rq->current_nr_sectors = blocks;
 
@@ -3843,7 +3849,7 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
 {
        idetape_tape_t *tape = drive->driver_data;
        int blocks, i, min;
-       struct buffer_head *bh;
+       struct bio *bio;
        
 #if IDETAPE_DEBUG_BUGS
        if (tape->chrdev_direction != idetape_direction_write) {
@@ -3860,22 +3866,22 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
                if (tape->merge_stage_size % tape->tape_block_size) {
                        blocks++;
                        i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
-                       bh = tape->bh->b_reqnext;
-                       while (bh) {
-                               atomic_set(&bh->b_count, 0);
-                               bh = bh->b_reqnext;
+                       bio = tape->bio->bi_next;
+                       while (bio) {
+                               atomic_set(&bio->bi_cnt, 0);
+                               bio = bio->bi_next;
                        }
-                       bh = tape->bh;
+                       bio = tape->bio;
                        while (i) {
-                               if (bh == NULL) {
-                                       printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+                               if (bio == NULL) {
+                                       printk(KERN_INFO "ide-tape: bug, bio NULL\n");
                                        break;
                                }
-                               min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count));
-                               memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
-                               atomic_add(min, &bh->b_count);
+                               min = IDE_MIN(i, bio->bi_size - atomic_read(&bio->bi_cnt));
+                               memset(bio_data(bio) + bio->bi_size, 0, min);
+                               atomic_add(min, &bio->bi_cnt);
                                i -= min;
-                               bh = bh->b_reqnext;
+                               bio = bio->bi_next;
                        }
                }
                (void) idetape_add_chrdev_write_request (drive, blocks);
@@ -3949,7 +3955,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
                 *      is switched from completion mode to buffer available
                 *      mode.
                 */
-               bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+               bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
                if (bytes_read < 0) {
                        kfree (tape->merge_stage);
                        tape->merge_stage = NULL;
@@ -3960,7 +3966,7 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
        if (tape->restart_speed_control_req)
                idetape_restart_speed_control(drive);
        ide_init_drive_cmd (&rq);
-       rq.cmd = IDETAPE_READ_RQ;
+       rq.flags = IDETAPE_READ_RQ;
        rq.sector = tape->first_frame_position;
        rq.nr_sectors = rq.current_nr_sectors = blocks;
        if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
@@ -4083,7 +4089,7 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
                }
                if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
                        return 0;
-               return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+               return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio);
        }
        rq_ptr = &tape->first_stage->rq;
        bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -4137,21 +4143,21 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
 static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
 {
        idetape_tape_t *tape = drive->driver_data;
-       struct buffer_head *bh;
+       struct bio *bio;
        int count, blocks;
        
        while (bcount) {
-               bh = tape->merge_stage->bh;
+               bio = tape->merge_stage->bio;
                count = IDE_MIN (tape->stage_size, bcount);
                bcount -= count;
                blocks = count / tape->tape_block_size;
                while (count) {
-                       atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
-                       memset (bh->b_data, 0, atomic_read(&bh->b_count));
-                       count -= atomic_read(&bh->b_count);
-                       bh = bh->b_reqnext;
+                       atomic_set(&bio->bi_cnt, IDE_MIN (count, bio->bi_size));
+                       memset (bio_data(bio), 0, bio->bi_size);
+                       count -= atomic_read(&bio->bi_cnt);
+                       bio = bio->bi_next;
                }
-               idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+               idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
        }
 }
 
@@ -4276,7 +4282,7 @@ static void idetape_pre_reset (ide_drive_t *drive)
  */
 static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
 {
-       unsigned int i = MINOR(i_rdev) & ~0xc0;
+       unsigned int i = minor(i_rdev) & ~0xc0;
 
        if (i >= MAX_HWIFS * MAX_DRIVES)
                return NULL;
@@ -4654,7 +4660,7 @@ static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr,
                printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
 #endif
        idetape_position_tape(drive, last_mark_addr, 0, 0);
-       if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+       if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
                printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
                __idetape_kfree_stage (stage);
                idetape_position_tape(drive, position, 0, 0);
@@ -4673,7 +4679,7 @@ static void idetape_update_last_marker (ide_drive_t *drive, int last_mark_addr,
 #endif
        aux->next_mark_addr = htonl(next_mark_addr);
        idetape_position_tape(drive, last_mark_addr, 0, 0);
-       if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+       if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
                printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
                __idetape_kfree_stage (stage);
                idetape_position_tape(drive, position, 0, 0);
@@ -4705,9 +4711,9 @@ static void idetape_write_filler (ide_drive_t *drive, int block, int cnt)
        if (rc != 0) 
                return; /* don't write fillers if we cannot position the tape. */
 
-       strcpy(stage->bh->b_data, "Filler");
+       strcpy(bio_data(stage->bio), "Filler");
        while (cnt--) {
-               if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+               if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
                        printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
                        __idetape_kfree_stage (stage);
                        return;
@@ -4739,9 +4745,9 @@ static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
        header.partition.last_frame_addr = htonl(tape->capacity);
        header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
        header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
-       memcpy(stage->bh->b_data, &header, sizeof(header));
+       memcpy(bio_data(stage->bio), &header, sizeof(header));
        while (cnt--) {
-               if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+               if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
                        printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
                        __idetape_kfree_stage (stage);
                        return;
@@ -4860,7 +4866,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char *buf,
                 *      is switched from completion mode to buffer available
                 *      mode.
                 */
-               retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+               retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
                if (retval < 0) {
                        kfree (tape->merge_stage);
                        tape->merge_stage = NULL;
@@ -5326,12 +5332,12 @@ static int __idetape_analyze_headers (ide_drive_t *drive, int block)
                printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
        idetape_position_tape(drive, block, 0, 0);
-       if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+       if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
                printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
                __idetape_kfree_stage (stage);
                return 0;
        }
-       header = (os_header_t *) stage->bh->b_data;
+       header = (os_header_t *) bio_data(stage->bio);
        aux = stage->aux;
        if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
                printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
@@ -5403,7 +5409,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp)
        ide_drive_t *drive;
        idetape_tape_t *tape;
        idetape_pc_t pc;
-       unsigned int minor=MINOR (inode->i_rdev);
+       unsigned int minor=minor(inode->i_rdev);
                        
 #if IDETAPE_DEBUG_LOG
        printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
@@ -5460,7 +5466,7 @@ static void idetape_write_release (struct inode *inode)
 {
        ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
        idetape_tape_t *tape = drive->driver_data;
-       unsigned int minor=MINOR (inode->i_rdev);
+       unsigned int minor=minor(inode->i_rdev);
 
        idetape_empty_write_pipeline (drive);
        tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
@@ -5486,7 +5492,7 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp)
        ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
        idetape_tape_t *tape;
        idetape_pc_t pc;
-       unsigned int minor=MINOR (inode->i_rdev);
+       unsigned int minor=minor(inode->i_rdev);
 
        tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
index b47951259228d367aa1c50de973149edf99c9415..daae0cfdd65a7700a1ebf15379ba6fc7955bd7ae 100644 (file)
@@ -706,8 +706,8 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
        ide__sti();     /* local CPU only */
 
        if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-               return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
-
+               return ide_error(drive, "task_no_data_intr", stat);
+               /* calls ide_end_drive_cmd */
        if (args)
                ide_end_drive_cmd (drive, stat, GET_ERR());
 
@@ -723,6 +723,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
        byte io_32bit           = drive->io_32bit;
        struct request *rq      = HWGROUP(drive)->rq;
        char *pBuf              = NULL;
+       unsigned long flags;
 
        if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
                if (stat & (ERR_STAT|DRQ_STAT)) {
@@ -735,17 +736,21 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
                }
        }
        DTF("stat: %02x\n", stat);
-       pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+       pBuf = ide_map_rq(rq, &flags);
        DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
 
        drive->io_32bit = 0;
        taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+       ide_unmap_rq(rq, pBuf, &flags);
        drive->io_32bit = io_32bit;
 
        if (--rq->current_nr_sectors <= 0) {
                /* (hs): swapped next 2 lines */
                DTF("Request Ended stat: %02x\n", GET_STAT());
-               ide_end_request(1, HWGROUP(drive));
+               if (ide_end_request(1, HWGROUP(drive))) {
+                       ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+                       return ide_started;
+               }
        } else {
                ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
                return ide_started;
@@ -809,13 +814,14 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive)
        byte io_32bit           = drive->io_32bit;
        struct request *rq      = HWGROUP(drive)->rq;
        char *pBuf              = NULL;
+       unsigned long flags;
 
        if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
                if (stat & (ERR_STAT|DRQ_STAT)) {
                        return ide_error(drive, "task_mulin_intr", stat);
                }
                /* no data yet, so wait for another interrupt */
-               ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+               ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
                return ide_started;
        }
 
@@ -834,10 +840,11 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive)
                 */
                nsect = 1;
                while (rq->current_nr_sectors) {
-                       pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+                       pBuf = ide_map_rq(rq, &flags);
                        DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
                        drive->io_32bit = 0;
                        taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+                       ide_unmap_rq(rq, pBuf, &flags);
                        drive->io_32bit = io_32bit;
                        rq->errors = 0;
                        rq->current_nr_sectors -= nsect;
@@ -848,22 +855,34 @@ ide_startstop_t task_mulin_intr (ide_drive_t *drive)
        }
 #endif /* ALTSTAT_SCREW_UP */
 
-       nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-       pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+       do {
+               nsect = rq->current_nr_sectors;
+               if (nsect > msect)
+                       nsect = msect;
 
-       DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-               pBuf, nsect, rq->current_nr_sectors);
-       drive->io_32bit = 0;
-       taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-       drive->io_32bit = io_32bit;
-       rq->errors = 0;
-       rq->current_nr_sectors -= nsect;
-       if (rq->current_nr_sectors != 0) {
-               ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
-               return ide_started;
-       }
-       ide_end_request(1, HWGROUP(drive));
-       return ide_stopped;
+               pBuf = ide_map_rq(rq, &flags);
+
+               DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+                       pBuf, nsect, rq->current_nr_sectors);
+               drive->io_32bit = 0;
+               taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+               ide_unmap_rq(rq, pBuf, &flags);
+               drive->io_32bit = io_32bit;
+               rq->errors = 0;
+               rq->current_nr_sectors -= nsect;
+               msect -= nsect;
+               if (!rq->current_nr_sectors) {
+                       if (!ide_end_request(1, HWGROUP(drive)))
+                               return ide_stopped;
+               }
+       } while (msect);
+
+
+       /*
+        * more data left
+        */
+       ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+       return ide_started;
 }
 
 ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
@@ -879,10 +898,12 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
        /* (ks/hs): Fixed Multi Write */
        if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
            (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+               unsigned long flags;
+               char *buf = ide_map_rq(rq, &flags);
                /* For Write_sectors we need to stuff the first sector */
-               taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+               taskfile_output_data(drive, buf, SECTOR_WORDS);
                rq->current_nr_sectors--;
-               return ide_started;
+               ide_unmap_rq(rq, buf, &flags);
        } else {
                /*
                 * (ks/hs): Stuff the first sector(s)
@@ -913,8 +934,10 @@ ide_startstop_t task_out_intr (ide_drive_t *drive)
        byte io_32bit           = drive->io_32bit;
        struct request *rq      = HWGROUP(drive)->rq;
        char *pBuf              = NULL;
+       unsigned long flags;
 
        if (!rq->current_nr_sectors) { 
+               printk("task_out_intr: should not trigger\n");
                ide_end_request(1, HWGROUP(drive));
                return ide_stopped;
        }
@@ -922,19 +945,24 @@ ide_startstop_t task_out_intr (ide_drive_t *drive)
        if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
                return ide_error(drive, "task_out_intr", stat);
        }
+
        if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
                rq = HWGROUP(drive)->rq;
-               pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+               pBuf = ide_map_rq(rq, &flags);
                DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
                drive->io_32bit = 0;
                taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+               ide_unmap_rq(rq, pBuf, &flags);
                drive->io_32bit = io_32bit;
                rq->errors = 0;
                rq->current_nr_sectors--;
        }
 
        if (rq->current_nr_sectors <= 0) {
-               ide_end_request(1, HWGROUP(drive));
+               if (ide_end_request(1, HWGROUP(drive))) {
+                       ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+                       return ide_started;
+               }
        } else {
                ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
                return ide_started;
@@ -961,14 +989,20 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive)
        struct request *rq      = HWGROUP(drive)->rq;
        ide_hwgroup_t *hwgroup  = HWGROUP(drive);
        char *pBuf              = NULL;
+       unsigned long flags;
 
        /*
         * (ks/hs): Handle last IRQ on multi-sector transfer,
-        * occurs after all data was sent
+        * occurs after all data was sent in this chunk
         */
        if (rq->current_nr_sectors == 0) {
                if (stat & (ERR_STAT|DRQ_STAT))
                        return ide_error(drive, "task_mulout_intr", stat);
+
+               /*
+                * there may be more, ide_do_request will restart it if
+                * necessary
+                */
                ide_end_request(1, HWGROUP(drive));
                return ide_stopped;
        }
@@ -994,10 +1028,11 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive)
        if (!msect) {
                nsect = 1;
                while (rq->current_nr_sectors) {
-                       pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+                       pBuf = ide_map_rq(rq, &flags);
                        DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
                        drive->io_32bit = 0;
                        taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+                       ide_unmap_rq(pBuf, &flags);
                        drive->io_32bit = io_32bit;
                        rq->errors = 0;
                        rq->current_nr_sectors -= nsect;
@@ -1008,12 +1043,16 @@ ide_startstop_t task_mulout_intr (ide_drive_t *drive)
        }
 #endif /* ALTSTAT_SCREW_UP */
 
-       nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-       pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+       nsect = rq->current_nr_sectors;
+       if (nsect > msect)
+               nsect = msect;
+
+       pBuf = ide_map_rq(rq, &flags);
        DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
                pBuf, nsect, rq->current_nr_sectors);
        drive->io_32bit = 0;
        taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+       ide_unmap_rq(rq, pBuf, &flags);
        drive->io_32bit = io_32bit;
        rq->errors = 0;
        rq->current_nr_sectors -= nsect;
index 9d272c37626a4a2ba4efe36d05f5163704d49462..bec8b9f0ed9e5efe817f4d236dfdb4acaa3274e2 100644 (file)
@@ -1458,14 +1458,11 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
        HWGROUP(drive)->rq = NULL;
 
        rq->errors = 0;
-       rq->sector = rq->bio->bi_sector;
-       rq->current_nr_sectors = bio_sectors(rq->bio);
-
-       /*
-        * just to make sure...
-        */
-       if (rq->bio)
+       if (rq->bio) {
+               rq->sector = rq->bio->bi_sector;
+               rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
                rq->buffer = NULL;
+       }
 }
 
 /*
index 5894c35b1ecc3eaba5f5b1b417f26104dc735021..ec2158289a358604a56ebd9da9b38e5419f2405d 100644 (file)
@@ -67,26 +67,6 @@ static void b1pci_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
 
        card->interrupt = 0;
 }
-/* ------------------------------------------------------------- */
-
-static void b1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-       avmcard *card = cinfo->card;
-       unsigned int port = card->port;
-
-       b1_reset(port);
-       b1_reset(port);
-
-       di->detach_ctr(ctrl);
-       free_irq(card->irq, card);
-       release_region(card->port, AVMB1_PORTLEN);
-       ctrl->driverdata = 0;
-       kfree(card->ctrlinfo);
-       kfree(card);
-
-       MOD_DEC_USE_COUNT;
-}
 
 /* ------------------------------------------------------------- */
 
@@ -118,20 +98,18 @@ static int b1pci_add_card(struct capi_driver *driver,
 
        MOD_INC_USE_COUNT;
 
-       card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+       retval = -ENOMEM;
+       card = kmalloc(sizeof(avmcard), GFP_KERNEL);
        if (!card) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err;
        }
        memset(card, 0, sizeof(avmcard));
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
        if (!cinfo) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err_kfree;
        }
        memset(cinfo, 0, sizeof(avmctrl_info));
        card->ctrlinfo = cinfo;
@@ -140,51 +118,38 @@ static int b1pci_add_card(struct capi_driver *driver,
        card->port = p->port;
        card->irq = p->irq;
        card->cardtype = avm_b1pci;
-
-       if (check_region(card->port, AVMB1_PORTLEN)) {
+       
+       if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
                printk(KERN_WARNING
                       "%s: ports 0x%03x-0x%03x in use.\n",
                       driver->name, card->port, card->port + AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               goto err_kfree_ctrlinfo;
        }
        b1_reset(card->port);
-       if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+       retval = b1_detect(card->port, card->cardtype);
+       if (retval) {
                printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-                                       driver->name, card->port, retval);
-               kfree(card->ctrlinfo);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EIO;
+                      driver->name, card->port, retval);
+               retval = -EIO;
+               goto err_release_region;
        }
        b1_reset(card->port);
        b1_getrevision(card);
-
-       request_region(p->port, AVMB1_PORTLEN, card->name);
-
+       
        retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
        if (retval) {
                printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-                               driver->name, card->irq);
-               release_region(card->port, AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+                      driver->name, card->irq);
+               retval = -EBUSY;
+               goto err_release_region;
        }
-
+       
        cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
        if (!cinfo->capi_ctrl) {
                printk(KERN_ERR "%s: attach controller failed.\n",
-                               driver->name);
-               free_irq(card->irq, card);
-               release_region(card->port, AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+                      driver->name);
+               retval = -EBUSY;
+               goto err_free_irq;
        }
 
        if (card->revision >= 4) {
@@ -198,6 +163,37 @@ static int b1pci_add_card(struct capi_driver *driver,
        }
 
        return 0;
+
+ err_free_irq:
+       free_irq(card->irq, card);
+ err_release_region:
+       release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+       kfree(card->ctrlinfo);
+ err_kfree:
+       kfree(card);
+ err:
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+static void b1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+       unsigned int port = card->port;
+
+       b1_reset(port);
+       b1_reset(port);
+
+       di->detach_ctr(ctrl);
+       free_irq(card->irq, card);
+       release_region(card->port, AVMB1_PORTLEN);
+       ctrl->driverdata = 0;
+       kfree(card->ctrlinfo);
+       kfree(card);
+
+       MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -226,25 +222,6 @@ static struct capi_driver_interface *div4;
 
 /* ------------------------------------------------------------- */
 
-static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
-{
-       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-       avmcard *card = cinfo->card;
-
-       b1dma_reset(card);
-
-       div4->detach_ctr(ctrl);
-       free_irq(card->irq, card);
-       iounmap(card->mbase);
-       release_region(card->port, AVMB1_PORTLEN);
-       ctrl->driverdata = 0;
-       kfree(card->ctrlinfo);
-        avmcard_dma_free(card->dma);
-       kfree(card);
-
-       MOD_DEC_USE_COUNT;
-}
-
 static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
 {
        avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -274,28 +251,23 @@ static int b1pciv4_add_card(struct capi_driver *driver,
 
        MOD_INC_USE_COUNT;
 
-       card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+       retval = -ENOMEM;
+       card = kmalloc(sizeof(avmcard), GFP_KERNEL);
        if (!card) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err;
        }
        memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
        if (!card->dma) {
                printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err_kfree;
        }
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
        if (!cinfo) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err_dma_free;
        }
        memset(cinfo, 0, sizeof(avmctrl_info));
        card->ctrlinfo = cinfo;
@@ -306,69 +278,47 @@ static int b1pciv4_add_card(struct capi_driver *driver,
        card->membase = p->membase;
        card->cardtype = avm_b1pci;
 
-       if (check_region(card->port, AVMB1_PORTLEN)) {
+       if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
                printk(KERN_WARNING
                       "%s: ports 0x%03x-0x%03x in use.\n",
                       driver->name, card->port, card->port + AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_kfree_ctrlinfo;
        }
 
        card->mbase = ioremap_nocache(card->membase, 64);
        if (!card->mbase) {
                printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
                                        driver->name, card->membase);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EIO;
+               retval = -EIO;
+               goto err_release_region;
        }
 
        b1dma_reset(card);
 
-       if ((retval = b1pciv4_detect(card)) != 0) {
+       retval = b1pciv4_detect(card);
+       if (retval) {
                printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
                                        driver->name, card->port, retval);
-                iounmap(card->mbase);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EIO;
+               retval = -EIO;
+               goto err_unmap;
        }
        b1dma_reset(card);
        b1_getrevision(card);
 
-       request_region(p->port, AVMB1_PORTLEN, card->name);
-
        retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
        if (retval) {
                printk(KERN_ERR "%s: unable to get IRQ %d.\n",
                                driver->name, card->irq);
-                iounmap(card->mbase);
-               release_region(card->port, AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_unmap;
        }
 
        cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
        if (!cinfo->capi_ctrl) {
                printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-               free_irq(card->irq, card);
-               release_region(card->port, AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_free_irq;
        }
        card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -378,6 +328,42 @@ static int b1pciv4_add_card(struct capi_driver *driver,
                card->membase, card->revision);
 
        return 0;
+
+ err_free_irq:
+       free_irq(card->irq, card);
+ err_unmap:
+       iounmap(card->mbase);
+ err_release_region:
+       release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+       kfree(card->ctrlinfo);
+ err_dma_free:
+       avmcard_dma_free(card->dma);
+ err_kfree:
+       kfree(card);
+ err:
+       MOD_DEC_USE_COUNT;
+       return retval;
+
+}
+
+static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+
+       b1dma_reset(card);
+
+       div4->detach_ctr(ctrl);
+       free_irq(card->irq, card);
+       iounmap(card->mbase);
+       release_region(card->port, AVMB1_PORTLEN);
+       ctrl->driverdata = 0;
+       kfree(card->ctrlinfo);
+        avmcard_dma_free(card->dma);
+       kfree(card);
+
+       MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -402,8 +388,6 @@ static struct capi_driver b1pciv4_driver = {
 
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
 
-static int ncards = 0;
-
 static int __devinit b1pci_probe(struct pci_dev *dev,
                                 const struct pci_device_id *ent)
 {
@@ -470,6 +454,7 @@ static int __init b1pci_init(void)
        struct capi_driver *driverv4 = &b1pciv4_driver;
 #endif
        char *p;
+       int ncards;
 
        MOD_INC_USE_COUNT;
 
index 970eec149d9a07f2bcc54dbeb1a2749ba00a8755..6ea98c6e27ca1ea69202208df2eda3940633a4af 100644 (file)
@@ -1133,28 +1133,23 @@ static int c4_add_card(struct capi_driver *driver,
 
        MOD_INC_USE_COUNT;
 
-       card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+       retval = -ENOMEM;
+       card = kmalloc(sizeof(avmcard), GFP_ATOMIC);
        if (!card) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err;
        }
        memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
        if (!card->dma) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err_kfree;
        }
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
        if (!cinfo) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err_dma_free;
        }
        memset(cinfo, 0, sizeof(avmctrl_info)*4);
        card->ctrlinfo = cinfo;
@@ -1168,53 +1163,37 @@ static int c4_add_card(struct capi_driver *driver,
        card->membase = p->membase;
        card->cardtype = nr == 4 ? avm_c4 : avm_c2;
 
-       if (check_region(card->port, AVMB1_PORTLEN)) {
+       if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
                printk(KERN_WARNING
                       "%s: ports 0x%03x-0x%03x in use.\n",
                       driver->name, card->port, card->port + AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_kfree_ctrlinfo;
        }
 
        card->mbase = ioremap_nocache(card->membase, 128);
        if (card->mbase == 0) {
                printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
                                        driver->name, card->membase);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EIO;
+               retval = -EIO;
+               goto err_release_region;
        }
 
-       if ((retval = c4_detect(card)) != 0) {
+       retval = c4_detect(card);
+       if (retval != 0) {
                printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
                                        driver->name, card->port, retval);
-                iounmap(card->mbase);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EIO;
+               retval = -EIO;
+               goto err_unmap;
        }
        c4_reset(card);
 
-       request_region(p->port, AVMB1_PORTLEN, card->name);
-
        retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
        if (retval) {
                printk(KERN_ERR "%s: unable to get IRQ %d.\n",
                                driver->name, card->irq);
-                iounmap(card->mbase);
-               release_region(card->port, AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_unmap;
        }
 
        for (i=0; i < nr ; i++) {
@@ -1228,14 +1207,7 @@ static int c4_add_card(struct capi_driver *driver,
                                cinfo = &card->ctrlinfo[i];
                                di->detach_ctr(cinfo->capi_ctrl);
                        }
-                       iounmap(card->mbase);
-                       free_irq(card->irq, card);
-                       release_region(card->port, AVMB1_PORTLEN);
-                        avmcard_dma_free(card->dma);
-                       kfree(card->ctrlinfo);
-                       kfree(card);
-                       MOD_DEC_USE_COUNT;
-                       return -EBUSY;
+                       goto err_free_irq;
                }
                if (i == 0)
                        card->cardnr = cinfo->capi_ctrl->cnr;
@@ -1246,6 +1218,22 @@ static int c4_add_card(struct capi_driver *driver,
                driver->name, nr, card->port, card->irq, card->membase);
 
        return 0;
+
+ err_free_irq:
+       free_irq(card->irq, card);
+ err_unmap:
+       iounmap(card->mbase);
+ err_release_region:
+       release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+       kfree(card->ctrlinfo);
+ err_dma_free:
+       avmcard_dma_free(card->dma);
+ err_kfree:
+       kfree(card);
+ err:
+       MOD_DEC_USE_COUNT;
+       return retval;
 }
 
 /* ------------------------------------------------------------- */
index e07ffe0d3051b63924556afbb33acebfa1a62179..85c054d2b577d19c8d0d952506b12e892db09747 100644 (file)
@@ -49,27 +49,6 @@ static struct capi_driver_interface *di;
 
 /* ------------------------------------------------------------- */
 
-static void t1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-       avmcard *card = cinfo->card;
-
-       b1dma_reset(card);
-
-       di->detach_ctr(ctrl);
-       free_irq(card->irq, card);
-       iounmap(card->mbase);
-       release_region(card->port, AVMB1_PORTLEN);
-       ctrl->driverdata = 0;
-       kfree(card->ctrlinfo);
-       avmcard_dma_free(card->dma);
-       kfree(card);
-
-       MOD_DEC_USE_COUNT;
-}
-
-/* ------------------------------------------------------------- */
-
 static int t1pci_add_card(struct capi_driver *driver,
                           struct capicardparams *p,
                          struct pci_dev *dev)
@@ -80,28 +59,22 @@ static int t1pci_add_card(struct capi_driver *driver,
 
        MOD_INC_USE_COUNT;
 
-       card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+       retval = -ENOMEM;
+       card = kmalloc(sizeof(avmcard), GFP_KERNEL);
        if (!card) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err;
        }
        memset(card, 0, sizeof(avmcard));
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
        if (!card->dma) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err_kfree;
        }
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
        if (!cinfo) {
                printk(KERN_WARNING "%s: no memory.\n", driver->name);
-               avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -ENOMEM;
+               goto err_dma_free;
        }
        memset(cinfo, 0, sizeof(avmctrl_info));
        card->ctrlinfo = cinfo;
@@ -112,72 +85,50 @@ static int t1pci_add_card(struct capi_driver *driver,
        card->membase = p->membase;
        card->cardtype = avm_t1pci;
 
-       if (check_region(card->port, AVMB1_PORTLEN)) {
+       if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
                printk(KERN_WARNING
                       "%s: ports 0x%03x-0x%03x in use.\n",
                       driver->name, card->port, card->port + AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-               avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_kfree_ctrlinfo;
        }
 
        card->mbase = ioremap_nocache(card->membase, 64);
        if (!card->mbase) {
                printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
                                        driver->name, card->membase);
-               kfree(card->ctrlinfo);
-               avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EIO;
+               retval = -EIO;
+               goto err_release_region;
        }
 
        b1dma_reset(card);
 
-       if ((retval = t1pci_detect(card)) != 0) {
+       retval = t1pci_detect(card);
+       if (retval != 0) {
                if (retval < 6)
                        printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
                                        driver->name, card->port, retval);
                else
                        printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
                                        driver->name, card->port, retval);
-                iounmap(card->mbase);
-               kfree(card->ctrlinfo);
-               avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EIO;
+               retval = -EIO;
+               goto err_unmap;
        }
        b1dma_reset(card);
 
-       request_region(p->port, AVMB1_PORTLEN, card->name);
-
        retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
        if (retval) {
                printk(KERN_ERR "%s: unable to get IRQ %d.\n",
                                driver->name, card->irq);
-                iounmap(card->mbase);
-               release_region(card->port, AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-               avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_unmap;
        }
 
        cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
        if (!cinfo->capi_ctrl) {
                printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-               free_irq(card->irq, card);
-               release_region(card->port, AVMB1_PORTLEN);
-               kfree(card->ctrlinfo);
-               avmcard_dma_free(card->dma);
-               kfree(card);
-               MOD_DEC_USE_COUNT;
-               return -EBUSY;
+               retval = -EBUSY;
+               goto err_free_irq;
        }
        card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -186,6 +137,43 @@ static int t1pci_add_card(struct capi_driver *driver,
                driver->name, card->port, card->irq, card->membase);
 
        return 0;
+
+ err_free_irq:
+       free_irq(card->irq, card);
+ err_unmap:
+       iounmap(card->mbase);
+ err_release_region:
+       release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+       kfree(card->ctrlinfo);
+ err_dma_free:
+       avmcard_dma_free(card->dma);
+ err_kfree:
+       kfree(card);
+ err:
+       MOD_DEC_USE_COUNT;
+       return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+       avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+       avmcard *card = cinfo->card;
+
+       b1dma_reset(card);
+
+       di->detach_ctr(ctrl);
+       free_irq(card->irq, card);
+       iounmap(card->mbase);
+       release_region(card->port, AVMB1_PORTLEN);
+       ctrl->driverdata = 0;
+       kfree(card->ctrlinfo);
+       avmcard_dma_free(card->dma);
+       kfree(card);
+
+       MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
index 2e78a0e3d5588427306a6598c7e96e45cc0895e9..933880c1638359f9545271f61bc554fa7ebac9c8 100644 (file)
@@ -65,7 +65,6 @@ static isdn_divert_if *divert_if; /* = NULL */
 #endif /* CONFIG_ISDN_DIVERSION */
 
 
-static int isdn_writebuf_stub(int, int, const u_char *, int, int);
 static void set_global_features(void);
 static void isdn_register_devfs(int);
 static void isdn_unregister_devfs(int);
@@ -946,7 +945,9 @@ isdn_statstr(void)
        return istatbuf;
 }
 
-/* Module interface-code */
+/* 
+ * /dev/isdninfo
+ */
 
 void
 isdn_info_update(void)
@@ -960,234 +961,309 @@ isdn_info_update(void)
        wake_up_interruptible(&(dev->info_waitq));
 }
 
+static int
+isdn_status_open(struct inode *ino, struct file *filep)
+{
+       infostruct *p;
+       
+       p = kmalloc(sizeof(infostruct), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+
+       p->next = (char *) dev->infochain;
+       p->private = (char *) &(filep->private_data);
+       dev->infochain = p;
+       /* At opening we allow a single update */
+       filep->private_data = (char *) 1;
+
+       return 0;
+}
+
+static int
+isdn_status_release(struct inode *ino, struct file *filep)
+{
+       infostruct *p = dev->infochain;
+       infostruct *q = NULL;
+       
+       lock_kernel();
+
+       while (p) {
+               if (p->private == (char *) &(filep->private_data)) {
+                       if (q)
+                               q->next = p->next;
+                       else
+                               dev->infochain = (infostruct *) (p->next);
+                       kfree(p);
+                       goto out;
+               }
+               q = p;
+               p = (infostruct *) (p->next);
+       }
+       printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+
+ out:
+       unlock_kernel();
+       return 0;
+}
+
 static ssize_t
-isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
-       uint minor = minor(file->f_dentry->d_inode->i_rdev);
-       int len = 0;
-       ulong flags;
-       int drvidx;
-       int chidx;
        int retval;
+       int len = 0;
        char *p;
 
        if (off != &file->f_pos)
                return -ESPIPE;
 
        lock_kernel();
-       if (minor == ISDN_MINOR_STATUS) {
-               if (!file->private_data) {
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               goto out;
-                       }
-                       interruptible_sleep_on(&(dev->info_waitq));
-               }
-               p = isdn_statstr();
-               file->private_data = 0;
-               if ((len = strlen(p)) <= count) {
-                       if (copy_to_user(buf, p, len)) {
-                               retval = -EFAULT;
-                               goto out;
-                       }
-                       *off += len;
-                       retval = len;
+       if (!file->private_data) {
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
                        goto out;
                }
-               retval = 0;
-               goto out;
+               interruptible_sleep_on(&(dev->info_waitq));
        }
-       if (!dev->drivers) {
-               retval = -ENODEV;
-               goto out;
-       }
-       if (minor <= ISDN_MINOR_BMAX) {
-               printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
-               drvidx = isdn_minor2drv(minor);
-               if (drvidx < 0) {
-                       retval = -ENODEV;
-                       goto out;
-               }
-               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-                       retval = -ENODEV;
-                       goto out;
-               }
-               chidx = isdn_minor2chan(minor);
-               if (!(p = kmalloc(count, GFP_KERNEL))) {
-                       retval = -ENOMEM;
+       p = isdn_statstr();
+       file->private_data = 0;
+       if ((len = strlen(p)) <= count) {
+               if (copy_to_user(buf, p, len)) {
+                       retval = -EFAULT;
                        goto out;
                }
-               save_flags(flags);
-               cli();
-               len = isdn_readbchan(drvidx, chidx, p, 0, count,
-                                    &dev->drv[drvidx]->rcv_waitq[chidx]);
                *off += len;
-               restore_flags(flags);
-               if (copy_to_user(buf,p,len)) 
-                       len = -EFAULT;
-               kfree(p);
                retval = len;
                goto out;
        }
-       if (minor <= ISDN_MINOR_CTRLMAX) {
-               drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-               if (drvidx < 0) {
-                       retval = -ENODEV;
-                       goto out;
-               }
-               if (!dev->drv[drvidx]->stavail) {
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               goto out;
-                       }
-                       interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
-               }
-               if (dev->drv[drvidx]->interface->readstat) {
-                       if (count > dev->drv[drvidx]->stavail)
-                               count = dev->drv[drvidx]->stavail;
-                       len = dev->drv[drvidx]->interface->
-                               readstat(buf, count, 1, drvidx,
-                                        isdn_minor2chan(minor));
-               } else {
-                       len = 0;
-               }
-               save_flags(flags);
-               cli();
-               if (len)
-                       dev->drv[drvidx]->stavail -= len;
-               else
-                       dev->drv[drvidx]->stavail = 0;
-               restore_flags(flags);
-               *off += len;
-               retval = len;
-               goto out;
-       }
-#ifdef CONFIG_ISDN_PPP
-       if (minor <= ISDN_MINOR_PPPMAX) {
-               retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
-               goto out;
-       }
-#endif
-       retval = -ENODEV;
+       retval = 0;
+       goto out;
+
  out:
        unlock_kernel();
        return retval;
 }
 
 static ssize_t
-isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+       return -EPERM;
+}
+
+static unsigned int
+isdn_status_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       lock_kernel();
+
+       poll_wait(file, &(dev->info_waitq), wait);
+       if (file->private_data)
+               mask |= POLLIN | POLLRDNORM;
+
+       unlock_kernel();
+       return mask;
+}
+
+static int
+isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       int ret;
+       union iocpar {
+               char name[10];
+               char bname[22];
+               isdn_ioctl_struct iocts;
+               isdn_net_ioctl_phone phone;
+               isdn_net_ioctl_cfg cfg;
+       } iocpar;
+
+#define name  iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg   iocpar.cfg
+
+       switch (cmd) {
+       case IIOCGETDVR:
+               return (TTY_DV +
+                       (NET_DV << 8) +
+                       (INF_DV << 16));
+       case IIOCGETCPS:
+               if (arg) {
+                       ulong *p = (ulong *) arg;
+                       int i;
+                       if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+                                              sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+                               return ret;
+                       for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+                               put_user(dev->ibytes[i], p++);
+                               put_user(dev->obytes[i], p++);
+                       }
+                       return 0;
+               } else
+                       return -EINVAL;
+               break;
+#ifdef CONFIG_NETDEVICES
+       case IIOCNETGPN:
+               /* Get peer phone number of a connected 
+                * isdn network interface */
+               if (arg) {
+                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+                               return -EFAULT;
+                       return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+               } else
+                       return -EINVAL;
+#endif
+       default:
+               return -EINVAL;
+       }
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
+}
+
+/*
+ * /dev/isdnctrlX
+ */
+
+static int
+isdn_ctrl_open(struct inode *ino, struct file *filep)
+{
+       uint minor = minor(ino->i_rdev);
+       int drvidx;
+
+       drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+       if (drvidx < 0)
+               return -ENODEV;
+
+       isdn_lock_drivers();
+       return 0;
+}
+
+static int
+isdn_ctrl_release(struct inode *ino, struct file *filep)
+{
+       lock_kernel();
+
+       if (dev->profd == current)
+               dev->profd = NULL;
+
+       isdn_unlock_drivers();
+
+       unlock_kernel();
+       return 0;
+}
+
+static ssize_t
+isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
        uint minor = minor(file->f_dentry->d_inode->i_rdev);
+       ulong flags;
+       int len = 0;
        int drvidx;
-       int chidx;
        int retval;
 
        if (off != &file->f_pos)
                return -ESPIPE;
 
-       if (minor == ISDN_MINOR_STATUS)
-               return -EPERM;
-       if (!dev->drivers)
-               return -ENODEV;
-
        lock_kernel();
-       if (minor <= ISDN_MINOR_BMAX) {
-               printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
-               drvidx = isdn_minor2drv(minor);
-               if (drvidx < 0) {
-                       retval = -ENODEV;
-                       goto out;
-               }
-               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-                       retval = -ENODEV;
-                       goto out;
-               }
-               chidx = isdn_minor2chan(minor);
-               while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
-                       interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
-               retval = count;
+
+       drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+       if (drvidx < 0) {
+               retval = -ENODEV;
                goto out;
        }
-       if (minor <= ISDN_MINOR_CTRLMAX) {
-               drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-               if (drvidx < 0) {
-                       retval = -ENODEV;
+       if (!dev->drv[drvidx]->stavail) {
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
                        goto out;
                }
-               /*
-                * We want to use the isdnctrl device to load the firmware
-                *
-                if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-                return -ENODEV;
-                */
-               if (dev->drv[drvidx]->interface->writecmd)
-                       retval = dev->drv[drvidx]->interface->
-                               writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
-               else
-                       retval = count;
+               interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
+       }
+       if (dev->drv[drvidx]->interface->readstat) {
+               if (count > dev->drv[drvidx]->stavail)
+                       count = dev->drv[drvidx]->stavail;
+               len = dev->drv[drvidx]->interface->
+                       readstat(buf, count, 1, drvidx,
+                                isdn_minor2chan(minor));
+       } else {
+               len = 0;
+       }
+       save_flags(flags);
+       cli();
+       if (len)
+               dev->drv[drvidx]->stavail -= len;
+       else
+               dev->drv[drvidx]->stavail = 0;
+       restore_flags(flags);
+       *off += len;
+       retval = len;
+       
+ out:
+       unlock_kernel();
+       return retval;
+}
+
+static ssize_t
+isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+       uint minor = minor(file->f_dentry->d_inode->i_rdev);
+       int drvidx;
+       int retval;
+
+       if (off != &file->f_pos)
+               return -ESPIPE;
+
+       lock_kernel();
+
+       drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+       if (drvidx < 0) {
+               retval = -ENODEV;
                goto out;
        }
-#ifdef CONFIG_ISDN_PPP
-       if (minor <= ISDN_MINOR_PPPMAX) {
-               retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
+       if (!dev->drv[drvidx]->interface->writecmd) {
+               retval = -EINVAL;
                goto out;
        }
-#endif
-       retval = -ENODEV;
+       retval = dev->drv[drvidx]->interface->
+               writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
+
  out:
        unlock_kernel();
        return retval;
 }
 
 static unsigned int
-isdn_poll(struct file *file, poll_table * wait)
+isdn_ctrl_poll(struct file *file, poll_table *wait)
 {
        unsigned int mask = 0;
        unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
-       int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+       int drvidx;
+
+       drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+       if (drvidx < 0)
+               /* driver deregistered while file open */
+               return POLLHUP;
 
        lock_kernel();
-       if (minor == ISDN_MINOR_STATUS) {
-               poll_wait(file, &(dev->info_waitq), wait);
-               /* mask = POLLOUT | POLLWRNORM; */
-               if (file->private_data) {
-                       mask |= POLLIN | POLLRDNORM;
-               }
-               goto out;
-       }
-       if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
-               if (drvidx < 0) {
-                       /* driver deregistered while file open */
-                       mask = POLLHUP;
-                       goto out;
-               }
-               poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
-               mask = POLLOUT | POLLWRNORM;
-               if (dev->drv[drvidx]->stavail) {
-                       mask |= POLLIN | POLLRDNORM;
-               }
-               goto out;
-       }
-#ifdef CONFIG_ISDN_PPP
-       if (minor <= ISDN_MINOR_PPPMAX) {
-               mask = isdn_ppp_poll(file, wait);
-               goto out;
-       }
-#endif
-       mask = POLLERR;
- out:
+
+       poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
+       mask = POLLOUT | POLLWRNORM;
+       if (dev->drv[drvidx]->stavail)
+               mask |= POLLIN | POLLRDNORM;
+
        unlock_kernel();
        return mask;
 }
 
 
 static int
-isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
-       uint minor = minor(inode->i_rdev);
        isdn_ctrl c;
        int drvidx;
-       int chidx;
        int ret;
        int i;
        char *p;
@@ -1205,55 +1281,6 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 #define iocts iocpar.iocts
 #define phone iocpar.phone
 #define cfg   iocpar.cfg
-
-       if (minor == ISDN_MINOR_STATUS) {
-               switch (cmd) {
-                       case IIOCGETDVR:
-                               return (TTY_DV +
-                                       (NET_DV << 8) +
-                                       (INF_DV << 16));
-                       case IIOCGETCPS:
-                               if (arg) {
-                                       ulong *p = (ulong *) arg;
-                                       int i;
-                                       if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-                                                              sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
-                                               return ret;
-                                       for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                               put_user(dev->ibytes[i], p++);
-                                               put_user(dev->obytes[i], p++);
-                                       }
-                                       return 0;
-                               } else
-                                       return -EINVAL;
-                               break;
-#ifdef CONFIG_NETDEVICES
-                       case IIOCNETGPN:
-                               /* Get peer phone number of a connected 
-                                * isdn network interface */
-                               if (arg) {
-                                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-                                               return -EFAULT;
-                                       return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
-                               } else
-                                       return -EINVAL;
-#endif
-                       default:
-                               return -EINVAL;
-               }
-       }
-       if (!dev->drivers)
-               return -ENODEV;
-       if (minor <= ISDN_MINOR_BMAX) {
-               drvidx = isdn_minor2drv(minor);
-               if (drvidx < 0)
-                       return -ENODEV;
-               chidx = isdn_minor2chan(minor);
-               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-                       return -ENODEV;
-               return 0;
-       }
-       if (minor <= ISDN_MINOR_CTRLMAX) {
 /*
  * isdn net devices manage lots of configuration variables as linked lists.
  * Those lists must only be manipulated from user space. Some of the ioctl's
@@ -1261,366 +1288,360 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
  * manipulating the lists and ioctl's sleeping while accessing the lists
  * are serialized by means of a semaphore.
  */
-               switch (cmd) {
-                       case IIOCNETDWRSET:
-                               printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
-                               return(-EINVAL);
-                       case IIOCNETLCR:
-                               printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
-                               return -ENODEV;
+       switch (cmd) {
+       case IIOCNETDWRSET:
+               printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+               return(-EINVAL);
+       case IIOCNETLCR:
+               printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
+               return -ENODEV;
 #ifdef CONFIG_NETDEVICES
-                       case IIOCNETAIF:
-                               /* Add a network-interface */
-                               if (arg) {
-                                       if (copy_from_user(name, (char *) arg, sizeof(name)))
-                                               return -EFAULT;
-                                       s = name;
-                               } else {
-                                       s = NULL;
-                               }
-                               ret = down_interruptible(&dev->sem);
-                               if( ret ) return ret;
-                               if ((s = isdn_net_new(s, NULL))) {
-                                       if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-                                               ret = -EFAULT;
-                                       } else {
-                                               ret = 0;
+       case IIOCNETAIF:
+               /* Add a network-interface */
+               if (arg) {
+                       if (copy_from_user(name, (char *) arg, sizeof(name)))
+                               return -EFAULT;
+                       s = name;
+               } else {
+                       s = NULL;
+               }
+               ret = down_interruptible(&dev->sem);
+               if( ret ) return ret;
+               if ((s = isdn_net_new(s, NULL))) {
+                       if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+                               ret = -EFAULT;
+                       } else {
+                               ret = 0;
+                       }
+               } else
+                       ret = -ENODEV;
+               up(&dev->sem);
+               return ret;
+       case IIOCNETASL:
+               /* Add a slave to a network-interface */
+               if (arg) {
+                       if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
+                               return -EFAULT;
+               } else
+                       return -EINVAL;
+               ret = down_interruptible(&dev->sem);
+               if( ret ) return ret;
+               if ((s = isdn_net_newslave(bname))) {
+                       if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+                               ret = -EFAULT;
+                       } else {
+                               ret = 0;
+                       }
+               } else
+                       ret = -ENODEV;
+               up(&dev->sem);
+               return ret;
+       case IIOCNETDIF:
+               /* Delete a network-interface */
+               if (arg) {
+                       if (copy_from_user(name, (char *) arg, sizeof(name)))
+                               return -EFAULT;
+                       ret = down_interruptible(&dev->sem);
+                       if( ret ) return ret;
+                       ret = isdn_net_rm(name);
+                       up(&dev->sem);
+                       return ret;
+               } else
+                       return -EINVAL;
+       case IIOCNETSCF:
+               /* Set configurable parameters of a network-interface */
+               if (arg) {
+                       if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+                               return -EFAULT;
+                       return isdn_net_setcfg(&cfg);
+               } else
+                       return -EINVAL;
+       case IIOCNETGCF:
+               /* Get configurable parameters of a network-interface */
+               if (arg) {
+                       if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+                               return -EFAULT;
+                       if (!(ret = isdn_net_getcfg(&cfg))) {
+                               if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+                                       return -EFAULT;
+                       }
+                       return ret;
+               } else
+                       return -EINVAL;
+       case IIOCNETANM:
+               /* Add a phone-number to a network-interface */
+               if (arg) {
+                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+                               return -EFAULT;
+                       ret = down_interruptible(&dev->sem);
+                       if( ret ) return ret;
+                       ret = isdn_net_addphone(&phone);
+                       up(&dev->sem);
+                       return ret;
+               } else
+                       return -EINVAL;
+       case IIOCNETGNM:
+               /* Get list of phone-numbers of a network-interface */
+               if (arg) {
+                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+                               return -EFAULT;
+                       ret = down_interruptible(&dev->sem);
+                       if( ret ) return ret;
+                       ret = isdn_net_getphones(&phone, (char *) arg);
+                       up(&dev->sem);
+                       return ret;
+               } else
+                       return -EINVAL;
+       case IIOCNETDNM:
+               /* Delete a phone-number of a network-interface */
+               if (arg) {
+                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+                               return -EFAULT;
+                       ret = down_interruptible(&dev->sem);
+                       if( ret ) return ret;
+                       ret = isdn_net_delphone(&phone);
+                       up(&dev->sem);
+                       return ret;
+               } else
+                       return -EINVAL;
+       case IIOCNETDIL:
+               /* Force dialing of a network-interface */
+               if (arg) {
+                       if (copy_from_user(name, (char *) arg, sizeof(name)))
+                               return -EFAULT;
+                       return isdn_net_force_dial(name);
+               } else
+                       return -EINVAL;
+#ifdef CONFIG_ISDN_PPP
+       case IIOCNETALN:
+               if (!arg)
+                       return -EINVAL;
+               if (copy_from_user(name, (char *) arg, sizeof(name)))
+                       return -EFAULT;
+               return isdn_ppp_dial_slave(name);
+       case IIOCNETDLN:
+               if (!arg)
+                       return -EINVAL;
+               if (copy_from_user(name, (char *) arg, sizeof(name)))
+                       return -EFAULT;
+               return isdn_ppp_hangup_slave(name);
+#endif
+       case IIOCNETHUP:
+               /* Force hangup of a network-interface */
+               if (!arg)
+                       return -EINVAL;
+               if (copy_from_user(name, (char *) arg, sizeof(name)))
+                       return -EFAULT;
+               return isdn_net_force_hangup(name);
+               break;
+#endif                          /* CONFIG_NETDEVICES */
+       case IIOCSETVER:
+               dev->net_verbose = arg;
+               printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+               return 0;
+       case IIOCSETGST:
+               if (arg)
+                       dev->global_flags |= ISDN_GLOBAL_STOPPED;
+               else
+                       dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+               printk(KERN_INFO "isdn: Global Mode %s\n",
+                      (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+               return 0;
+       case IIOCSETBRJ:
+               drvidx = -1;
+               if (arg) {
+                       int i;
+                       char *p;
+                       if (copy_from_user((char *) &iocts, (char *) arg,
+                                          sizeof(isdn_ioctl_struct)))
+                               return -EFAULT;
+                       if (strlen(iocts.drvid)) {
+                               if ((p = strchr(iocts.drvid, ',')))
+                                       *p = 0;
+                               drvidx = -1;
+                               for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+                                       if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+                                               drvidx = i;
+                                               break;
                                        }
-                               } else
-                                       ret = -ENODEV;
-                               up(&dev->sem);
+                       }
+               }
+               if (drvidx == -1)
+                       return -ENODEV;
+               if (iocts.arg)
+                       dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
+               else
+                       dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+               return 0;
+       case IIOCSIGPRF:
+               dev->profd = current;
+               return 0;
+               break;
+       case IIOCGETPRF:
+               /* Get all Modem-Profiles */
+               if (arg) {
+                       char *p = (char *) arg;
+                       int i;
+
+                       if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+                                              (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+                                              * ISDN_MAX_CHANNELS)))
                                return ret;
-                       case IIOCNETASL:
-                               /* Add a slave to a network-interface */
-                               if (arg) {
-                                       if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
-                                               return -EFAULT;
-                               } else
-                                       return -EINVAL;
-                               ret = down_interruptible(&dev->sem);
-                               if( ret ) return ret;
-                               if ((s = isdn_net_newslave(bname))) {
-                                       if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-                                               ret = -EFAULT;
-                                       } else {
-                                               ret = 0;
-                                       }
-                               } else
-                                       ret = -ENODEV;
-                               up(&dev->sem);
+
+                       for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+                               if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+                                                ISDN_MODEM_NUMREG))
+                                       return -EFAULT;
+                               p += ISDN_MODEM_NUMREG;
+                               if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+                                       return -EFAULT;
+                               p += ISDN_MSNLEN;
+                               if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+                                       return -EFAULT;
+                               p += ISDN_LMSNLEN;
+                       }
+                       return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
+               } else
+                       return -EINVAL;
+               break;
+       case IIOCSETPRF:
+               /* Set all Modem-Profiles */
+               if (arg) {
+                       char *p = (char *) arg;
+                       int i;
+
+                       if ((ret = verify_area(VERIFY_READ, (void *) arg,
+                                              (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+                                              * ISDN_MAX_CHANNELS)))
                                return ret;
-                       case IIOCNETDIF:
-                               /* Delete a network-interface */
-                               if (arg) {
-                                       if (copy_from_user(name, (char *) arg, sizeof(name)))
-                                               return -EFAULT;
-                                       ret = down_interruptible(&dev->sem);
-                                       if( ret ) return ret;
-                                       ret = isdn_net_rm(name);
-                                       up(&dev->sem);
-                                       return ret;
-                               } else
-                                       return -EINVAL;
-                       case IIOCNETSCF:
-                               /* Set configurable parameters of a network-interface */
-                               if (arg) {
-                                       if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-                                               return -EFAULT;
-                                       return isdn_net_setcfg(&cfg);
-                               } else
-                                       return -EINVAL;
-                       case IIOCNETGCF:
-                               /* Get configurable parameters of a network-interface */
-                               if (arg) {
-                                       if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-                                               return -EFAULT;
-                                       if (!(ret = isdn_net_getcfg(&cfg))) {
-                                               if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
-                                                       return -EFAULT;
-                                       }
-                                       return ret;
-                               } else
-                                       return -EINVAL;
-                       case IIOCNETANM:
-                               /* Add a phone-number to a network-interface */
-                               if (arg) {
-                                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-                                               return -EFAULT;
-                                       ret = down_interruptible(&dev->sem);
-                                       if( ret ) return ret;
-                                       ret = isdn_net_addphone(&phone);
-                                       up(&dev->sem);
-                                       return ret;
-                               } else
-                                       return -EINVAL;
-                       case IIOCNETGNM:
-                               /* Get list of phone-numbers of a network-interface */
-                               if (arg) {
-                                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-                                               return -EFAULT;
-                                       ret = down_interruptible(&dev->sem);
-                                       if( ret ) return ret;
-                                       ret = isdn_net_getphones(&phone, (char *) arg);
-                                       up(&dev->sem);
-                                       return ret;
-                               } else
-                                       return -EINVAL;
-                       case IIOCNETDNM:
-                               /* Delete a phone-number of a network-interface */
-                               if (arg) {
-                                       if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-                                               return -EFAULT;
-                                       ret = down_interruptible(&dev->sem);
-                                       if( ret ) return ret;
-                                       ret = isdn_net_delphone(&phone);
-                                       up(&dev->sem);
-                                       return ret;
-                               } else
-                                       return -EINVAL;
-                       case IIOCNETDIL:
-                               /* Force dialing of a network-interface */
-                               if (arg) {
-                                       if (copy_from_user(name, (char *) arg, sizeof(name)))
-                                               return -EFAULT;
-                                       return isdn_net_force_dial(name);
-                               } else
-                                       return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
-                       case IIOCNETALN:
-                               if (!arg)
-                                       return -EINVAL;
-                               if (copy_from_user(name, (char *) arg, sizeof(name)))
+
+                       for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+                               if (copy_from_user(dev->mdm.info[i].emu.profile, p,
+                                                  ISDN_MODEM_NUMREG))
                                        return -EFAULT;
-                               return isdn_ppp_dial_slave(name);
-                       case IIOCNETDLN:
-                               if (!arg)
-                                       return -EINVAL;
-                               if (copy_from_user(name, (char *) arg, sizeof(name)))
+                               p += ISDN_MODEM_NUMREG;
+                               if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
                                        return -EFAULT;
-                               return isdn_ppp_hangup_slave(name);
-#endif
-                       case IIOCNETHUP:
-                               /* Force hangup of a network-interface */
-                               if (!arg)
-                                       return -EINVAL;
-                               if (copy_from_user(name, (char *) arg, sizeof(name)))
+                               p += ISDN_LMSNLEN;
+                               if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
                                        return -EFAULT;
-                               return isdn_net_force_hangup(name);
-                               break;
-#endif                          /* CONFIG_NETDEVICES */
-                       case IIOCSETVER:
-                               dev->net_verbose = arg;
-                               printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
-                               return 0;
-                       case IIOCSETGST:
-                               if (arg)
-                                       dev->global_flags |= ISDN_GLOBAL_STOPPED;
-                               else
-                                       dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
-                               printk(KERN_INFO "isdn: Global Mode %s\n",
-                                      (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
-                               return 0;
-                       case IIOCSETBRJ:
+                               p += ISDN_MSNLEN;
+                       }
+                       return 0;
+               } else
+                       return -EINVAL;
+               break;
+       case IIOCSETMAP:
+       case IIOCGETMAP:
+               /* Set/Get MSN->EAZ-Mapping for a driver */
+               if (arg) {
+
+                       if (copy_from_user((char *) &iocts,
+                                          (char *) arg,
+                                          sizeof(isdn_ioctl_struct)))
+                               return -EFAULT;
+                       if (strlen(iocts.drvid)) {
                                drvidx = -1;
-                               if (arg) {
-                                       int i;
-                                       char *p;
-                                       if (copy_from_user((char *) &iocts, (char *) arg,
-                                            sizeof(isdn_ioctl_struct)))
-                                               return -EFAULT;
-                                       if (strlen(iocts.drvid)) {
-                                               if ((p = strchr(iocts.drvid, ',')))
-                                                       *p = 0;
-                                               drvidx = -1;
-                                               for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-                                                       if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-                                                               drvidx = i;
-                                                               break;
-                                                       }
-                                       }
-                               }
-                               if (drvidx == -1)
-                                       return -ENODEV;
-                               if (iocts.arg)
-                                       dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
-                               else
-                                       dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
-                               return 0;
-                       case IIOCSIGPRF:
-                               dev->profd = current;
-                               return 0;
-                               break;
-                       case IIOCGETPRF:
-                               /* Get all Modem-Profiles */
-                               if (arg) {
-                                       char *p = (char *) arg;
-                                       int i;
-
-                                       if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-                                       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-                                                  * ISDN_MAX_CHANNELS)))
-                                               return ret;
-
-                                       for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                               if (copy_to_user(p, dev->mdm.info[i].emu.profile,
-                                                     ISDN_MODEM_NUMREG))
-                                                       return -EFAULT;
-                                               p += ISDN_MODEM_NUMREG;
-                                               if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
-                                                       return -EFAULT;
-                                               p += ISDN_MSNLEN;
-                                               if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
-                                                       return -EFAULT;
-                                               p += ISDN_LMSNLEN;
-                                       }
-                                       return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
-                               } else
-                                       return -EINVAL;
-                               break;
-                       case IIOCSETPRF:
-                               /* Set all Modem-Profiles */
-                               if (arg) {
-                                       char *p = (char *) arg;
-                                       int i;
-
-                                       if ((ret = verify_area(VERIFY_READ, (void *) arg,
-                                       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-                                                  * ISDN_MAX_CHANNELS)))
-                                               return ret;
-
-                                       for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-                                               if (copy_from_user(dev->mdm.info[i].emu.profile, p,
-                                                    ISDN_MODEM_NUMREG))
-                                                       return -EFAULT;
-                                               p += ISDN_MODEM_NUMREG;
-                                               if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
-                                                       return -EFAULT;
-                                               p += ISDN_LMSNLEN;
-                                               if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
-                                                       return -EFAULT;
-                                               p += ISDN_MSNLEN;
+                               for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+                                       if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+                                               drvidx = i;
+                                               break;
                                        }
-                                       return 0;
-                               } else
-                                       return -EINVAL;
-                               break;
-                       case IIOCSETMAP:
-                       case IIOCGETMAP:
-                               /* Set/Get MSN->EAZ-Mapping for a driver */
-                               if (arg) {
-
-                                       if (copy_from_user((char *) &iocts,
-                                                           (char *) arg,
-                                            sizeof(isdn_ioctl_struct)))
-                                               return -EFAULT;
-                                       if (strlen(iocts.drvid)) {
-                                               drvidx = -1;
-                                               for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-                                                       if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-                                                               drvidx = i;
-                                                               break;
-                                                       }
-                                       } else
-                                               drvidx = 0;
-                                       if (drvidx == -1)
-                                               return -ENODEV;
-                                       if (cmd == IIOCSETMAP) {
-                                               int loop = 1;
-
-                                               p = (char *) iocts.arg;
-                                               i = 0;
-                                               while (loop) {
-                                                       int j = 0;
-
-                                                       while (1) {
-                                                               if ((ret = verify_area(VERIFY_READ, p, 1)))
-                                                                       return ret;
-                                                               get_user(bname[j], p++);
-                                                               switch (bname[j]) {
-                                                                       case '\0':
-                                                                               loop = 0;
-                                                                               /* Fall through */
-                                                                       case ',':
-                                                                               bname[j] = '\0';
-                                                                               strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
-                                                                               j = ISDN_MSNLEN;
-                                                                               break;
-                                                                       default:
-                                                                               j++;
-                                                               }
-                                                               if (j >= ISDN_MSNLEN)
-                                                                       break;
-                                                       }
-                                                       if (++i > 9)
-                                                               break;
-                                               }
-                                       } else {
-                                               p = (char *) iocts.arg;
-                                               for (i = 0; i < 10; i++) {
-                                                       sprintf(bname, "%s%s",
-                                                               strlen(dev->drv[drvidx]->msn2eaz[i]) ?
-                                                               dev->drv[drvidx]->msn2eaz[i] : "_",
-                                                               (i < 9) ? "," : "\0");
-                                                       if (copy_to_user(p, bname, strlen(bname) + 1))
-                                                               return -EFAULT;
-                                                       p += strlen(bname);
+                       } else
+                               drvidx = 0;
+                       if (drvidx == -1)
+                               return -ENODEV;
+                       if (cmd == IIOCSETMAP) {
+                               int loop = 1;
+
+                               p = (char *) iocts.arg;
+                               i = 0;
+                               while (loop) {
+                                       int j = 0;
+
+                                       while (1) {
+                                               if ((ret = verify_area(VERIFY_READ, p, 1)))
+                                                       return ret;
+                                               get_user(bname[j], p++);
+                                               switch (bname[j]) {
+                                               case '\0':
+                                                       loop = 0;
+                                                       /* Fall through */
+                                               case ',':
+                                                       bname[j] = '\0';
+                                                       strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+                                                       j = ISDN_MSNLEN;
+                                                       break;
+                                               default:
+                                                       j++;
                                                }
+                                               if (j >= ISDN_MSNLEN)
+                                                       break;
                                        }
-                                       return 0;
-                               } else
-                                       return -EINVAL;
-                       case IIOCDBGVAR:
-                               if (arg) {
-                                       if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
-                                               return -EFAULT;
-                                       return 0;
-                               } else
-                                       return -EINVAL;
-                               break;
-                       default:
-                               if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
-                                       cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
-                               else
-                                       return -EINVAL;
-                               if (arg) {
-                                       int i;
-                                       char *p;
-                                       if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
-                                               return -EFAULT;
-                                       if (strlen(iocts.drvid)) {
-                                               if ((p = strchr(iocts.drvid, ',')))
-                                                       *p = 0;
-                                               drvidx = -1;
-                                               for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-                                                       if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-                                                               drvidx = i;
-                                                               break;
-                                                       }
-                                       } else
-                                               drvidx = 0;
-                                       if (drvidx == -1)
-                                               return -ENODEV;
-                                       if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-                                            sizeof(isdn_ioctl_struct))))
-                                               return ret;
-                                       c.driver = drvidx;
-                                       c.command = ISDN_CMD_IOCTL;
-                                       c.arg = cmd;
-                                       memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
-                                       ret = isdn_command(&c);
-                                       memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
-                                       if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+                                       if (++i > 9)
+                                               break;
+                               }
+                       } else {
+                               p = (char *) iocts.arg;
+                               for (i = 0; i < 10; i++) {
+                                       sprintf(bname, "%s%s",
+                                               strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+                                               dev->drv[drvidx]->msn2eaz[i] : "_",
+                                               (i < 9) ? "," : "\0");
+                                       if (copy_to_user(p, bname, strlen(bname) + 1))
                                                return -EFAULT;
-                                       return ret;
-                               } else
-                                       return -EINVAL;
-               }
+                                       p += strlen(bname);
+                               }
+                       }
+                       return 0;
+               } else
+                       return -EINVAL;
+       case IIOCDBGVAR:
+               if (arg) {
+                       if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
+                               return -EFAULT;
+                       return 0;
+               } else
+                       return -EINVAL;
+               break;
+       default:
+               if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+                       cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+               else
+                       return -EINVAL;
+               if (arg) {
+                       int i;
+                       char *p;
+                       if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
+                               return -EFAULT;
+                       if (strlen(iocts.drvid)) {
+                               if ((p = strchr(iocts.drvid, ',')))
+                                       *p = 0;
+                               drvidx = -1;
+                               for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+                                       if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+                                               drvidx = i;
+                                               break;
+                                       }
+                       } else
+                               drvidx = 0;
+                       if (drvidx == -1)
+                               return -ENODEV;
+                       if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+                                              sizeof(isdn_ioctl_struct))))
+                               return ret;
+                       c.driver = drvidx;
+                       c.command = ISDN_CMD_IOCTL;
+                       c.arg = cmd;
+                       memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+                       ret = isdn_command(&c);
+                       memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+                       if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+                               return -EFAULT;
+                       return ret;
+               } else
+                       return -EINVAL;
        }
-#ifdef CONFIG_ISDN_PPP
-       if (minor <= ISDN_MINOR_PPPMAX)
-               return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
-       return -ENODEV;
 
 #undef name
 #undef bname
@@ -1629,6 +1650,98 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 #undef cfg
 }
 
+/*
+ *
+ */
+
+static ssize_t
+isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+       uint minor = minor(file->f_dentry->d_inode->i_rdev);
+
+       if (minor < ISDN_MINOR_CTRL)
+               return -ENODEV;
+       
+       if (minor <= ISDN_MINOR_CTRLMAX)
+               return isdn_ctrl_read(file, buf, count, off);
+
+#ifdef CONFIG_ISDN_PPP
+       if (minor <= ISDN_MINOR_PPPMAX)
+               return isdn_ppp_read(file, buf, count, off);
+#endif
+
+       if (minor == ISDN_MINOR_STATUS)
+               return isdn_status_read(file, buf, count, off);
+
+       return -ENODEV;
+}
+
+static ssize_t
+isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+       uint minor = minor(file->f_dentry->d_inode->i_rdev);
+
+       if (minor < ISDN_MINOR_CTRL)
+               return -ENODEV;
+
+       if (minor <= ISDN_MINOR_CTRLMAX)
+               return isdn_ctrl_write(file, buf, count, off);
+
+#ifdef CONFIG_ISDN_PPP
+       if (minor <= ISDN_MINOR_PPPMAX)
+               return isdn_ppp_write(file, buf, count, off);
+#endif
+
+       if (minor == ISDN_MINOR_STATUS)
+               return isdn_status_write(file, buf, count, off);
+
+       return -ENODEV;
+}
+
+static unsigned int
+isdn_poll(struct file *file, poll_table * wait)
+{
+       unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
+
+       if (minor < ISDN_MINOR_CTRL)
+               return POLLERR;
+
+       if (minor <= ISDN_MINOR_CTRLMAX)
+               return isdn_ctrl_poll(file, wait);
+
+#ifdef CONFIG_ISDN_PPP
+       if (minor <= ISDN_MINOR_PPPMAX)
+               return isdn_ppp_poll(file, wait);
+#endif
+
+       if (minor == ISDN_MINOR_STATUS)
+               return isdn_status_poll(file, wait);
+
+       return POLLERR;
+}
+
+static int
+isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+       uint minor = minor(inode->i_rdev);
+
+       if (minor == ISDN_MINOR_STATUS)
+               return isdn_status_ioctl(inode, file, cmd, arg);
+
+       if (minor < ISDN_MINOR_CTRL)
+               return -ENODEV;
+
+       if (minor <= ISDN_MINOR_CTRLMAX)
+               return isdn_ctrl_ioctl(inode, file, cmd, arg);
+
+#ifdef CONFIG_ISDN_PPP
+       if (minor <= ISDN_MINOR_PPPMAX)
+               return isdn_ppp_ioctl(inode, file, cmd, arg);
+#endif
+
+       return -ENODEV;
+}
+
 /*
  * Open the device code.
  */
@@ -1636,61 +1749,22 @@ static int
 isdn_open(struct inode *ino, struct file *filep)
 {
        uint minor = minor(ino->i_rdev);
-       int drvidx;
-       int chidx;
-       int retval = -ENODEV;
 
+       if (minor < ISDN_MINOR_CTRL)
+               return -ENODEV;
 
-       if (minor == ISDN_MINOR_STATUS) {
-               infostruct *p;
+       if (minor <= ISDN_MINOR_CTRLMAX)
+               return isdn_ctrl_open(ino, filep);
+
+       if (minor == ISDN_MINOR_STATUS)
+               return isdn_status_open(ino, filep);
 
-               if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
-                       p->next = (char *) dev->infochain;
-                       p->private = (char *) &(filep->private_data);
-                       dev->infochain = p;
-                       /* At opening we allow a single update */
-                       filep->private_data = (char *) 1;
-                       retval = 0;
-                       goto out;
-               } else {
-                       retval = -ENOMEM;
-                       goto out;
-               }
-       }
-       if (!dev->channels)
-               goto out;
-       if (minor <= ISDN_MINOR_BMAX) {
-               printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
-               drvidx = isdn_minor2drv(minor);
-               if (drvidx < 0)
-                       goto out;
-               chidx = isdn_minor2chan(minor);
-               if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-                       goto out;
-               if (!(dev->drv[drvidx]->online & (1 << chidx)))
-                       goto out;
-               isdn_lock_drivers();
-               retval = 0;
-               goto out;
-       }
-       if (minor <= ISDN_MINOR_CTRLMAX) {
-               drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-               if (drvidx < 0)
-                       goto out;
-               isdn_lock_drivers();
-               retval = 0;
-               goto out;
-       }
 #ifdef CONFIG_ISDN_PPP
-       if (minor <= ISDN_MINOR_PPPMAX) {
-               retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
-               if (retval == 0)
-                       isdn_lock_drivers();
-               goto out;
-       }
+       if (minor <= ISDN_MINOR_PPPMAX)
+               return isdn_ppp_open(ino, filep);
 #endif
- out:
-       return retval;
+
+       return -ENODEV;
 }
 
 static int
@@ -1698,42 +1772,21 @@ isdn_close(struct inode *ino, struct file *filep)
 {
        uint minor = minor(ino->i_rdev);
 
-       lock_kernel();
-       if (minor == ISDN_MINOR_STATUS) {
-               infostruct *p = dev->infochain;
-               infostruct *q = NULL;
-
-               while (p) {
-                       if (p->private == (char *) &(filep->private_data)) {
-                               if (q)
-                                       q->next = p->next;
-                               else
-                                       dev->infochain = (infostruct *) (p->next);
-                               kfree(p);
-                               goto out;
-                       }
-                       q = p;
-                       p = (infostruct *) (p->next);
-               }
-               printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-               goto out;
-       }
-       isdn_unlock_drivers();
-       if (minor <= ISDN_MINOR_BMAX)
-               goto out;
-       if (minor <= ISDN_MINOR_CTRLMAX) {
-               if (dev->profd == current)
-                       dev->profd = NULL;
-               goto out;
-       }
+       if (minor == ISDN_MINOR_STATUS)
+               return isdn_status_release(ino, filep);
+
+       if (minor < ISDN_MINOR_CTRL)
+               return -ENODEV;
+
+       if (minor <= ISDN_MINOR_CTRLMAX)
+               return isdn_ctrl_release(ino, filep);
+
 #ifdef CONFIG_ISDN_PPP
        if (minor <= ISDN_MINOR_PPPMAX)
-               isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
+               return isdn_ppp_release(ino, filep);
 #endif
 
- out:
-       unlock_kernel();
-       return 0;
+       return -ENODEV;
 }
 
 static struct file_operations isdn_fops =
@@ -1877,32 +1930,6 @@ isdn_unexclusive_channel(int di, int ch)
        restore_flags(flags);
 }
 
-/*
- *  writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
-                  int user)
-{
-       int ret;
-       int hl = dev->drv[drvidx]->interface->hl_hdrlen;
-       struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
-       if (!skb)
-               return 0;
-       skb_reserve(skb, hl);
-       if (user)
-               copy_from_user(skb_put(skb, len), buf, len);
-       else
-               memcpy(skb_put(skb, len), buf, len);
-       ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
-       if (ret <= 0)
-               dev_kfree_skb(skb);
-       if (ret > 0)
-               dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
-       return ret;
-}
-
 /*
  * Return: length of data on success, -ERRcode on failure.
  */
index 2565366ffeab7d414bf8565867bee16f5bd5393b..492b3c42e930cd3575364b1e5a24dcb3d21afb79 100644 (file)
@@ -27,6 +27,8 @@
 /* Prototypes */
 extern void isdn_MOD_INC_USE_COUNT(void);
 extern void isdn_MOD_DEC_USE_COUNT(void);
+extern void isdn_lock_drivers(void);
+extern void isdn_unlock_drivers(void);
 extern void isdn_free_channel(int di, int ch, int usage);
 extern void isdn_all_eaz(int di, int ch);
 extern int isdn_command(isdn_ctrl *);
index 431683e13627639782fa37c78ff4262c20490038..5d60bb2d4f729c13aa13cb4b48446efb1ed43ba9 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/isdn.h>
+#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/ppp-comp.h>
 
@@ -269,21 +270,19 @@ isdn_ppp_get_slot(void)
  */
 
 int
-isdn_ppp_open(int min, struct file *file)
+isdn_ppp_open(struct inode *ino, struct file *file)
 {
+       uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
        int slot;
        struct ippp_struct *is;
 
-       if (min < 0 || min > ISDN_MAX_CHANNELS)
-               return -ENODEV;
-
        slot = isdn_ppp_get_slot();
        if (slot < 0) {
                return -EBUSY;
        }
        is = file->private_data = ippp_table[slot];
 
-               printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+               printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
 
        /* compression stuff */
        is->link_compressor   = is->compressor = NULL;
@@ -306,7 +305,7 @@ isdn_ppp_open(int min, struct file *file)
        init_waitqueue_head(&is->wq);
        is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
        is->last = is->rq;
-       is->minor = min;
+       is->minor = minor;
 #ifdef CONFIG_ISDN_PPP_VJ
        /*
         * VJ header compression init
@@ -315,6 +314,7 @@ isdn_ppp_open(int min, struct file *file)
 #endif
 
        is->state = IPPP_OPEN;
+       isdn_lock_drivers();
 
        return 0;
 }
@@ -322,18 +322,19 @@ isdn_ppp_open(int min, struct file *file)
 /*
  * release ippp device
  */
-void
-isdn_ppp_release(int min, struct file *file)
+int
+isdn_ppp_release(struct inode *ino, struct file *file)
 {
+       uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
        int i;
        struct ippp_struct *is;
 
-       if (min < 0 || min >= ISDN_MAX_CHANNELS)
-               return;
+       lock_kernel();
+
        is = file->private_data;
 
        if (is->debug & 0x1)
-               printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
+               printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) is->lp);
 
        if (is->lp) {           /* a lp address says: this link is still up */
                isdn_net_dev *p = is->lp->netdev;
@@ -381,6 +382,11 @@ isdn_ppp_release(int min, struct file *file)
 
        /* this slot is ready for new connections */
        is->state = 0;
+
+       isdn_unlock_drivers();
+       
+       unlock_kernel();
+       return 0;
 }
 
 /*
@@ -413,7 +419,7 @@ set_arg(void *b, void *val,int len)
  * ippp device ioctl
  */
 int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg)
 {
        unsigned long val;
        int r,i,j;
@@ -425,7 +431,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
        lp = is->lp;
 
        if (is->debug & 0x1)
-               printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
+               printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state);
 
        if (!(is->state & IPPP_OPEN))
                return -EINVAL;
@@ -438,7 +444,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
                        if ((r = get_arg((void *) arg, &val, sizeof(val) )))
                                return r;
                        printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
-                              (int) min, (int) is->unit, (int) val);
+                              (int) is->minor, (int) is->unit, (int) val);
                        return isdn_ppp_bundle(is, val);
 #else
                        return -1;
@@ -582,6 +588,7 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
        unsigned long flags;
        struct ippp_struct *is;
 
+       lock_kernel();
        is = file->private_data;
 
        if (is->debug & 0x2)
@@ -592,10 +599,13 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
        poll_wait(file, &is->wq, wait);
 
        if (!(is->state & IPPP_OPEN)) {
-               if(is->state == IPPP_CLOSEWAIT)
-                       return POLLHUP;
+               if(is->state == IPPP_CLOSEWAIT) {
+                       mask = POLLHUP;
+                       goto out;
+               }
                printk(KERN_DEBUG "isdn_ppp: device not open\n");
-               return POLLERR;
+               mask = POLLERR;
+               goto out;
        }
        /* we're always ready to send .. */
        mask = POLLOUT | POLLWRNORM;
@@ -612,6 +622,9 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
                mask |= POLLIN | POLLRDNORM;
        }
        restore_flags(flags);
+
+ out:
+       unlock_kernel();
        return mask;
 }
 
@@ -678,21 +691,28 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
  */
 
 int
-isdn_ppp_read(int min, struct file *file, char *buf, int count)
+isdn_ppp_read(struct file *file, char *buf, int count, loff_t *off)
 {
        struct ippp_struct *is;
        struct ippp_buf_queue *b;
-       int r;
        unsigned long flags;
        unsigned char *save_buf;
+       int retval;
 
-       is = file->private_data;
+       if (off != &file->f_pos)
+               return -ESPIPE;
+       
+       lock_kernel();
 
-       if (!(is->state & IPPP_OPEN))
-               return 0;
+       is = file->private_data;
 
-       if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
-               return r;
+       if (!(is->state & IPPP_OPEN)) {
+               retval = 0;
+               goto out;
+       }
+       retval = verify_area(VERIFY_WRITE, (void *) buf, count);
+       if (retval)
+               goto out;
 
        save_flags(flags);
        cli();
@@ -701,7 +721,8 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
        save_buf = b->buf;
        if (!save_buf) {
                restore_flags(flags);
-               return -EAGAIN;
+               retval = -EAGAIN;
+               goto out;
        }
        if (b->len < count)
                count = b->len;
@@ -713,7 +734,11 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
        copy_to_user(buf, save_buf, count);
        kfree(save_buf);
 
-       return count;
+       retval = count;
+
+ out:
+       unlock_kernel();
+       return retval;
 }
 
 /*
@@ -721,17 +746,25 @@ isdn_ppp_read(int min, struct file *file, char *buf, int count)
  */
 
 int
-isdn_ppp_write(int min, struct file *file, const char *buf, int count)
+isdn_ppp_write(struct file *file, const char *buf, int count, loff_t *off)
 {
        isdn_net_local *lp;
        struct ippp_struct *is;
        int proto;
        unsigned char protobuf[4];
+       int retval;
+
+       if (off != &file->f_pos)
+               return -ESPIPE;
+
+       lock_kernel();
 
        is = file->private_data;
 
-       if (!(is->state & IPPP_CONNECT))
-               return 0;
+       if (!(is->state & IPPP_CONNECT)) {
+               retval = 0;
+               goto out;
+       }
 
        lp = is->lp;
 
@@ -744,15 +777,18 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
                 * Don't reset huptimer for
                 * LCP packets. (Echo requests).
                 */
-               if (copy_from_user(protobuf, buf, 4))
-                       return -EFAULT;
+               if (copy_from_user(protobuf, buf, 4)) {
+                       retval = -EFAULT;
+                       goto out;
+               }
                proto = PPP_PROTOCOL(protobuf);
                if (proto != PPP_LCP)
                        lp->huptimer = 0;
 
-               if (lp->isdn_device < 0 || lp->isdn_channel < 0)
-                       return 0;
-
+               if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
+                       retval = 0;
+                       goto out;
+               }
                if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
                        lp->dialstate == 0 &&
                    (lp->flags & ISDN_NET_CONNECTED)) {
@@ -767,13 +803,15 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
                        skb = alloc_skb(hl+count, GFP_ATOMIC);
                        if (!skb) {
                                printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
-                               return count;
+                               retval = count;
+                               goto out;
                        }
                        skb_reserve(skb, hl);
                        if (copy_from_user(skb_put(skb, count), buf, count))
                        {
                                kfree_skb(skb);
-                               return -EFAULT;
+                               retval = -EFAULT;
+                               goto out;
                        }
                        if (is->debug & 0x40) {
                                printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
@@ -785,7 +823,11 @@ isdn_ppp_write(int min, struct file *file, const char *buf, int count)
                        isdn_net_write_super(lp, skb);
                }
        }
-       return count;
+       retval = count;
+       
+ out:
+       unlock_kernel();
+       return retval;
 }
 
 /*
index 4495b079f8cf71e814a622be3704946345756b3c..9dad0b5eac1b6c48e6570f979ca0b201d1ea49cb 100644 (file)
 #include <linux/ppp_defs.h>     /* for PPP_PROTOCOL */
 #include <linux/isdn_ppp.h>    /* for isdn_ppp info */
 
-extern int isdn_ppp_read(int, struct file *, char *, int);
-extern int isdn_ppp_write(int, struct file *, const char *, int);
-extern int isdn_ppp_open(int, struct file *);
+extern int isdn_ppp_open(struct inode *, struct file *);
+extern int isdn_ppp_release(struct inode *, struct file *);
+extern int isdn_ppp_read(struct file *, char *, int, loff_t *off);
+extern int isdn_ppp_write(struct file *, const char *, int, loff_t *off);
+extern int isdn_ppp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
+
 extern int isdn_ppp_init(void);
 extern void isdn_ppp_cleanup(void);
 extern int isdn_ppp_free(isdn_net_local *);
@@ -22,9 +26,6 @@ extern int isdn_ppp_bind(isdn_net_local *);
 extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
 extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
 extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
 extern int isdn_ppp_dial_slave(char *);
 extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 
index 3fb9ad117ac0dad178a3df9258f69b98246085d2..48bcb9516e867f5de213fe2cbf8888aeb10fdcfd 100644 (file)
@@ -3458,8 +3458,7 @@ recheck:
                 * about not overloading the IO subsystem. (things like an
                 * e2fsck being done on the RAID array should execute fast)
                 */
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
 
                currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
 
index a4c643ce92f834cefc4aebd6ff97b04505978bc5..19158bbc0fe52f6c2e362cba9d80edb5dac5be12 100644 (file)
@@ -94,8 +94,7 @@ static inline int fmi_setfreq(struct fmi_device *dev)
        for(i=0; i< 100; i++)
        {
                udelay(1400);
-               if(current->need_resched)
-                       schedule();
+               cond_resched();
        }
 /* If this becomes allowed use it ...  
        current->state = TASK_UNINTERRUPTIBLE;
@@ -121,8 +120,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
        for(i=0; i< 100; i++)
        {
                udelay(1400);
-               if(current->need_resched)
-                       schedule();
+               cond_resched();
        }
 /* If this becomes allowed use it ...  
        current->state = TASK_UNINTERRUPTIBLE;
index 6ca1f83dc4027c25fd1e1981ff0eb39bd68c48e0..02e0f68819c26ce21222d04a9fbec0c0ebeb3711 100644 (file)
@@ -425,8 +425,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
                wantlen -= t;
                if (t < s)
                        break;
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
        }
 
        len = outptr;
@@ -445,8 +444,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
                int l;
                do {
                        l = qcam_read_bytes(q, tmpbuf, 3);
-                       if (current->need_resched)
-                               schedule();
+                       cond_resched();
                } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
                if (force_rgb) {
                        if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
@@ -478,8 +476,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
                int l;
                do {
                        l = qcam_read_bytes(q, tmpbuf, 1);
-                       if (current->need_resched)
-                               schedule();
+                       cond_resched();
                } while (l && tmpbuf[0] == 0x7e);
                l = qcam_read_bytes(q, tmpbuf+1, 2);
                if (force_rgb) {
index 3dfa777e5faef48b37543a0717622dee7f04ae04..00de51d3bc80b7fca9b5819d052fb94d9c46eae5 100644 (file)
@@ -2147,8 +2147,7 @@ static void fetch_frame(void *data)
                        /* loop until image ready */
                        do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
                        while (cam->params.status.streamState != STREAM_READY) {
-                               if (current->need_resched)
-                                       schedule();
+                               cond_resched();
 
                                current->state = TASK_INTERRUPTIBLE;
 
@@ -2163,8 +2162,7 @@ static void fetch_frame(void *data)
                }
 
                /* grab image from camera */
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
 
                oldjif = jiffies;
                image_size = cam->ops->streamRead(cam->lowlevel_data,
@@ -2189,8 +2187,7 @@ static void fetch_frame(void *data)
                /* decompress and convert image to by copying it from
                 * raw_image to decompressed_frame
                 */
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
 
                cam->image_size = parse_picture(cam, image_size);
                if (cam->image_size <= 0)
index 05001ea50fa8527966e54319092892a467b08af6..36157f5a139c01bdd7cac132b45ad74903e52ebe 100644 (file)
@@ -392,7 +392,7 @@ static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
        endseen = 0;
        block_size = PARPORT_CHUNK_SIZE;
        while( !cam->image_complete ) {
-               if(current->need_resched)  schedule();
+               cond_resched();
                
                new_bytes = cpia_pp_read(cam->port, buffer, block_size );
                if( new_bytes <= 0 ) {
index 8d4bd9cc1c5554d35b9e1832b327c0fa2fac9239..81f91ebd61751794104edfdce3b2b69025e4b7a5 100644 (file)
@@ -127,11 +127,7 @@ struct saa5249_device
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
-#define RESCHED \
-        do { \
-          if (current->need_resched) \
-            schedule(); \
-        } while (0)
+#define RESCHED do { cond_resched(); } while(0)
 
 static struct video_device saa_template;       /* Declared near bottom */
 
index 67cdf1b11e6e06a42ecc60a3f488da8b6bae3369..52a81d8a1139647fabf0330273d844dee1ef35b7 100644 (file)
@@ -889,7 +889,7 @@ retry:
 
        times_left = 500000;
        while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
-               if (current->need_resched) {
+               if (need_resched()) {
                        spin_unlock_bh(chip->mutex);
                        schedule();
                        spin_lock_bh(chip->mutex);
@@ -1126,7 +1126,7 @@ retry:
                /* Latency issues. Drop the lock, wait a while and retry */
                spin_unlock_bh(chip->mutex);
 
-               if (current->need_resched)
+               if (need_resched())
                        schedule();
                else
                        udelay(1);
index 837ed5fc8ea625dcc20c6f1ab55feed2215f127f..36ad7dee6918abd250f5a3874ae4af6b3d0b9601 100644 (file)
@@ -97,7 +97,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc)
                        DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
                        return -EIO;
                }
-               if (current->need_resched) {
+               if (need_resched()) {
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        schedule_timeout(1);
                }
index a2207139f543169ff5f9298a088d7acb49d8a80f..815bf8e37922787739c608340550ca1542bb7712 100644 (file)
@@ -585,7 +585,7 @@ struct ace_info {
 
 struct ring_info {
        struct sk_buff          *skb;
-       dma_addr_t              mapping;
+       DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
 
@@ -596,8 +596,8 @@ struct ring_info {
  */
 struct tx_ring_info {
        struct sk_buff          *skb;
-       dma_addr_t              mapping;
-       int                     maplen;
+       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DECLARE_PCI_UNMAP_LEN(maplen)
 };
 
 
index 2d03b182c6fadff4322bd738d74b09e494c7be01..da8acc08d189f59583bd740ea9b481d916255eeb 100644 (file)
@@ -88,6 +88,7 @@ const short   channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
  */
 const int      fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
 
+
 /*************************** PC INTERFACE ****************************/
 
 /* WaveLAN host interface definitions */
@@ -316,6 +317,7 @@ struct mmw_t
 /* Calculate offset of a field in the above structure */
 #define        mmwoff(p,f)     (unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /*
  * Modem Management Controller (MMC) read structure.
  */
@@ -373,6 +375,7 @@ struct mmr_t
 /* Calculate offset of a field in the above structure */
 #define        mmroff(p,f)     (unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /* Make the two above structures one */
 typedef union mm_t
 {
index c2efbe4240c79582016767226c951fc10202c404..c4ba93ddaaa3b7f8d15b417a5adefcada60d96c7 100644 (file)
@@ -22,7 +22,7 @@
 #ifdef WAVELAN_ROAMING 
  * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
  * based on patch by Joe Finney from Lancaster University.
-#endif :-)
+#endif
  *
  * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
  * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
  * Apr 2 '98  made changes to bring the i82593 control/int handling in line
  *             with offical specs...
  *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
- * - reorganize kmallocs in wavelan_attach, checking all for failure
- *   and releasing the previous allocations if one fails
- *
- *
  ****************************************************************************
  *   Copyright 1995
  *   Anthony D. Joseph
  * (wavelan modem or i82593)
  */
 
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *           lp,
+        unsigned long *        pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *            lp,
+       unsigned long *         pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Wrapper for reporting error to cardservices
@@ -103,7 +125,7 @@ wv_structuct_check(void)
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the wavelan
  */
 
 /*------------------------------------------------------------------*/
@@ -138,7 +160,7 @@ hacr_write_slow(u_long      base,
 {
   hacr_write(base, hacr);
   /* delay might only be needed sometimes */
-  mdelay(1L);
+  mdelay(1);
 } /* hacr_write_slow */
 
 /*------------------------------------------------------------------*/
@@ -529,7 +551,7 @@ void wv_roam_init(struct net_device *dev)
   lp->curr_point=NULL;                        /* No default WavePoint */
   lp->cell_search=0;
   
-  lp->cell_timer.data=(int)lp;                /* Start cell expiry timer */
+  lp->cell_timer.data=(long)lp;               /* Start cell expiry timer */
   lp->cell_timer.function=wl_cell_expiry;
   lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
   add_timer(&lp->cell_timer);
@@ -569,18 +591,18 @@ void wv_nwid_filter(unsigned char mode, net_local *lp)
 #endif
   
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
   
   m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
   mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
   
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
   if(mode==NWID_PROMISC)
     lp->cell_search=1;
   else
-       lp->cell_search=0;
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
 }
 
 /* Find a record in the WavePoint table matching a given NWID */
@@ -737,7 +759,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
   ioaddr_t              base = lp->dev->base_addr;  
   mm_t                  m;
   unsigned long         flags;
-  
+
   if(wavepoint==lp->curr_point)          /* Sanity check... */
     {
       wv_nwid_filter(!NWID_PROMISC,lp);
@@ -749,16 +771,16 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
 #endif
        
   /* Disable interrupts & save flags */
-  spin_lock_irqsave(&lp->lock, flags);
-  
+  wv_splhi(lp, &flags);
+
   m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
   m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
   
   mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
   
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
+  wv_splx(lp, &flags);
+
   wv_nwid_filter(!NWID_PROMISC,lp);
   lp->curr_point=wavepoint;
 }
@@ -775,6 +797,11 @@ static inline void wl_roam_gather(device *  dev,
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
   net_local *lp=(net_local *)dev->priv;              /* Device info */
 
+#if 0
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
 #if WAVELAN_ROAMING_DEBUG > 1
   printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
   printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
@@ -832,7 +859,9 @@ static inline int WAVELAN_BEACON(unsigned char *data)
 /*------------------------------------------------------------------*/
 /*
  * Routine to synchronously send a command to the i82593 chip. 
- * Should be called with interrupts enabled.
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
  */
 static int
 wv_82593_cmd(device *  dev,
@@ -841,74 +870,98 @@ wv_82593_cmd(device *     dev,
             int        result)
 {
   ioaddr_t     base = dev->base_addr;
-  net_local *  lp = (net_local *)dev->priv;
   int          status;
+  int          wait_completed;
   long         spin;
-  u_long       flags;
 
   /* Spin until the chip finishes executing its current command (if any) */
+  spin = 1000;
   do
     {
-      spin_lock_irqsave (&lp->lock, flags);
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  /* If the interrupt hasn't be posted */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+            str, status);
+#endif
+      return(FALSE);
+    }
 
   /* Issue the command to the controller */
   outb(cmd, LCCR(base));
 
-  /* If we don't have to check the result of the command */
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
   if(result == SR0_NO_RESULT)
-    {
-      wv_wait_completed = FALSE;
-      return(TRUE);
-    }
+    return(TRUE);
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 1000))
-    udelay(10);
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
 
-  /* If the interrupt handler hasn't be called */
-  if(wv_wait_completed)
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
     {
-      outb(OP0_NOP, LCCR(base));
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
       status = inb(LCSR(base));
-      if(status & SR0_INTERRUPT)
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
        {
-         /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
-         printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
+         /* Acknowledge the interrupt */
+         outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
 
-         wavelan_interrupt(dev->irq, (void *) dev,
-                           (struct pt_regs *) NULL);
+         /* Check if interrupt is a command completion */
+         if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+            ((status & SR0_BOTH_RX_TX) != 0x0) &&
+            !(status & SR0_RECEPTION))
+           {
+             /* Signal command completion */
+             wait_completed = FALSE;
+           }
+         else
+           {
+             /* Note : Rx interrupts will be handled later, because we can
+              * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+             printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+           }
        }
-      else
-       {
-         wv_wait_completed = 0; /* XXX */
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
 #ifdef DEBUG_INTERRUPT_ERROR
-         printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
-                str, status);
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+            str, status);
 #endif
-         /* We probably should reset the controller here */
-         return(FALSE);
-       }
+      return(FALSE);
     }
 
-  /* Check the return code provided by the interrupt handler against
+  /* Check the return code returned by the card (see above) against
    * the expected return code provided by the caller */
-  if((lp->status & SR0_EVENT_MASK) != result)
+  if((status & SR0_EVENT_MASK) != result)
     {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
-            str, lp->status);
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+            str, status);
 #endif
       return(FALSE);
     }
@@ -924,14 +977,16 @@ wv_82593_cmd(device *     dev,
 static inline int
 wv_diag(device *       dev)
 {
+  int          ret = FALSE;
+
   if(wv_82593_cmd(dev, "wv_diag(): diagnose",
                  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
-    return(TRUE);
+    ret = TRUE;
 
 #ifdef DEBUG_CONFIG_ERROR
   printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
 #endif
-  return(FALSE);
+  return(ret);
 } /* wv_diag */
 
 /*------------------------------------------------------------------*/
@@ -951,15 +1006,6 @@ read_ringbuf(device *     dev,
   int          chunk_len;
   char *       buf_ptr = buf;
 
-#ifdef OLDIES
-  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
-   * quite safe to remove this... */
-
-  /* If buf is NULL, just increment the ring buffer pointer */
-  if(buf == NULL)
-    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
   /* Get all the buffer */
   while(len > 0)
     {
@@ -990,70 +1036,32 @@ read_ringbuf(device *    dev,
  * wavelan_interrupt is not an option...), so you may experience
  * some delay sometime...
  */
-static inline void wv_82593_reconfig (device * dev)
+static inline void
+wv_82593_reconfig(device *     dev)
 {
-       net_local *lp = (net_local *) dev->priv;
-       dev_link_t *link = ((net_local *) dev->priv)->link;
+  net_local *          lp = (net_local *)dev->priv;
+  dev_link_t *         link = ((net_local *) dev->priv)->link;
+  unsigned long                flags;
+
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
 
-       /* Check if we can do it now ! */
-       if (!(link->open)) {
-               lp->reconfig_82593 = TRUE;
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_splhi(lp, &flags);    /* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);     /* Re-enable interrupts */
+    }
+  else
+    {
 #ifdef DEBUG_IOCTL_INFO
-               printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
-                       dev->name, link->open);
+      printk(KERN_DEBUG
+            "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+            dev->name, dev->state, link->open);
 #endif
-       } else {
-               netif_stop_queue (dev);
-
-               lp->reconfig_82593 = FALSE;
-               wv_82593_config (dev);
-               netif_wake_queue (dev);
-       }
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
-  ioaddr_t base = dev->base_addr;
-  int i, c;
-
-  /* disable receiver so we can use channel 1 */
-  outb(OP0_RCV_DISABLE, LCCR(base));
-
-  /* reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* dump into receive buffer */
-  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
-  /* set read pointer to start of receive buffer */
-  outb(0, PIORL(base));
-  outb(0, PIORH(base));
-
-  printk(KERN_DEBUG "wavelan_cs: dump:\n");
-  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
-  for(i = 0; i < 73; i++){
-    if((i % 16) == 0) {
-      printk("\n0x%02x:", i);
-      if (!i) {
-       printk("   ");
-       continue;
-      }
     }
-    c = inb(PIOP(base));
-    printk("%02x ", c);
-  }
-  printk("\n");
-
-  /* enable the receiver again */
-  wv_ru_start(dev);
 }
-#endif
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
@@ -1171,6 +1179,8 @@ wv_mmc_show(device *      dev)
       return;
     }
 
+  wv_splhi(lp, &flags);
+
   /* Read the mmc */
   mmc_out(base, mmwoff(0, mmw_freeze), 1);
   mmc_read(base, 0, (u_char *)&m, sizeof(m));
@@ -1181,6 +1191,8 @@ wv_mmc_show(device *      dev)
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif /* WIRELESS_EXT */
 
+  wv_splx(lp, &flags);
+
   printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1265,6 +1277,7 @@ static void
 wv_dev_show(device *   dev)
 {
   printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", dev->state);
   printk(" trans_start=%ld,", dev->trans_start);
   printk(" flags=0x%x,", dev->flags);
   printk("\n");
@@ -1404,7 +1417,7 @@ wv_init_info(device *     dev)
          printk("2430.5");
          break;
        default:
-         printk("unknown");
+         printk("???");
        }
     }
 
@@ -1719,7 +1732,7 @@ wv_set_frequency(u_long           base,   /* i/o port of the card */
         memcmp(dac, dac_verify, 2 * 2))
        {
 #ifdef DEBUG_IOCTL_ERROR
-         printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
+         printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
 #endif
          return -EOPNOTSUPP;
        }
@@ -1892,7 +1905,7 @@ wavelan_ioctl(struct net_device * dev,    /* Device on wich the ioctl apply */
 #endif
 
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Look what is the request */
   switch(cmd)
@@ -1968,7 +1981,7 @@ wavelan_ioctl(struct net_device * dev,    /* Device on wich the ioctl apply */
 
     case SIOCGIWFREQ:
       /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody XXX - especially old cards...) */
+       * (does it work for everybody ??? - especially old cards...) */
       if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
           (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
        {
@@ -2239,15 +2252,17 @@ wavelan_ioctl(struct net_device *       dev,    /* Device on wich the ioctl apply */
        {
          struct iw_range       range;
 
-         /* Set the length (very important for backward compatibility) */
-         wrq->u.data.length = sizeof(struct iw_range);
+          /* Set the length (very important for backward compatibility) */
+          wrq->u.data.length = sizeof(struct iw_range);
 
-         /* Set all the info we don't care or don't know about to zero */
-         memset(&range, 0, sizeof(range));
+          /* Set all the info we don't care or don't know about to zero */
+          memset(&range, 0, sizeof(range));
 
-         /* Set the Wireless Extension versions */
-         range.we_version_compiled = WIRELESS_EXT;
-         range.we_version_source = 9;  /* Nothing for us in v10 and v11 */
+#if WIRELESS_EXT > 10
+          /* Set the Wireless Extension versions */
+          range.we_version_compiled = WIRELESS_EXT;
+          range.we_version_source = 9; /* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
 
          /* Set information in the range struct */
          range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
@@ -2517,7 +2532,7 @@ wavelan_ioctl(struct net_device * dev,    /* Device on wich the ioctl apply */
     }
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2543,11 +2558,8 @@ wavelan_get_wireless_stats(device *      dev)
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  if (lp == NULL) /* XXX will this ever occur? */
-    return NULL;
-
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   wstats = &lp->wstats;
 
@@ -2573,7 +2585,7 @@ wavelan_get_wireless_stats(device *       dev)
   wstats->discard.misc = 0L;
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2692,12 +2704,6 @@ wv_packet_read(device *          dev,
   skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  /* Another glitch : Due to the way the GET_PACKET macro is written,
-   * we are not sure to have the same thing in skb->data. On the other
-   * hand, skb->mac.raw is not defined everywhere...
-   * For versions between 1.2.13 and those where skb->mac.raw appear,
-   * I don't have a clue...
-   */
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif /* DEBUG_RX_INFO */
      
@@ -2731,9 +2737,7 @@ wv_packet_read(device *           dev,
          wl_roam_gather(dev, skb->data, stats);
 #endif /* WAVELAN_ROAMING */
          
-      /* Spying stuff */
 #ifdef WIRELESS_SPY
-      /* Same as above */
       wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
 #endif /* WIRELESS_SPY */
 #ifdef HISTOGRAM
@@ -2766,6 +2770,7 @@ wv_packet_read(device *           dev,
  * called to do the actual transfer of the card's data including the
  * ethernet header into a packet consisting of an sk_buff chain.
  * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
  */
 static inline void
 wv_packet_rcv(device * dev)
@@ -2916,7 +2921,7 @@ wv_packet_write(device *  dev,
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Check if we need some padding */
   if(clen < ETH_ZLEN)
@@ -2946,15 +2951,7 @@ wv_packet_write(device * dev,
   /* Keep stats up to date */
   lp->stats.tx_bytes += length;
 
-  /* If watchdog not already active, activate it... */
-  if (!timer_pending(&lp->watchdog))
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_TX_INFO
   wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2963,56 +2960,57 @@ wv_packet_write(device *        dev,
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
-
-  netif_start_queue (dev);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
+ * In this routine, we check if the harware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
-static int wavelan_packet_xmit (struct sk_buff *skb,
-                               device * dev)
+static int
+wavelan_packet_xmit(struct sk_buff *   skb,
+                   device *            dev)
 {
-       net_local *lp = (net_local *) dev->priv;
+  net_local *          lp = (net_local *)dev->priv;
+  unsigned long                flags;
 
 #ifdef DEBUG_TX_TRACE
-       printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-               (unsigned) skb);
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+        (unsigned) skb);
 #endif
 
-       /*
-        * For ethernet, fill in the header.
-        */
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
 
-       netif_stop_queue (dev);
+  /* If somebody has asked to reconfigure the controller,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_splhi(lp, &flags);    /* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);     /* Re-enable interrupts */
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
 
-       /*
-        * Block a timer-based transmit from overlapping a previous transmit.
-        * In other words, prevent reentering this routine.
-        */
-       if (1) {
-               /* If somebody has asked to reconfigure the controller, we can do it now */
-               if (lp->reconfig_82593) {
-                       lp->reconfig_82593 = FALSE;
-                       wv_82593_config (dev);
-               }
 #ifdef DEBUG_TX_ERROR
-               if (skb->next)
-                       printk (KERN_INFO "skb has next\n");
+       if (skb->next)
+               printk(KERN_INFO "skb has next\n");
 #endif
 
-               wv_packet_write (dev, skb->data, skb->len);
-       }
-       dev_kfree_skb (skb);
+  wv_packet_write(dev, skb->data, skb->len);
+
+  dev_kfree_skb(skb);
 
 #ifdef DEBUG_TX_TRACE
-       printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-       return (0);
+  return(0);
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
@@ -3165,7 +3163,7 @@ wv_mmc_init(device *      dev)
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody XXX - especially old cards...) */
+   * (does it work for everybody ??? - especially old cards...) */
   /* Note : WFREQSEL verify that it is able to read from EEprom
    * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
    * is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3223,7 +3221,7 @@ static int
 wv_ru_stop(device *    dev)
 {
   ioaddr_t     base = dev->base_addr;
-  net_local *lp = (net_local *) dev->priv;
+  net_local *  lp = (net_local *) dev->priv;
   unsigned long        flags;
   int          status;
   int          spin;
@@ -3232,35 +3230,35 @@ wv_ru_stop(device *     dev)
   printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
 #endif
 
+  wv_splhi(lp, &flags);
+
   /* First, send the LAN controller a stop receive command */
   wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
               OP0_STOP_RCV, SR0_NO_RESULT);
 
   /* Then, spin until the receive unit goes idle */
-  spin = 0;
+  spin = 300;
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
 
   /* Now, spin until the chip finishes executing its current command */
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
 
   /* If there was a problem */
-  if(spin > 300)
+  if(spin <= 0)
     {
 #ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
@@ -3287,6 +3285,7 @@ wv_ru_start(device *      dev)
 {
   ioaddr_t     base = dev->base_addr;
   net_local *  lp = (net_local *) dev->priv;
+  unsigned long        flags;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
@@ -3300,6 +3299,8 @@ wv_ru_start(device *      dev)
   if(!wv_ru_stop(dev))
     return FALSE;
 
+  wv_splhi(lp, &flags);
+
   /* Now we know that no command is being executed. */
 
   /* Set the receive frame pointer and stop pointer */
@@ -3309,8 +3310,17 @@ wv_ru_start(device *     dev)
   /* Reset ring management.  This sets the receive frame pointer to 1 */
   outb(OP1_RESET_RING_MNGMT, LCCR(base));
 
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
   /* but I set it to 3 bytes per packet less than 8K */
   lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
   outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
   outb(OP1_INT_ENABLE, LCCR(base));
   outb(OP1_SWIT_TO_PORT_0, LCCR(base));
@@ -3326,17 +3336,15 @@ wv_ru_start(device *    dev)
 #ifdef DEBUG_I82593_SHOW
   {
     int        status;
-    unsigned long flags;
-    int        i = 0;
+    int        opri;
+    int        spin = 10000;
 
     /* spin until the chip starts receiving */
     do
       {
-       spin_lock_irqsave (&lp->lock, flags);
        outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
        status = inb(LCSR(base));
-       spin_unlock_irqrestore (&lp->lock, flags);
-       if(i++ > 10000)
+       if(spin-- <= 0)
          break;
       }
     while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
@@ -3345,6 +3353,9 @@ wv_ru_start(device *      dev)
           (status & SR3_RCV_STATE_MASK), i);
   }
 #endif
+
+  wv_splx(lp, &flags);
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
 #endif
@@ -3363,6 +3374,7 @@ wv_82593_config(device *  dev)
   ioaddr_t                     base = dev->base_addr;
   net_local *                  lp = (net_local *) dev->priv;
   struct i82593_conf_block     cfblk;
+  int                          ret = TRUE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
@@ -3457,7 +3469,7 @@ wv_82593_config(device *  dev)
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
                   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
-    return(FALSE);
+    ret = FALSE;
 
   /* Initialize adapter's ethernet MAC address */
   outb(TX_BASE & 0xff, PIORL(base));
@@ -3471,7 +3483,7 @@ wv_82593_config(device *  dev)
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
                   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
-    return(FALSE);
+    ret = FALSE;
 
 #ifdef WAVELAN_ROAMING
     /* If roaming is enabled, join the "Beacon Request" multicast group... */
@@ -3508,14 +3520,17 @@ wv_82593_config(device *        dev)
       hacr_write(base, HACR_DEFAULT);
       if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
                       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
-       return(FALSE);
+       ret = FALSE;
       lp->mc_count = dev->mc_count;    /* remember to avoid repeated reset */
     }
 
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
 #endif
-  return(TRUE);
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3594,6 +3609,8 @@ wv_hw_config(device *     dev)
 {
   net_local *          lp = (net_local *) dev->priv;
   ioaddr_t             base = dev->base_addr;
+  unsigned long                flags;
+  int                  ret = FALSE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
@@ -3612,50 +3629,78 @@ wv_hw_config(device *   dev)
   if(wv_pcmcia_reset(dev) == FALSE)
     return FALSE;
 
-  /* Power UP the module + reset the modem + reset host adapter
-   * (in fact, reset DMA channels) */
-  hacr_write_slow(base, HACR_RESET);
-  hacr_write(base, HACR_DEFAULT);
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
 
-  /* Check if the module has been powered up... */
-  if(hasr_read(base) & HASR_NO_CLK)
+  /* Disguised goto ;-) */
+  do
     {
+      /* Power UP the module + reset the modem + reset host adapter
+       * (in fact, reset DMA channels) */
+      hacr_write_slow(base, HACR_RESET);
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+       {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
-            dev->name);
+         printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+                dev->name);
 #endif
-      return FALSE;
-    }
+         break;
+       }
 
-  /* initialize the modem */
-  if(wv_mmc_init(dev) == FALSE)
-    return FALSE;
+      /* initialize the modem */
+      if(wv_mmc_init(dev) == FALSE)
+       {
+#ifdef DEBUG_CONFIG_ERRORS
+         printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+                dev->name);
+#endif
+         break;
+       }
 
-  /* reset the LAN controller (i82593) */
-  outb(OP0_RESET, LCCR(base));
-  mdelay(1);   /* A bit crude ! */
+      /* reset the LAN controller (i82593) */
+      outb(OP0_RESET, LCCR(base));
+      mdelay(1);       /* A bit crude ! */
 
-  /* Initialize the LAN controller */
-  if((wv_82593_config(dev) == FALSE) ||
-     (wv_diag(dev) == FALSE))
-    {
+      /* Initialize the LAN controller */
+      if(wv_82593_config(dev) == FALSE)
+       {
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+         printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+                dev->name);
 #endif
-      return FALSE;
-    }
+         break;
+       }
 
-  /* 
-   * insert code for loopback test here
-   */
+      /* Diagnostic */
+      if(wv_diag(dev) == FALSE)
+       {
+#ifdef DEBUG_CONFIG_ERRORS
+         printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+                dev->name);
+#endif
+         break;
+       }
+
+      /* 
+       * insert code for loopback test here
+       */
 
-  /* The device is now configured */
-  lp->configured = 1;
+      /* The device is now configured */
+      lp->configured = 1;
+      ret = TRUE;
+    }
+  while(0);
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
 #endif
-  return TRUE;
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3675,10 +3720,6 @@ wv_hw_reset(device *     dev)
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
 #endif
 
-  /* If watchdog was activated, kill it ! */
-  if (timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   lp->nresets++;
   lp->configured = 0;
   
@@ -3786,13 +3827,13 @@ wv_pcmcia_config(dev_link_t *   link)
        }
 
       /*
-       * Allocate a 4K memory window.  Note that the dev_link_t
+       * Allocate a small memory window.  Note that the dev_link_t
        * structure provides space for one window handle -- if your
        * device needs several windows, you'll need to keep track of
        * the handles in your private data structure, link->priv.
        */
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-      req.Base = 0; req.Size = 0x1000;
+      req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       link->win = (window_handle_t)link->handle;
       i = CardServices(RequestWindow, &link->win, &req);
@@ -3803,7 +3844,7 @@ wv_pcmcia_config(dev_link_t *     link)
        }
 
       dev->rmem_start = dev->mem_start =
-         (u_long)ioremap(req.Base, 0x1000);
+         (u_long)ioremap(req.Base, req.Size);
       dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
 
       mem.CardOffset = 0; mem.Page = 0;
@@ -3817,7 +3858,7 @@ wv_pcmcia_config(dev_link_t *     link)
       /* Feed device with this info... */
       dev->irq = link->irq.AssignedIRQ;
       dev->base_addr = link->io.BasePort1;
-      netif_start_queue (dev);
+      netif_start_queue(dev);
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3843,7 +3884,7 @@ wv_pcmcia_config(dev_link_t *     link)
       return FALSE;
     }
 
-  /* XXX Could you explain me this, Dave ? */
+  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
   link->dev = &((net_local *) dev->priv)->node;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3887,7 +3928,7 @@ wv_pcmcia_release(u_long  arg)    /* Address of the interface struct */
   CardServices(ReleaseIO, link->handle, &link->io);
   CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
@@ -3896,7 +3937,7 @@ wv_pcmcia_release(u_long  arg)    /* Address of the interface struct */
 
 /*------------------------------------------------------------------*/
 /*
- * Sometimes, netwave_detach can't be performed following a call from
+ * Sometimes, wavelan_detach can't be performed following a call from
  * cardmgr (device still open, pcmcia_release not done) and the device
  * is put in a STALE_LINK state and remains in memory.
  *
@@ -3970,7 +4011,19 @@ wavelan_interrupt(int            irq,
   lp = (net_local *) dev->priv;
   base = dev->base_addr;
 
-  spin_lock (&lp->lock);
+#ifdef DEBUG_INTERRUPT_INFO
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_DEBUG
+          "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+          dev->name);
+#endif
+
+  /* Prevent reentrancy. We need to do that because we may have
+   * multiple interrupt handler running concurently.
+   * It is safe because wv_splhi() disable interrupts before aquiring
+   * the spinlock. */
+  spin_lock(&lp->spinlock);
 
   /* Treat all pending interrupts */
   while(1)
@@ -4015,8 +4068,6 @@ wavelan_interrupt(int             irq,
          break;
        }
 
-      lp->status = status0;    /* Save current status (for commands) */
-
       /* ----------------- RECEIVING PACKET ----------------- */
       /*
        * When the wavelan signal the reception of a new packet,
@@ -4054,22 +4105,6 @@ wavelan_interrupt(int            irq,
        * Most likely : transmission done
        */
 
-      /* If we are already waiting elsewhere for the command to complete */
-      if(wv_wait_completed)
-       {
-#ifdef DEBUG_INTERRUPT_INFO
-         printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
-                dev->name);
-#endif
-
-         /* Signal command completion */
-         wv_wait_completed = 0;
-
-         /* Acknowledge the interrupt */
-         outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-         continue;
-       }
-
       /* If a transmission has been done */
       if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
         (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
@@ -4081,10 +4116,6 @@ wavelan_interrupt(int            irq,
                   dev->name);
 #endif
 
-         /* If watchdog was activated, kill it ! */
-         if(timer_pending(&lp->watchdog))
-           del_timer(&lp->watchdog);
-
          /* Get transmission status */
          tx_status = inb(LCSR(base));
          tx_status |= (inb(LCSR(base)) << 8);
@@ -4174,7 +4205,7 @@ wavelan_interrupt(int             irq,
          lp->stats.collisions += (tx_status & TX_NCOL_MASK);
          lp->stats.tx_packets++;
 
-         netif_wake_queue (dev);
+         netif_wake_queue(dev);
          outb(CR0_INT_ACK | OP0_NOP, LCCR(base));      /* Acknowledge the interrupt */
        } 
       else     /* if interrupt = transmit done or retransmit done */
@@ -4185,9 +4216,9 @@ wavelan_interrupt(int             irq,
 #endif
          outb(CR0_INT_ACK | OP0_NOP, LCCR(base));      /* Acknowledge the interrupt */
        }
-    }
+    }  /* while(1) */
 
-  spin_unlock_irq (&lp->lock);
+  spin_unlock(&lp->spinlock);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4196,30 +4227,23 @@ wavelan_interrupt(int           irq,
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
  */
 static void
-wavelan_watchdog(u_long                a)
+wavelan_watchdog(device *      dev)
 {
-  device *             dev;
-  net_local *          lp;
-  ioaddr_t             base;
-  int                  spin;
-
-  dev = (device *) a;
-  base = dev->base_addr;
-  lp = (net_local *) dev->priv;
+  net_local *          lp = (net_local *) dev->priv;
+  ioaddr_t             base = dev->base_addr;
+  unsigned long                flags;
+  int                  aborted = FALSE;
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -4230,21 +4254,21 @@ wavelan_watchdog(u_long         a)
         dev->name);
 #endif
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  wv_splhi(lp, &flags);
 
   /* Ask to abort the current command */
   outb(OP0_ABORT, LCCR(base));
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 250))
-    udelay(10);
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+                 OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
 
-  /* If the interrupt handler hasn't be called or invalid status */
-  if((wv_wait_completed) ||
-     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+  /* Check if we were successful in aborting it */
+  if(!aborted)
     {
       /* It seem that it wasn't enough */
 #ifdef DEBUG_INTERRUPT_ERROR
@@ -4269,7 +4293,7 @@ wavelan_watchdog(u_long           a)
 #endif
 
   /* We are no more waiting for something... */
-  netif_start_queue (dev);
+  netif_wake_queue(dev);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4322,7 +4346,7 @@ wavelan_open(device *     dev)
     return FALSE;
   if(!wv_ru_start(dev))
     wv_hw_reset(dev);          /* If problem : reset */
-  netif_start_queue (dev);
+  netif_start_queue(dev);
 
   /* Mark the device as used */
   link->open++;
@@ -4348,7 +4372,6 @@ static int
 wavelan_close(device * dev)
 {
   dev_link_t * link = ((net_local *) dev->priv)->link;
-  net_local *  lp = (net_local *)dev->priv;
   ioaddr_t     base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4356,8 +4379,6 @@ wavelan_close(device *    dev)
         (unsigned int) dev);
 #endif
 
-  netif_stop_queue (dev);
-
   /* If the device isn't open, then nothing to do */
   if(!link->open)
     {
@@ -4373,17 +4394,13 @@ wavelan_close(device *  dev)
     wv_roam_cleanup(dev);
 #endif /* WAVELAN_ROAMING */
 
-  /* If watchdog was activated, kill it ! */
-  if(timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   link->open--;
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if (netif_device_present(dev))
+  if(netif_running(dev))
     {
-      netif_stop_queue (dev);
+      netif_stop_queue(dev);
 
       /* Stop receiving new messages and wait end of transmission */
       wv_ru_stop(dev);
@@ -4402,21 +4419,6 @@ wavelan_close(device *   dev)
   return 0;
 }
 
-/*------------------------------------------------------------------*/
-/*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device *  dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
-  return(0);
-}
-
 /*------------------------------------------------------------------*/
 /*
  * wavelan_attach() creates an "instance" of the driver, allocating
@@ -4445,24 +4447,8 @@ wavelan_attach(void)
 
   /* Initialize the dev_link_t structure */
   link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link)
-         return NULL;
-  
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  if (!dev)
-         goto fail_alloc_dev;
-  
-  /* Allocate the wavelan-specific data structure. */
-  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  if (!lp)
-         goto fail_alloc_dev_priv;
-  
-  memset(lp, 0, sizeof(net_local));
+  if (!link) return NULL;
   memset(link, 0, sizeof(struct dev_link_t));
-  memset(dev, 0, sizeof(struct net_device));
-
-  dev->priv = lp;
 
   /* Unused for the Wavelan */
   link->release.function = &wv_pcmcia_release;
@@ -4492,18 +4478,35 @@ wavelan_attach(void)
   link->next = dev_list;
   dev_list = link;
 
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev) {
+      kfree(link);
+      return NULL;
+  }
+  memset(dev, 0x00, sizeof(struct net_device));
   link->priv = link->irq.Instance = dev;
 
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp) {
+      kfree(link);
+      kfree(dev);
+      return NULL;
+  }
+  memset(lp, 0x00, sizeof(net_local));
+
   /* Init specific data */
-  wv_wait_completed = 0;
-  lp->status = FALSE;
   lp->configured = 0;
   lp->reconfig_82593 = FALSE;
   lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
 
-  /* Set the watchdog timer */
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
 
   /* back links */
   lp->link = link;
@@ -4513,7 +4516,6 @@ wavelan_attach(void)
   ether_setup(dev);
 
   /* wavelan NET3 callbacks */
-  dev->init = &wavelan_init;
   dev->open = &wavelan_open;
   dev->stop = &wavelan_close;
   dev->hard_start_xmit = &wavelan_packet_xmit;
@@ -4523,14 +4525,16 @@ wavelan_attach(void)
   dev->set_mac_address = &wavelan_set_mac_address;
 #endif /* SET_MAC_ADDRESS */
 
+  /* Set the watchdog timer */
+  dev->tx_timeout      = &wavelan_watchdog;
+  dev->watchdog_timeo  = WATCHDOG_JIFFIES;
+
 #ifdef WIRELESS_EXT    /* If wireless extension exist in the kernel */
   dev->do_ioctl = wavelan_ioctl;       /* wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   /* Other specific data */
-  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
-  netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
   /* Register with Card Services */
@@ -4562,12 +4566,6 @@ wavelan_attach(void)
 #endif
 
   return link;
-
-fail_alloc_dev_priv:
-  kfree(dev);
-fail_alloc_dev:
-  kfree(link);
-  return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -4698,7 +4696,7 @@ wavelan_event(event_t             event,          /* The event received */
        if(link->state & DEV_CONFIG)
          {
            /* Accept no more transmissions */
-           netif_device_detach(dev);
+           netif_device_detach(dev);
 
            /* Release the card */
            wv_pcmcia_release((u_long) link);
@@ -4720,7 +4718,7 @@ wavelan_event(event_t             event,          /* The event received */
         * obliged to close nicely the wavelan here. David, could you
         * close the device before suspending them ? And, by the way,
         * could you, on resume, add a "route add -net ..." after the
-        * ifconfig up XXX Thanks... */
+        * ifconfig up ??? Thanks... */
 
        /* Stop receiving new messages and wait end of transmission */
        wv_ru_stop(dev);
@@ -4735,8 +4733,7 @@ wavelan_event(event_t             event,          /* The event received */
        if(link->state & DEV_CONFIG)
          {
            if(link->open)
-               netif_device_detach(dev);
-
+             netif_device_detach(dev);
            CardServices(ReleaseConfiguration, link->handle);
          }
        break;
@@ -4748,7 +4745,7 @@ wavelan_event(event_t             event,          /* The event received */
        if(link->state & DEV_CONFIG)
          {
            CardServices(RequestConfiguration, link->handle, &link->conf);
-           if(link->open)      /* If RESET -> True, If RESUME -> False XXX */
+           if(link->open)      /* If RESET -> True, If RESUME -> False ??? */
              {
                wv_hw_reset(dev);
                netif_device_attach(dev);
@@ -4838,4 +4835,3 @@ exit_wavelan_cs(void)
 
 module_init(init_wavelan_cs);
 module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
index 6b613414c770a6ffd55c260a697941f7b55079c1..b0f6e417254b3456abee79330ba979912488c970 100644 (file)
  *     I try to maintain a web page with the Wireless LAN Howto at :
  *         http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
  *
+ * SMP
+ * ---
+ *     We now are SMP compliant (I eventually fixed the remaining bugs).
+ *     The driver has been tested on a dual P6-150 and survived my usual
+ *     set of torture tests.
+ *     Anyway, I spent enough time chasing interrupt re-entrancy during
+ *     errors or reconfigure, and I designed the locked/unlocked sections
+ *     of the driver with great care, and with the recent addition of
+ *     the spinlock (thanks to the new API), we should be quite close to
+ *     the truth.
+ *     The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *     but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *     I have also looked into disabling only our interrupt on the card
+ *     (via HACR) instead of all interrupts in the processor (via cli),
+ *     so that other driver are not impacted, and it look like it's
+ *     possible, but it's very tricky to do right (full of races). As
+ *     the gain would be mostly for SMP systems, it can wait...
+ *
  * Debugging and options
  * ---------------------
  *     You will find below a set of '#define" allowing a very fine control
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * correctly 2.00 cards (2.4 GHz with frequency selection).
- * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * Pcmcia package (+ bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
  *
  *    This software was originally developed under Linux 1.2.3
  *     (Slackware 2.0 distribution).
- *    And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
- *     HP OmniBook 4000 & 5500.
+ *    And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ *     with an HP OmniBook 4000 and then a 5500.
  *
  *    It is based on other device drivers and information either written
  *    or supplied by:
  *     Matthew Geier (matthew@cs.su.oz.au),
  *     Remo di Giovanni (remo@cs.su.oz.au),
  *     Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *     David Hinds <dhinds@pcmcia.sourceforge.org>,
+ *     David Hinds <dahinds@users.sourceforge.net>,
  *     Jan Hoogendoorn (c/o marteijn@lucent.com),
  *      Bruce Janson <bruce@cs.usyd.edu.au>,
  *     Anthony D. Joseph <adj@lcs.mit.edu>,
  *     - Fix check for root permission (break instead of exit)
  *     - New nwid & encoding setting (Wireless Extension 9)
  *
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ *     - reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ *       ugly things with interrupts.
+ *     - Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ *     - Update to new network API (softnet - 2.3.43) :
+ *             o replace dev->tbusy (David + me)
+ *             o replace dev->tstart (David + me)
+ *             o remove dev->interrupt (David)
+ *             o add SMP locking via spinlock in splxx (me)
+ *             o add spinlock in interrupt handler (me)
+ *             o use kernel watchdog instead of ours (me)
+ *             o verify that all the changes make sense and work (me)
+ *     - Re-sync kernel/pcmcia versions (not much actually)
+ *     - A few other cleanups (David & me)...
+ *
+ * Changes made for release in 3.1.22 :
+ * ----------------------------------
+ *     - Check that SMP works, remove annoying log message
+ *
+ * Changes made for release in 3.1.24 :
+ * ----------------------------------
+ *     - Fix unfrequent card lockup when watchdog was reseting the hardware :
+ *             o control first busy loop in wv_82593_cmd()
+ *             o Extend spinlock protection in wv_hw_config()
+ *
  * Wishes & dreams:
  * ----------------
  *     - Cleanup and integrate the roaming code
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/in.h>
 #include <linux/delay.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_NET_PCMCIA_RADIO
 #include <linux/wireless.h>            /* Wireless extensions */
-#endif /* CONFIG_NET_PCMCIA_RADIO */
+#endif
 
 /* Pcmcia headers that we need */
 #include <pcmcia/cs_types.h>
 #undef DEBUG_RX_INFO           /* Header of the transmitted packet */
 #undef DEBUG_RX_FAIL           /* Normal failure conditions */
 #define DEBUG_RX_ERROR         /* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP       /* Dump packet on the screen */
+#undef DEBUG_PACKET_DUMP       32      /* Dump packet on the screen */
 #undef DEBUG_IOCTL_TRACE       /* Misc call by Linux */
 #undef DEBUG_IOCTL_INFO                /* Various debug info */
 #define DEBUG_IOCTL_ERROR      /* What's going wrong */
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
+static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
 #endif
 
 /* Watchdog temporisation */
@@ -557,9 +603,9 @@ typedef u_char              mac_addr[WAVELAN_ADDR_SIZE];    /* Hardware address */
  */
 struct net_local
 {
-  spinlock_t   lock;
   dev_node_t   node;           /* ???? What is this stuff ???? */
   device *     dev;            /* Reverse link... */
+  spinlock_t   spinlock;       /* Serialize access to the hardware (SMP) */
   dev_link_t * link;           /* pcmcia structure */
   en_stats     stats;          /* Ethernet interface statistics */
   int          nresets;        /* Number of hw resets */
@@ -568,9 +614,7 @@ struct net_local
   u_char       promiscuous;    /* Promiscuous mode */
   u_char       allmulticast;   /* All Multicast mode */
   int          mc_count;       /* Number of multicast addresses */
-  timer_list   watchdog;       /* To avoid blocking state */
 
-  u_char        status;                /* Current i82593 status */
   int          stop;           /* Current i82593 Stop Hit Register */
   int          rfp;            /* Last DMA machine receive pointer */
   int          overrunning;    /* Receiver overrun flag */
@@ -617,8 +661,14 @@ void wv_roam_cleanup(struct net_device *dev);
 #endif /* WAVELAN_ROAMING */
 
 /* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+       wv_splhi(net_local *,           /* Disable interrupts */
+                unsigned long *);      /* flags */
+static inline void
+       wv_splx(net_local *,            /* ReEnable interrupts */
+               unsigned long *);       /* flags */
 static void
-       cs_error(client_handle_t, /* Report error to cardmgr */
+       cs_error(client_handle_t,       /* Report error to cardmgr */
                 int,
                 int);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
@@ -722,16 +772,15 @@ static void
        wv_flush_stale_links(void);     /* "detach" all possible devices */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static void
-wavelan_interrupt(int, /* Interrupt handler */
-                 void *,
-                 struct pt_regs *);
+       wavelan_interrupt(int,  /* Interrupt handler */
+                         void *,
+                         struct pt_regs *);
 static void
-       wavelan_watchdog(u_long);       /* Transmission watchdog */
+       wavelan_watchdog(device *);     /* Transmission watchdog */
 /* ------------------- CONFIGURATION CALLBACKS ------------------- */
 static int
        wavelan_open(device *),         /* Open the device */
-       wavelan_close(device *),        /* Close the device */
-       wavelan_init(device *);         /* Do nothing */
+       wavelan_close(device *);        /* Close the device */
 static dev_link_t *
        wavelan_attach(void);           /* Create a new device */
 static void
@@ -744,11 +793,7 @@ static int
 /**************************** VARIABLES ****************************/
 
 static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list;           /* Linked list of devices */
-
-/* WARNING : the following variable MUST be volatile
- * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
-static volatile int    wv_wait_completed;
+static dev_link_t *dev_list = NULL;    /* Linked list of devices */
 
 /*
  * Parameters that can be set with 'insmod'
@@ -761,7 +806,7 @@ static int  irq_mask = 0xdeb8;
 static int     irq_list[4] = { -1 };
 
 /* Shared memory speed, in ns */
-static int     mem_speed;
+static int     mem_speed = 0;
 
 /* New module interface */
 MODULE_PARM(irq_mask, "i");
@@ -770,9 +815,11 @@ MODULE_PARM(mem_speed, "i");
 
 #ifdef WAVELAN_ROAMING         /* Conditional compile, see above in options */
 /* Enable roaming mode ? No ! Please keep this to 0 */
-static int     do_roaming;
+static int     do_roaming = 0;
 MODULE_PARM(do_roaming, "i");
 #endif /* WAVELAN_ROAMING */
 
+MODULE_LICENSE("GPL");
+
 #endif /* WAVELAN_CS_H */
 
index 735c0d17eeb4c6aa036df815849c2584faf1bfbe..766376671e9567fc24972b1104f51e250e753cab 100644 (file)
@@ -1039,3 +1039,5 @@ void __init nubus_init(void)
        nubus_proc_init();
 #endif
 }
+
+subsys_initcall(nubus_init);
index 129450bf68156be68a543944063b45a06bad0bc8..f5ed5694b8af2063664d8d85e51f178057971b4b 100644 (file)
@@ -1,3 +1,23 @@
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+       * ieee1284_ops.c (parport_ieee1284_epp_write_addr,
+       parport_ieee1284_epp_read_addr): Actually do something useful.
+
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+       * parport_pc.c (dmaval): Don't use DMA by default.  It seems to be
+       too buggy at the moment.  Use 'dma=auto' to restore the previous
+       behaviour.
+
+2001-12-03  Rich Liu  <Rich.Liu@ite.com.tw>
+
+       * parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port
+       serial board, not a serial+parallel.
+
+2001-11-30  Niels Kristian Bech Jensen  <nkbj@image.dk>
+
+       * parport_pc.c: Fix compiler warning.
+
 2001-12-06  Tim Waugh  <twaugh@redhat.com>
 
        * ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off
index 1000fe08823ea29c45869e0d94e02efccf0fdaa5..fa32e769636b67bc8607c3e0b67c2d456188397b 100644 (file)
@@ -128,7 +128,7 @@ int parport_poll_peripheral(struct parport *port,
                        return 0;
                if (signal_pending (current))
                        return -EINTR;
-               if (current->need_resched)
+               if (need_resched())
                        break;
                if (i >= 2)
                        udelay (5);
index 8fcd6f2f103c89d6470a67d7b7b6f0f6bef9401f..23263479e1ae7e25661f5ee834aa351319e9771d 100644 (file)
@@ -136,7 +136,7 @@ size_t parport_ieee1284_write_compat (struct parport *port,
                 /* Let another process run if it needs to. */
                if (time_before (jiffies, expire))
                        if (!parport_yield_blocking (dev)
-                           && current->need_resched)
+                           && need_resched())
                                schedule ();
        }
  stop:
@@ -824,35 +824,40 @@ size_t parport_ieee1284_epp_write_addr (struct parport *port,
                                        const void *buffer, size_t len,
                                        int flags)
 {
-       /* This is untested */
        unsigned char *bp = (unsigned char *) buffer;
        size_t ret = 0;
 
+       /* set EPP idle state (just to make sure) with strobe low */
        parport_frob_control (port,
                              PARPORT_CONTROL_STROBE |
+                             PARPORT_CONTROL_AUTOFD |
                              PARPORT_CONTROL_SELECT |
-                             PARPORT_CONTROL_AUTOFD,
+                             PARPORT_CONTROL_INIT,
                              PARPORT_CONTROL_STROBE |
-                             PARPORT_CONTROL_SELECT);
+                             PARPORT_CONTROL_INIT);
        port->ops->data_forward (port);
        for (; len > 0; len--, bp++) {
-               /* Write data and assert nAStrb. */
+               /* Event 56: Write data and set nAStrb low. */
                parport_write_data (port, *bp);
                parport_frob_control (port, PARPORT_CONTROL_SELECT,
                                      PARPORT_CONTROL_SELECT);
 
-               if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-                                            PARPORT_STATUS_BUSY, 10))
+               /* Event 58: wait for busy (nWait) to go high */
+               if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
                        break;
 
+               /* Event 59: set nAStrb high */
                parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
 
-               if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+               /* Event 60: wait for busy (nWait) to go low */
+               if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
+                                            PARPORT_STATUS_BUSY, 5))
                        break;
 
                ret++;
        }
 
+       /* Event 61: set strobe (nWrite) high */
        parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 
        return ret;
@@ -863,28 +868,36 @@ size_t parport_ieee1284_epp_read_addr (struct parport *port,
                                       void *buffer, size_t len,
                                       int flags)
 {
-       /* This is untested. */
        unsigned char *bp = (unsigned char *) buffer;
        unsigned ret = 0;
 
+       /* Set EPP idle state (just to make sure) with strobe high */
        parport_frob_control (port,
                              PARPORT_CONTROL_STROBE |
-                             PARPORT_CONTROL_AUTOFD, 0);
+                             PARPORT_CONTROL_AUTOFD |
+                             PARPORT_CONTROL_SELECT |
+                             PARPORT_CONTROL_INIT,
+                             PARPORT_CONTROL_INIT);
        port->ops->data_reverse (port);
        for (; len > 0; len--, bp++) {
-               parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+               /* Event 64: set nSelectIn (nAStrb) low */
+               parport_frob_control (port, PARPORT_CONTROL_SELECT,
+                                     PARPORT_CONTROL_SELECT);
 
-               /* Event 58 */
-               if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-                                            PARPORT_STATUS_BUSY, 10))
+               /* Event 58: wait for Busy to go high */
+               if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
                        break;
+               }
 
                *bp = parport_read_data (port);
 
+               /* Event 59: set nSelectIn (nAStrb) high */
                parport_frob_control (port, PARPORT_CONTROL_SELECT,
                                      PARPORT_CONTROL_SELECT);
 
-               if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+               /* Event 60: wait for Busy to go low */
+               if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 
+                                            PARPORT_STATUS_BUSY, 5))
                        break;
 
                ret++;
index 0c5c82a3bebd1b1edbe0df30be310f5f5eab676f..45e1abded4a0cac763215f385ae5db7e97b5cdbf 100644 (file)
@@ -91,7 +91,9 @@ static struct superio_struct {        /* For Super-IO chips autodetection */
 } superios[NR_SUPERIOS] __devinitdata = { {0,},};
 
 static int user_specified __devinitdata = 0;
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 static int verbose_probing;
+#endif
 static int registered_parport;
 
 /* frob_control, but for ECR */
@@ -596,7 +598,7 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
                unsigned char ecrval = inb (ECONTROL (port));
                int i = 0;
 
-               if (current->need_resched && time_before (jiffies, expire))
+               if (need_resched() && time_before (jiffies, expire))
                        /* Can't yield the port. */
                        schedule ();
 
@@ -622,7 +624,7 @@ static size_t parport_pc_fifo_write_block_pio (struct parport *port,
                        }
                        ecrval = inb (ECONTROL (port));
                        if (!(ecrval & (1<<2))) {
-                               if (current->need_resched &&
+                               if (need_resched() &&
                                    time_before (jiffies, expire))
                                        schedule ();
 
@@ -746,8 +748,7 @@ dump_parport_state ("enter fifo_write_block_dma", port);
                }
                /* Is serviceIntr set? */
                if (!(inb (ECONTROL (port)) & (1<<2))) {
-                       if (current->need_resched)
-                               schedule ();
+                       cond_resched();
 
                        goto false_alarm;
                }
@@ -758,9 +759,7 @@ dump_parport_state ("enter fifo_write_block_dma", port);
                count = get_dma_residue(port->dma);
                release_dma_lock(dmaflag);
 
-               if (current->need_resched)
-                       /* Can't yield the port. */
-                       schedule ();
+               cond_resched(); /* Can't yield the port. */
 
                /* Anyone else waiting for the port? */
                if (port->waithead) {
@@ -1093,7 +1092,7 @@ dump_parport_state ("rev idle", port);
                long int expire = jiffies + port->cad->timeout;
                unsigned char ecrval = inb (ECONTROL (port));
 
-               if (current->need_resched && time_before (jiffies, expire))
+               if (need_resched() && time_before (jiffies, expire))
                        /* Can't yield the port. */
                        schedule ();
 
@@ -1130,7 +1129,7 @@ dump_parport_state ("timeout", port);
                        }
                        ecrval = inb (ECONTROL (port));
                        if (!(ecrval & (1<<2))) {
-                               if (current->need_resched &&
+                               if (need_resched() &&
                                    time_before (jiffies, expire)) {
                                        schedule ();
                                }
@@ -1780,6 +1779,7 @@ static int __devinit parport_PS2_supported(struct parport *pb)
        return ok;
 }
 
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb)
 {
        int i;
@@ -1905,6 +1905,7 @@ static int __devinit parport_ECP_supported(struct parport *pb)
 
        return 1;
 }
+#endif
 
 static int __devinit parport_ECPPS2_supported(struct parport *pb)
 {
@@ -2004,7 +2005,9 @@ static int __devinit parport_ECPEPP_supported(struct parport *pb)
 
 /* Don't bother probing for modes we know we won't use. */
 static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
+#endif
 static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
 static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
 static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
@@ -2453,9 +2456,8 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
                ite8872set = 0x64e00000;
                break;
        case 0x6:
-               printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n");
-               ite8872set = 0x64a00000;
-               break;
+               printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n");
+               return 0;
        case 0x8:
                DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
                return 0;
@@ -3007,7 +3009,7 @@ EXPORT_SYMBOL (parport_pc_unregister_port);
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int io_hi[PARPORT_PC_MAX_PORTS+1] =
        { [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
-static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
@@ -3024,8 +3026,10 @@ MODULE_PARM_DESC(irq, "IRQ line");
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM_DESC(dma, "DMA channel");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(verbose_probing, "i");
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
+MODULE_PARM(verbose_probing, "i");
+#endif
 
 int init_module(void)
 {      
index 471ae4bb3e398936a7faa15131029dddc9a77ba6..28af5d0f596b998a8a0c74809d98e2d3523f490c 100644 (file)
@@ -1929,7 +1929,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 +1942,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 +1960,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 9835bfccf1df95398d1521d41bb2de590b2c6c36..361fa6b70fa61763145b4700465befdb503d0f74 100644 (file)
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3G"    /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3GG"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
          1. Return an error from narrow boards if passed a 16 byte
             CDB. The wide board can already handle 16 byte CDBs.
 
+     3.3GG (01/02/02):
+        1. hacks for lk 2.5 series (D. Gilbert)
+
   I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -3610,6 +3613,23 @@ typedef struct {
 #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif /* CONFIG_PROC_FS */
 
+/*
+ * XXX - Release and acquire the io_request_lock. These macros are needed
+ * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
+ * on entry to SCSI low-level drivers.
+ *
+ * These definitions and all code that uses code should be removed when the
+ * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
+ * SCSI low-level driver detect, queuecommand, and reset entrypoints.
+ *
+ * The interrupt flags values doesn't matter in the macros because the
+ * SCSI mid-level will save and restore the flags values before and after
+ * calling advansys_detect, advansys_queuecommand, and advansys_reset where
+ * these macros are used. We do want interrupts enabled after the lock is
+ * released so an explicit sti() is done. The driver only needs interrupts
+ * disabled when it acquires the per board lock.
+ */
+
 /* Asc Library return codes */
 #define ASC_TRUE        1
 #define ASC_FALSE       0
@@ -4054,6 +4074,7 @@ typedef struct asc_board {
         ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
+    spinlock_t lock;                            /* Board spinlock */
 #ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
     char                 *prtbuf;               /* /proc print buffer */
@@ -4206,7 +4227,7 @@ STATIC PortAddr     _asc_def_iop_base[];
 STATIC void       advansys_interrupt(int, void *, struct pt_regs *);
 STATIC void       advansys_select_queue_depths(struct Scsi_Host *,
                                                Scsi_Device *);
-STATIC void       asc_scsi_done_list(Scsi_Cmnd *);
+STATIC void       asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
@@ -4799,6 +4820,9 @@ advansys_detect(Scsi_Host_Template *tpnt)
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
+            /* Initialize spinlock. */
+            boardp->lock = SPIN_LOCK_UNLOCKED; /* replaced by host_lock dpg */
+
             /*
              * Handle both narrow and wide boards.
              *
@@ -5511,7 +5535,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
                 }
             } else {
                 ADV_CARR_T      *carrp;
-                int             req_cnt;
+                int             req_cnt = 0;
                 adv_req_t       *reqp = NULL;
                 int             sg_cnt = 0;
 
@@ -5845,7 +5869,9 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
     boardp = ASC_BOARDP(shp);
     ASC_STATS(shp, queuecommand);
 
-    spin_lock_irqsave(&shp->host_lock, flags);
+    /* host_lock taken by mid-level prior to call but need to protect */
+    /* against own ISR */
+    spin_lock_irqsave(&boardp->lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
@@ -5862,7 +5888,7 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+       spin_unlock_irqrestore(&boardp->lock, flags);
         return 0;
     }
 
@@ -5902,11 +5928,11 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *))
     default:
         done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
         /* Interrupts could be enabled here. */
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
         break;
     }
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
-    spin_unlock_irqrestore(&shp->host_lock, flags);
     return 0;
 }
 
@@ -5952,13 +5978,13 @@ advansys_reset(Scsi_Cmnd *scp)
     /*
      * Check for re-entrancy.
      */
-    spin_lock_irqsave(&shp->host_lock, flags);
+    spin_lock_irqsave(&boardp->lock, flags);
     if (boardp->flags & ASC_HOST_IN_RESET) {
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+       spin_unlock_irqrestore(&boardp->lock, flags);
         return FAILED;
     }
     boardp->flags |= ASC_HOST_IN_RESET;
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     if (ASC_NARROW_BOARD(boardp)) {
         /*
@@ -5989,11 +6015,7 @@ advansys_reset(Scsi_Cmnd *scp)
         }
 
         ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-
-        /*
-         * Acquire the board lock.
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+       spin_lock_irqsave(&boardp->lock, flags);
 
     } else {
         /*
@@ -6020,14 +6042,9 @@ advansys_reset(Scsi_Cmnd *scp)
             ret = FAILED;
             break;
         }
-        /*
-         * Acquire the board lock and ensure all requests completed by the
-         * microcode have been processed by calling AdvISR().
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+       spin_lock_irqsave(&boardp->lock, flags);
         (void) AdvISR(adv_dvc_varp);
     }
-
     /* Board lock is held. */
 
     /*
@@ -6088,15 +6105,13 @@ advansys_reset(Scsi_Cmnd *scp)
 
     /* Clear reset flag. */
     boardp->flags &= ~ASC_HOST_IN_RESET;
-
-    /* Release the board. */
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     /*
      * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
     }
 
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6259,6 +6274,7 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     asc_board_t     *boardp;
     Scsi_Cmnd       *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd       *new_last_scp;
+    struct Scsi_Host *shp;
 
     ASC_DBG(1, "advansys_interrupt: begin\n");
 
@@ -6267,17 +6283,17 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
      * AscISR() will call asc_isr_callback().
      */
     for (i = 0; i < asc_board_count; i++) {
-       struct Scsi_Host *shp = asc_host[i];
+       shp = asc_host[i];
         boardp = ASC_BOARDP(shp);
         ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
             i, (ulong) boardp);
-        spin_lock_irqsave(&shp->host_lock, flags);
+        spin_lock_irqsave(&boardp->lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
              */
-            if (AscIsIntPending(asc_host[i]->io_port)) {
-                ASC_STATS(asc_host[i], interrupt);
+            if (AscIsIntPending(shp->io_port)) {
+                ASC_STATS(shp, interrupt);
                 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
                 AscISR(&boardp->dvc_var.asc_dvc_var);
             }
@@ -6287,7 +6303,7 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
              */
             ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
             if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
-                ASC_STATS(asc_host[i], interrupt);
+                ASC_STATS(shp, interrupt);
             }
         }
 
@@ -6327,7 +6343,7 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                 }
             }
         }
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+        spin_unlock_irqrestore(&boardp->lock, flags);
     }
 
     /*
@@ -6336,7 +6352,8 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
      *
      * Complete all requests on the done list.
      */
-    asc_scsi_done_list(done_scp);
+
+    asc_scsi_done_list(done_scp, 1);
 
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
@@ -6383,9 +6400,10 @@ advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
  * Interrupts can be enabled on entry.
  */
 STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp)
+asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
 {
     Scsi_Cmnd    *tscp;
+    ulong        flags = 0;
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
@@ -6394,7 +6412,11 @@ asc_scsi_done_list(Scsi_Cmnd *scp)
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
+       if (from_isr)
+           spin_lock_irqsave(&scp->host->host_lock, flags);
         scp->scsi_done(scp);
+       if (from_isr)
+           spin_unlock_irqrestore(&scp->host->host_lock, flags);
         scp = tscp;
     }
     ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6728,7 +6750,9 @@ asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
             asc_sg_head.sg_list[sgcnt].addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+               (unsigned char *)slp->address :
+               (unsigned char *)page_address(slp->page) + slp->offset));
             asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
@@ -6986,7 +7010,9 @@ adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp)
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+               (unsigned char *)slp->address :
+                (unsigned char *)page_address(slp->page) + slp->offset));
             sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
index e656d4d081a2e96e04ea6f7bece84c7d4cca3487..5e0029feecc8d7484f591add9ab3dae3ded755ac 100644 (file)
@@ -1700,6 +1700,7 @@ ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
                               cmd->request_buffer,
                               cmd->request_bufflen,
                               scsi_to_pci_dma_dir(cmd->sc_data_direction));
+                       scb->sg_count = 0;
                        scb->sg_count = ahc_linux_map_seg(ahc, scb,
                                                          sg, addr,
                                                          cmd->request_bufflen);
index fda3c65283354b10626593b1e844a49172a7f018..48b82933be05a67ea6db80007f5b05d2450307ef 100644 (file)
@@ -3,8 +3,19 @@
  *
  *  Copyright (C) 1992  Eric Youngdale
  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
- *  to make sure that we are not getting blocks mixed up, and panic if
+ *  to make sure that we are not getting blocks mixed up, and PANIC if
  *  anything out of the ordinary is seen.
+ *
+ *  This version is more generic, simulating a variable number of disk 
+ *  (or disk like devices) sharing a common amount of RAM (default 8 MB
+ *  but can be set at driver/module load time).
+ *
+ *  For documentation see http://www.torque.net/sg/sdebug.html
+ *
+ *   D. Gilbert (dpg) work for MOD device test [20010421]
+ *   dpg, work for devfs large number of disks [20010809]
+ *   dpg, make more generic [20011123]
+ *   dpg, forked for lk 2.5 series [20011216, 20020101]
  */
 
 #include <linux/config.h>
@@ -18,7 +29,9 @@
 #include <linux/string.h>
 #include <linux/genhd.h>
 #include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include "scsi.h"
 #include "hosts.h"
 
-#include "sd.h"
-
 #include<linux/stat.h>
 
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+static char scsi_debug_version_str[] = "Version: 1.57 (20011216)";
+
+#ifndef SCSI_CMD_READ_16
+#define SCSI_CMD_READ_16 0x88
+#endif
+#ifndef SCSI_CMD_WRITE_16
+#define SCSI_CMD_WRITE_16 0x8a
+#endif
+
 /* A few options that we want selected */
+#define DEF_NR_FAKE_DEVS   1
+#define DEF_DEV_SIZE_MB   8
+#define DEF_FAKE_BLK0   0
+
+static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
 
-#define NR_HOSTS_PRESENT 1
-#define NR_FAKE_DISKS   3
-#define N_HEAD          255
-#define N_SECTOR        63
-#define N_CYLINDER      524
+#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
+#define N_HEAD          8
+#define N_SECTOR        32
 #define DISK_READONLY(TGT)      (0)
-#define DISK_REMOVEABLE(TGT)    (1)
-#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
+#define DISK_REMOVEABLE(TGT)    (0)
+#define DEVICE_TYPE(TGT) (TYPE_DISK);
+
+#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
+#define STORE_ELEM_ORDER 1
+#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER))
+#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1)
+
+/* default sector size is 512 bytes, 2**9 bytes */
+#define POW2_SECT_SIZE 9
+#define SECT_SIZE (1 << POW2_SECT_SIZE)
+
+#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
+
+static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0;
 
 /* Do not attempt to use a timer to simulate a real disk with latency */
 /* Only use this in the actual kernel, not in the simulator. */
 #define IMMEDIATE
 
-/* Skip some consistency checking.  Good for benchmarking */
-#define SPEEDY
-/* Read return zeros. Undefine for benchmarking */
-#define CLEAR
-
-/* Number of real scsi disks that will be detected ahead of time */
-static int NR_REAL = -1;
+#define SDEBUG_SG_ADDRESS
 
-#define NR_BLK_DEV  12
-#ifndef MAJOR_NR
-#define MAJOR_NR 8
-#endif
 #define START_PARTITION 4
 
 /* Time to wait before completing a command */
 #define DISK_SPEED     (HZ/10) /* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
-#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
+#define SECT_SIZE_PER(TGT) SECT_SIZE
+#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE)
 
 static int starts[] =
 {N_SECTOR,
  N_HEAD * N_SECTOR,            /* Single cylinder */
  N_HEAD * N_SECTOR * 4,
CAPACITY, 0};
0 /* CAPACITY */, 0};
 static int npart = 0;
 
-#include "scsi_debug.h"
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
+typedef struct scsi_debug_store_elem {
+       unsigned char * p;
+} Sd_store_elem;
 
-#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW)
-#define VERIFY_DEBUG(RW)
-#else
+static Sd_store_elem * store_arr = 0;
 
-#define VERIFY1_DEBUG(RW)                           \
-    if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};         \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (bh){                            \
-       if (bh->b_size != 1024) panic ("Wrong bh size");    \
-       if ((bh->b_blocknr << 1) + start != block)          \
-       {   printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \
-           panic ("Wrong bh block#"); \
-       };  \
-       if (bh->b_dev != SCpnt->request.rq_dev)  \
-           panic ("Bad bh target"); \
-    };
-
-#define VERIFY_DEBUG(RW)                            \
-    if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};    \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition");    \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (SCpnt->request.cmd != RW) panic ("Wrong  operation");       \
-    if (SCpnt->request.sector + start != block) panic("Wrong block.");  \
-    if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks");   \
-    if (SCpnt->request.bh){                         \
-       if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
-       if ((SCpnt->request.bh->b_blocknr << 1) + start != block)           \
-       {   printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \
-           panic ("Wrong bh block#"); \
-       };  \
-       if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
-           panic ("Bad bh target");\
-    };
-#endif
+typedef struct sdebug_dev_info {
+       Scsi_Device * sdp;
+       unsigned short host_no;
+       unsigned short id;
+       char reset;
+       char sb_index;
+} Sdebug_dev_info;
+static Sdebug_dev_info * devInfop;
+
+static int num_aborts = 0;
+static int num_dev_resets = 0;
+static int num_bus_resets = 0;
+static int num_host_resets = 0;
+
+static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
+
+#include "scsi_debug.h"
 
 typedef void (*done_fct_t) (Scsi_Cmnd *);
 
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
+static volatile done_fct_t * do_done = 0;
 
 struct Scsi_Host * SHpnt = NULL;
 
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+                          int num, int * errstsp, Sdebug_dev_info * devip);
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+                           int num, int * errstsp, Sdebug_dev_info * devip);
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);
 static void scsi_debug_intr_handle(unsigned long);
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+                           int asc, int asq, int inbandLen);
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
 
-static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
-
-Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
-static char SCrst[SCSI_DEBUG_MAILBOXES] =
-{0,};
+static struct timer_list * timeout = 0;
+static Scsi_Cmnd ** SCint = 0;
 
 /*
  * Semaphore used to simulate bus lockups.
  */
 static int scsi_debug_lockup = 0;
 
-static char sense_buffer[128] =
-{0,};
+#define NUM_SENSE_BUFFS 4
+#define SENSE_BUFF_LEN 32
+static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
+
+static int made_block0 = 0;
 
-static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
+static void scsi_debug_mkblock0(unsigned char * buff, int bufflen,
+                               Scsi_Cmnd * SCpnt)
 {
        int i;
-#if 0
-       unsigned char *pnt;
-#endif
-       unsigned int *lpnt;
-       struct scatterlist *sgpnt = NULL;
-       printk("use_sg: %d", SCpnt->use_sg);
-       if (SCpnt->use_sg) {
-               sgpnt = (struct scatterlist *) SCpnt->buffer;
-               for (i = 0; i < SCpnt->use_sg; i++) {
-                       printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length);
-               };
-       } else {
-               printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
-                      SCpnt->bufflen);
-               lpnt = (int *) SCpnt->request.buffer;
-               if (lpnt)
-                       printk(" (Alt %x) ", lpnt[15]);
-       };
-       lpnt = (unsigned int *) SCpnt;
-       for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-               if ((i & 7) == 0)
-                       printk("\n");
-               printk("%x ", *lpnt++);
-       };
-       printk("\n");
-       if (flag == 0)
-               return;
-#if 0
-       printk("\n");
-       lpnt = (unsigned int *) sgpnt[0].address;
-       for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-               if ((i & 7) == 0)
-                       printk("\n");
-               printk("%x ", *lpnt++);
-       };
-       printk("\n");
-#endif
+       struct partition *p;
+
+       memset(buff, 0, bufflen);
+       *((unsigned short *) (buff + 510)) = 0xAA55;
+       p = (struct partition *) (buff + 0x1be);
+       i = 0;
+       while (starts[i + 1]) {
+               int start_cyl, end_cyl;
+
+               start_cyl = starts[i] / N_HEAD / N_SECTOR;
+               end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
+               p->boot_ind = 0;
+
+               p->head = (i == 0 ? 1 : 0);
+               p->sector = 1 | ((start_cyl >> 8) << 6);
+               p->cyl = (start_cyl & 0xff);
+
+               p->end_head = N_HEAD - 1;
+               p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
+               p->end_cyl = (end_cyl & 0xff);
+
+               p->start_sect = starts[i];
+               p->nr_sects = starts[i + 1] - starts[i];
+               p->sys_ind = 0x83;      /* Linux ext2 partition */
+               p++;
+               i++;
+       }
+       if (!npart)
+               npart = i;
+       made_block0 = 1;
+       i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen;
+       memcpy(store_arr[0].p, buff, i);
 }
 
 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
        unchar *cmd = (unchar *) SCpnt->cmnd;
-       struct partition *p;
        int block;
-       struct buffer_head *bh = NULL;
+       int upper_blk;
        unsigned char *buff;
-       int nbytes, sgcount;
        int scsi_debug_errsts;
-       struct scatterlist *sgpnt;
        int target = SCpnt->target;
        int bufflen = SCpnt->request_bufflen;
-       unsigned long flags;
-       int i;
-       sgcount = 0;
-       sgpnt = NULL;
-
-#ifdef CONFIG_SMP
-        /*
-         * The io_request_lock *must* be held at this point.
-         */
-        if( io_request_lock.lock == 0 )
-        {
-                printk("Warning - io_request_lock is not held in queuecommand\n");
-        }
-#endif
+       unsigned long iflags;
+       int i, num, capac;
+       Sdebug_dev_info * devip = NULL;
+       char * sbuff;
 
        /*
-        * If we are being notified of the mid-level reposessing a command due to timeout,
-        * just return.
+        * If we are being notified of the mid-level reposessing a command
+        * due to timeout, just return.
         */
        if (done == NULL) {
                return 0;
        }
-       DEB(if (target >= NR_FAKE_DISKS) {
-           SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0;
-           }
-       );
 
        buff = (unsigned char *) SCpnt->request_buffer;
 
@@ -229,249 +228,201 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
          * If a command comes for the ID of the host itself, just print
          * a silly message and return.
          */
-        if( target == 7 ) {
+        if(target == 7) {
                 printk("How do you do!\n");
                 SCpnt->result = 0;
                 done(SCpnt);
                 return 0;
         }
 
-       if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
+       if ((target > 7) || (SCpnt->lun != 0)) {
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
                return 0;
        }
-       if (SCrst[target] != 0 && !scsi_debug_lockup) {
-               SCrst[target] = 0;
-               memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-               SCpnt->sense_buffer[0] = 0x70;
-               SCpnt->sense_buffer[2] = UNIT_ATTENTION;
-               SCpnt->result = (CHECK_CONDITION << 1);
-               done(SCpnt);
+#if 0
+       printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
+              (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
+              SCpnt->device, (int)(unsigned char)*cmd);
+#endif
+       if (NULL == SCpnt->device->hostdata) {
+               devip = devInfoReg(SCpnt->device);
+               if (NULL == devip) {
+                       SCpnt->result = DID_NO_CONNECT << 16;
+                       done(SCpnt);
+                       return 0;
+               }
+               SCpnt->device->hostdata = devip;
        }
+       devip = SCpnt->device->hostdata;
+
        switch (*cmd) {
-       case REQUEST_SENSE:
+       case REQUEST_SENSE:     /* mandatory */
                SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
-#ifndef DEBUG
-               {
-                       int i;
-                       printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
-                       for (i = 0; i < 12; i++)
-                               printk("%d ", sense_buffer[i]);
-                       printk("\n");
-               };
-#endif
-               memset(buff, 0, bufflen);
-               memcpy(buff, sense_buffer, bufflen);
-               memset(sense_buffer, 0, sizeof(sense_buffer));
+               if (devip) {
+                       sbuff = &sense_buffers[(int)devip->sb_index][0];
+                       devip->sb_index = 0; 
+               }
+               else
+                   sbuff = &sense_buffers[0][0]; 
+               memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? 
+                                    bufflen : SENSE_BUFF_LEN);
+               memset(sbuff, 0, SENSE_BUFF_LEN);
+               sbuff[0] = 0x70;
                SCpnt->result = 0;
                done(SCpnt);
                return 0;
        case START_STOP:
+               if (check_reset(SCpnt, devip)) {
+                       done(SCpnt);
+                       return 0;
+               }
                SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
                scsi_debug_errsts = 0;
                break;
        case ALLOW_MEDIUM_REMOVAL:
+               if (check_reset(SCpnt, devip)) {
+                       done(SCpnt);
+                       return 0;
+               }
                if (cmd[4]) {
-                       SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
+                       SCSI_LOG_LLQUEUE(2, printk(
+                                       "Medium removal inhibited..."));
                } else {
-                       SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
+                       SCSI_LOG_LLQUEUE(2, 
+                                       printk("Medium removal enabled..."));
                }
                scsi_debug_errsts = 0;
                break;
-       case INQUIRY:
+       case INQUIRY:     /* mandatory */
                SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
                memset(buff, 0, bufflen);
                buff[0] = DEVICE_TYPE(target);
-               buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;   /* Removable disk */
-               buff[2] = 1;
-               buff[4] = 33 - 5;
-               memcpy(&buff[8], "Foo Inc", 7);
-               memcpy(&buff[16], "XYZZY", 5);
-               memcpy(&buff[32], "1", 1);
+               buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;   
+                               /* Removable disk */
+               buff[2] = 2;    /* claim SCSI 2 */
+               buff[4] = 36 - 5;
+               memcpy(&buff[8], "Linux   ", 8);
+               memcpy(&buff[16], "scsi_debug      ", 16);
+               memcpy(&buff[32], "0002", 4);
+               scsi_debug_errsts = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+               if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+                       SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+#endif
+               break;
+       case SEND_DIAGNOSTIC:     /* mandatory */
+               SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
+               if (buff)
+                       memset(buff, 0, bufflen);
                scsi_debug_errsts = 0;
                break;
-       case TEST_UNIT_READY:
+       case TEST_UNIT_READY:     /* mandatory */
                SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
                if (buff)
                        memset(buff, 0, bufflen);
                scsi_debug_errsts = 0;
                break;
        case READ_CAPACITY:
+               if (check_reset(SCpnt, devip)) {
+                       done(SCpnt);
+                       return 0;
+               }
                SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
                 SHpnt = SCpnt->host;
-               if (NR_REAL < 0)
-                       NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
                memset(buff, 0, bufflen);
-               buff[0] = (CAPACITY >> 24);
-               buff[1] = (CAPACITY >> 16) & 0xff;
-               buff[2] = (CAPACITY >> 8) & 0xff;
-               buff[3] = CAPACITY & 0xff;
+               capac = CAPACITY - 1;
+               buff[0] = (capac >> 24);
+               buff[1] = (capac >> 16) & 0xff;
+               buff[2] = (capac >> 8) & 0xff;
+               buff[3] = capac & 0xff;
                buff[4] = 0;
                buff[5] = 0;
-               buff[6] = (SIZE(target) >> 8) & 0xff;   /* 512 byte sectors */
-               buff[7] = SIZE(target) & 0xff;
+               buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+               buff[7] = SECT_SIZE_PER(target) & 0xff;
 
                scsi_debug_errsts = 0;
                break;
+       case SCSI_CMD_READ_16:  /* SBC-2 */
+       case READ_12:
        case READ_10:
        case READ_6:
-#ifdef DEBUG
-               printk("Read...");
-#endif
-               if ((*cmd) == READ_10)
-                       block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-               else
-                       block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-               VERIFY_DEBUG(READ);
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-               {
-                       int delay = SCSI_SETUP_LATENCY;
-
-                       delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
-                       if (delay)
-                               usleep(delay);
-               };
-#endif
-
-#ifdef DEBUG
-               printk("(r%d)", SCpnt->request.nr_sectors);
-#endif
-               nbytes = bufflen;
-               if (SCpnt->use_sg) {
-                       sgcount = 0;
-                       sgpnt = (struct scatterlist *) buff;
-                       buff = sgpnt[sgcount].address;
-                       bufflen = sgpnt[sgcount].length;
-                       bh = SCpnt->request.bh;
-               };
-               scsi_debug_errsts = 0;
-               do {
-                       VERIFY1_DEBUG(READ);
-                       /* For the speedy test, we do not even want to fill the buffer with anything */
-#ifdef CLEAR
-                       memset(buff, 0, bufflen);
-#endif
-                       /* If this is block 0, then we want to read the partition table for this
-                        * device.  Let's make one up */
-                       if (block == 0) {
-                               int i;
-                               memset(buff, 0, bufflen);
-                               *((unsigned short *) (buff + 510)) = 0xAA55;
-                               p = (struct partition *) (buff + 0x1be);
-                               i = 0;
-                               while (starts[i + 1]) {
-                                       int start_cyl, end_cyl;
-
-                                       start_cyl = starts[i] / N_HEAD / N_SECTOR;
-                                       end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
-                                       p->boot_ind = 0;
-
-                                       p->head = (i == 0 ? 1 : 0);
-                                       p->sector = 1 | ((start_cyl >> 8) << 6);
-                                       p->cyl = (start_cyl & 0xff);
-
-                                       p->end_head = N_HEAD - 1;
-                                       p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
-                                       p->end_cyl = (end_cyl & 0xff);
-
-                                       p->start_sect = starts[i];
-                                       p->nr_sects = starts[i + 1] - starts[i];
-                                       p->sys_ind = 0x81;      /* Linux partition */
-                                       p++;
-                                       i++;
-                               };
-                               if (!npart)
-                                       npart = i;
-                               scsi_debug_errsts = 0;
-                               break;
-                       };
-#ifdef DEBUG
-                       if (SCpnt->use_sg)
-                               printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
-                                      SCpnt->request.current_nr_sectors);
-#endif
-
-#if 0
-                       /* Simulate a disk change */
-                       if (block == 0xfff0) {
-                               sense_buffer[0] = 0x70;
-                               sense_buffer[2] = UNIT_ATTENTION;
-                               starts[0] += 10;
-                               starts[1] += 10;
-                               starts[2] += 10;
-
-#ifdef DEBUG
-                               {
-                                       int i;
-                                       printk("scsi_debug: Filling sense buffer:");
-                                       for (i = 0; i < 12; i++)
-                                               printk("%d ", sense_buffer[i]);
-                                       printk("\n");
-                               };
-#endif
-                               scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-                               break;
-                       }       /* End phony disk change code */
-#endif
-
-#ifdef CLEAR
-                       memcpy(buff, &target, sizeof(target));
-                       memcpy(buff + sizeof(target), cmd, 24);
-                       memcpy(buff + 60, &block, sizeof(block));
-                       memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));
-#endif
-                       nbytes -= bufflen;
-                       if (SCpnt->use_sg) {
-#ifdef CLEAR
-                               memcpy(buff + 128, bh, sizeof(struct buffer_head));
-#endif
-                               block += bufflen >> 9;
-                               bh = bh->b_reqnext;
-                               sgcount++;
-                               if (nbytes) {
-                                       if (!bh)
-                                               panic("Too few blocks for linked request.");
-                                       buff = sgpnt[sgcount].address;
-                                       bufflen = sgpnt[sgcount].length;
-                               };
-                       }
-               } while (nbytes);
-
+               if (check_reset(SCpnt, devip)) {
+                       done(SCpnt);
+                       return 0;
+               }
+               upper_blk = 0;
+               if ((*cmd) == SCSI_CMD_READ_16) {
+                       upper_blk = cmd[5] + (cmd[4] << 8) + 
+                                   (cmd[3] << 16) + (cmd[2] << 24);
+                       block = cmd[9] + (cmd[8] << 8) + 
+                               (cmd[7] << 16) + (cmd[6] << 24);
+                       num = cmd[13] + (cmd[12] << 8) + 
+                               (cmd[11] << 16) + (cmd[10] << 24);
+               }
+               else if ((*cmd) == READ_12) {
+                       block = cmd[5] + (cmd[4] << 8) + 
+                               (cmd[3] << 16) + (cmd[2] << 24);
+                       num = cmd[9] + (cmd[8] << 8) + 
+                               (cmd[7] << 16) + (cmd[6] << 24);
+               }
+               else if ((*cmd) == READ_10) {
+                       block = cmd[5] + (cmd[4] << 8) + 
+                               (cmd[3] << 16) + (cmd[2] << 24);
+                       num = cmd[8] + (cmd[7] << 8);
+               }
+               else {
+                       block = cmd[3] + (cmd[2] << 8) + 
+                               ((cmd[1] & 0x1f) << 16);
+                       num = cmd[4];
+               }
+               if (scsi_debug_read(SCpnt, upper_blk, block, num, 
+                                   &scsi_debug_errsts, devip))
+                       break;
                SCpnt->result = 0;
-               (done) (SCpnt);
+/* calls bottom half in upper layers before return from scsi_do_...() */
+               (done) (SCpnt); 
                return 0;
-
-               if (SCpnt->use_sg && !scsi_debug_errsts)
-                       if (bh)
-                               scsi_dump(SCpnt, 0);
-               break;
+       case SCSI_CMD_WRITE_16: /* SBC-2 */
+       case WRITE_12:
        case WRITE_10:
        case WRITE_6:
-#ifdef DEBUG
-               printk("Write\n");
-#endif
-               if ((*cmd) == WRITE_10)
-                       block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-               else
-                       block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-               VERIFY_DEBUG(WRITE);
-               /*      printk("(w%d)",SCpnt->request.nr_sectors); */
-               if (SCpnt->use_sg) {
-                       if ((bufflen >> 9) != SCpnt->request.nr_sectors)
-                               panic("Trying to write wrong number of blocks\n");
-                       sgpnt = (struct scatterlist *) buff;
-                       buff = sgpnt[sgcount].address;
-               };
-#if 0
-               if (block != *((unsigned long *) (buff + 60))) {
-                       printk("%x %x :", block, *((unsigned long *) (buff + 60)));
-                       scsi_dump(SCpnt, 1);
-                       panic("Bad block written.\n");
-               };
-#endif
-               scsi_debug_errsts = 0;
-               break;
+               if (check_reset(SCpnt, devip)) {
+                       done(SCpnt);
+                       return 0;
+               }
+               upper_blk = 0;
+               if ((*cmd) == SCSI_CMD_WRITE_16) {
+                       upper_blk = cmd[5] + (cmd[4] << 8) + 
+                                   (cmd[3] << 16) + (cmd[2] << 24);
+                       block = cmd[9] + (cmd[8] << 8) + 
+                               (cmd[7] << 16) + (cmd[6] << 24);
+                       num = cmd[13] + (cmd[12] << 8) + 
+                               (cmd[11] << 16) + (cmd[10] << 24);
+               }
+               else if ((*cmd) == WRITE_12) {
+                       block = cmd[5] + (cmd[4] << 8) + 
+                               (cmd[3] << 16) + (cmd[2] << 24);
+                       num = cmd[9] + (cmd[8] << 8) + 
+                               (cmd[7] << 16) + (cmd[6] << 24);
+               }
+               else if ((*cmd) == WRITE_10) {
+                       block = cmd[5] + (cmd[4] << 8) + 
+                               (cmd[3] << 16) + (cmd[2] << 24);
+                       num = cmd[8] + (cmd[7] << 8);
+               }
+               else {
+                       block = cmd[3] + (cmd[2] << 8) + 
+                               ((cmd[1] & 0x1f) << 16);
+                       num = cmd[4];
+               }
+               if (scsi_debug_write(SCpnt, upper_blk, block, num, 
+                                    &scsi_debug_errsts, devip))
+                       break;
+               SCpnt->result = 0;
+/* calls bottom half in upper layers before return from scsi_do_...() */
+               (done) (SCpnt); 
+               return 0;
        case MODE_SENSE:
                /*
                 * Used to detect write protected status.
@@ -480,26 +431,36 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
                memset(buff, 0, 6);
                break;
        default:
+#if 0
                SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
                return 0;
-       };
+#else
+               if (check_reset(SCpnt, devip)) {
+                       done(SCpnt);
+                       return 0;
+               }
+               scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
+                                   (CHECK_CONDITION << 1);
+               mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
+               break;
+#endif
+       }
 
-       save_flags(flags);
-       cli();
+       spin_lock_irqsave(&mailbox_lock, iflags);
        for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
                if (timeout[i].function == NULL)
                        break;
-       };
+       }
 
        /*
-        * If all of the slots are full, just return 1.  The new error handling scheme
-        * allows this, and the mid-level should queue things.
+        * If all of the slots are full, just return 1.  The new error 
+        * handling scheme allows this, and the mid-level should queue things.
         */
        if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
                SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
-               restore_flags(flags);
+               spin_unlock_irqrestore(&mailbox_lock, iflags);
                return 1;
        }
        SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
@@ -511,7 +472,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
                do_done[i] = done;
                scsi_debug_intr_handle(i);      /* No timer - do this one right away */
        }
-       restore_flags(flags);
+       spin_unlock_irqrestore(&mailbox_lock, iflags);
 #else
 
        SCpnt->result = scsi_debug_errsts;
@@ -521,19 +482,200 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        SCint[i] = SCpnt;
        do_done[i] = done;
 
-       restore_flags(flags);
+       spin_unlock_irqrestore(&mailbox_lock, iflags);
        add_timer(&timeout[i]);
        if (!done)
-               panic("scsi_debug_queuecommand: done can't be NULL\n");
+               printk("scsi_debug_queuecommand: done can't be NULL\n");
 
 #if 0
-       printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
+       printk("Sending command (%d %x %d %d)...", i, done, 
+              timeout[i].expires, jiffies);
 #endif
 #endif
 
        return 0;
 }
 
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+{
+       if (devip->reset) {
+               devip->reset = 0;
+               mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
+               SCpnt->result = (COMMAND_COMPLETE << 8) | 
+                               (CHECK_CONDITION << 1);
+                return 1;
+       }
+       return 0;
+}
+
+static inline 
+unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp)
+{
+       if (NULL == sclp)
+               return NULL;
+       else if (sclp->page)
+               return (unsigned char *)page_address(sclp->page) + 
+                      sclp->offset;
+       else {
+#ifdef SDEBUG_SG_ADDRESS
+               return sclp->address;
+#else
+               return NULL;
+#endif
+       }
+}
+
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+                          int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+       unsigned long iflags;
+
+       if (upper_blk || (block + num > CAPACITY)) {
+               *errstsp = (COMMAND_COMPLETE << 8) |
+                          (CHECK_CONDITION << 1);
+               mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+               return 1;
+       }
+#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
+       {
+               int delay = SCSI_SETUP_LATENCY;
+
+               delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+               if (delay)
+                       usleep(delay);
+       }
+#endif
+
+       read_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+       nbytes = bufflen;
+       /* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", 
+              block, bufflen); */
+       if (SCpnt->use_sg) {
+               sgcount = 0;
+               sgpnt = (struct scatterlist *) buff;
+               buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+               bufflen = sgpnt[sgcount].length;
+       }
+       *errstsp = 0;
+       do {
+               int resid, k, off, len, rem, blk;
+               unsigned char * bp;
+
+               /* If this is block 0, then we want to read the partition
+                * table for this device.  Let's make one up */
+               if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) {
+                       scsi_debug_mkblock0(buff, bufflen, SCpnt);
+                       *errstsp = 0;
+                       break;
+               }
+               bp = buff;
+               blk = block;
+               for (resid = bufflen; resid > 0; resid -= len) {
+                       k = blk / SECT_PER_ELEM; 
+                       off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+                       rem = STORE_ELEM_SIZE - off;
+                       len = (resid > rem) ? rem : resid;
+/* printk("sdr: blk=%d k=%d off=%d rem=%d resid"
+                              "=%d len=%d  sgcount=%d\n", blk, k, 
+                               off, rem, resid, len, sgcount); */
+                       memcpy(bp, store_arr[k].p + off, len);
+                       bp += len;
+                       blk += len / SECT_SIZE;
+               }
+#if 0
+               /* Simulate a disk change */
+               if (block == 0xfff0) {
+                       sense_buffer[0] = 0x70;
+                       sense_buffer[2] = UNIT_ATTENTION;
+                       starts[0] += 10;
+                       starts[1] += 10;
+                       starts[2] += 10;
+
+                       *errstsp = (COMMAND_COMPLETE << 8) | 
+                                  (CHECK_CONDITION << 1);
+                       read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+                       return 1;
+               }       /* End phony disk change code */
+#endif
+               nbytes -= bufflen;
+               if (SCpnt->use_sg) {
+                       block += bufflen >> POW2_SECT_SIZE;
+                       sgcount++;
+                       if (nbytes) {
+                               buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+                               bufflen = sgpnt[sgcount].length;
+                       }
+               }
+               else if (nbytes > 0)
+                       printk("sdebug_read: unexpected nbytes=%d\n", nbytes);
+       } while (nbytes);
+       read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+       return 0;
+}
+
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+                           int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+       unsigned long iflags;
+
+       if (upper_blk || (block + num > CAPACITY)) {
+               *errstsp = (COMMAND_COMPLETE << 8) |
+                          (CHECK_CONDITION << 1);
+               mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+               return 1;
+       }
+
+       write_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+       nbytes = bufflen;
+       if (SCpnt->use_sg) {
+               sgcount = 0;
+               sgpnt = (struct scatterlist *) buff;
+               buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+               bufflen = sgpnt[sgcount].length;
+       }
+       *errstsp = 0;
+       do {
+               int resid, k, off, len, rem, blk;
+               unsigned char * bp;
+
+               bp = buff;
+               blk = block;
+               for (resid = bufflen; resid > 0; resid -= len) {
+                       k = blk / SECT_PER_ELEM; 
+                       off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+                       rem = STORE_ELEM_SIZE - off;
+                       len = (resid > rem) ? rem : resid;
+                       memcpy(store_arr[k].p + off, bp, len);
+                       bp += len;
+                       blk += len / SECT_SIZE;
+               }
+
+               nbytes -= bufflen;
+               if (SCpnt->use_sg) {
+                       block += bufflen >> POW2_SECT_SIZE;
+                       sgcount++;
+                       if (nbytes) {
+                               buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+                               bufflen = sgpnt[sgcount].length;
+                       }
+               }
+               else if (nbytes > 0)
+                       printk("sdebug_write: unexpected nbytes=%d\n", nbytes);
+       } while (nbytes);
+       write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+       return 0;
+}
+
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
 {
        static unsigned char cmd[6] =
@@ -581,10 +723,6 @@ static void scsi_debug_intr_handle(unsigned long indx)
 {
        Scsi_Cmnd *SCtmp;
        void (*my_done) (Scsi_Cmnd *);
-#ifdef DEBUG
-       int to;
-#endif
-
 #if 0
        del_timer(&timeout[indx]);
 #endif
@@ -599,59 +737,219 @@ static void scsi_debug_intr_handle(unsigned long indx)
                printk("scsi_debug_intr_handle: Unexpected interrupt\n");
                return;
        }
-#ifdef DEBUG
+#if 0
        printk("In intr_handle...");
        printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
        printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
 #endif
 
        my_done(SCtmp);
-#ifdef DEBUG
+#if 0
        printk("Called done.\n");
 #endif
 }
 
+static int initialized = 0;
+
+static int do_init(void)
+{
+       int sz;
+
+       starts[3] = CAPACITY;
+       sz = sizeof(Sd_store_elem) * STORE_ELEMENTS;
+       store_arr = kmalloc(sz, GFP_ATOMIC);
+       if (NULL == store_arr)
+               return 1;
+       memset(store_arr, 0, sz);
+
+       sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
+       do_done = kmalloc(sz, GFP_ATOMIC);
+       if (NULL == do_done)
+               goto out;
+       memset((void *)do_done, 0, sz);
+
+       sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
+       timeout = kmalloc(sz, GFP_ATOMIC);
+       if (NULL == timeout)
+               goto out;
+       memset(timeout, 0, sz);
+
+       sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
+       SCint = kmalloc(sz, GFP_ATOMIC);
+       if (NULL == SCint)
+               goto out;
+       memset(SCint, 0, sz);
+
+       return 0;
+
+out:
+       if (store_arr)
+               kfree(store_arr);
+       if (do_done)
+               kfree((void *)do_done);
+       if (timeout)
+               kfree(timeout);
+       if (SCint)
+               kfree(SCint);
+       return 1;
+}
+
+static void do_end(void)
+{
+       kfree(SCint);
+       kfree(timeout);
+       kfree((void *)do_done);
+       kfree(store_arr);
+}
+
 
 int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
-       int i;
+       int k, num, sz;
+
+       if (0 == initialized) {
+               ++initialized;
+               sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
+               devInfop = kmalloc(sz, GFP_ATOMIC);
+               if (NULL == devInfop) {
+                       printk("scsi_debug_detect: out of memory, 0.5\n");
+                       return 0;
+               }
+               memset(devInfop, 0, sz);
+               if (do_init()) {
+                       printk("scsi_debug_detect: out of memory, 0\n");
+                       return 0;
+               }
+               for (k = 0; k < STORE_ELEMENTS; ++k) {
+                       store_arr[k].p = (unsigned char *)
+                               __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER);
+                       if (0 == store_arr[k].p)
+                               goto detect_err;
+                       memset(store_arr[k].p, 0, STORE_ELEM_SIZE);
+               }
+               for (k = 0; k < NUM_SENSE_BUFFS; ++k)
+                       sense_buffers[k][0] = 0x70;
+               for (k = 0; k < NR_HOSTS_PRESENT; k++) {
+                       tpnt->proc_name = "scsi_debug"; /* In the loop??? */
+                       scsi_register(tpnt, 0);
+               }
+               return NR_HOSTS_PRESENT;
+       }
+       else {
+               printk("scsi_debug_detect: called again\n");
+               return 0;
+       }
+
+detect_err:
+       num = k;
+       for (k = 0; k < STORE_ELEMENTS; ++k) {
+               if (0 != store_arr[k].p) {
+                       free_pages((unsigned long)store_arr[k].p, 
+                                  STORE_ELEM_ORDER);
+                       store_arr[k].p = NULL;
+               }
+       }
+       printk("scsi_debug_detect: out of memory: %d out of %d bytes\n",
+              (int)(num * STORE_ELEM_SIZE), 
+              (int)(scsi_debug_dev_size_mb * 1024 * 1024));
+       return 0;
+}
+
+
+static int num_releases = 0;
+
+int scsi_debug_release(struct Scsi_Host * hpnt)
+{
+       int k;
+       
+       scsi_unregister(hpnt);
+       if (++num_releases != NR_HOSTS_PRESENT)
+               return 0;
 
-       for (i = 0; i < NR_HOSTS_PRESENT; i++) {
-               tpnt->proc_name = "scsi_debug"; /* Huh? In the loop??? */
-               scsi_register(tpnt, 0);
+       for (k = 0; k < STORE_ELEMENTS; ++k) {
+               if (0 != store_arr[k].p) {
+                       free_pages((unsigned long)store_arr[k].p, 
+                                  STORE_ELEM_ORDER);
+                       store_arr[k].p = NULL;
+               }
        }
-       return NR_HOSTS_PRESENT;
+       do_end();
+       kfree(devInfop);
+       return 0;
+}
+
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+{
+       int k;
+       unsigned short host_no, id;
+       Sdebug_dev_info * devip;
+
+       host_no = sdp->host->host_no;
+       id = (unsigned short)sdp->id;
+       for (k = 0; k < scsi_debug_num_devs; ++k) {
+               devip = &devInfop[k];
+               if (devip->sdp && (host_no == devip->host_no) &&
+                   (id == devip->id)) {
+                       devip->sdp = sdp; /* overwrite previous sdp */
+                       return devip;
+               }
+               if (NULL == devip->sdp) {
+                       devip->sdp = sdp;
+                       devip->host_no = host_no;
+                       devip->id = id;
+                       devip->reset = 1;
+                       devip->sb_index = 0;
+                       return devip;
+               }
+       }
+       return NULL;
+}
+
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+                           int asc, int asq, int inbandLen)
+{
+       char * sbuff;
+       if ((index < 0) || (index >= NUM_SENSE_BUFFS))
+               return;
+       if (devip)
+               devip->sb_index = index;
+       sbuff = &sense_buffers[index][0];
+       memset(sbuff, 0, SENSE_BUFF_LEN);
+       sbuff[0] = 0x70;
+       sbuff[2] = key;
+       sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
+       sbuff[12] = asc;
+       sbuff[13] = asq;
 }
 
 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
-#if 0
+#if 1
+       ++num_aborts;
+       return SUCCESS;
+#else
        int j;
        void (*my_done) (Scsi_Cmnd *);
-       unsigned long flags;
-#endif
-
-       DEB(printk("scsi_debug_abort\n"));
-#if 0
+       unsigned long iflags;
        SCpnt->result = SCpnt->abort_reason << 16;
        for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
                if (SCpnt == SCint[j]) {
                        my_done = do_done[j];
                        my_done(SCpnt);
-                       save_flags(flags);
-                       cli();
+                       spin_lock_irqsave(&mailbox_lock, iflags);
                        timeout[j] = 0;
                        SCint[j] = NULL;
                        do_done[j] = NULL;
-                       restore_flags(flags);
-               };
-       };
-#endif
+                       spin_unlock_irqrestore(&mailbox_lock, iflags);
+               }
+       }
        return SCSI_ABORT_SNOOZE;
+#endif
 }
 
 int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
 {
+       /* int size = disk->capacity; */
        info[0] = N_HEAD;
        info[1] = N_SECTOR;
        info[2] = N_CYLINDER;
@@ -660,35 +958,130 @@ int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
        return 0;
 }
 
+#if 0
 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
 {
        int i;
-       unsigned long flags;
+       unsigned long iflags;
 
        void (*my_done) (Scsi_Cmnd *);
        printk("Bus unlocked by reset - %d\n", why);
        scsi_debug_lockup = 0;
-       DEB(printk("scsi_debug_reset called\n"));
        for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
                if (SCint[i] == NULL)
                        continue;
                SCint[i]->result = DID_RESET << 16;
                my_done = do_done[i];
                my_done(SCint[i]);
-               save_flags(flags);
-               cli();
+               spin_lock_irqsave(&mailbox_lock, iflags);
                SCint[i] = NULL;
                do_done[i] = NULL;
                timeout[i].function = NULL;
-               restore_flags(flags);
+               spin_unlock_irqrestore(&mailbox_lock, iflags);
        }
        return SCSI_RESET_SUCCESS;
 }
+#endif
 
-const char *scsi_debug_info(void)
+int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
 {
-       static char buffer[] = " ";     /* looks nicer without anything here */
-       return buffer;
+       Scsi_Device * sdp;
+       int k;
+
+       ++num_dev_resets;
+       if (SCpnt && ((sdp = SCpnt->device))) {
+               for (k = 0; k < scsi_debug_num_devs; ++k) {
+                       if (sdp->hostdata == (devInfop + k))
+                               break;
+               }
+               if (k < scsi_debug_num_devs)
+                       devInfop[k].reset = 1;
+       }
+       return SUCCESS;
+}
+
+int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
+{
+       Scsi_Device * sdp;
+       struct Scsi_Host * hp;
+       int k;
+
+       ++num_bus_resets;
+       if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
+               for (k = 0; k < scsi_debug_num_devs; ++k) {
+                       if (hp == devInfop[k].sdp->host)
+                               devInfop[k].reset = 1;
+               }
+       }
+       return SUCCESS;
+}
+
+int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+{
+       int k;
+
+       ++num_host_resets;
+       for (k = 0; k < scsi_debug_num_devs; ++k)
+               devInfop[k].reset = 1;
+
+       return SUCCESS;
+}
+
+#ifndef MODULE
+static int __init scsi_debug_num_devs_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_num_devs = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
+               "(<n> can be from 1 to around 2000)\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
+
+static int __init scsi_debug_dev_size_mb_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_dev_size_mb = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n"
+               "    (<n> is number of MB ram shared by all devs\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
+#endif
+
+MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI debug adapter driver");
+MODULE_PARM(scsi_debug_num_devs, "i");
+MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
+MODULE_PARM(scsi_debug_dev_size_mb, "i");
+MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+static char sdebug_info[256];
+
+const char * scsi_debug_info(struct Scsi_Host * shp)
+{
+       sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
+               "dev_size_mb=%d\n", scsi_debug_version_str,
+               scsi_debug_num_devs, scsi_debug_dev_size_mb);
+       return sdebug_info;
 }
 
 /* scsi_debug_proc_info
@@ -738,10 +1131,20 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
 
        }
        begin = 0;
-       pos = len = sprintf(buffer,
-       "This driver is not a real scsi driver, but it plays one on TV.\n"
+       pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
+           "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" 
+           "cylinders=%d, heads=%d, sectors=%d\n"
+           "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
+           "host_resets=%d\n",
+           scsi_debug_version_str, scsi_debug_num_devs, 
+           scsi_debug_dev_size_mb, SECT_SIZE,
+           N_CYLINDER, N_HEAD, N_SECTOR,
+           num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+#if 0
+        "This driver is not a real scsi driver, but it plays one on TV.\n"
         "It is very handy for debugging specific problems because you\n"
                         "can simulate a variety of error conditions\n");
+#endif
        if (pos < offset) {
                len = 0;
                begin = pos;
@@ -754,44 +1157,8 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
        return (len);
 }
 
-#ifdef CONFIG_USER_DEBUG
-/*
- * This is a hack for the user space emulator.  It allows us to
- * "insert" arbitrary numbers of additional drivers.
- */
-void *scsi_debug_get_handle(void)
-{
-       static Scsi_Host_Template driver_copy = SCSI_DEBUG;
-       void *rtn;
-       rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
-       if(rtn==NULL)
-               return NULL;
-       memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
-       return rtn;
-}
-#endif
-
 /* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG;
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
 
 #include "scsi_module.c"
 
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-MODULE_LICENSE("GPL");
index b0135317a739ab5bfa81a7c46d7a2e2d4f3613e6..bf3815b62641e40d5c30c554cab605a1d07b2838 100644 (file)
@@ -8,34 +8,41 @@ int scsi_debug_command(Scsi_Cmnd *);
 int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int scsi_debug_abort(Scsi_Cmnd *);
 int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
+int scsi_debug_bus_reset(Scsi_Cmnd *);
+int scsi_debug_dev_reset(Scsi_Cmnd *);
+int scsi_debug_host_reset(Scsi_Cmnd *);
 int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
+const char * scsi_debug_info(struct Scsi_Host *);
 
 #ifndef NULL
 #define NULL 0
 #endif
 
-
-#define SCSI_DEBUG_MAILBOXES 1
-
 /*
- * Allow the driver to reject commands.  Thus we accept only one, but
- * and the mid-level will queue the remainder.
+ * This driver is written for the lk 2.5 series
  */
 #define SCSI_DEBUG_CANQUEUE  255
 
-#define SCSI_DEBUG {proc_info:         scsi_debug_proc_info,   \
+#define SCSI_DEBUG_MAX_CMD_LEN 16
+
+#define SCSI_DEBUG_TEMPLATE \
+                  {proc_info:         scsi_debug_proc_info,    \
                    name:              "SCSI DEBUG",            \
+                   info:              scsi_debug_info,         \
                    detect:            scsi_debug_detect,       \
+                   release:           scsi_debug_release,      \
                    queuecommand:      scsi_debug_queuecommand, \
-                   abort:             scsi_debug_abort,        \
-                   reset:             scsi_debug_reset,        \
+                   eh_abort_handler:  scsi_debug_abort,        \
+                   eh_bus_reset_handler: scsi_debug_bus_reset, \
+                   eh_device_reset_handler: scsi_debug_device_reset,   \
+                   eh_host_reset_handler: scsi_debug_host_reset,       \
                    bios_param:        scsi_debug_biosparam,    \
                    can_queue:         SCSI_DEBUG_CANQUEUE,     \
                    this_id:           7,                       \
-                   sg_tablesize:      16,                      \
+                   sg_tablesize:      64,                      \
                    cmd_per_lun:       3,                       \
                    unchecked_isa_dma: 0,                       \
                    use_clustering:    ENABLE_CLUSTERING,       \
 }
+
 #endif
index b88aeb25ccb89b028eaa49da39bfed3cc5c7892a..62263c59d05ca0b7fcacc1319ff5863d5de4f7cb 100644 (file)
@@ -19,9 +19,9 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char sg_version_str[] = "Version: 3.1.20 (20010814)";
+ static char sg_version_str[] = "Version: 3.5.23 (20020103)";
 #endif
- static int sg_version_num = 30120; /* 2 digits for each component */
+ static int sg_version_num = 30523; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -76,12 +76,18 @@ static void sg_proc_cleanup(void);
 #include <linux/version.h>
 #endif /* LINUX_VERSION_CODE */
 
+#define SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+
 #define SG_ALLOW_DIO_DEF 0
 #define SG_ALLOW_DIO_CODE      /* compile out be commenting this define */
 #ifdef SG_ALLOW_DIO_CODE
 #include <linux/iobuf.h>
 #endif
 
+#define SG_NEW_KIOVEC 0        /* use alloc_kiovec(), not alloc_kiovec_sz() */
+
+#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
+
 int sg_big_buff = SG_DEF_RESERVED_SIZE;
 /* N.B. This variable is readable and writeable via
    /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -95,14 +101,8 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF;
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_LOW_POOL_THRESHHOLD 30
-#define SG_MAX_POOL_SECTORS 320  /* Max. number of pool sectors to take */
-
-static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS;
-
 #define SG_HEAP_PAGE 1  /* heap from kernel via get_free_pages() */
 #define SG_HEAP_KMAL 2  /* heap from kernel via kmalloc() */
-#define SG_HEAP_POOL 3  /* heap from scsi dma pool (mid-level) */
 #define SG_USER_MEM 4   /* memory belongs to user space */
 
 #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
@@ -136,10 +136,10 @@ static struct Scsi_Device_Template sg_template =
 typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */
 {
     unsigned short k_use_sg;    /* Count of kernel scatter-gather pieces */
-    unsigned short sglist_len;  /* size of malloc'd scatter-gather list */
+    unsigned short sglist_len;  /* size of malloc'd scatter-gather list ++ */
     unsigned bufflen;           /* Size of (aggregate) data buffer */
     unsigned b_malloc_len;      /* actual len malloc'ed in buffer */
-    void * buffer;              /* Data buffer or scatter list,12 bytes each*/
+    void * buffer;              /* Data buffer or scatter list + mem_src_arr */
     struct kiobuf * kiobp;      /* for direct IO information */
     char mapped;                /* indicates kiobp has locked pages */
     char buffer_mem_src;        /* heap whereabouts of 'buffer' */
@@ -182,6 +182,7 @@ typedef struct sg_fd /* holds the state of a file descriptor */
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
     char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */
+    char mmap_called;   /* 0 -> mmap() never called on this fd */
 } Sg_fd; /* 2760 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
@@ -203,7 +204,8 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt);
 static int sg_start_req(Sg_request * srp);
 static void sg_finish_rem_req(Sg_request * srp);
 static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp);
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+                        int tablesize);
 static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
                           Sg_request * srp);
 static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
@@ -233,13 +235,15 @@ static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id);
 static Sg_request * sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
-static void sg_clr_srpnt(Scsi_Request * SRpnt);
 static int sg_ms_to_jif(unsigned int msecs);
-static unsigned sg_jif_to_ms(int jifs);
+static inline unsigned sg_jif_to_ms(int jifs);
 static int sg_allow_access(unsigned char opcode, char dev_type);
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
 static Sg_device * sg_get_dev(int dev);
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp);
 #ifdef CONFIG_PROC_FS
 static int sg_last_dev(void);
 #endif
@@ -337,9 +341,8 @@ static int sg_release(struct inode * inode, struct file * filp)
     Sg_device * sdp;
     Sg_fd * sfp;
 
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {
+    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
-    }
     SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
     sg_fasync(-1, filp, 0);   /* remove filp from async notification list */
     if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
@@ -615,6 +618,20 @@ static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
        sg_remove_request(sfp, srp);
        return -ENOSYS;
     }
+    if (hp->flags & SG_FLAG_MMAP_IO) {
+       if (hp->dxfer_len > sfp->reserve.bufflen) {
+           sg_remove_request(sfp, srp);
+           return -ENOMEM;     /* MMAP_IO size must fit in reserve buffer */
+       }
+       if (hp->flags & SG_FLAG_DIRECT_IO) {
+           sg_remove_request(sfp, srp);
+           return -EINVAL;     /* either MMAP_IO or DIRECT_IO (not both) */
+       }
+       if (sg_res_in_use(sfp)) {
+           sg_remove_request(sfp, srp);
+           return -EBUSY;      /* reserve buffer already being used */
+       }
+    }
     timeout = sg_ms_to_jif(srp->header.timeout);
     if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) {
        sg_remove_request(sfp, srp);
@@ -681,7 +698,6 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
     srp->my_cmdp = SRpnt;
     q = &SRpnt->sr_device->request_queue;
     SRpnt->sr_request.rq_dev = sdp->i_rdev;
-    SRpnt->sr_request.rq_status = RQ_ACTIVE;
     SRpnt->sr_sense_buffer[0] = 0;
     SRpnt->sr_cmd_len = hp->cmd_len;
     if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
@@ -849,7 +865,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp,
         result = get_user(val, (int *)arg);
         if (result) return result;
         if (val != sfp->reserve.bufflen) {
-            if (sg_res_in_use(sfp))
+            if (sg_res_in_use(sfp) || sfp->mmap_called)
                 return -EBUSY;
             sg_remove_scat(&sfp->reserve);
             sg_build_reserve(sfp, val);
@@ -1030,6 +1046,146 @@ static int sg_fasync(int fd, struct file * filp, int mode)
     return (retval < 0) ? retval : 0;
 }
 
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp)
+{
+    return (sclp && sclp->page) ? 
+               (unsigned char *)page_address(sclp->page) + sclp->offset :
+               NULL;
+}
+
+static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
+{
+    void * page_ptr;
+    struct page * page;
+    int k, m;
+
+    SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, "
+                          "scatg=%d\n", startFinish, rsv_schp->k_use_sg)); 
+    /* N.B. correction _not_ applied to base page of aech allocation */
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+           for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
+               page_ptr = sg_scatg2virt(sclp) + m;
+               page = virt_to_page(page_ptr);
+               if (startFinish)
+                   get_page(page);     /* increment page count */
+               else {
+                   if (page_count(page) > 0)
+                       put_page_testzero(page); /* decrement page count */
+               }
+           }
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+       for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
+           page_ptr = (unsigned char *)rsv_schp->buffer + m;
+           page = virt_to_page(page_ptr);
+           if (startFinish)
+               get_page(page); /* increment page count */
+           else {
+               if (page_count(page) > 0)
+                   put_page_testzero(page); /* decrement page count */
+           }
+       }
+    }
+}
+
+static struct page * sg_vma_nopage(struct vm_area_struct *vma, 
+                                  unsigned long addr, int unused)
+{
+    Sg_fd * sfp;
+    struct page * page = NOPAGE_SIGBUS;
+    void * page_ptr = NULL;
+    unsigned long offset;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data)))
+       return page;
+    rsv_schp = &sfp->reserve;
+    offset = addr - vma->vm_start;
+    if (offset >= rsv_schp->bufflen)
+       return page;
+    SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", 
+                              offset, rsv_schp->k_use_sg));
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        int k;
+        unsigned long sa = vma->vm_start;
+        unsigned long len;
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+             ++k, ++sclp) {
+            len = vma->vm_end - sa;
+            len = (len < sclp->length) ? len : sclp->length;
+           if (offset < len) {
+               page_ptr = sg_scatg2virt(sclp) + offset;
+               page = virt_to_page(page_ptr);
+               get_page(page); /* increment page count */
+               break;
+           }
+            sa += len;
+           offset -= len;
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+        page_ptr = (unsigned char *)rsv_schp->buffer + offset;
+       page = virt_to_page(page_ptr);
+       get_page(page); /* increment page count */
+    }
+    return page;
+}
+
+static struct vm_operations_struct sg_mmap_vm_ops = {
+    nopage : sg_vma_nopage,
+};
+
+static int sg_mmap(struct file * filp, struct vm_area_struct *vma)
+{
+    Sg_fd * sfp;
+    unsigned long req_sz = vma->vm_end - vma->vm_start;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data)))
+        return -ENXIO;
+    SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", 
+                              (void *)vma->vm_start, (int)req_sz));
+    if (vma->vm_pgoff)
+       return -EINVAL;         /* want no offset */
+    rsv_schp = &sfp->reserve;
+    if (req_sz > rsv_schp->bufflen)
+       return -ENOMEM;         /* cannot map more than reserved buffer */
+
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+       int k;
+       unsigned long sa = vma->vm_start;
+       unsigned long len;
+       struct scatterlist * sclp = rsv_schp->buffer;
+
+       for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); 
+            ++k, ++sclp) {
+           if (0 != sclp->offset)
+               return -EFAULT;     /* non page aligned memory ?? */
+           len = vma->vm_end - sa;
+           len = (len < sclp->length) ? len : sclp->length;
+           sa += len;
+       }
+    }
+    else { /* reserve buffer is just a single allocation */
+       if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1))
+           return -EFAULT;     /* non page aligned memory ?? */
+    }
+    if (0 == sfp->mmap_called) {
+       sg_rb_correct4mmap(rsv_schp, 1);  /* do only once per fd lifetime */
+       sfp->mmap_called = 1;
+    }
+    vma->vm_flags |= (VM_RESERVED | VM_IO);
+    vma->vm_private_data = sfp;
+    vma->vm_ops = &sg_mmap_vm_ops;
+    return 0;
+}
+
 /* This function is a "bottom half" handler that is called by the
  * mid level when a command is completed (or has failed). */
 static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
@@ -1076,7 +1232,14 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
     srp->data.sglist_len = SRpnt->sr_sglist_len;
     srp->data.bufflen = SRpnt->sr_bufflen;
     srp->data.buffer = SRpnt->sr_buffer;
-    sg_clr_srpnt(SRpnt);
+    /* now clear out request structure */
+    SRpnt->sr_use_sg = 0;
+    SRpnt->sr_sglist_len = 0;
+    SRpnt->sr_bufflen = 0;
+    SRpnt->sr_buffer = NULL;
+    SRpnt->sr_underflow = 0;
+    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ request blk */
+
     srp->my_cmdp = NULL;
     srp->done = 1;
     read_unlock(&sg_dev_arr_lock);
@@ -1121,14 +1284,15 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
        if (NULL == sfp->headrp) {
             SCSI_LOG_TIMEOUT(1,
                printk("sg...bh: already closed, final cleanup\n"));
-            sg_remove_sfp(sdp, sfp);
+            if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
+               sdp->device->access_count--;
+               if (sdp->device->host->hostt->module)
+                   __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+           }
+           if (sg_template.module)
+                   __MOD_DEC_USE_COUNT(sg_template.module);
            sfp = NULL;
         }
-       sdp->device->access_count--;
-       if (sg_template.module)
-               __MOD_DEC_USE_COUNT(sg_template.module);
-       if (sdp->device->host->hostt->module)
-           __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
     }
     else if (srp && srp->orphan) {
        if (sfp->keep_orphan)
@@ -1152,6 +1316,7 @@ static struct file_operations sg_fops = {
        poll:           sg_poll,
        ioctl:          sg_ioctl,
        open:           sg_open,
+       mmap:           sg_mmap,
        release:        sg_release,
        fasync:         sg_fasync,
 };
@@ -1176,7 +1341,7 @@ static int sg_init()
     if(!sg_registered) {
        if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
         {
-            printk("Unable to get major %d for generic SCSI device\n",
+            printk(KERN_ERR "Unable to get major %d for generic SCSI device\n",
                    SCSI_GENERIC_MAJOR);
            write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
             return 1;
@@ -1189,7 +1354,7 @@ static int sg_init()
     sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * 
                                        sizeof(Sg_device *), GFP_ATOMIC);
     if (NULL == sg_dev_arr) {
-        printk("sg_init: no space for sg_dev_arr\n");
+        printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
        write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
         return 1;
     }
@@ -1212,8 +1377,8 @@ static int __init sg_def_reserved_size_setup(char *str)
            sg_big_buff = tmp;
        return 1;
     } else {
-       printk("sg_def_reserved_size : usage sg_def_reserved_size=n "
-              "(n could be 65536, 131072 or 262144)\n");
+       printk(KERN_WARNING "sg_def_reserved_size : usage "
+           "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n");
        return 0;
     }
 }
@@ -1238,7 +1403,7 @@ static int sg_attach(Scsi_Device * scsidp)
        if (NULL == tmp_da) {
            scsidp->attached--;
            write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-           printk("sg_attach: device array cannot be resized\n");
+           printk(KERN_ERR "sg_attach: device array cannot be resized\n");
            return 1;
        }
        memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
@@ -1250,13 +1415,13 @@ static int sg_attach(Scsi_Device * scsidp)
 
     for(k = 0; k < sg_template.dev_max; k++)
         if(! sg_dev_arr[k]) break;
-    if (k > MINORMASK) {
+    if (k > SG_MAX_DEVS_MASK) {
        scsidp->attached--;
        write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-       printk("Unable to attach sg device <%d, %d, %d, %d>"
+       printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>"
               " type=%d, minor number exceed %d\n", scsidp->host->host_no, 
               scsidp->channel, scsidp->id, scsidp->lun, scsidp->type,
-              MINORMASK);
+              SG_MAX_DEVS_MASK);
        return 1;
     }
     if(k < sg_template.dev_max)
@@ -1266,7 +1431,7 @@ static int sg_attach(Scsi_Device * scsidp)
     if (NULL == sdp) {
        scsidp->attached--;
        write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-       printk("sg_attach: Sg_device cannot be allocated\n");
+       printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
        return 1;
     }
 
@@ -1293,8 +1458,8 @@ static int sg_attach(Scsi_Device * scsidp)
        case TYPE_WORM:
        case TYPE_TAPE: break;
        default:
-           printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d,"
-                  " lun %d,  type %d\n", k, scsidp->host->host_no, 
+           printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel"
+                  " %d, id %d, lun %d,  type %d\n", k, scsidp->host->host_no, 
                   scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
     }
     return 0;
@@ -1371,7 +1536,10 @@ static void sg_detach(Scsi_Device * scsidp)
 
 MODULE_AUTHOR("Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI generic (sg) driver");
+
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
+#endif
 
 MODULE_PARM(def_reserved_size, "i");
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
@@ -1417,9 +1585,8 @@ static int sg_start_req(Sg_request * srp)
        if (res <= 0)   /* -ve -> error, 0 -> done, 1 -> try indirect */
            return res;
     }
-    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) {
+    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
        sg_link_reserve(sfp, srp, dxfer_len);
-    }
     else {
        res = sg_build_indi(req_schp, sfp, dxfer_len);
         if (res) {
@@ -1445,23 +1612,24 @@ static void sg_finish_rem_req(Sg_request * srp)
     sg_remove_request(sfp, srp);
 }
 
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp)
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+                        int tablesize)
 {
     int mem_src, ret_sz;
-    int sg_bufflen = PAGE_SIZE;
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+    /* scatter gather array, followed by mem_src_arr (array of chars) */
+    int sg_bufflen = tablesize * elem_sz;
+    int mx_sc_elems = tablesize;
 
     mem_src = SG_HEAP_KMAL;
-    schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen,
-                                                  &ret_sz, &mem_src);
-    schp->buffer_mem_src = (char)mem_src;
+    schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src);
     if (! schp->buffer)
        return -ENOMEM;
     else if (ret_sz != sg_bufflen) {
        sg_bufflen = ret_sz;
-       mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+       mx_sc_elems = sg_bufflen / elem_sz;
     }
+    schp->buffer_mem_src = (char)mem_src;
     schp->sglist_len = sg_bufflen;
     memset(schp->buffer, 0, sg_bufflen);
     return mx_sc_elems; /* number of scat_gath elements allocated */
@@ -1470,13 +1638,15 @@ static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp)
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
 {
 #ifdef SG_ALLOW_DIO_CODE
+    int nbhs = 0;
+
     if (schp && schp->kiobp) {
        if (schp->mapped) {
            unmap_kiobuf(schp->kiobp);
            schp->mapped = 0;
        }
        if (free_also) {
-           free_kiovec(1, &schp->kiobp);
+           sg_free_kiovec(1, &schp->kiobp, &nbhs);
            schp->kiobp = NULL;
        }
     }
@@ -1494,10 +1664,12 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
     sg_io_hdr_t * hp = &srp->header;
     Sg_scatter_hold * schp = &srp->data;
     int sg_tablesize = sfp->parentdp->sg_tablesize;
+    int nbhs = 0;
 
-    res = alloc_kiovec(1, &schp->kiobp);
+    res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs);
     if (0 != res) {
-       SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res));
+       SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n", 
+                        res));
        return 1;
     }
     res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0,
@@ -1527,7 +1699,7 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
        hp->info |= SG_INFO_DIRECT_IO;
        return 0;
     }
-    mx_sc_elems = sg_build_sgat(schp, sfp);
+    mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
     if (mx_sc_elems <= 1) {
        sg_unmap_and(schp, 1);
        sg_remove_scat(schp);
@@ -1535,19 +1707,22 @@ static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
     }
     mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist));
     for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len;
-        (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+        (rem_sz > 0) && (k < mx_sc_elems);
         ++k, ++sclp) {
        offset = (0 == k) ? kp->offset : 0;
        num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) :
                                                rem_sz;
+       sclp->page = kp->maplist[k];
+       sclp->offset = offset;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
        sclp->address = page_address(kp->maplist[k]) + offset;
-       sclp->page = NULL;
+#endif
        sclp->length = num;
        mem_src_arr[k] = SG_USER_MEM;
        rem_sz -= num;
        SCSI_LOG_TIMEOUT(5,
            printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n",
-           k, sclp->address, num, mem_src_arr[k]));
+           k, sg_scatg2virt(sclp), num, mem_src_arr[k]));
     }
     schp->k_use_sg = k;
     SCSI_LOG_TIMEOUT(5,
@@ -1569,7 +1744,7 @@ static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
 {
     int ret_sz, mem_src;
     int blk_size = buff_size;
-    char * p = NULL;
+    unsigned char * p = NULL;
 
     if ((blk_size < 0) || (! sfp))
         return -EFAULT;
@@ -1609,14 +1784,14 @@ static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
        char * mem_src_arr;
 
         /* N.B. ret_sz and mem_src carried into this block ... */
-       mx_sc_elems = sg_build_sgat(schp, sfp);
+       mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
        if (mx_sc_elems < 0)
            return mx_sc_elems; /* most likely -ENOMEM */
        mem_src_arr = schp->buffer +
                      (mx_sc_elems * sizeof(struct scatterlist));
 
        for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
-            (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+            (rem_sz > 0) && (k < mx_sc_elems);
              ++k, rem_sz -= ret_sz, ++sclp) {
            if (first)
                 first = 0;
@@ -1627,14 +1802,17 @@ static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
                 if (! p)
                     break;
             }
+            sclp->page = virt_to_page(p);
+            sclp->offset = (unsigned long)p & ~PAGE_MASK;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
             sclp->address = p;
-           sclp->page = NULL;
+#endif
             sclp->length = ret_sz;
            mem_src_arr[k] = mem_src;
 
            SCSI_LOG_TIMEOUT(5,
                printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
-                k, sclp->address, ret_sz, mem_src));
+                k, sg_scatg2virt(sclp), ret_sz, mem_src));
         } /* end of for loop */
        schp->k_use_sg = k;
        SCSI_LOG_TIMEOUT(5,
@@ -1664,7 +1842,8 @@ static int sg_write_xfer(Sg_request * srp)
        if (schp->bufflen < num_xfer)
            num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+       (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
        return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -1698,14 +1877,15 @@ static int sg_write_xfer(Sg_request * srp)
        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
        char * mem_src_arr = sg_get_sgat_msa(schp);
        ksglen = (int)sclp->length;
-       p = sclp->address;
+       p = sg_scatg2virt(sclp);
 
        for (j = 0, k = 0; j < onum; ++j) {
            res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
            if (res) return res;
 
            for (; (k < schp->k_use_sg) && p;
-                ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+                ++k, ++sclp, ksglen = (int)sclp->length, 
+                       p = sg_scatg2virt(sclp)) {
                ok = (SG_USER_MEM != mem_src_arr[k]);
                if (usglen <= 0)
                    break;
@@ -1766,7 +1946,7 @@ static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
 static char * sg_get_sgat_msa(Sg_scatter_hold * schp)
 {
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (schp->sglist_len / elem_sz) - 1;
+    int mx_sc_elems = schp->sglist_len / elem_sz;
     return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);
 }
 
@@ -1779,14 +1959,17 @@ static void sg_remove_scat(Sg_scatter_hold * schp)
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
        char * mem_src_arr = sg_get_sgat_msa(schp);
 
-       for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+       for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
            mem_src = mem_src_arr[k];
            SCSI_LOG_TIMEOUT(5,
                printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
-                       k, sclp->address, sclp->length, mem_src));
-            sg_free(sclp->address, sclp->length, mem_src);
-            sclp->address = NULL;
+                       k, sg_scatg2virt(sclp), sclp->length, mem_src));
+            sg_free(sg_scatg2virt(sclp), sclp->length, mem_src);
            sclp->page = NULL;
+            sclp->offset = 0;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+           sclp->address = 0;
+#endif
             sclp->length = 0;
         }
        sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);
@@ -1814,7 +1997,8 @@ static int sg_read_xfer(Sg_request * srp)
        if (schp->bufflen < num_xfer)
            num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+       (new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
        return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -1848,14 +2032,15 @@ static int sg_read_xfer(Sg_request * srp)
        struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
        char * mem_src_arr = sg_get_sgat_msa(schp);
        ksglen = (int)sclp->length;
-       p = sclp->address;
+       p = sg_scatg2virt(sclp);
 
        for (j = 0, k = 0; j < onum; ++j) {
            res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
            if (res) return res;
 
            for (; (k < schp->k_use_sg) && p;
-                ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+                ++k, ++sclp, ksglen = (int)sclp->length, 
+                       p = sg_scatg2virt(sclp)) {
                ok = (SG_USER_MEM != mem_src_arr[k]);
                if (usglen <= 0)
                    break;
@@ -1896,14 +2081,14 @@ static void sg_read_oxfer(Sg_request * srp, char * outp, int num_read_xfer)
         int k, num;
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 
-       for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+       for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
             num = (int)sclp->length;
             if (num > num_read_xfer) {
-                __copy_to_user(outp, sclp->address, num_read_xfer);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer);
                 break;
             }
             else {
-                __copy_to_user(outp, sclp->address, num);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num);
                 num_read_xfer -= num;
                 if (num_read_xfer <= 0)
                     break;
@@ -1949,7 +2134,7 @@ static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
             if (rem <= num) {
                if (0 == k) {
                    req_schp->k_use_sg = 0;
-                   req_schp->buffer = sclp->address;
+                   req_schp->buffer = sg_scatg2virt(sclp);
                }
                else {
                    sfp->save_scat_len = num;
@@ -2189,6 +2374,8 @@ static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
     if (sfp->reserve.bufflen > 0) {
     SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
             (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
+       if (sfp->mmap_called)
+           sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */
        sg_remove_scat(&sfp->reserve);
     }
     sfp->parentdp = NULL;
@@ -2237,7 +2424,7 @@ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
        /* MOD_INC's to inhibit unloading sg and associated adapter driver */
        if (sg_template.module)
            __MOD_INC_USE_COUNT(sg_template.module);
-        if (sdp->device->host->hostt->module)
+       if (sdp->device->host->hostt->module)
            __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
         SCSI_LOG_TIMEOUT(1, printk(
           "sg_remove_sfp: worrisome, %d writes pending\n", dirty));
@@ -2270,30 +2457,6 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
         if (resp && retSzp) *retSzp = rqSz;
         return resp;
     }
-    if (SG_HEAP_POOL == mem_src) {
-        int num_sect = rqSz / SG_SECTOR_SZ;
-
-        if (0 != (rqSz & SG_SECTOR_MSK)) {
-            if (! retSzp)
-                return resp;
-            ++num_sect;
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-        while (num_sect > 0) {
-            if ((num_sect <= sg_pool_secs_avail)) {
-                resp = kmalloc(rqSz, page_mask);
-                if (resp) {
-                    if (retSzp) *retSzp = rqSz;
-                    sg_pool_secs_avail -= num_sect;
-                    return resp;
-                }
-            }
-            if (! retSzp)
-                return resp;
-            num_sect /= 2;      /* try half as many */
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-    }
     else if (SG_HEAP_PAGE == mem_src) {
         int order, a_size;
         int resSz = rqSz;
@@ -2311,7 +2474,8 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, int * retSzp)
         if (retSzp) *retSzp = resSz;
     }
     else
-        printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz);
+        printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", 
+              mem_src, rqSz);
     return resp;
 }
 
@@ -2330,29 +2494,20 @@ static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
        switch (*mem_srcp)
         {
         case SG_HEAP_PAGE:
-            l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
+            l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE;
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
             if (resp)
                 break;
             resp = sg_low_malloc(size, low_dma, l_ms, &size);
             if (! resp) {
-                l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
+                l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL;
                 resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                if (! resp) {
-                    l_ms = SG_HEAP_KMAL;
-                    resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                }
             }
             if (resp && retSzp) *retSzp = size;
             break;
         case SG_HEAP_KMAL:
-            l_ms = SG_HEAP_PAGE;
+            l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
-            if (resp)
-                break;
-            l_ms = SG_HEAP_POOL;
-            resp = sg_low_malloc(size, low_dma, l_ms, &size);
-            if (resp && retSzp) *retSzp = size;
             break;
         default:
             SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp));
@@ -2365,18 +2520,19 @@ static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
     return resp;
 }
 
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp)
+{
+#if SG_NEW_KIOVEC
+    return alloc_kiovec_sz(nr, bufp, szp);
+#else
+    return alloc_kiovec(nr, bufp);
+#endif
+}
+
 static void sg_low_free(char * buff, int size, int mem_src)
 {
     if (! buff) return;
     switch (mem_src) {
-    case SG_HEAP_POOL:
-       {
-           int num_sect = size / SG_SECTOR_SZ;
-
-           kfree(buff);
-           sg_pool_secs_avail += num_sect;
-       }
-       break;
     case SG_HEAP_KMAL:
        kfree(buff);    /* size not used */
        break;
@@ -2392,7 +2548,7 @@ static void sg_low_free(char * buff, int size, int mem_src)
     case SG_USER_MEM:
        break; /* nothing to do */
     default:
-       printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
+       printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
                mem_src, buff, size);
        break;
     }
@@ -2408,14 +2564,13 @@ static void sg_free(char * buff, int size, int mem_src)
         sg_low_free(buff, size, mem_src);
 }
 
-static void sg_clr_srpnt(Scsi_Request * SRpnt)
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp)
 {
-    SRpnt->sr_use_sg = 0;
-    SRpnt->sr_sglist_len = 0;
-    SRpnt->sr_bufflen = 0;
-    SRpnt->sr_buffer = NULL;
-    SRpnt->sr_underflow = 0;
-    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ command blk */
+#if SG_NEW_KIOVEC
+    free_kiovec_sz(nr, bufp, szp);
+#else
+    free_kiovec(nr, bufp);
+#endif
 }
 
 static int sg_ms_to_jif(unsigned int msecs)
@@ -2427,7 +2582,7 @@ static int sg_ms_to_jif(unsigned int msecs)
                                               : (((int)msecs / 1000) * HZ);
 }
 
-static unsigned sg_jif_to_ms(int jifs)
+static inline unsigned sg_jif_to_ms(int jifs)
 {
     if (jifs <= 0)
        return 0U;
@@ -2477,8 +2632,8 @@ static Sg_device * sg_get_dev(int dev)
     if (sg_dev_arr && (dev >= 0))
     {
        read_lock_irqsave(&sg_dev_arr_lock, iflags);
-    if (dev < sg_template.dev_max)
-       sdp = sg_dev_arr[dev];
+       if (dev < sg_template.dev_max)
+           sdp = sg_dev_arr[dev];
        read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
     }
     return sdp;
@@ -2671,7 +2826,7 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
 {
     Sg_device * sdp;
     const sg_io_hdr_t * hp;
-    int j, max_dev;
+    int j, max_dev, new_interface;
 
     if (NULL == sg_dev_arr) {
        PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
@@ -2680,8 +2835,7 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
     max_dev = sg_last_dev();
     PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
               sg_template.dev_max, max_dev);
-    PRINT_PROC(" sg_pool_secs_aval=%d def_reserved_size=%d\n",
-              sg_pool_secs_avail, sg_big_buff);
+    PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
     for (j = 0; j < max_dev; ++j) {
        if ((sdp = sg_get_dev(j))) {
            Sg_fd * fp;
@@ -2717,8 +2871,10 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
                           (int)fp->keep_orphan, (int)fp->closed);
                for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
                    hp = &srp->header;
+                   new_interface = (hp->interface_id == '\0') ? 0 : 1;
 /* stop indenting so far ... */
-       PRINT_PROC(srp->res_used ? "     rb>> " :
+       PRINT_PROC(srp->res_used ? ((new_interface && 
+           (SG_FLAG_MMAP_IO & hp->flags)) ? "     mmap>> " : "     rb>> ") :
            ((SG_INFO_DIRECT_IO_MASK & hp->info) ? "     dio>> " : "     "));
        blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen;
        usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
@@ -2728,8 +2884,8 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin,
        if (srp->done)
            PRINT_PROC(" dur=%d", hp->duration);
        else
-           PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ?
-                       sg_jif_to_ms(fp->timeout) : hp->timeout),
+           PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout :
+                       sg_jif_to_ms(fp->timeout),
                  sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0));
        PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode);
 /* reset indenting */
index 660cf3bc6bacd60863400441cee886d19af0fcce..a6069580da1a40706d90791744e4f150c5b1eec9 100644 (file)
@@ -331,7 +331,7 @@ static int sr_init_command(Scsi_Cmnd * SCpnt)
 
        SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n",
                                    devm,
-                  (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+                  (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
                                 this_count, SCpnt->request.nr_sectors));
 
        SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
index a860d28898f9cf9f67995f5108439b74523556dc..cdb44556274e92340bd452732432f14a615f0168 100644 (file)
@@ -1995,7 +1995,7 @@ handle_one_block:
        /* just to be a nice neighbor */
        /* Thomas Sailer:
         * But also to ourselves, release semaphore if we do so */
-       if (current->need_resched) {
+       if (need_resched()) {
                up(&card->syscall_sem);
                schedule ();
                ret = via_syscall_down (card, nonblock);
@@ -2171,7 +2171,7 @@ handle_one_block:
        /* just to be a nice neighbor */
        /* Thomas Sailer:
         * But also to ourselves, release semaphore if we do so */
-       if (current->need_resched) {
+       if (need_resched()) {
                up(&card->syscall_sem);
                schedule ();
                ret = via_syscall_down (card, nonblock);
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 8d4799ae576def705a1cd8d13ea9283d2fcd87af..1e6cefb31d2f7cfc80c4e0d93ff0e8c921a1143e 100644 (file)
@@ -1081,20 +1081,20 @@ static int hcd_unlink_urb (struct urb *urb)
        if (!urb)
                return -EINVAL;
 
-       // FIXME:  add some explicit records to flag the
-       // state where the URB is "in periodic completion".
-       // Workaround is for driver to set the urb status
-       // to "-EINPROGRESS", so it can get through here
-       // and unlink from the completion handler.
-
        /*
         * we contend for urb->status with the hcd core,
         * which changes it while returning the urb.
+        *
+        * Caller guaranteed that the urb pointer hasn't been freed, and
+        * that it was submitted.  But as a rule it can't know whether or
+        * not it's already been unlinked ... so we respect the reversed
+        * lock sequence needed for the usb_hcd_giveback_urb() code paths
+        * (urb lock, then hcd_data_lock) in case some other CPU is now
+        * unlinking it.
         */
        spin_lock_irqsave (&urb->lock, flags);
-       if (!urb->hcpriv
-                       || urb->status != -EINPROGRESS
-                       || urb->transfer_flags & USB_TIMEOUT_KILLED) {
+       spin_lock (&hcd_data_lock);
+       if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
                retval = -EINVAL;
                goto done;
        }
@@ -1103,6 +1103,8 @@ static int hcd_unlink_urb (struct urb *urb)
                retval = -ENODEV;
                goto done;
        }
+
+       /* giveback clears dev; non-null means it's linked at this level */
        dev = urb->dev->hcpriv;
        hcd = urb->dev->bus->hcpriv;
        if (!dev || !hcd) {
@@ -1110,6 +1112,27 @@ static int hcd_unlink_urb (struct urb *urb)
                goto done;
        }
 
+       /* For non-periodic transfers, any status except -EINPROGRESS means
+        * the HCD has already started to unlink this URB from the hardware.
+        * In that case, there's no more work to do.
+        *
+        * For periodic transfers, this is the only way to trigger unlinking
+        * from the hardware.  Since we (currently) overload urb->status to
+        * tell the driver to unlink, error status might get clobbered ...
+        * unless that transfer hasn't yet restarted.  One such case is when
+        * the URB gets unlinked from its completion handler.
+        *
+        * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
+        */
+       switch (usb_pipetype (urb->pipe)) {
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+               if (urb->status != -EINPROGRESS) {
+                       retval = 0;
+                       goto done;
+               }
+       }
+
        /* maybe set up to block on completion notification */
        if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
                urb->status = -ETIMEDOUT;
@@ -1130,6 +1153,7 @@ static int hcd_unlink_urb (struct urb *urb)
                /* asynchronous unlink */
                urb->status = -ECONNRESET;
        }
+       spin_unlock (&hcd_data_lock);
        spin_unlock_irqrestore (&urb->lock, flags);
 
        if (urb == (struct urb *) hcd->rh_timer.data) {
@@ -1154,6 +1178,7 @@ if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
        }
        goto bye;
 done:
+       spin_unlock (&hcd_data_lock);
        spin_unlock_irqrestore (&urb->lock, flags);
 bye:
        if (retval)
index 41b8f3fd2df07413579194b90e2bf90097c2f3af..f48416cbbb8a96f356578b8f1f80a0b490eac6a1 100644 (file)
  *     Brad Hards
  *     Rory Bolt
  *     ...
+ *
+ * HISTORY:
+ * 2002-01-14  Minor cleanup; version synch.
+ * 2002-01-08  Fix roothub handoff of FS/LS to companion controllers.
+ * 2002-01-04  Control/Bulk queuing behaves.
+ * 2001-12-12  Initial patch version for Linux 2.5.1 kernel.
  */
 
-#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_VERSION "$Revision: 0.26 $"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -98,9 +104,6 @@ static int log2_irq_thresh = 0;              // 0 to 6
 MODULE_PARM (log2_irq_thresh, "i");
 MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
 
-/* Some A steppings of the NEC controller need soft retries */
-//#define      EHCI_SOFT_RETRIES       5       /* after CERR-induced fault */
-
 #define        INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
 
 /*-------------------------------------------------------------------------*/
index 4234fd8f27a6a6b2b5adc60036f2cc060af2fafd..798fd6066430b5827be70c35250871fe8a7e8104 100644 (file)
@@ -82,11 +82,12 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
        for (i = 0; i < ports; i++) {
                temp = readl (&ehci->regs->port_status [i]);
                if (temp & PORT_OWNER) {
-                       // get disconnected ports back if no companion driver
-                       if (temp & PORT_CONNECT)
-                               continue;
-                       temp &= ~(PORT_OWNER|PORT_CSC);
-                       writel (temp, &ehci->regs->port_status [i]);
+                       /* don't report this in GetPortStatus */
+                       if (temp & PORT_CSC) {
+                               temp &= ~PORT_CSC;
+                               writel (temp, &ehci->regs->port_status [i]);
+                       }
+                       continue;
                }
                if (!(temp & PORT_CONNECT))
                        ehci->reset_done [i] = 0;
index d559e894575bfb12f51046c9f38935864b17b1d3..df6c07d3d6feef35723714b47ec8c9ab12b1ef51 100644 (file)
@@ -883,11 +883,10 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                /* can't get here without STS_ASS set */
                if (ehci->hcd.state != USB_STATE_HALT) {
                        if (cmd & CMD_PSE)
-                               writel (cmd & __constant_cpu_to_le32 (~CMD_ASE),
-                                       &ehci->regs->command);
+                               writel (cmd & ~CMD_ASE, &ehci->regs->command);
                        else {
                                ehci_ready (ehci);
-                               while (!(readl (&ehci->regs->status) & STS_ASS))
+                               while (readl (&ehci->regs->status) & STS_ASS)
                                        udelay (100);
                        }
                }
index 5a971fee2d9f058b638f49b57afafe999090c18a..1328913d6f29fce2894a6b0def0b04e0941dfdb9 100644 (file)
@@ -381,7 +381,7 @@ static int intr_submit (
                        vdbg ("qh %p usecs %d period %d starting frame %d.%d",
                                qh, qh->usecs, period, frame, uframe);
                        do {
-                               if (unlikely ((long)ehci->pshadow [frame].ptr)) {
+                               if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 // FIXME -- just link to the end, before any qh with a shorter period,
 // AND handle it already being (implicitly) linked into this frame
                                        BUG ();
index e184832bd9fd2cb5683a4770b875b2921ce0e609..e771ff6d0d4e31a6aff7e68df1ab660a70a52718 100644 (file)
@@ -272,7 +272,7 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
        if (!srb->bufflen) {
                usb_callback = simple_command_callback;
        } else {
-               if (srb->use_sg) {
+               if (likely(srb->use_sg)) {
                        usb_callback = scatter_gather_callback;
                        hpusbscsi->fragment = 0;
                } else {
@@ -288,10 +288,6 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
 
 
        TRACE_STATE;
-       if (hpusbscsi->state != HP_STATE_FREE) {
-               printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n");
-               return 1; /* This must not happen */
-       }
 
         /* We zero the sense buffer to avoid confusing user space */
         memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
@@ -313,10 +309,10 @@ static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
        hpusbscsi->srb = srb;
 
        res = usb_submit_urb(&hpusbscsi->dataurb);
-       if (res) {
+       if (unlikely(res)) {
                hpusbscsi->state = HP_STATE_FREE;
                TRACE_STATE;
-               if (callback) {
+               if (likely(callback != NULL)) {
                        srb->result = DID_ERROR;
                        callback(srb);
                }
@@ -355,7 +351,7 @@ static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb)
 
 static void handle_usb_error (struct hpusbscsi *hpusbscsi)
 {
-       if (hpusbscsi->scallback != NULL) {
+       if (likely(hpusbscsi->scallback != NULL)) {
                hpusbscsi->srb->result = DID_ERROR;
                hpusbscsi->scallback(hpusbscsi->srb);
        }
@@ -367,8 +363,8 @@ static void  control_interrupt_callback (struct urb *u)
        struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
 DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
-       if(u->status < 0) {
-                if (hpusbscsi->state != HP_STATE_FREE)
+       if(unlikely(u->status < 0)) {
+                if (likely(hpusbscsi->state != HP_STATE_FREE))
                         handle_usb_error(hpusbscsi);
                return;
        }
@@ -402,7 +398,7 @@ DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
 static void simple_command_callback(struct urb *u)
 {
        struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-       if (u->status<0) {
+       if (unlikely(u->status<0)) {
                handle_usb_error(hpusbscsi);
                return;
         }
@@ -411,7 +407,7 @@ static void simple_command_callback(struct urb *u)
                TRACE_STATE;
                hpusbscsi->state = HP_STATE_WAIT;
        } else {
-               if (hpusbscsi->scallback != NULL)
+               if (likely(hpusbscsi->scallback != NULL))
                        hpusbscsi->scallback(hpusbscsi->srb);
                hpusbscsi->state = HP_STATE_FREE;
        TRACE_STATE;
@@ -426,7 +422,7 @@ static void scatter_gather_callback(struct urb *u)
         int res;
 
         DEBUG("Going through scatter/gather\n");
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
@@ -452,7 +448,7 @@ static void scatter_gather_callback(struct urb *u)
         );
 
         res = usb_submit_urb(u);
-        if (res)
+        if (unlikely(res))
                 hpusbscsi->state = HP_STATE_ERROR;
        TRACE_STATE;
 }
@@ -461,20 +457,20 @@ static void simple_done (struct urb *u)
 {
        struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
         DEBUG("Data transfer done\n");
        TRACE_STATE;
        if (hpusbscsi->state != HP_STATE_PREMATURE) {
-               if (u->status < 0)
+               if (unlikely(u->status < 0))
                        hpusbscsi->state = HP_STATE_ERROR;
                else
                        hpusbscsi->state = HP_STATE_WAIT;
                TRACE_STATE;
        } else {
-               if (hpusbscsi->scallback != NULL)
+               if (likely(hpusbscsi->scallback != NULL))
                        hpusbscsi->scallback(hpusbscsi->srb);
                hpusbscsi->state = HP_STATE_FREE;
        }
@@ -485,7 +481,7 @@ static void simple_payload_callback (struct urb *u)
        struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
        int res;
 
-       if (u->status<0) {
+       if (unlikely(u->status<0)) {
                 handle_usb_error(hpusbscsi);
                return;
         }
@@ -501,7 +497,7 @@ static void simple_payload_callback (struct urb *u)
        );
 
        res = usb_submit_urb(u);
-       if (res) {
+       if (unlikely(res)) {
                 handle_usb_error(hpusbscsi);
                return;
         }
@@ -510,10 +506,11 @@ static void simple_payload_callback (struct urb *u)
                hpusbscsi->state = HP_STATE_WORKING;
        TRACE_STATE;
        } else {
-               if (hpusbscsi->scallback != NULL)
+               if (likely(hpusbscsi->scallback != NULL))
                        hpusbscsi->scallback(hpusbscsi->srb);
                hpusbscsi->state = HP_STATE_FREE;
        TRACE_STATE;
        }
 }
 
+
index 78b9f1926b6e1204aa2feb98853c02f4f3255594..f741f808a244a7e612d43a0b3485051d88673f52 100644 (file)
@@ -557,6 +557,10 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
                dbg("port %d, portstatus %x, change %x, %s", port + 1,
                        portstatus, portchange, portspeed (portstatus));
 
+               /* Device went away? */
+               if (!(portstatus & USB_PORT_STAT_CONNECTION))
+                       return 1;
+
                /* bomb out completely if something weird happened */
                if ((portchange & USB_PORT_STAT_C_CONNECTION))
                        return -1;
index 10c5d93f8097d89adc209090a2dfc4b40de1028c..ba056f1ed6b24976011e4f9578e70e95d10d70d6 100644 (file)
@@ -320,11 +320,6 @@ static inline void mts_debug_dump(struct mts_desc* dummy)
 
 #endif
 
-
-/* static inline int mts_is_aborting(struct mts_desc* desc) {
-       return (atomic_read(&desc->context.do_abort));
-}  */
-
 static inline void mts_urb_abort(struct mts_desc* desc) {
        MTS_DEBUG_GOT_HERE();
        mts_debug_dump(desc);
@@ -504,7 +499,7 @@ void mts_int_submit_urb (struct urb* transfer,
        transfer->status = 0;
 
        res = usb_submit_urb( transfer );
-       if ( res ) {
+       if ( unlikely(res) ) {
                MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
                context->srb->result = DID_ERROR << 16;
                mts_transfer_cleanup(transfer);
@@ -518,7 +513,7 @@ static void mts_transfer_cleanup( struct urb *transfer )
 {
        MTS_INT_INIT();
 
-       if ( context->final_callback )
+       if ( likely(context->final_callback != NULL) )
                context->final_callback(context->srb);
 
 }
@@ -556,7 +551,7 @@ static void mts_data_done( struct urb* transfer )
 
        if ( context->data_length != transfer->actual_length ) {
                context->srb->resid = context->data_length - transfer->actual_length;
-       } else if ( transfer->status ) {
+       } else if ( unlikely(transfer->status) ) {
                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
        }
 
@@ -571,7 +566,7 @@ static void mts_command_done( struct urb *transfer )
 {
        MTS_INT_INIT();
 
-       if ( transfer->status ) {
+       if ( unlikely(transfer->status) ) {
                if (transfer->status == -ENOENT) {
                        /* We are being killed */
                        MTS_DEBUG_GOT_HERE();
@@ -605,7 +600,7 @@ static void mts_do_sg (struct urb* transfer)
        
        MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-       if (transfer->status) {
+       if (unlikely(transfer->status)) {
                 context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
                mts_transfer_cleanup(transfer);
         }
@@ -703,7 +698,7 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
 
                srb->result = DID_BAD_TARGET << 16;
 
-               if(callback)
+               if(likely(callback != NULL))
                        callback(srb);
 
                goto out;
@@ -725,11 +720,11 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
        
        res=usb_submit_urb(&desc->urb);
 
-       if(res){
+       if(unlikely(res)){
                MTS_ERROR("error %d submitting URB\n",(int)res);
                srb->result = DID_ERROR << 16;
 
-               if(callback)
+               if(likely(callback != NULL))
                        callback(srb);
 
        }
@@ -1062,3 +1057,4 @@ MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
 
+
index d73a7c3a759e967ea96fb7c909e9ee31b8e25ce5..7672fc1c5558954dbd736f555937ce7ae518ed73 100644 (file)
@@ -2,6 +2,7 @@
  * USB IR Dongle driver
  *
  *     Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *     Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com)
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2002_Jan_14  gb
+ *     Added module parameter to force specific number of XBOFs.
+ *     Added ir_xbof_change().
+ *     Reorganized read_bulk_callback error handling.
+ *     Switched from FILL_BULK_URB() to usb_fill_bulk_urb().
+ *
  * 2001_Nov_08  greg kh
  *     Changed the irda_usb_find_class_desc() function based on comments and
  *     code from Martin Diehl.
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
 static int buffer_size = 0;
+/* if overridden by the user, then use the specified number of XBOFs */
+static int xbof = -1;
 
 static int  ir_startup (struct usb_serial *serial);
 static int  ir_open (struct usb_serial_port *port, struct file *filep);
@@ -78,6 +87,9 @@ static void ir_write_bulk_callback (struct urb *urb);
 static void ir_read_bulk_callback (struct urb *urb);
 static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
 
+static u8 ir_baud = 0;
+static u8 ir_xbof = 0;
+static u8 ir_add_bof = 0;
 
 static __devinitdata struct usb_device_id id_table [] = {
        { USB_DEVICE(0x050f, 0x0180) },         /* KC Technology, KC-180 */
@@ -148,14 +160,16 @@ static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev,
                        USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                        0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
        
-       dbg(__FUNCTION__ " -  ret=%d", ret);
+       dbg("%s -  ret=%d", __FUNCTION__, ret);
        if (ret < sizeof(*desc)) {
-               dbg(__FUNCTION__ " - class descriptor read %s (%d)",
-                               (ret<0) ? "failed" : "too short", ret);
+               dbg("%s - class descriptor read %s (%d)",
+                               __FUNCTION__, 
+                               (ret<0) ? "failed" : "too short",
+                               ret);
                goto error;
        }
        if (desc->bDescriptorType != USB_DT_IRDA) {
-               dbg(__FUNCTION__ " - bad class descriptor type");
+               dbg("%s - bad class descriptor type", __FUNCTION__);
                goto error;
        }
        
@@ -166,6 +180,28 @@ error:
        return NULL;
 }
 
+
+static u8 ir_xbof_change(u8 xbof)
+{
+       u8 result;
+       /* reference irda-usb.c */
+       switch(xbof) {
+               case 48: result = 0x10; break;
+               case 28:
+               case 24: result = 0x20; break;
+               default:
+               case 12: result = 0x30; break;
+               case  5:
+               case  6: result = 0x40; break;
+               case  3: result = 0x50; break;
+               case  2: result = 0x60; break;
+               case  1: result = 0x70; break;
+               case  0: result = 0x80; break;
+       }
+       return(result);
+}
+
+
 static int ir_startup (struct usb_serial *serial)
 {
        struct irda_class_desc *irda_desc;
@@ -175,16 +211,30 @@ static int ir_startup (struct usb_serial *serial)
                err ("IRDA class descriptor not found, device not bound");
                return -ENODEV;
        }
-       dbg (__FUNCTION__" - Baud rates supported: %s%s%s%s%s%s%s%s%s",
-            (irda_desc->wBaudRate & 0x0001) ? "2400 " : "",
-            irda_desc->wBaudRate & 0x0002 ? "9600 " : "",
-            irda_desc->wBaudRate & 0x0004 ? "19200 " : "",
-            irda_desc->wBaudRate & 0x0008 ? "38400 " : "",
-            irda_desc->wBaudRate & 0x0010 ? "57600 " : "",
-            irda_desc->wBaudRate & 0x0020 ? "115200 " : "",
-            irda_desc->wBaudRate & 0x0040 ? "576000 " : "",
-            irda_desc->wBaudRate & 0x0080 ? "1152000 " : "",
-            irda_desc->wBaudRate & 0x0100 ? "4000000 " : "");
+
+       dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+               __FUNCTION__,
+               (irda_desc->wBaudRate & 0x0001) ? " 2400"    : "",
+               (irda_desc->wBaudRate & 0x0002) ? " 9600"    : "",
+               (irda_desc->wBaudRate & 0x0004) ? " 19200"   : "",
+               (irda_desc->wBaudRate & 0x0008) ? " 38400"   : "",
+               (irda_desc->wBaudRate & 0x0010) ? " 57600"   : "",
+               (irda_desc->wBaudRate & 0x0020) ? " 115200"  : "",
+               (irda_desc->wBaudRate & 0x0040) ? " 576000"  : "",
+               (irda_desc->wBaudRate & 0x0080) ? " 1152000" : "",
+               (irda_desc->wBaudRate & 0x0100) ? " 4000000" : "");
+
+       switch( irda_desc->bmAdditionalBOFs ) {
+               case 0x01: ir_add_bof = 48; break;
+               case 0x02: ir_add_bof = 24; break;
+               case 0x04: ir_add_bof = 12; break;
+               case 0x08: ir_add_bof =  6; break;
+               case 0x10: ir_add_bof =  3; break;
+               case 0x20: ir_add_bof =  2; break;
+               case 0x40: ir_add_bof =  1; break;
+               case 0x80: ir_add_bof =  0; break;
+               default:
+       }
 
        kfree (irda_desc);
 
@@ -200,7 +250,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
        
-       dbg(__FUNCTION__ " - port %d", port->number);
+       dbg("%s - port %d", __FUNCTION__, port->number);
 
        down (&port->sem);
        
@@ -211,7 +261,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
                        /* override the default buffer sizes */
                        buffer = kmalloc (buffer_size, GFP_KERNEL);
                        if (!buffer) {
-                               err (__FUNCTION__ " - out of memory.");
+                               err ("%s - out of memory.", __FUNCTION__);
                                return -ENOMEM;
                        }
                        kfree (port->read_urb->transfer_buffer);
@@ -220,7 +270,7 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
 
                        buffer = kmalloc (buffer_size, GFP_KERNEL);
                        if (!buffer) {
-                               err (__FUNCTION__ " - out of memory.");
+                               err ("%s - out of memory.", __FUNCTION__);
                                return -ENOMEM;
                        }
                        kfree (port->write_urb->transfer_buffer);
@@ -230,13 +280,18 @@ static int ir_open (struct usb_serial_port *port, struct file *filp)
                }
 
                /* Start reading from the device */
-               FILL_BULK_URB(port->read_urb, serial->dev, 
-                             usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-                             port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-                             ir_read_bulk_callback, port);
+               usb_fill_bulk_urb (
+                       port->read_urb,
+                       serial->dev, 
+                       usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+                       port->read_urb->transfer_buffer,
+                       port->read_urb->transfer_buffer_length,
+                       ir_read_bulk_callback,
+                       port);
+               port->read_urb->transfer_flags = USB_QUEUE_BULK;
                result = usb_submit_urb(port->read_urb);
                if (result)
-                       err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+                       err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
        }
        
        up (&port->sem);
@@ -251,7 +306,7 @@ static void ir_close (struct usb_serial_port *port, struct file * filp)
        if (port_paranoia_check (port, __FUNCTION__))
                return;
        
-       dbg(__FUNCTION__ " - port %d", port->number);
+       dbg("%s - port %d", __FUNCTION__, port->number);
                         
        serial = get_usb_serial (port, __FUNCTION__);
        if (!serial)
@@ -276,11 +331,12 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned
 {
        unsigned char *transfer_buffer;
        int result;
+       int transfer_size;
 
-       dbg(__FUNCTION__ " - port = %d, count = %d", port->number, count);
+       dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count);
 
        if (!port->tty) {
-               err (__FUNCTION__ " - no tty???");
+               err ("%s - no tty???", __FUNCTION__);
                return 0;
        }
 
@@ -288,37 +344,49 @@ static int ir_write (struct usb_serial_port *port, int from_user, const unsigned
                return 0;
 
        if (port->write_urb->status == -EINPROGRESS) {
-               dbg (__FUNCTION__ " - already writing");
+               dbg ("%s - already writing", __FUNCTION__);
                return 0;
        }
 
+       transfer_buffer = port->write_urb->transfer_buffer;
+       transfer_size = min(count, port->bulk_out_size - 1);
+
        /*
-        * The first byte of the packet we send to the device contains a BOD
-        * and baud rate change.  So we set it to 0.
+        * The first byte of the packet we send to the device contains an
+        * inband header which indicates an additional number of BOFs and
+        * a baud rate change.
+        *
         * See section 5.4.2.2 of the USB IrDA spec.
         */
-       transfer_buffer = port->write_urb->transfer_buffer;
-       count = min (port->bulk_out_size-1, count);
+       *transfer_buffer = ir_xbof | ir_baud;
+       ++transfer_buffer;
+
        if (from_user) {
-               if (copy_from_user (&transfer_buffer[1], buf, count))
+               if (copy_from_user (transfer_buffer, buf, transfer_size))
                        return -EFAULT;
        } else {
-               memcpy (&transfer_buffer[1], buf, count);
+               memcpy (transfer_buffer, buf, transfer_size);
        }
 
-       /* use 12 XBOF's as default */
-       transfer_buffer[0] = 0x30;
+       usb_fill_bulk_urb (
+               port->write_urb,
+               port->serial->dev,
+               usb_sndbulkpipe(port->serial->dev,
+                       port->bulk_out_endpointAddress),
+               port->write_urb->transfer_buffer,
+               transfer_size + 1,
+               ir_write_bulk_callback,
+               port);
 
-       usb_serial_debug_data (__FILE__, __FUNCTION__, count+1, transfer_buffer);
+       port->write_urb->transfer_flags
+               = USB_QUEUE_BULK
+               | USB_ZERO_PACKET;
 
-       port->write_urb->transfer_buffer_length = count + 1;
-       port->write_urb->dev = port->serial->dev;
-       port->write_urb->transfer_flags |= USB_ZERO_PACKET;
        result = usb_submit_urb (port->write_urb);
        if (result)
-               err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+               err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
        else
-               result = count;
+               result = transfer_size;
 
        return result;
 }
@@ -330,13 +398,19 @@ static void ir_write_bulk_callback (struct urb *urb)
        if (port_paranoia_check (port, __FUNCTION__))
                return;
        
-       dbg(__FUNCTION__ " - port %d", port->number);
+       dbg("%s - port %d", __FUNCTION__, port->number);
        
        if (urb->status) {
-               dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+               dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
                return;
        }
 
+       usb_serial_debug_data (
+               __FILE__,
+               __FUNCTION__,
+               urb->actual_length,
+               urb->transfer_buffer);
+
        queue_task(&port->tqueue, &tq_immediate);
        mark_bh(IMMEDIATE_BH);
        
@@ -354,34 +428,87 @@ static void ir_read_bulk_callback (struct urb *urb)
        if (port_paranoia_check (port, __FUNCTION__))
                return;
 
-       dbg(__FUNCTION__ " - port %d", port->number);
+       dbg("%s - port %d", __FUNCTION__, port->number);
 
        if (!serial) {
-               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               dbg("%s - bad serial pointer, exiting", __FUNCTION__);
                return;
        }
 
-       if (urb->status) {
-               dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+       if (!port->open_count) {
+               dbg("%s - port closed.", __FUNCTION__);
                return;
        }
 
-       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+       switch (urb->status) {
+
+               case 0: /* Successful */
+
+                       /*
+                        * The first byte of the packet we get from the device
+                        * contains a busy indicator and baud rate change.
+                        * See section 5.4.1.2 of the USB IrDA spec.
+                        */
+                       if((*data & 0x0f) > 0) ir_baud = *data & 0x0f;
+
+                       usb_serial_debug_data (
+                               __FILE__,
+                               __FUNCTION__,
+                               urb->actual_length,
+                               data);
+
+                       /*
+                        * Bypass flip-buffers, and feed the ldisc directly
+                        * due to our potentally large buffer size.  Since we
+                        * used to set low_latency, this is exactly what the
+                        * tty layer did anyway :)
+                        */
+                       tty = port->tty;
+
+                       tty->ldisc.receive_buf(
+                               tty,
+                               data+1,
+                               NULL,
+                               urb->actual_length-1);
+
+                       /*
+                        * No break here.
+                        * We want to resubmit the urb so we can read
+                        * again.
+                        */
+
+               case -EPROTO: /* taking inspiration from pl2303.c */
+
+                       /* Continue trying to always read */
+                       usb_fill_bulk_urb (
+                               port->read_urb,
+                               serial->dev, 
+                               usb_rcvbulkpipe(serial->dev,
+                                       port->bulk_in_endpointAddress),
+                               port->read_urb->transfer_buffer,
+                               port->read_urb->transfer_buffer_length,
+                               ir_read_bulk_callback,
+                               port);
+
+                       port->read_urb->transfer_flags = USB_QUEUE_BULK;
+
+                       result = usb_submit_urb(port->read_urb);
+
+                       if (result)
+                               err("%s - failed resubmitting read urb, error %d",
+                                       __FUNCTION__, 
+                                       result);
+
+                       break ;
+
+               default:
+                       dbg("%s - nonzero read bulk status received: %d",
+                               __FUNCTION__, 
+                               urb->status);
+                       break ;
 
-       /* Bypass flip-buffers, and feed the ldisc directly due to our 
-        * potentally large buffer size.  Since we used to set low_latency,
-        * this is exactly what the tty layer did anyway :) */
-       tty = port->tty;
-       tty->ldisc.receive_buf(tty, data+1, NULL, urb->actual_length-1);
+       }
 
-       /* Continue trying to always read  */
-       FILL_BULK_URB(port->read_urb, serial->dev, 
-                     usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-                     port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-                     ir_read_bulk_callback, port);
-       result = usb_submit_urb(port->read_urb);
-       if (result)
-               err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
        return;
 }
 
@@ -390,12 +517,11 @@ static void ir_set_termios (struct usb_serial_port *port, struct termios *old_te
        unsigned char *transfer_buffer;
        unsigned int cflag;
        int result;
-       u8 baud;
 
-       dbg(__FUNCTION__ " - port %d", port->number);
+       dbg("%s - port %d", __FUNCTION__, port->number);
 
        if ((!port->tty) || (!port->tty->termios)) {
-               dbg(__FUNCTION__" - no tty structures");
+               dbg("%s - no tty structures", __FUNCTION__);
                return;
        }
 
@@ -404,44 +530,70 @@ static void ir_set_termios (struct usb_serial_port *port, struct termios *old_te
        if (old_termios) {
                if ((cflag == old_termios->c_cflag) &&
                    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-                       dbg(__FUNCTION__ " - nothing to change...");
+                       dbg("%s - nothing to change...", __FUNCTION__);
                        return;
                }
        }
 
        /* All we can change is the baud rate */
        if (cflag & CBAUD) {
-               dbg (__FUNCTION__ " - asking for baud %d", tty_get_baud_rate(port->tty));
+
+               dbg ("%s - asking for baud %d",
+                       __FUNCTION__,
+                       tty_get_baud_rate(port->tty));
+
                /* 
                 * FIXME, we should compare the baud request against the
                 * capability stated in the IR header that we got in the
                 * startup funtion.
                 */
                switch (cflag & CBAUD) {
-                       case B2400:     baud = SPEED_2400;      break;
-                       case B9600:     baud = SPEED_9600;      break;
-                       case B19200:    baud = SPEED_19200;     break;
-                       case B38400:    baud = SPEED_38400;     break;
-                       case B57600:    baud = SPEED_57600;     break;
-                       case B115200:   baud = SPEED_115200;    break;
-                       case B576000:   baud = SPEED_576000;    break;
-                       case B1152000:  baud = SPEED_1152000;   break;
-                       case B4000000:  baud = SPEED_4000000;   break;
+                       case B2400:    ir_baud = SPEED_2400;    break;
                        default:
-                               err ("ir-usb driver does not support the baudrate (%d) requested", tty_get_baud_rate(port->tty));
-                               return;
+                       case B9600:    ir_baud = SPEED_9600;    break;
+                       case B19200:   ir_baud = SPEED_19200;   break;
+                       case B38400:   ir_baud = SPEED_38400;   break;
+                       case B57600:   ir_baud = SPEED_57600;   break;
+                       case B115200:  ir_baud = SPEED_115200;  break;
+                       case B576000:  ir_baud = SPEED_576000;  break;
+                       case B1152000: ir_baud = SPEED_1152000; break;
+                       case B4000000: ir_baud = SPEED_4000000; break;
                }
-               
+
+               if (xbof == -1) {
+                       ir_xbof = ir_xbof_change(ir_add_bof);
+               } else {
+                       ir_xbof = ir_xbof_change(xbof) ;
+               }
+
+               /* Notify the tty driver that the termios have changed. */
+               port->tty->ldisc.set_termios(port->tty, NULL);
+
                /* FIXME need to check to see if our write urb is busy right
-                * now, or use a urb pool. */
-               /* send the baud change out on an "empty" data packet */
+                * now, or use a urb pool.
+                *
+                * send the baud change out on an "empty" data packet
+                */
                transfer_buffer = port->write_urb->transfer_buffer;
-               transfer_buffer[0] = baud;
-               port->write_urb->transfer_buffer_length = 1;
-               port->write_urb->dev = port->serial->dev;
+               *transfer_buffer = ir_xbof | ir_baud;
+
+               usb_fill_bulk_urb (
+                       port->write_urb,
+                       port->serial->dev,
+                       usb_sndbulkpipe(port->serial->dev,
+                               port->bulk_out_endpointAddress),
+                       port->write_urb->transfer_buffer,
+                       1,
+                       ir_write_bulk_callback,
+                       port);
+
+               port->write_urb->transfer_flags
+                       = USB_QUEUE_BULK
+                       | USB_ZERO_PACKET;
+
                result = usb_submit_urb (port->write_urb);
                if (result)
-                       err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+                       err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
        }
        return;
 }
@@ -470,6 +622,8 @@ MODULE_LICENSE("GPL");
 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+MODULE_PARM(xbof, "i");
+MODULE_PARM_DESC(xbof, "Force specific number of XBOFs");
 MODULE_PARM(buffer_size, "i");
 MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
 
index e3062760fce463d43bd56247cc90eebb77c629a5..f736290afefa985f1968e727117a0aae69201482 100644 (file)
@@ -178,15 +178,7 @@ struct keyspan_port_private {
 /* Functions used by new usb-serial code. */
 static int __init keyspan_init (void)
 {
-       usb_serial_register (&keyspan_usa18x_pre_device);
-       usb_serial_register (&keyspan_usa19_pre_device);
-       usb_serial_register (&keyspan_usa19w_pre_device);
-       usb_serial_register (&keyspan_usa28_pre_device);
-       usb_serial_register (&keyspan_usa28x_pre_device);
-       usb_serial_register (&keyspan_usa28xa_pre_device);
-       usb_serial_register (&keyspan_usa28xb_pre_device);
-       usb_serial_register (&keyspan_usa49w_pre_device);
-
+       usb_serial_register (&keyspan_pre_device);
        usb_serial_register (&keyspan_usa18x_device);
        usb_serial_register (&keyspan_usa19_device);
        usb_serial_register (&keyspan_usa19w_device);
@@ -203,15 +195,7 @@ static int __init keyspan_init (void)
 
 static void __exit keyspan_exit (void)
 {
-       usb_serial_deregister (&keyspan_usa18x_pre_device);
-       usb_serial_deregister (&keyspan_usa19_pre_device);
-       usb_serial_deregister (&keyspan_usa19w_pre_device);
-       usb_serial_deregister (&keyspan_usa28_pre_device);
-       usb_serial_deregister (&keyspan_usa28x_pre_device);
-       usb_serial_deregister (&keyspan_usa28xa_pre_device);
-       usb_serial_deregister (&keyspan_usa28xb_pre_device);
-       usb_serial_deregister (&keyspan_usa49w_pre_device);
-
+       usb_serial_deregister (&keyspan_pre_device);
        usb_serial_deregister (&keyspan_usa18x_device);
        usb_serial_deregister (&keyspan_usa19_device);
        usb_serial_deregister (&keyspan_usa19w_device);
index e4cf84a4196075fe298299e3662d8f66fd87e080..b309c0978584d21d19f05ce5931343982fcf8d99 100644 (file)
@@ -372,42 +372,15 @@ MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
    ID pattern.  But, for now, it looks like we need slightly different
    behavior for each match. */
 
-static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = {
+/* usb_device_id table for the pre-firmware download keyspan devices */
+static __devinitdata struct usb_device_id keyspan_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
-       { }     /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
-       { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
-       { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
-       { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
-       { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xa_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
-       { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xb_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
-       { } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
        { } /* Terminating entry */
 };
@@ -448,10 +421,10 @@ static __devinitdata struct usb_device_id keyspan_usa49w_ids[] = {
 };
 
     /* Structs for the devices, pre and post renumeration. */
-static struct usb_serial_device_type keyspan_usa18x_pre_device = {
+static struct usb_serial_device_type keyspan_pre_device = {
        owner:                  THIS_MODULE,
-       name:                   "Keyspan USA18X - (without firmware)",
-       id_table:               keyspan_usa18x_pre_ids,
+       name:                   "Keyspan - (without firmware)",
+       id_table:               keyspan_pre_ids,
        num_interrupt_in:       NUM_DONT_CARE,
        num_bulk_in:            NUM_DONT_CARE,
        num_bulk_out:           NUM_DONT_CARE,
@@ -459,84 +432,6 @@ static struct usb_serial_device_type keyspan_usa18x_pre_device = {
        startup:                keyspan_fake_startup    
 };
 
-static struct usb_serial_device_type keyspan_usa19_pre_device = {
-       owner:                  THIS_MODULE,
-       name:                   "Keyspan USA19 - (without firmware)",
-       id_table:               keyspan_usa19_pre_ids,
-       num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
-       num_ports:              1,
-       startup:                keyspan_fake_startup    
-};
-
-
-static struct usb_serial_device_type keyspan_usa19w_pre_device = {
-       owner:                  THIS_MODULE,
-       name:                   "Keyspan USA19W - (without firmware)",
-       id_table:               keyspan_usa19w_pre_ids,
-       num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
-       num_ports:              1,
-       startup:                keyspan_fake_startup    
-};
-
-
-static struct usb_serial_device_type keyspan_usa28_pre_device = {
-       owner:                  THIS_MODULE,
-       name:                   "Keyspan USA28 - (without firmware)",
-       id_table:               keyspan_usa28_pre_ids,
-       num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
-       num_ports:              2,
-       startup:                keyspan_fake_startup    
-};
-
-static struct usb_serial_device_type keyspan_usa28x_pre_device = {
-       owner:                  THIS_MODULE,
-       name:                   "Keyspan USA28X - (without firmware)",
-       id_table:               keyspan_usa28x_pre_ids,
-       num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
-       num_ports:              2,
-       startup:                keyspan_fake_startup    
-};
-
-static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
-       owner:                  THIS_MODULE,
-       name:                   "Keyspan USA28XA - (without firmware)",
-       id_table:               keyspan_usa28xa_pre_ids,
-       num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
-       num_ports:              2,
-       startup:                keyspan_fake_startup    
-};
-
-static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
-       owner:                  THIS_MODULE,
-       name:                   "Keyspan USA28XB - (without firmware)",
-       id_table:               keyspan_usa28xb_pre_ids,
-       num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
-       num_ports:              2,
-       startup:                keyspan_fake_startup    
-};
-
-static struct usb_serial_device_type keyspan_usa49w_pre_device = {
-       owner:                  THIS_MODULE,
-       name:                   "Keyspan USA49W - (without firmware)",
-       id_table:               keyspan_usa49w_pre_ids,
-       num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
-       num_ports:              4,
-       startup:                keyspan_fake_startup    
-};
 
 static struct usb_serial_device_type keyspan_usa18x_device = {
        owner:                  THIS_MODULE,
@@ -550,8 +445,6 @@ static struct usb_serial_device_type keyspan_usa18x_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-       //write_bulk_callback:  Not used - we define our own herbs
-       //read_int_callback:    keyspan_usa26_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
@@ -574,8 +467,6 @@ static struct usb_serial_device_type keyspan_usa19_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-//     write_bulk_callback:    keyspan_write_bulk_callback,
-//     read_int_callback:      keyspan_usa28_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
@@ -599,8 +490,6 @@ static struct usb_serial_device_type keyspan_usa19w_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-       //write_bulk_callback:  Not used - we define our own herbs
-       //read_int_callback:    keyspan_usa26_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
@@ -640,8 +529,6 @@ static struct usb_serial_device_type keyspan_usa28x_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-//     write_bulk_callback:    keyspan_write_bulk_callback,
-//     read_int_callback:      keyspan_usa26_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
@@ -665,8 +552,6 @@ static struct usb_serial_device_type keyspan_usa28xa_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-//     write_bulk_callback:    keyspan_write_bulk_callback,
-//     read_int_callback:      keyspan_usa26_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
@@ -690,8 +575,6 @@ static struct usb_serial_device_type keyspan_usa49w_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-       //write_bulk_callback:  Not used - we define our own herbs
-       //read_int_callback:    keyspan_usa26_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
index 7b8172850632809465813d1fddad6abfd991dfe5..c4e397cb970a38fc518afcd6f8311cb53d49798f 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.10 2001/07/30 00:27:59 mdharm Exp $
+ * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -76,7 +76,7 @@ void fix_inquiry_data(Scsi_Cmnd *srb)
                data_ptr = (unsigned char *)srb->request_buffer;
 
        /* Change the SCSI revision number */
-       data_ptr[2] |= 0x2;
+       data_ptr[2] = (data_ptr[2] & ~7) | 2;
 }
 
 /***********************************************************************
index 729c5ff602e78a8ffcaab6990c644d1d51d0233e..87ba0ccb0d3088c1de11a365dee4e8dde4fbd008 100644 (file)
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Ununsual Devices File
  *
- * $Id: unusual_devs.h,v 1.24 2001/12/29 03:12:45 mdharm Exp $
+ * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -459,6 +459,14 @@ UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
                 0 ),
 #endif
 
+/* Submitted by Brian Hall <brihall@bigfoot.com>
+ * Needed for START_STOP flag */
+UNUSUAL_DEV(  0x0c76, 0x0003, 0x0100, 0x0100,
+               "JMTek",
+               "USBDrive",
+               US_SC_SCSI, US_PR_BULK, NULL,
+               US_FL_START_STOP ),
+
 /* Reported by Dan Pilone <pilone@slac.com>
  * The device needs the flags only.
  */
index 579519d9f7b81375517625ad2b355dcba26df837..6d93cbbe76bb4d5f572df01ed9a073010a6790fa 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.69 2001/11/11 03:33:03 mdharm Exp $
+ * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -316,6 +316,13 @@ static int usb_stor_control_thread(void * __us)
         */
        daemonize();
 
+       /* avoid getting signals */
+       spin_lock_irq(&current->sigmask_lock);
+       flush_signals(current);
+       sigfillset(&current->blocked);
+       recalc_sigpending(current);
+       spin_unlock_irq(&current->sigmask_lock);
+
        /* set our name for identification purposes */
        sprintf(current->comm, "usb-storage-%d", us->host_number);
 
index c3df86637ed1c482bfeb72cccbd5ceb05a98a07c..31786c2fdf2b50e5ee7d037047cf7d66b4d32cf6 100644 (file)
  *                        Took out sharpen function, ran code through
  *                        Lindent, and did other minor tweaks to get
  *                        things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
  */
 
 #include <linux/config.h>
@@ -65,7 +72,8 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
 
 static unsigned int debug = 0;
 
@@ -79,7 +87,7 @@ static unsigned int debug = 0;
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
 #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -88,8 +96,8 @@ MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_LICENSE ("GPL");
 MODULE_PARM (debug, "i");
 MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
 MODULE_PARM (video_nr, "i");
 EXPORT_NO_SYMBOLS;
 
@@ -521,8 +529,15 @@ exit:
        stv680->palette = STV_VIDEO_PALETTE;
        stv680->depth = 24;     /* rgb24 bits */
        swapRGB = 0;
-       PDEBUG (1, "STV(i): swapRGB is OFF");
-
+       if ((swapRGB_on == 0) && (swapRGB == 0))
+               PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+       else if ((swapRGB_on == 1) && (swapRGB == 1))
+               PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+       else if (swapRGB_on == 1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+       else if (swapRGB_on == -1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+       
        if (stv_set_video_mode (stv680) < 0) {
                PDEBUG (0, "STV(e): Could not set video mode in stv_init");
                return -1;
@@ -543,6 +558,7 @@ static struct proc_dir_entry *stv680_proc_entry = NULL;
 extern struct proc_dir_entry *video_proc_entry;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
 
 static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -559,7 +575,13 @@ static int stv680_read_proc (char *page, char **start, off_t off, int count, int
        out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
 
        out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, stv680->vheight);
-       out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+       if (swapRGB_on == 0)
+               out += sprintf (out, "swapRGB         : %s\n", ON_OFF (swapRGB));
+       else if (swapRGB_on == 1)
+               out += sprintf (out, "swapRGB         : (forced) on\n");
+       else if (swapRGB_on == -1)
+               out += sprintf (out, "swapRGB         : (forced) off\n");
+
        out += sprintf (out, "Palette         : %i", stv680->palette);
 
        out += sprintf (out, "\n");
@@ -671,9 +693,7 @@ static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
        if (stv680->brightness != p->brightness) {
                stv680->chgbright = 1;
                stv680->brightness = p->brightness;
-       } else {
-               stv680->chgbright = 0;
-       }
+       } 
 
        stv680->whiteness = p->whiteness;       /* greyscale */
        stv680->colour = p->colour;
@@ -888,7 +908,7 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
 {
        int x, y, i;
        int w = stv680->cwidth;
-       int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+       int vw = stv680->cwidth, vh = stv680->cheight;
        unsigned int p = 0;
        int colour = 0, bayer = 0;
        unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
                return;
        }
 
-       if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+       if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
                vw = 320;
                vh = 240;
-               vstep = 1;
        }
-       if ((stv680->vwidth == 352)) {
+       if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
                vw = 352;
                vh = 288;
-               vstep = 1;
        }
-       if ((stv680->vwidth == 160)) {
-               vw = 160;
-               vh = 120;
-               vstep = 2;
-       }
-       if ((stv680->vwidth == 176)) {
-               vw = 176;
-               vh = 144;
-               vstep = 2;
-       }
-       memset (output, 0, 3 * vw * vh);        /* clear output matrix. Maybe not necessary. */
+
+       memset (output, 0, 3 * vw * vh);        /* clear output matrix. */
 
        for (y = 0; y < vh; y++) {
                for (x = 0; x < vw; x++) {
-
-                       switch (vstep) {
-                       case 1:
-                               if (x & 1)
-                                       p = *(raw + y * w + (x >> 1));
-                               else
-                                       p = *(raw + y * w + (x >> 1) + (w >> 1));
-                               break;
-
-                       case 2:
-                               if (x & 1)
-                                       p = *(raw + ((y * w) << 1) + x);
-                               else
-                                       p = *(raw + ((y * w) << 1) + x + (w >> 1));
-                               break;
-                       }
+                       if (x & 1)
+                               p = *(raw + y * w + (x >> 1));
+                       else
+                               p = *(raw + y * w + (x >> 1) + (w >> 1));
 
                        if (y & 1)
                                bayer = 2;
@@ -968,9 +965,10 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
                                colour = 2;
                                break;
                        }
-                       i = (y * vw + x) * 3;   /* output already zeroed out with memset */
+                       i = (y * vw + x) * 3;   
                        *(output + i + colour) = (unsigned char) p;
                }               /* for x */
+
        }                       /* for y */
 
        /****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
           (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
           White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
           converted to unsigned char. Values are in stv680.h  */
+
        for (y = 0; y < vh; y++) {
                for (x = 0; x < vw; x++) {
                        i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@ static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buff
                }               /* for x */
        }                       /* for y  - end demosaic  */
 
+       /* fix top and bottom row, left and right side */
+       i = vw * 3;
+       memcpy (output, (output + i), i);
+       memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+       for (y = 0; y < vh; y++) {
+               i = y * vw * 3;
+               memcpy ((output + i), (output + i + 3), 3);
+               memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+       }
+
+       /*  process all raw data, then trim to size if necessary */
+       if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+               i = 0;
+               for (y = 0; y < vh; y++) {
+                       if (!(y & 1)) {
+                               for (x = 0; x < vw; x++) {
+                                       p = (y * vw + x) * 3;
+                                       if (!(x & 1)) {
+                                               *(output + i) = *(output + p);
+                                               *(output + i + 1) = *(output + p + 1);
+                                               *(output + i + 2) = *(output + p + 2);
+                                               i += 3;
+                                       }
+                               }  /* for x */
+                       }
+               }  /* for y */
+       }
+       /* reset to proper width */
+       if ((stv680->vwidth == 160)) {
+               vw = 160;
+               vh = 120;
+       }
+       if ((stv680->vwidth == 176)) {
+               vw = 176;
+               vh = 144;
+       }
+
        /* output is RGB; some programs want BGR  */
-       if (swapRGB == 1) {
+       /* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+       /* swapRGB_on=-1, never swap */
+       if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
                for (y = 0; y < vh; y++) {
                        for (x = 0; x < vw; x++) {
                                i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
                                return -EFAULT;
                        }
                        copy_from_user (&p, arg, sizeof (p));
-                       PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+                       PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
 
                        if (stv680_set_pict (stv680, &p))
                                return -EINVAL;
@@ -1309,8 +1347,8 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
                        if (vm.format != STV_VIDEO_PALETTE) {
                                PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
                                        vm.format, STV_VIDEO_PALETTE);
-                               if (vm.format == 3) {
-                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+                               if ((vm.format == 3) && (swapRGB_on == 0))  {
+                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
                                        /* this may fix those apps (e.g., xawtv) that want BGR */
                                        swapRGB = 1;
                                }
@@ -1320,8 +1358,10 @@ static int stv680_ioctl (struct video_device *vdev, unsigned int cmd, void *arg)
                                PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
                                return -EINVAL;
                        }
-                       if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+                       if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+                           || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+                                       stv680->frame[vm.frame].grabstate);
                                return -EBUSY;
                        }
                        /* Is this according to the v4l spec??? */
index 74abaabb9044b6387abdc422828e795ec35cade4..69a4c33a1ba982ccba98e95d5f60a862f20ec42f 100644 (file)
@@ -43,7 +43,7 @@
 #define USB_PENCAM_PRODUCT_ID  0x0202
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
-#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -146,77 +146,78 @@ struct usb_stv {
        int nullpackets;
 };
 
-unsigned char red[256] = {
-       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-       245, 245, 246, 246
-};
+
+unsigned char red[256] = { 
+       0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+       18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+       44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+       71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+       88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+       102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+       114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+       125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+       134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+       143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+       152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+       159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+       167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+       173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+       180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+       187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+       192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+       198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+       204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+       209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+       215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+       220, 220, 221, 221 
+}; 
 
 unsigned char green[256] = {
-       0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-       24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
-       58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
-       92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
-       114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
-       133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
-       148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
-       162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
-       175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
-       187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
-       197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
-       207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
-       217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
-       225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
-       235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
-       243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
-       250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255
-};
+       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+       245, 245, 246, 246 
+}; 
 
 unsigned char blue[256] = {
-       0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-       31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
-       74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
-       116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
-       145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
-       168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
-       187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
-       205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
-       222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
-       236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
-       250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-       255, 255, 255, 255
-};
+       0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+       23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+       55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+       86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+       107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+       125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+       139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+       152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+       165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+       176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+       185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+       194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+       204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+       212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+       228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+       235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+       243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+       249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+       255, 255, 255, 255 
+}; 
index ce267032d6efdf5b07d2de0c8321611bf6f8b929..3e8099cc7f9a0a8d468ae737596be1a2c86a2932 100644 (file)
@@ -2252,6 +2252,14 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
                return -EINVAL;
        }
 
+       /* 9.4.10 says devices don't need this, if the interface
+          only has one alternate setting */
+       if (iface->num_altsetting == 1) {
+               warn("ignoring set_interface for dev %d, iface %d, alt %d",
+                       dev->devnum, interface, alternate);
+               return 0;
+       }
+
        if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
            USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
            interface, NULL, 0, HZ * 5)) < 0)
index 5121d8ddcb71b97d52a7dbb4ad3a6e2ea639fe08..1868b6f2125723d40323cca446759452756c84ca 100644 (file)
@@ -550,7 +550,7 @@ int __init vesafb_init(void)
                ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
 
        if (ypan || pmi_setpal) {
-               pmi_base  = (unsigned short*)isa_bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
+               pmi_base  = (unsigned short*)bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
                pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
                pmi_pal   = (void*)((char*)pmi_base + pmi_base[2]);
                printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
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 0ca1cff140adb87fb5ac7feba0cbce4590c87abc..bbdcfa520d193b870bf496bae667bd2d0f81efab 100644 (file)
@@ -1,2 +1,2 @@
-obj-$(CONFIG_FS_JFFS2)         += crc32.o
+obj-$(CONFIG_JFFS2_FS)         += crc32.o
 obj-$(CONFIG_EFI_PARTITION)    += crc32.o
index 244dc64ac4c13ff912725645ee58210e44c94f72..dcbc3a688ae7df8947ce4b3905b4ac470ace24bf 100644 (file)
@@ -49,6 +49,8 @@ typedef struct {
 } Node;
 
 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
+static struct vfsmount *bm_mnt;
+static int entry_count = 0;
 
 /* 
  * Check if we support the binfmt
@@ -390,10 +392,15 @@ static void bm_clear_inode(struct inode *inode)
        Node *e = inode->u.generic_ip;
 
        if (e) {
+               struct vfsmount *mnt;
                write_lock(&entries_lock);
                list_del(&e->list);
+               mnt = bm_mnt;
+               if (!--entry_count)
+                       bm_mnt = NULL;
                write_unlock(&entries_lock);
                kfree(e);
+               mntput(mnt);
        }
 }
 
@@ -404,8 +411,7 @@ static void kill_node(Node *e)
        write_lock(&entries_lock);
        dentry = e->dentry;
        if (dentry) {
-               list_del(&e->list);
-               INIT_LIST_HEAD(&e->list);
+               list_del_init(&e->list);
                e->dentry = NULL;
        }
        write_unlock(&entries_lock);
@@ -484,12 +490,16 @@ static struct file_operations bm_entry_operations = {
        write:          bm_entry_write,
 };
 
+static struct file_system_type bm_fs_type;
+
 /* /register */
 
 static ssize_t bm_register_write(struct file *file, const char *buffer,
                               size_t count, loff_t *ppos)
 {
        Node *e;
+       struct inode *inode;
+       struct vfsmount *mnt = NULL;
        struct dentry *root, *dentry;
        struct super_block *sb = file->f_vfsmnt->mnt_sb;
        int err = 0;
@@ -503,31 +513,52 @@ static ssize_t bm_register_write(struct file *file, const char *buffer,
        down(&root->d_inode->i_sem);
        dentry = lookup_one_len(e->name, root, strlen(e->name));
        err = PTR_ERR(dentry);
-       if (!IS_ERR(dentry)) {
-               down(&root->d_inode->i_zombie);
-               if (dentry->d_inode) {
-                       err = -EEXIST;
-               } else {
-                       struct inode * inode = bm_get_inode(sb, S_IFREG | 0644);
-                       err = -ENOMEM;
+       if (IS_ERR(dentry))
+               goto out;
 
-                       if (inode) {
-                               write_lock(&entries_lock);
+       down(&root->d_inode->i_zombie);
 
-                               e->dentry = dget(dentry);
-                               inode->u.generic_ip = e;
-                               inode->i_fop = &bm_entry_operations;
-                               d_instantiate(dentry, inode);
+       err = -EEXIST;
+       if (dentry->d_inode)
+               goto out2;
 
-                               list_add(&e->list, &entries);
-                               write_unlock(&entries_lock);
+       inode = bm_get_inode(sb, S_IFREG | 0644);
 
-                               err = 0;
-                       }
+       err = -ENOMEM;
+       if (!inode)
+               goto out2;
+
+       write_lock(&entries_lock);
+       if (!bm_mnt) {
+               write_unlock(&entries_lock);
+               mnt = kern_mount(&bm_fs_type);
+               if (IS_ERR(mnt)) {
+                       err = PTR_ERR(mnt);
+                       iput(inode);
+                       inode = NULL;
+                       goto out2;
                }
-               up(&root->d_inode->i_zombie);
-               dput(dentry);
+               write_lock(&entries_lock);
+               if (!bm_mnt)
+                       bm_mnt = mnt;
        }
+       mntget(bm_mnt);
+       entry_count++;
+
+       e->dentry = dget(dentry);
+       inode->u.generic_ip = e;
+       inode->i_fop = &bm_entry_operations;
+       d_instantiate(dentry, inode);
+
+       list_add(&e->list, &entries);
+       write_unlock(&entries_lock);
+
+       mntput(mnt);
+       err = 0;
+out2:
+       up(&root->d_inode->i_zombie);
+       dput(dentry);
+out:
        up(&root->d_inode->i_sem);
        dput(root);
 
@@ -687,23 +718,13 @@ static struct linux_binfmt misc_format = {
 
 static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
 
-static struct vfsmount *bm_mnt;
-
 static int __init init_misc_binfmt(void)
 {
        int err = register_filesystem(&bm_fs_type);
        if (!err) {
-               bm_mnt = kern_mount(&bm_fs_type);
-               err = PTR_ERR(bm_mnt);
-               if (IS_ERR(bm_mnt))
+               err = register_binfmt(&misc_format);
+               if (err)
                        unregister_filesystem(&bm_fs_type);
-               else {
-                       err = register_binfmt(&misc_format);
-                       if (err) {
-                               unregister_filesystem(&bm_fs_type);
-                               kern_umount(bm_mnt);
-                       }
-               }
        }
        return err;
 }
@@ -712,7 +733,6 @@ static void __exit exit_misc_binfmt(void)
 {
        unregister_binfmt(&misc_format);
        unregister_filesystem(&bm_fs_type);
-       kern_umount(bm_mnt);
 }
 
 EXPORT_NO_SYMBOLS;
index 8a9233a44356de7a3d9e2505931b0ca3ee9c4d4f..baaf40a16d3cee7b2c7df37b663843a80f186b34 100644 (file)
@@ -582,23 +582,13 @@ struct buffer_head * __get_hash_table(struct block_device *bdev, sector_t block,
        return bh;
 }
 
-void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
 {
        spin_lock(&lru_list_lock);
        if (bh->b_inode)
                list_del(&bh->b_inode_buffers);
-       bh->b_inode = inode;
-       list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
-       spin_unlock(&lru_list_lock);
-}
-
-void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
-       spin_lock(&lru_list_lock);
-       if (bh->b_inode)
-               list_del(&bh->b_inode_buffers);
-       bh->b_inode = inode;
-       list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
+       bh->b_inode = 1;
+       list_add(&bh->b_inode_buffers, list);
        spin_unlock(&lru_list_lock);
 }
 
@@ -606,7 +596,7 @@ void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
    remove_inode_queue functions.  */
 static void __remove_inode_queue(struct buffer_head *bh)
 {
-       bh->b_inode = NULL;
+       bh->b_inode = 0;
        list_del(&bh->b_inode_buffers);
 }
 
@@ -826,73 +816,24 @@ inline void set_buffer_async_io(struct buffer_head *bh)
  * any newly dirty buffers for write.
  */
 
-int fsync_inode_buffers(struct inode *inode)
-{
-       struct buffer_head *bh;
-       struct inode tmp;
-       int err = 0, err2;
-       
-       INIT_LIST_HEAD(&tmp.i_dirty_buffers);
-       
-       spin_lock(&lru_list_lock);
-
-       while (!list_empty(&inode->i_dirty_buffers)) {
-               bh = BH_ENTRY(inode->i_dirty_buffers.next);
-               list_del(&bh->b_inode_buffers);
-               if (!buffer_dirty(bh) && !buffer_locked(bh))
-                       bh->b_inode = NULL;
-               else {
-                       bh->b_inode = &tmp;
-                       list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
-                       if (buffer_dirty(bh)) {
-                               get_bh(bh);
-                               spin_unlock(&lru_list_lock);
-                               ll_rw_block(WRITE, 1, &bh);
-                               brelse(bh);
-                               spin_lock(&lru_list_lock);
-                       }
-               }
-       }
-
-       while (!list_empty(&tmp.i_dirty_buffers)) {
-               bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
-               remove_inode_queue(bh);
-               get_bh(bh);
-               spin_unlock(&lru_list_lock);
-               wait_on_buffer(bh);
-               if (!buffer_uptodate(bh))
-                       err = -EIO;
-               brelse(bh);
-               spin_lock(&lru_list_lock);
-       }
-       
-       spin_unlock(&lru_list_lock);
-       err2 = osync_inode_buffers(inode);
-
-       if (err)
-               return err;
-       else
-               return err2;
-}
-
-int fsync_inode_data_buffers(struct inode *inode)
+int fsync_buffers_list(struct list_head *list)
 {
        struct buffer_head *bh;
-       struct inode tmp;
+       struct list_head tmp;
        int err = 0, err2;
        
-       INIT_LIST_HEAD(&tmp.i_dirty_data_buffers);
+       INIT_LIST_HEAD(&tmp);
        
        spin_lock(&lru_list_lock);
 
-       while (!list_empty(&inode->i_dirty_data_buffers)) {
-               bh = BH_ENTRY(inode->i_dirty_data_buffers.next);
+       while (!list_empty(list)) {
+               bh = BH_ENTRY(list->next);
                list_del(&bh->b_inode_buffers);
                if (!buffer_dirty(bh) && !buffer_locked(bh))
-                       bh->b_inode = NULL;
+                       bh->b_inode = 0;
                else {
-                       bh->b_inode = &tmp;
-                       list_add(&bh->b_inode_buffers, &tmp.i_dirty_data_buffers);
+                       bh->b_inode = 1;
+                       list_add(&bh->b_inode_buffers, &tmp);
                        if (buffer_dirty(bh)) {
                                get_bh(bh);
                                spin_unlock(&lru_list_lock);
@@ -903,8 +844,8 @@ int fsync_inode_data_buffers(struct inode *inode)
                }
        }
 
-       while (!list_empty(&tmp.i_dirty_data_buffers)) {
-               bh = BH_ENTRY(tmp.i_dirty_data_buffers.prev);
+       while (!list_empty(&tmp)) {
+               bh = BH_ENTRY(tmp.prev);
                remove_inode_queue(bh);
                get_bh(bh);
                spin_unlock(&lru_list_lock);
@@ -916,7 +857,7 @@ int fsync_inode_data_buffers(struct inode *inode)
        }
        
        spin_unlock(&lru_list_lock);
-       err2 = osync_inode_data_buffers(inode);
+       err2 = osync_buffers_list(list);
 
        if (err)
                return err;
@@ -935,19 +876,19 @@ int fsync_inode_data_buffers(struct inode *inode)
  * write will not be flushed to disk by the osync.
  */
 
-int osync_inode_buffers(struct inode *inode)
+int osync_buffers_list(struct list_head *list)
 {
        struct buffer_head *bh;
-       struct list_head *list;
+       struct list_head *p;
        int err = 0;
 
        spin_lock(&lru_list_lock);
        
  repeat:
        
-       for (list = inode->i_dirty_buffers.prev; 
-            bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
-            list = bh->b_inode_buffers.prev) {
+       for (p = list->prev; 
+            bh = BH_ENTRY(p), p != list;
+            p = bh->b_inode_buffers.prev) {
                if (buffer_locked(bh)) {
                        get_bh(bh);
                        spin_unlock(&lru_list_lock);
@@ -964,36 +905,6 @@ int osync_inode_buffers(struct inode *inode)
        return err;
 }
 
-int osync_inode_data_buffers(struct inode *inode)
-{
-       struct buffer_head *bh;
-       struct list_head *list;
-       int err = 0;
-
-       spin_lock(&lru_list_lock);
-       
- repeat:
-
-       for (list = inode->i_dirty_data_buffers.prev; 
-            bh = BH_ENTRY(list), list != &inode->i_dirty_data_buffers;
-            list = bh->b_inode_buffers.prev) {
-               if (buffer_locked(bh)) {
-                       get_bh(bh);
-                       spin_unlock(&lru_list_lock);
-                       wait_on_buffer(bh);
-                       if (!buffer_uptodate(bh))
-                               err = -EIO;
-                       brelse(bh);
-                       spin_lock(&lru_list_lock);
-                       goto repeat;
-               }
-       }
-
-       spin_unlock(&lru_list_lock);
-       return err;
-}
-
-
 /*
  * Invalidate any and all dirty buffers on a given inode.  We are
  * probably unmounting the fs, but that doesn't mean we have already
index da07d94626a7017418e4b0576d51d83a2d187752..b54d2c4356fc6fdf68915207e34bf8429ca3de5f 100644 (file)
@@ -42,19 +42,20 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
        unsigned long group_desc;
        unsigned long desc;
        struct ext2_group_desc * gdp;
+       struct ext2_sb_info *sbi = &sb->u.ext2_sb;
 
-       if (block_group >= sb->u.ext2_sb.s_groups_count) {
+       if (block_group >= sbi->s_groups_count) {
                ext2_error (sb, "ext2_get_group_desc",
                            "block_group >= groups_count - "
                            "block_group = %d, groups_count = %lu",
-                           block_group, sb->u.ext2_sb.s_groups_count);
+                           block_group, sbi->s_groups_count);
 
                return NULL;
        }
        
        group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
        desc = block_group % EXT2_DESC_PER_BLOCK(sb);
-       if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+       if (!sbi->s_group_desc[group_desc]) {
                ext2_error (sb, "ext2_get_group_desc",
                            "Group descriptor not loaded - "
                            "block_group = %d, group_desc = %lu, desc = %lu",
@@ -62,10 +63,9 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
                return NULL;
        }
        
-       gdp = (struct ext2_group_desc *) 
-             sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+       gdp = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;
        if (bh)
-               *bh = sb->u.ext2_sb.s_group_desc[group_desc];
+               *bh = sbi->s_group_desc[group_desc];
        return gdp + desc;
 }
 
@@ -73,37 +73,26 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
  * Read the bitmap for a given block_group, reading into the specified 
  * slot in the superblock's bitmap cache.
  *
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head on success or NULL in case of failure.
  */
 
-static int read_block_bitmap (struct super_block * sb,
-                              unsigned int block_group,
-                              unsigned long bitmap_nr)
+static struct buffer_head *read_block_bitmap(struct super_block *sb,
+                                               unsigned int block_group)
 {
        struct ext2_group_desc * gdp;
        struct buffer_head * bh = NULL;
-       int retval = -EIO;
        
        gdp = ext2_get_group_desc (sb, block_group, NULL);
        if (!gdp)
                goto error_out;
-       retval = 0;
        bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
-       if (!bh) {
+       if (!bh)
                ext2_error (sb, "read_block_bitmap",
                            "Cannot read block bitmap - "
                            "block_group = %d, block_bitmap = %lu",
                            block_group, (unsigned long) gdp->bg_block_bitmap);
-               retval = -EIO;
-       }
-       /*
-        * On IO error, just leave a zero in the superblock's block pointer for
-        * this group.  The IO will be retried next time.
-        */
 error_out:
-       sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
-       sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
-       return retval;
+       return bh;
 }
 
 /*
@@ -117,134 +106,65 @@ error_out:
  * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
  *    this function reads the bitmap without maintaining a LRU cache.
  * 
- * Return the slot used to store the bitmap, or a -ve error code.
+ * Return the buffer_head of the bitmap or ERR_PTR(-ve).
  */
-static int __load_block_bitmap (struct super_block * sb,
-                               unsigned int block_group)
+static struct buffer_head *load_block_bitmap(struct super_block * sb,
+                                               unsigned int block_group)
 {
-       int i, j, retval = 0;
-       unsigned long block_bitmap_number;
-       struct buffer_head * block_bitmap;
+       struct ext2_sb_info *sbi = &sb->u.ext2_sb;
+       int i, slot = 0;
+       struct buffer_head *bh = sbi->s_block_bitmap[0];
 
-       if (block_group >= sb->u.ext2_sb.s_groups_count)
+       if (block_group >= sbi->s_groups_count)
                ext2_panic (sb, "load_block_bitmap",
                            "block_group >= groups_count - "
                            "block_group = %d, groups_count = %lu",
-                           block_group, sb->u.ext2_sb.s_groups_count);
-
-       if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-               if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
-                       if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
-                           block_group)
-                               return block_group;
-                       ext2_error (sb, "__load_block_bitmap",
-                                   "block_group != block_bitmap_number");
-               }
-               retval = read_block_bitmap (sb, block_group, block_group);
-               if (retval < 0)
-                       return retval;
-               return block_group;
-       }
-
-       for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-                   sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++)
-               ;
-       if (i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-           sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) {
-               block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i];
-               block_bitmap = sb->u.ext2_sb.s_block_bitmap[i];
-               for (j = i; j > 0; j--) {
-                       sb->u.ext2_sb.s_block_bitmap_number[j] =
-                               sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-                       sb->u.ext2_sb.s_block_bitmap[j] =
-                               sb->u.ext2_sb.s_block_bitmap[j - 1];
-               }
-               sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
-               sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
-
-               /*
-                * There's still one special case here --- if block_bitmap == 0
-                * then our last attempt to read the bitmap failed and we have
-                * just ended up caching that failure.  Try again to read it.
-                */
-               if (!block_bitmap)
-                       retval = read_block_bitmap (sb, block_group, 0);
-       } else {
-               if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
-                       sb->u.ext2_sb.s_loaded_block_bitmaps++;
-               else
-                       brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
-               for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
-                       sb->u.ext2_sb.s_block_bitmap_number[j] =
-                               sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-                       sb->u.ext2_sb.s_block_bitmap[j] =
-                               sb->u.ext2_sb.s_block_bitmap[j - 1];
-               }
-               retval = read_block_bitmap (sb, block_group, 0);
-       }
-       return retval;
-}
-
-/*
- * Load the block bitmap for a given block group.  First of all do a couple
- * of fast lookups for common cases and then pass the request onto the guts
- * of the bitmap loader.
- *
- * Return the slot number of the group in the superblock bitmap cache's on
- * success, or a -ve error code.
- *
- * There is still one inconsistency here --- if the number of groups in this
- * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of 
- * differentiating between a group for which we have never performed a bitmap
- * IO request, and a group for which the last bitmap read request failed.
- */
-static inline int load_block_bitmap (struct super_block * sb,
-                                    unsigned int block_group)
-{
-       int slot;
+                           block_group, sbi->s_groups_count);
        
        /*
         * Do the lookup for the slot.  First of all, check if we're asking
         * for the same slot as last time, and did we succeed that last time?
         */
-       if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
-           sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
-           sb->u.ext2_sb.s_block_bitmap[0]) {
-               return 0;
-       }
-       /*
-        * Or can we do a fast lookup based on a loaded group on a filesystem
-        * small enough to be mapped directly into the superblock?
-        */
-       else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && 
-                sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
-                sb->u.ext2_sb.s_block_bitmap[block_group]) {
+       if (sbi->s_loaded_block_bitmaps > 0 &&
+           sbi->s_block_bitmap_number[0] == block_group && bh)
+               goto found;
+
+       if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
                slot = block_group;
+               bh = sbi->s_block_bitmap[slot];
+               if (!bh)
+                       goto read_it;
+               if (sbi->s_block_bitmap_number[slot] == slot)
+                       goto found;
+               ext2_panic (sb, "__load_block_bitmap",
+                           "block_group != block_bitmap_number");
        }
-       /*
-        * If not, then do a full lookup for this block group.
-        */
-       else {
-               slot = __load_block_bitmap (sb, block_group);
+
+       bh = NULL;
+       for (i = 0; i < sbi->s_loaded_block_bitmaps &&
+                   sbi->s_block_bitmap_number[i] != block_group; i++)
+               ;
+       if (i < sbi->s_loaded_block_bitmaps)
+               bh = sbi->s_block_bitmap[i];
+       else if (sbi->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
+               sbi->s_loaded_block_bitmaps++;
+       else
+               brelse (sbi->s_block_bitmap[--i]);
+
+       while (i--) {
+               sbi->s_block_bitmap_number[i+1] = sbi->s_block_bitmap_number[i];
+               sbi->s_block_bitmap[i+1] = sbi->s_block_bitmap[i];
        }
 
-       /*
-        * <0 means we just got an error
-        */
-       if (slot < 0)
-               return slot;
-       
-       /*
-        * If it's a valid slot, we may still have cached a previous IO error,
-        * in which case the bh in the superblock cache will be zero.
-        */
-       if (!sb->u.ext2_sb.s_block_bitmap[slot])
-               return -EIO;
-       
-       /*
-        * Must have been read in OK to get this far.
-        */
-       return slot;
+read_it:
+       if (!bh)
+               bh = read_block_bitmap(sb, block_group);
+       sbi->s_block_bitmap_number[slot] = block_group;
+       sbi->s_block_bitmap[slot] = bh;
+       if (!bh)
+               return ERR_PTR(-EIO);
+found:
+       return bh;
 }
 
 /* Free given blocks, update quota and i_blocks field */
@@ -256,7 +176,6 @@ void ext2_free_blocks (struct inode * inode, unsigned long block,
        unsigned long block_group;
        unsigned long bit;
        unsigned long i;
-       int bitmap_nr;
        unsigned long overflow;
        struct super_block * sb;
        struct ext2_group_desc * gdp;
@@ -293,11 +212,10 @@ do_more:
                overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
                count -= overflow;
        }
-       bitmap_nr = load_block_bitmap (sb, block_group);
-       if (bitmap_nr < 0)
+       bh = load_block_bitmap (sb, block_group);
+       if (IS_ERR(bh))
                goto error_return;
        
-       bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
        gdp = ext2_get_group_desc (sb, block_group, &bh2);
        if (!gdp)
                goto error_return;
@@ -361,7 +279,6 @@ int ext2_new_block (struct inode * inode, unsigned long goal,
        struct buffer_head * bh2;
        char * p, * r;
        int i, j, k, tmp;
-       int bitmap_nr;
        struct super_block * sb;
        struct ext2_group_desc * gdp;
        struct ext2_super_block * es;
@@ -404,12 +321,10 @@ repeat:
                if (j)
                        goal_attempts++;
 #endif
-               bitmap_nr = load_block_bitmap (sb, i);
-               if (bitmap_nr < 0)
+               bh = load_block_bitmap (sb, i);
+               if (IS_ERR(bh))
                        goto io_error;
                
-               bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
-
                ext2_debug ("goal is at %d:%d.\n", i, j);
 
                if (!ext2_test_bit(j, bh->b_data)) {
@@ -477,11 +392,10 @@ repeat:
        }
        if (k >= sb->u.ext2_sb.s_groups_count)
                goto out;
-       bitmap_nr = load_block_bitmap (sb, i);
-       if (bitmap_nr < 0)
+       bh = load_block_bitmap (sb, i);
+       if (IS_ERR(bh))
                goto io_error;
        
-       bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
        r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
        j = (r - bh->b_data) << 3;
        if (j < EXT2_BLOCKS_PER_GROUP(sb))
@@ -619,7 +533,6 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
 #ifdef EXT2FS_DEBUG
        struct ext2_super_block * es;
        unsigned long desc_count, bitmap_count, x;
-       int bitmap_nr;
        struct ext2_group_desc * gdp;
        int i;
        
@@ -629,16 +542,16 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
        bitmap_count = 0;
        gdp = NULL;
        for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+               struct buffer_head *bh;
                gdp = ext2_get_group_desc (sb, i, NULL);
                if (!gdp)
                        continue;
                desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-               bitmap_nr = load_block_bitmap (sb, i);
-               if (bitmap_nr < 0)
+               bh = load_block_bitmap (sb, i);
+               if (IS_ERR(bh))
                        continue;
                
-               x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
-                                    sb->s_blocksize);
+               x = ext2_count_free (bh, sb->s_blocksize);
                printk ("group %d: stored = %d, counted = %lu\n",
                        i, le16_to_cpu(gdp->bg_free_blocks_count), x);
                bitmap_count += x;
@@ -720,7 +633,6 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
        struct ext2_super_block * es;
        unsigned long desc_count, bitmap_count, x, j;
        unsigned long desc_blocks;
-       int bitmap_nr;
        struct ext2_group_desc * gdp;
        int i;
 
@@ -733,12 +645,10 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
                if (!gdp)
                        continue;
                desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-               bitmap_nr = load_block_bitmap (sb, i);
-               if (bitmap_nr < 0)
+               bh = load_block_bitmap (sb, i);
+               if (IS_ERR(bh))
                        continue;
 
-               bh = EXT2_SB(sb)->s_block_bitmap[bitmap_nr];
-
                if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data))
                        ext2_error(sb, __FUNCTION__,
                                   "Superblock in group %d is marked free", i);
index 524f18d056b3ab31c6e4b8b510be04f3274b76fd..f769ee09ee51f37a51ca6a2fa0f6a4f0c8b256ea 100644 (file)
@@ -559,9 +559,9 @@ fat_read_super(struct super_block *sb, void *data, int silent,
        struct buffer_head *bh;
        struct fat_boot_sector *b;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
-       int logical_sector_size, fat_clusters;
+       int logical_sector_size, fat_clusters, debug, cp;
        unsigned int total_sectors, rootdir_sectors;
-       int debug, cp;
+       long error = -EIO;
        char buf[50];
        int i;
        char cvf_format[21];
@@ -786,9 +786,8 @@ fat_read_super(struct super_block *sb, void *data, int silent,
        return sb;
 
 out_invalid:
-       if (!silent)
-               printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
-                       sb->s_id);
+       error = 0;
+
 out_fail:
        if (sbi->nls_io)
                unload_nls(sbi->nls_io);
@@ -799,8 +798,8 @@ out_fail:
        if (sbi->private_data)
                kfree(sbi->private_data);
        sbi->private_data = NULL;
-       return NULL;
+
+       return ERR_PTR(error);
 }
 
 int fat_statfs(struct super_block *sb,struct statfs *buf)
index 22b6d538ed0f579fbab15b9b0dd8cfc25b8ee20a..c23323fbae70af34fef8788bcebff6a965d7fd6a 100644 (file)
@@ -75,13 +75,53 @@ struct inodes_stat_t inodes_stat;
 
 static kmem_cache_t * inode_cachep;
 
-#define alloc_inode() \
-        ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+static struct inode *alloc_inode(struct super_block *sb)
+{
+       static struct address_space_operations empty_aops;
+       static struct inode_operations empty_iops;
+       static struct file_operations empty_fops;
+       struct inode *inode;
+
+       if (sb->s_op->alloc_inode)
+               inode = sb->s_op->alloc_inode(sb);
+       else
+               inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
+
+       if (inode) {
+               inode->i_sb = sb;
+               inode->i_dev = sb->s_dev;
+               inode->i_blkbits = sb->s_blocksize_bits;
+               inode->i_flags = 0;
+               atomic_set(&inode->i_count, 1);
+               inode->i_sock = 0;
+               inode->i_op = &empty_iops;
+               inode->i_fop = &empty_fops;
+               inode->i_nlink = 1;
+               atomic_set(&inode->i_writecount, 0);
+               inode->i_size = 0;
+               inode->i_blocks = 0;
+               inode->i_generation = 0;
+               memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+               inode->i_pipe = NULL;
+               inode->i_bdev = NULL;
+               inode->i_cdev = NULL;
+               inode->i_data.a_ops = &empty_aops;
+               inode->i_data.host = inode;
+               inode->i_data.gfp_mask = GFP_HIGHUSER;
+               inode->i_mapping = &inode->i_data;
+               memset(&inode->u, 0, sizeof(inode->u));
+       }
+       return inode;
+}
+
 static void destroy_inode(struct inode *inode) 
 {
        if (inode_has_buffers(inode))
                BUG();
-       kmem_cache_free(inode_cachep, (inode));
+       if (inode->i_sb->s_op->destroy_inode)
+               inode->i_sb->s_op->destroy_inode(inode);
+       else
+               kmem_cache_free(inode_cachep, (inode));
 }
 
 
@@ -90,27 +130,30 @@ static void destroy_inode(struct inode *inode)
  * once, because the fields are idempotent across use
  * of the inode, so let the slab aware of that.
  */
+void inode_init_once(struct inode *inode)
+{
+       memset(inode, 0, sizeof(*inode));
+       init_waitqueue_head(&inode->i_wait);
+       INIT_LIST_HEAD(&inode->i_hash);
+       INIT_LIST_HEAD(&inode->i_data.clean_pages);
+       INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+       INIT_LIST_HEAD(&inode->i_data.locked_pages);
+       INIT_LIST_HEAD(&inode->i_dentry);
+       INIT_LIST_HEAD(&inode->i_dirty_buffers);
+       INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
+       INIT_LIST_HEAD(&inode->i_devices);
+       sema_init(&inode->i_sem, 1);
+       sema_init(&inode->i_zombie, 1);
+       spin_lock_init(&inode->i_data.i_shared_lock);
+}
+
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 {
        struct inode * inode = (struct inode *) foo;
 
        if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
            SLAB_CTOR_CONSTRUCTOR)
-       {
-               memset(inode, 0, sizeof(*inode));
-               init_waitqueue_head(&inode->i_wait);
-               INIT_LIST_HEAD(&inode->i_hash);
-               INIT_LIST_HEAD(&inode->i_data.clean_pages);
-               INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-               INIT_LIST_HEAD(&inode->i_data.locked_pages);
-               INIT_LIST_HEAD(&inode->i_dentry);
-               INIT_LIST_HEAD(&inode->i_dirty_buffers);
-               INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
-               INIT_LIST_HEAD(&inode->i_devices);
-               sema_init(&inode->i_sem, 1);
-               sema_init(&inode->i_zombie, 1);
-               spin_lock_init(&inode->i_data.i_shared_lock);
-       }
+               inode_init_once(inode);
 }
 
 /*
@@ -768,72 +811,28 @@ static struct inode * find_inode(struct super_block * sb, unsigned long ino, str
        return inode;
 }
 
-/*
- * This just initializes the inode fields
- * to known values before returning the inode..
- *
- * i_sb, i_ino, i_count, i_state and the lists have
- * been initialized elsewhere..
- */
-static void clean_inode(struct inode *inode)
-{
-       static struct address_space_operations empty_aops;
-       static struct inode_operations empty_iops;
-       static struct file_operations empty_fops;
-       memset(&inode->u, 0, sizeof(inode->u));
-       inode->i_sock = 0;
-       inode->i_op = &empty_iops;
-       inode->i_fop = &empty_fops;
-       inode->i_nlink = 1;
-       atomic_set(&inode->i_writecount, 0);
-       inode->i_size = 0;
-       inode->i_blocks = 0;
-       inode->i_generation = 0;
-       memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-       inode->i_pipe = NULL;
-       inode->i_bdev = NULL;
-       inode->i_cdev = NULL;
-       inode->i_data.a_ops = &empty_aops;
-       inode->i_data.host = inode;
-       inode->i_data.gfp_mask = GFP_HIGHUSER;
-       inode->i_mapping = &inode->i_data;
-}
-
 /**
- * get_empty_inode     - obtain an inode
- *
- * This is called by things like the networking layer
- * etc that want to get an inode without any inode
- * number, or filesystems that allocate new inodes with
- * no pre-existing information.
+ *     new_inode       - obtain an inode
+ *     @sb: superblock
  *
- * On a successful return the inode pointer is returned. On a failure
- * a %NULL pointer is returned. The returned inode is not on any superblock
- * lists.
+ *     Allocates a new inode for given superblock.
  */
  
-struct inode * get_empty_inode(void)
+struct inode *new_inode(struct super_block *sb)
 {
        static unsigned long last_ino;
        struct inode * inode;
 
        spin_lock_prefetch(&inode_lock);
        
-       inode = alloc_inode();
-       if (inode)
-       {
+       inode = alloc_inode(sb);
+       if (inode) {
                spin_lock(&inode_lock);
                inodes_stat.nr_inodes++;
                list_add(&inode->i_list, &inode_in_use);
-               inode->i_sb = NULL;
-               inode->i_dev = NODEV;
-               inode->i_blkbits = 0;
                inode->i_ino = ++last_ino;
-               inode->i_flags = 0;
-               atomic_set(&inode->i_count, 1);
                inode->i_state = 0;
                spin_unlock(&inode_lock);
-               clean_inode(inode);
        }
        return inode;
 }
@@ -848,7 +847,7 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
 {
        struct inode * inode;
 
-       inode = alloc_inode();
+       inode = alloc_inode(sb);
        if (inode) {
                struct inode * old;
 
@@ -859,17 +858,10 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
                        inodes_stat.nr_inodes++;
                        list_add(&inode->i_list, &inode_in_use);
                        list_add(&inode->i_hash, head);
-                       inode->i_sb = sb;
-                       inode->i_dev = sb->s_dev;
-                       inode->i_blkbits = sb->s_blocksize_bits;
                        inode->i_ino = ino;
-                       inode->i_flags = 0;
-                       atomic_set(&inode->i_count, 1);
                        inode->i_state = I_LOCK;
                        spin_unlock(&inode_lock);
 
-                       clean_inode(inode);
-
                        /* reiserfs specific hack right here.  We don't
                        ** want this to last, and are looking for VFS changes
                        ** that will allow us to get rid of it.
index bd2c058cf803ba97e9ad3f6d6d48afbbe657db29..9eeecfc5b8e014a5fa5d3ecbf2312db5b1e287df 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_psdev.h>
index 29e96b885f62f82780054c5b6b6aba58794ec516..ee8f2248cff0392c51ac79f457db3d185a4b7bcc 100644 (file)
@@ -224,14 +224,13 @@ write_out_data_locked:
                }
        } while (jh != last_jh);
 
-       if (bufs || current->need_resched) {
+       if (bufs || need_resched()) {
                jbd_debug(2, "submit %d writes\n", bufs);
                spin_unlock(&journal_datalist_lock);
                unlock_journal(journal);
                if (bufs)
                        ll_rw_block(WRITE, bufs, wbuf);
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
                journal_brelse_array(wbuf, bufs);
                lock_journal(journal);
                spin_lock(&journal_datalist_lock);
@@ -458,8 +457,7 @@ start_journal_io:
                                bh->b_end_io = journal_end_buffer_io_sync;
                                submit_bh(WRITE, bh);
                        }
-                       if (current->need_resched)
-                               schedule();
+                       cond_resched();
                        lock_journal(journal);
 
                        /* Force a new descriptor to be generated next
index 6cd846e46367cb5cd072995ee94f06dade435e0f..be5f8be03bbbce9bb84dd97113f274ea5ada754c 100644 (file)
@@ -127,8 +127,7 @@ static int jffs2_garbage_collect_thread(void *_c)
                        schedule();
                }
                 
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
 
                 /* Put_super will send a SIGKILL and then wait on the sem. 
                  */
index 115c7a20f7651255d5c5955693746a0b7386d509..2dc9b5f382942c500bedda80ef3f0b13833f9a64 100644 (file)
@@ -131,8 +131,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
                
                jffs2_erase_block(c, jeb);
                /* Be nice */
-               if (current->need_resched)
-                       schedule();
+               cond_resched();
                spin_lock_bh(&c->erase_completion_lock);
        }
        spin_unlock_bh(&c->erase_completion_lock);
index 6d93dd5d663cefa13542885e3c8a7a64851dec1d..55206f024ec0188dd8e78b2362788a87218a76c8 100644 (file)
@@ -101,8 +101,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u3
                        if (ret)
                                return ret;
 
-                       if (current->need_resched)
-                               schedule();
+                       cond_resched();
 
                        if (signal_pending(current))
                                return -EINTR;
index 38b2e0d6c70a01f9f8d056e21343fcee8e3c9723..4dc34bf6ec4456fd0365585f594eab822e1aa724 100644 (file)
@@ -23,7 +23,6 @@ EXPORT_SYMBOL(msdos_mkdir);
 EXPORT_SYMBOL(msdos_rename);
 EXPORT_SYMBOL(msdos_rmdir);
 EXPORT_SYMBOL(msdos_unlink);
-EXPORT_SYMBOL(msdos_read_super);
 EXPORT_SYMBOL(msdos_put_super);
 
 static DECLARE_FSTYPE_DEV(msdos_fs_type, "msdos", msdos_read_super);
index 92ece621077388bc446d02001f2dac366bdae8c8..e431184b7cebbecb2d5912095321b2f70c136794 100644 (file)
@@ -589,7 +589,15 @@ struct super_block *msdos_read_super(struct super_block *sb,void *data, int sile
 
        MSDOS_SB(sb)->options.isvfat = 0;
        res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
-       if (res)
-               sb->s_root->d_op = &msdos_dentry_operations;
+       if (IS_ERR(res))
+               return NULL;
+       if (res == NULL) {
+               if (!silent)
+                       printk(KERN_INFO "VFS: Can't find a valid"
+                              " MSDOS filesystem on dev %s.\n", sb->s_id);
+               return NULL;
+       }
+
+       sb->s_root->d_op = &msdos_dentry_operations;
        return res;
 }
index 3d9b2dbecde1fc13ce0044fabe41b2fa2952925c..a629546c6e6ddebc219793fbd7f24f37f6913d6a 100644 (file)
@@ -339,7 +339,7 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
                goto loop;
        if (current->total_link_count >= 40)
                goto loop;
-       if (current->need_resched) {
+       if (need_resched()) {
                current->state = TASK_RUNNING;
                schedule();
        }
index 688d5c8e6de9c5ce226973a4ea61105a7d47b69e..f9748aac81cf4d783f104081e45b48678ca070b2 100644 (file)
@@ -101,9 +101,9 @@ inline void make_le_item_head (struct item_head * ih, const struct cpu_key * key
 }
 
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
-    struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+    struct list_head *list = &(SB_JOURNAL(inode->i_sb)->j_dirty_buffers) ;
 
-    buffer_insert_inode_queue(bh, jinode) ;
+    buffer_insert_list(bh, list) ;
 }
 
 //
@@ -808,8 +808,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
        /* inserting indirect pointers for a hole can take a 
        ** long time.  reschedule if needed
        */
-       if (current->need_resched)
-           schedule() ;
+       cond_resched();
 
        retval = search_for_position_by_key (inode->i_sb, &key, &path);
        if (retval == IO_ERROR) {
index 98d6b2dc31aa05d414dfc5bfe91de78a665a9f2b..1c9dc427c8a8e46de725edf79b87da59b0093c82 100644 (file)
@@ -1897,7 +1897,7 @@ int journal_init(struct super_block *p_s_sb) {
   memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */
 
   INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
-  INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ;
+  INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ;
   reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, 
                                  SB_BMAP_NR(p_s_sb)) ;
   allocate_bitmap_nodes(p_s_sb) ;
@@ -2902,7 +2902,7 @@ printk("journal-2020: do_journal_end: BAD desc->j_len is ZERO\n") ;
   SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
 
   /* write any buffers that must hit disk before this commit is done */
-  fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ;
+  fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
 
   /* honor the flush and async wishes from the caller */
   if (flush) {
index cbe1b4ee44a3143ac0d3d327b14bcbea347ce9c3..9ecd1dbaa30dc351dace879ad05fb80f0c91828d 100644 (file)
@@ -363,10 +363,17 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
         * Call msdos-fs to mount the disk.
         * Note: this returns res == sb or NULL
         */
-       res = msdos_read_super (sb, data, silent);
-
-       if (!res)
-               goto out_fail;
+       MSDOS_SB(sb)->options.isvfat = 0;
+       res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations);
+
+       if (IS_ERR(res))
+               return NULL;
+       if (res == NULL) {
+               if (!silent)
+                       printk(KERN_INFO "VFS: Can't find a valid "
+                              "UMSDOS filesystem on dev %s.\n", sb->s_id);
+               return NULL;
+       }
 
        printk (KERN_INFO "UMSDOS 0.86k "
                "(compatibility level %d.%d, fast msdos)\n", 
@@ -394,10 +401,6 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
                dget (sb->s_root); sb->s_root = dget(new_root);
        }
        return sb;
-
-out_fail:
-       printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
-       return NULL;
 }
 
 /*
index 656b58f1b2340eeb14a32a16c23e013ce4af44d9..2e1d0f3aa2eaa9ca88847439b27c9e74934f2eae 100644 (file)
@@ -1266,10 +1266,15 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
        struct super_block *res;
   
        MSDOS_SB(sb)->options.isvfat = 1;
-
        res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
-       if (res == NULL)
+       if (IS_ERR(res))
+               return NULL;
+       if (res == NULL) {
+               if (!silent)
+                       printk(KERN_INFO "VFS: Can't find a valid"
+                              " VFAT filesystem on dev %s.\n", sb->s_id);
                return NULL;
+       }
 
        if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
                MSDOS_SB(sb)->options.dotsOK = 0;
index fce24985d3a198c62b518fda863b0efa94e0801a..5886cbeb8718961bfb89419b1509d9facff3af5f 100644 (file)
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-       while (!current->need_resched && !hlt_counter);
+       while (!need_resched() && !hlt_counter);
 }
 
 static inline void arch_reset(char mode)
index 2bdd19913af2dafcbb9c537447d394d93cc6b366..6cb0021948345145acce7876b36041d1d2e7996c 100644 (file)
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-       while (!current->need_resched && !hlt_counter)
+       while (!need_resched() && !hlt_counter)
                iomd_writeb(0, IOMD_SUSMODE);
 }
 
index c4af29befbd9130b51f93f68896629b04e6c8993..e33951995e689f20827d542c64b58c3280674ed3 100644 (file)
@@ -17,7 +17,7 @@
  * will stop our MCLK signal (which provides the clock for the glue
  * logic, and therefore the timer interrupt).
  *
- * Instead, we spin, waiting for either hlt_counter or need_resched
+ * Instead, we spin, waiting for either hlt_counter or need_resched()
  * to be set.  If we have been spinning for 2cs, then we drop the
  * core clock down to the memory clock.
  */
@@ -28,13 +28,13 @@ static void arch_idle(void)
        start_idle = jiffies;
 
        do {
-               if (current->need_resched || hlt_counter)
+               if (need_resched() || hlt_counter)
                        goto slow_out;
        } while (time_before(jiffies, start_idle + HZ/50));
 
        cpu_do_idle(IDLE_CLOCK_SLOW);
 
-       while (!current->need_resched && !hlt_counter) {
+       while (!need_resched() && !hlt_counter) {
                /* do nothing slowly */
        }
 
index e9b4da1e93a7cc856a4479b51220bbe6895664e9..9559db04486091b1232c7c71b8f45122a9d530b4 100644 (file)
@@ -20,14 +20,14 @@ static void arch_idle(void)
        start_idle = jiffies;
 
        do {
-               if (current->need_resched || hlt_counter)
+               if (need_resched() || hlt_counter)
                        goto slow_out;
                cpu_do_idle(IDLE_WAIT_FAST);
        } while (time_before(jiffies, start_idle + HZ/50));
 
        cpu_do_idle(IDLE_CLOCK_SLOW);
 
-       while (!current->need_resched && !hlt_counter) {
+       while (!need_resched() && !hlt_counter) {
                cpu_do_idle(IDLE_WAIT_SLOW);
        }
 
index 028788bdc7437082e37bde92161bfe07e5486067..c5257807042b6e962be23333f97a371fe3d7348c 100644 (file)
@@ -16,7 +16,7 @@
 
 static void arch_idle(void)
 {
-       while (!current->need_resched && !hlt_counter)
+       while (!need_resched() && !hlt_counter)
                cpu_do_idle(IDLE_WAIT_SLOW);
 }
 
index 6e070b9071a9a082a2e5c96032142a99bbecb0ef..7c781a6d1848a84c4561126e9af07183e43859d9 100644 (file)
@@ -18,14 +18,14 @@ static void arch_idle(void)
        start_idle = jiffies;
 
        do {
-               if (current->need_resched || hlt_counter)
+               if (need_resched() || hlt_counter)
                        goto slow_out;
                cpu_do_idle(IDLE_WAIT_FAST);
        } while (time_before(jiffies, start_idle + HZ/50));
 
        cpu_do_idle(IDLE_CLOCK_SLOW);
 
-       while (!current->need_resched && !hlt_counter) {
+       while (!need_resched() && !hlt_counter) {
                cpu_do_idle(IDLE_WAIT_SLOW);
        }
 
index d020a49268a21391ffe08037bed4e6202dd6586f..6dbf2a45b06198beb882d92751cca271d55055f0 100644 (file)
@@ -10,7 +10,7 @@ static inline void arch_idle(void)
        if (!hlt_counter) {
                int flags;
                local_irq_save(flags);
-               if (!current->need_resched)
+               if (!need_resched())
                        cpu_do_idle(0);
                local_irq_restore(flags);
        }
index e52bb50fdf62444485f9ba9f0756bf6c6c357c2c..cf90aafef2972d7e73292f6ea379319b56e13a40 100644 (file)
@@ -13,14 +13,14 @@ static void arch_idle(void)
        start_idle = jiffies;
 
        do {
-               if (current->need_resched || hlt_counter)
+               if (need_resched() || hlt_counter)
                        goto slow_out;
                cpu_do_idle(IDLE_WAIT_FAST);
        } while (time_before(jiffies, start_idle + HZ/50));
 
        cpu_do_idle(IDLE_CLOCK_SLOW);
 
-       while (!current->need_resched && !hlt_counter) {
+       while (!need_resched() && !hlt_counter) {
                cpu_do_idle(IDLE_WAIT_SLOW);
        }
 
index 2f76058591fbbda20248730c20c1801eda62c658..6525a4b66495c98970d3b1bf34b310d171a125d0 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __I386_MMU_CONTEXT_H
-#define __I386_MMU_CONTEXT_H
+#ifndef __I386_SCHED_H
+#define __I386_SCHED_H
 
 #include <linux/config.h>
 #include <asm/desc.h>
 # error update this function.
 #endif
 
-static inline int sched_find_first_zero_bit(char *bitmap)
+static inline int sched_find_first_zero_bit(unsigned long *b)
 {
-       unsigned int *b = (unsigned int *)bitmap;
        unsigned int rt;
 
        rt = b[0] & b[1] & b[2] & b[3];
        if (unlikely(rt != 0xffffffff))
-               return find_first_zero_bit(bitmap, MAX_RT_PRIO);
+               return find_first_zero_bit(b, MAX_RT_PRIO);
 
        if (b[4] != ~0)
                return ffz(b[4]) + MAX_RT_PRIO;
index 10cfc1fd0c43da0f7cf421ded987e4a346102075..c270defe9be48c562f2e2f7a6784641525fcd9bd 100644 (file)
@@ -19,8 +19,8 @@ extern spinlock_t kernel_flag;
 do {                                           \
        if (unlikely(task->lock_depth >= 0)) {  \
                spin_unlock(&kernel_flag);      \
-               release_irqlock(cpu);           \
-               __sti();                        \
+               if (global_irq_holder == (cpu)) \
+                       BUG();                  \
        }                                       \
 } while (0)
 
index efede40e24083b179428de4eb648a9b67928f6fe..b6507e62eb4b20ea56a8752e3da7e3a7caca8323 100644 (file)
@@ -90,9 +90,9 @@ extern inline struct request *elv_next_request(request_queue_t *q)
 
 #define _elv_add_request(q, rq, back, p) do {                                \
        if ((back))                                                           \
-               _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
+               _elv_add_request_core((q), (rq), (q)->queue_head.prev, (p));  \
        else                                                                  \
-               _elv_add_request_core((q), (rq), &(q)->queue_head, 0);        \
+               _elv_add_request_core((q), (rq), &(q)->queue_head, (p));      \
 } while (0)
 
 #define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1)
index bac31250708cb51adb57a0a3ad76db9ea278bf11..5e006ad08df0fbceaf9d8cf0581c3416269895c0 100644 (file)
@@ -5,12 +5,9 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
-#ifndef _LINUX_POSIX_TYPES_H   /* __FD_CLR */
+#include <asm/atomic.h>
 #include <linux/posix_types.h>
-#endif
-#ifndef __LINUX_COMPILER_H     /* unlikely */
 #include <linux/compiler.h>
-#endif
 
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
index a01f0c3b4d34df475a84532417c42d46eb0974ed..4e5de1286d87969509d812eb9c2f813ae61fd252 100644 (file)
@@ -262,7 +262,7 @@ struct buffer_head {
 
        wait_queue_head_t b_wait;
 
-       struct inode *       b_inode;
+       int b_inode;                            /* will go away */
        struct list_head     b_inode_buffers;   /* doubly linked list of inode dirty buffers */
 };
 
@@ -859,6 +859,9 @@ struct seq_file;
  * without the big kernel lock held in all filesystems.
  */
 struct super_operations {
+       struct inode *(*alloc_inode)(struct super_block *sb);
+       void (*destroy_inode)(struct inode *);
+
        void (*read_inode) (struct inode *);
   
        /* reiserfs kludge.  reiserfs needs 64 bits of information to
@@ -1151,7 +1154,16 @@ static inline void mark_buffer_clean(struct buffer_head * bh)
 extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
 extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
+extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
+
+static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+       buffer_insert_list(bh, &inode->i_dirty_buffers);
+}
+static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
+{
+       buffer_insert_list(bh, &inode->i_dirty_data_buffers);
+}
 
 #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
 
@@ -1219,10 +1231,16 @@ extern int fsync_dev(kdev_t);
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(struct block_device *);
 extern void sync_inodes_sb(struct super_block *);
-extern int osync_inode_buffers(struct inode *);
-extern int osync_inode_data_buffers(struct inode *);
-extern int fsync_inode_buffers(struct inode *);
-extern int fsync_inode_data_buffers(struct inode *);
+extern int osync_buffers_list(struct list_head *);
+extern int fsync_buffers_list(struct list_head *);
+static inline int fsync_inode_buffers(struct inode *inode)
+{
+       return fsync_buffers_list(&inode->i_dirty_buffers);
+}
+static inline int fsync_inode_data_buffers(struct inode *inode)
+{
+       return fsync_buffers_list(&inode->i_dirty_data_buffers);
+}
 extern int inode_has_buffers(struct inode *);
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
@@ -1327,6 +1345,7 @@ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
 #define user_path_walk(name,nd)         __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
+extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -1340,20 +1359,8 @@ static inline struct inode *iget(struct super_block *sb, unsigned long ino)
 }
 
 extern void clear_inode(struct inode *);
-extern struct inode * get_empty_inode(void);
-
-static inline struct inode * new_inode(struct super_block *sb)
-{
-       struct inode *inode = get_empty_inode();
-       if (inode) {
-               inode->i_sb = sb;
-               inode->i_dev = sb->s_dev;
-               inode->i_blkbits = sb->s_blocksize_bits;
-       }
-       return inode;
-}
+extern struct inode *new_inode(struct super_block *);
 extern void remove_suid(struct inode *inode);
-
 extern void insert_inode_hash(struct inode *);
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
index b5e752a49e7da02d0511c15acedbef3a68903f50..8b81bcc98cb3fa22fe1f88462fa1775638c2e6e2 100644 (file)
@@ -884,6 +884,9 @@ typedef enum {
  */
 #define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
+#define task_rq_offset(rq) \
+       (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
 extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
 {
        return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
@@ -894,6 +897,24 @@ extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
        bio_kunmap_irq(buffer, flags);
 }
 
+/*
+ * for now, taskfile requests are special :/
+ */
+extern inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+       if (rq->bio)
+               return ide_map_buffer(rq, flags);
+       else
+               return rq->buffer + task_rq_offset(rq);
+}
+
+extern inline void ide_unmap_rq(struct request *rq, char *buf,
+                               unsigned long *flags)
+{
+       if (rq->bio)
+               ide_unmap_buffer(buf, flags);
+}
+
 /*
  * This function issues a special IDE device request
  * onto the request queue.
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 3c4e71fc0a60a38f7762d6f396ce83f2b7369f40..b496169b6023fe584371f01593d22e623b9e107a 100644 (file)
@@ -1,9 +1,7 @@
 #ifndef _LINUX__INIT_TASK_H
 #define _LINUX__INIT_TASK_H
 
-#ifndef __LINUX_FILE_H
 #include <linux/file.h>
-#endif
 
 #define INIT_FILES \
 {                                                      \
index 6f6ae516028f924f2f92622ac0829e3f72de55e7..b59350f01f32a830d6c0a7c47a712052bb67e556 100644 (file)
@@ -178,8 +178,6 @@ typedef struct {
  * the correspondent code in isdn.c
  */
 
-#define ISDN_MINOR_B        0
-#define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
 #define ISDN_MINOR_CTRL     64
 #define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
 #define ISDN_MINOR_PPP      128
index 7d6b31638321d9974dc1154413afdec38b17a121..0ad3d186597dbc995bd9ba8a5dca2630f0e21624 100644 (file)
@@ -368,7 +368,7 @@ static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
 static inline void cfi_udelay(int us)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-       if (current->need_resched) {
+       if (need_resched()) {
                unsigned long t = us * HZ / 1000000;
                if (t < 1)
                        t = 1;
index 4971fa3c3586394b70244e8bb34675d91c0fdc32..7660a0bf8e9bfe4f70e36f9b7affa70b2986d5d0 100644 (file)
@@ -525,7 +525,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 a78f789867235de9498afa60ad52a87768b0072b..73d6d823fbbb4ed7817068e3b2b4d43e98dcda99 100644 (file)
@@ -300,7 +300,7 @@ struct reiserfs_journal {
   int j_free_bitmap_nodes ;
   int j_used_bitmap_nodes ;
   struct list_head j_bitmap_nodes ;
-  struct inode j_dummy_inode ;
+  struct list_head j_dirty_buffers ;
   struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ;     /* array of bitmaps to record the deleted blocks */
   struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ;        /* array of all the journal lists */
   struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ;         /* hash table for real buffer heads in current trans */ 
index b8d564fd0c083da0ce403c1372eac7ed330f1878..3797423a4fbe5572c6b61a12a0e4cd7842f70575 100644 (file)
@@ -25,6 +25,7 @@ extern unsigned long event;
 #include <linux/signal.h>
 #include <linux/securebits.h>
 #include <linux/fs_struct.h>
+#include <linux/compiler.h>
 
 struct exec_domain;
 
@@ -136,6 +137,8 @@ struct completion;
 extern rwlock_t tasklist_lock;
 extern spinlock_t mmlist_lock;
 
+typedef struct task_struct task_t;
+
 extern void sched_init(void);
 extern void init_idle(void);
 extern void show_state(void);
@@ -144,8 +147,7 @@ extern void trap_init(void);
 extern void update_process_times(int user);
 extern void update_one_process(struct task_struct *p, unsigned long user,
                               unsigned long system, int cpu);
-extern void expire_task(struct task_struct *p);
-extern void idle_tick(void);
+extern void scheduler_tick(struct task_struct *p);
 
 #define        MAX_SCHEDULE_TIMEOUT    LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -221,7 +223,6 @@ struct user_struct {
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
-typedef struct task_struct task_t;
 typedef struct prio_array prio_array_t;
 
 struct task_struct {
@@ -251,7 +252,10 @@ struct task_struct {
        prio_array_t *array;
 
        unsigned int time_slice;
-       unsigned long sleep_jtime;
+
+       #define MAX_SLEEP_AVG (2*HZ)
+       unsigned long sleep_avg;
+       unsigned long sleep_timestamp;
 
        unsigned long policy;
        unsigned long cpus_allowed;
@@ -390,30 +394,47 @@ struct task_struct {
  * them out at 128 to make it easier to search the
  * scheduler bitmap.
  */
-#define MAX_RT_PRIO    128
+#define MAX_RT_PRIO            128
 /*
  * The lower the priority of a process, the more likely it is
  * to run. Priority of a process goes from 0 to 167. The 0-99
  * priority range is allocated to RT tasks, the 128-167 range
  * is for SCHED_OTHER tasks.
  */
-#define MAX_PRIO       (MAX_RT_PRIO+40)
-#define DEF_USER_NICE  0
+#define MAX_PRIO               (MAX_RT_PRIO + 40)
 
 /*
- * Default timeslice is 80 msecs, maximum is 160 msecs.
+ * Scales user-nice values [ -20 ... 0 ... 19 ]
+ * to static priority [ 128 ... 167 (MAX_PRIO-1) ]
+ *
+ * User-nice value of -20 == static priority 128, and
+ * user-nice value 19 == static priority 167. The lower
+ * the priority value, the higher the task's priority.
+ */
+#define NICE_TO_PRIO(n)                (MAX_RT_PRIO + (n) + 20)
+#define DEF_USER_NICE          0
+
+/*
+ * Default timeslice is 90 msecs, maximum is 180 msecs.
  * Minimum timeslice is 10 msecs.
  */
-#define MIN_TIMESLICE  (10 * HZ / 1000)
-#define MAX_TIMESLICE  (160 * HZ / 1000)
+#define MIN_TIMESLICE          ( 10 * HZ / 1000)
+#define MAX_TIMESLICE          (180 * HZ / 1000)
 
-#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
-#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
-#define DEF_PRIO       (MAX_RT_PRIO + MAX_USER_PRIO / 3)
-#define NICE_TO_PRIO(n) (MAX_PRIO-1 + (n) - 19)
+#define USER_PRIO(p)           ((p)-MAX_RT_PRIO)
+#define MAX_USER_PRIO          (USER_PRIO(MAX_PRIO))
 
-#define NICE_TO_TIMESLICE(n)   (MIN_TIMESLICE + \
-       ((MAX_TIMESLICE - MIN_TIMESLICE) * (19 - (n))) / 39)
+/*
+ * NICE_TO_TIMESLICE scales nice values [ -20 ... 19 ]
+ * to time slice values.
+ *
+ * The higher a process's priority, the bigger timeslices
+ * it gets during one round of execution. But even the lowest
+ * priority process gets MIN_TIMESLICE worth of execution time.
+ */
+
+#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \
+       ((MAX_TIMESLICE - MIN_TIMESLICE) * (19-(n))) / 39)
 
 extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
 extern void set_user_nice(task_t *p, long nice);
@@ -542,6 +563,17 @@ static inline int signal_pending(struct task_struct *p)
 {
        return (p->sigpending != 0);
 }
+  
+static inline int need_resched(void)
+{
+       return unlikely(current->need_resched != 0);
+}
+
+static inline void cond_resched(void)
+{
+       if (need_resched())
+               schedule();
+}
 
 /*
  * Re-calculate pending state from the set of locally pending
index 26ee7fea25d2fb76dda992597a328ace649e22ec..20624abce6c7c3eba7b18641e37dca871b11c3cf 100644 (file)
@@ -11,78 +11,71 @@ Original driver (sg.h):
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2001 Douglas Gilbert
 
-    Version: 3.1.20 (20010814)
-    This version is for 2.4 series kernels.
-
-    Changes since 3.1.19 (20010623)
-       - add SG_GET_ACCESS_COUNT ioctl 
-       - make open() increment and close() decrement access_count
-       - only register first 256 devices, reject subsequent devices
-    Changes since 3.1.18 (20010505)
-       - fix bug that caused long wait when large buffer requested
-       - fix leak in error case of sg_new_read() [report: Eric Barton]
-       - add 'online' column to /proc/scsi/sg/devices
-    Changes since 3.1.17 (20000921)
-       - add CAP_SYS_RAWIO capability for sensitive stuff
-       - compile in dio stuff, procfs 'allow_dio' defaulted off (0)
-       - make premature close and detach more robust
-       - lun masked into commands <= SCSI_2
-       - poll() and async notification now yield POLL_HUP on detach
-       - various 3rd party tweaks tracking lk 2.4 internal changes
+    Version: 3.5.23 (20011231)
+    This version is for 2.5 series kernels.
+
+    Changes since 3.1.22 (20011208)
+       - branch sg driver for lk 2.5 series
+       - remove lock_kernel() from sg_close()
+       - remove code based on scsi mid level dma pool
+       - change scatterlist 'address' to use page + offset
+       - add SG_INTERFACE_ID_ORIG
 
 Map of SG verions to the Linux kernels in which they appear:
        ----------        ----------------------------------
        original          all kernels < 2.2.6
-       2.1.38            2.2.16
-       2.1.39            2.2.17 - 2.2.19
+       2.1.40            2.2.20
        3.0.x             optional version 3 sg driver for 2.2 series
-       3.1.17            2.4.0 ++
+       3.1.17++          2.4.0++
+       3.5.23++          2.5.0++
 
 Major new features in SG 3.x driver (cf SG 2.x drivers)
        - SG_IO ioctl() combines function if write() and read()
        - new interface (sg_io_hdr_t) but still supports old interface
-       - scatter/gather in user space and direct IO supported
-
- The term "indirect IO" refers a method by which data is DMAed into kernel
- buffers from the hardware and afterwards is transferred into the user
- space (or vice versa if you are writing). Transfer speeds of up to 20 to
- 30MBytes/sec have been measured using indirect IO. For faster throughputs
- "direct IO" which cuts out the double handling of data is required.
- Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels
- and requires the use of the new interface.
-
- Requests for direct IO with the new interface will automatically fall back
- to indirect IO mode if they cannot be fulfilled. An example of such a case
- is an ISA SCSI adapter which is only capable of DMAing to the lower 16MB of
- memory due to the architecture of ISA. The 'info' field in the new
- interface indicates whether a direct or indirect data transfer took place.
-
- Obtaining memory for the kernel buffers used in indirect IO is done by
- first checking if the "reserved buffer" for the current file descriptor
- is available and large enough. If these conditions are _not_ met then
- kernel memory is obtained on a per SCSI command basis. This corresponds
- to a write(), read() sequence or a SG_IO ioctl() call. Further, the
- kernel memory that is suitable for DMA may be constrained by the
- architecture of the SCSI adapter (e.g. ISA adapters).
+       - scatter/gather in user space, direct IO, and mmap supported
+
+ The normal action of this driver is to use the adapter (HBA) driver to DMA
+ data into kernel buffers and then use the CPU to copy the data into the 
+ user space (vice versa for writes). That is called "indirect" IO due to 
+ the double handling of data. There are two methods offered to remove the
+ redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and 
+ 2) using the mmap() system call to map the reserve buffer (this driver has 
+ one reserve buffer per fd) into the user space. Both have their advantages.
+ In terms of absolute speed mmap() is faster. If speed is not a concern, 
+ indirect IO should be fine. Read the documentation for more information.
 
  ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
          needed. That pseudo file's content is defaulted to 0. **
+ Historical note: this SCSI pass-through driver has been known as "sg" for 
+ a decade. In broader kernel discussions "sg" is used to refer to scatter
+ gather techniques. The context should clarify which "sg" is referred to.
 
  Documentation
  =============
- A web site for SG device drivers can be found at:
+ A web site for the SG device driver can be found at:
        http://www.torque.net/sg  [alternatively check the MAINTAINERS file]
- The main documents are still based on 2.x versions:
+ The documentation for the sg version 3 driver can be found at:
+       http://www.torque.net/sg/p/sg_v3_ho.html
+ This is a rendering from DocBook source [change the extension to "sgml"
+ or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
+
+ The older, version 2 documents discuss the original sg interface in detail:
        http://www.torque.net/sg/p/scsi-generic.txt
        http://www.torque.net/sg/p/scsi-generic_long.txt
- Documentation on the changes and additions in 3.x version of the sg driver
- can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
  A version of this document (potentially out of date) may also be found in
  the kernel source tree, probably at:
         /usr/src/linux/Documentation/scsi-generic.txt .
- Utility and test programs are available at the sg web site.
+
+ Utility and test programs are available at the sg web site. They are 
+ bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
+ lk 2.4 series).
+
+ There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
+       http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
 */
 
+
 /* New interface introduced in the 3.x SG drivers follows */
 
 typedef struct sg_iovec /* same structure as used by readv() Linux system */
@@ -119,20 +112,23 @@ typedef struct sg_io_hdr
     unsigned int info;          /* [o] auxiliary information */
 } sg_io_hdr_t;  /* 64 bytes long (on i386) */
 
+#define SG_INTERFACE_ID_ORIG 'S'
+
 /* Use negative values to flag difference from original sg_header structure */
-#define SG_DXFER_NONE -1        /* e.g. a SCSI Test Unit Ready command */
-#define SG_DXFER_TO_DEV -2      /* e.g. a SCSI WRITE command */
-#define SG_DXFER_FROM_DEV -3    /* e.g. a SCSI READ command */
-#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the
+#define SG_DXFER_NONE (-1)      /* e.g. a SCSI Test Unit Ready command */
+#define SG_DXFER_TO_DEV (-2)    /* e.g. a SCSI WRITE command */
+#define SG_DXFER_FROM_DEV (-3)  /* e.g. a SCSI READ command */
+#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
                                   additional property than during indirect
                                   IO the user buffer is copied into the
                                   kernel buffers before the transfer */
-#define SG_DXFER_UNKNOWN -5     /* Unknown data direction */
+#define SG_DXFER_UNKNOWN (-5)   /* Unknown data direction */
 
 /* following flag values can be "or"-ed together */
 #define SG_FLAG_DIRECT_IO 1     /* default is indirect IO */
-#define SG_FLAG_LUN_INHIBIT 2   /* default is to put device's lun into */
-                               /* the 2nd byte of SCSI command */
+#define SG_FLAG_LUN_INHIBIT 2   /* default is overwrite lun in SCSI */
+                               /* command block (when <= SCSI_2) */
+#define SG_FLAG_MMAP_IO 4       /* request memory mapped IO */
 #define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
                                /* user space (debug indirect IO) */
 
index f36a314cf3f7c1027406cfcfd66cbc02b1320da6..4670b7d9bbd6539015e9b91f60efd18b6b0de17a 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
@@ -490,50 +461,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 60dd04cb61d15eda7eb21e0431725dd5f837b23f..fc47857460de06e12db14ead17ebbf6bc8f05452 100644 (file)
@@ -704,8 +704,9 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
                 * runqueue lock is not a problem.
                 */
                current->time_slice = 1;
-               expire_task(current);
+               scheduler_tick(current);
        }
+       p->sleep_timestamp = jiffies;
        __restore_flags(flags);
 
        if (p->policy == SCHED_OTHER)
index 948329e6be700293cc43c5177814afbab03d1ea8..e51c417a72c1076a20367aa4a42a0bcb3dada4f7 100644 (file)
@@ -137,6 +137,7 @@ EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(inode_init_once);
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
@@ -502,17 +503,16 @@ EXPORT_SYMBOL(si_meminfo);
 /* Added to make file system as module */
 EXPORT_SYMBOL(sys_tz);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(fsync_inode_buffers);
-EXPORT_SYMBOL(fsync_inode_data_buffers);
+EXPORT_SYMBOL(fsync_buffers_list);
 EXPORT_SYMBOL(clear_inode);
 EXPORT_SYMBOL(___strtok);
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(__get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(new_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
-EXPORT_SYMBOL(buffer_insert_inode_queue);
+EXPORT_SYMBOL(buffer_insert_list);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
index 365aed1d39ae61b8ff61011cdab9b76feb5af1d8..00f07e116885de22a36a3acc370046c32d667a6f 100644 (file)
@@ -524,7 +524,7 @@ void release_console_sem(void)
  */
 void console_conditional_schedule(void)
 {
-       if (console_may_schedule && current->need_resched) {
+       if (console_may_schedule && need_resched()) {
                set_current_state(TASK_RUNNING);
                schedule();
        }
index f38bee70448d3689a54b2e0effb491ec59f97baa..ac6c61912ac59713596e50699b6968f22d3f2358 100644 (file)
 #include <linux/interrupt.h>
 #include <asm/mmu_context.h>
 
-#define BITMAP_SIZE ((MAX_PRIO+7)/8)
-#define PRIO_INTERACTIVE       (MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 3)
-#define TASK_INTERACTIVE(p)    ((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
-#define JSLEEP_TO_PRIO(t)      (((t) * 20) / HZ)
+#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long))
 
 typedef struct runqueue runqueue_t;
 
@@ -31,7 +28,7 @@ struct prio_array {
        int nr_active;
        spinlock_t *lock;
        runqueue_t *rq;
-       char bitmap[BITMAP_SIZE];
+       unsigned long bitmap[BITMAP_SIZE];
        list_t queue[MAX_PRIO];
 };
 
@@ -40,33 +37,36 @@ struct prio_array {
  *
  * Locking rule: those places that want to lock multiple runqueues
  * (such as the load balancing or the process migration code), lock
- * acquire operations must be ordered by rq->cpu.
+ * acquire operations must be ordered by the runqueue's cpu id.
  *
  * The RT event id is used to avoid calling into the the RT scheduler
  * if there is a RT task active in an SMP system but there is no
  * RT scheduling activity otherwise.
  */
-static struct runqueue {
-       int cpu;
+struct runqueue {
        spinlock_t lock;
        unsigned long nr_running, nr_switches;
        task_t *curr, *idle;
        prio_array_t *active, *expired, arrays[2];
-       char __pad [SMP_CACHE_BYTES];
-} runqueues [NR_CPUS] __cacheline_aligned;
+       int prev_nr_running[NR_CPUS];
+} ____cacheline_aligned;
+
+static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
 
-#define this_rq()              (runqueues + smp_processor_id())
-#define task_rq(p)             (runqueues + (p)->cpu)
 #define cpu_rq(cpu)            (runqueues + (cpu))
-#define cpu_curr(cpu)          (runqueues[(cpu)].curr)
+#define this_rq()              cpu_rq(smp_processor_id())
+#define task_rq(p)             cpu_rq((p)->cpu)
+#define cpu_curr(cpu)          (cpu_rq(cpu)->curr)
+#define rq_cpu(rq)             ((rq) - runqueues)
 #define rt_task(p)             ((p)->policy != SCHED_OTHER)
 
+
 #define lock_task_rq(rq,p,flags)                               \
 do {                                                           \
 repeat_lock_task:                                              \
        rq = task_rq(p);                                        \
        spin_lock_irqsave(&rq->lock, flags);                    \
-       if (unlikely((rq)->cpu != (p)->cpu)) {                  \
+       if (unlikely(rq_cpu(rq) != (p)->cpu)) {                 \
                spin_unlock_irqrestore(&rq->lock, flags);       \
                goto repeat_lock_task;                          \
        }                                                       \
@@ -94,18 +94,56 @@ static inline void enqueue_task(struct task_struct *p, prio_array_t *array)
        p->array = array;
 }
 
+/*
+ * A task is 'heavily interactive' if it has reached the
+ * bottom 25% of the SCHED_OTHER priority range - in this
+ * case we favor it by reinserting it on the active array,
+ * even after it expired its current timeslice.
+ *
+ * A task can get a priority bonus by being 'somewhat
+ * interactive' - and it will get a priority penalty for
+ * being a CPU hog.
+ *
+ * CPU-hog penalties cannot go more than 5 above the default
+ * priority level. Priority bonus cannot go below the minimum
+ * priority level.
+ */
+#define PRIO_INTERACTIVE (MAX_RT_PRIO + MAX_USER_PRIO/3)
+#define TASK_INTERACTIVE(p) ((p)->prio <= PRIO_INTERACTIVE)
+
+static inline int effective_prio(task_t *p)
+{
+       int bonus, prio;
+
+       /*
+        * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG]
+        * into the 20 ... -20 bonus/penalty range.
+        */
+       bonus = MAX_USER_PRIO * p->sleep_avg / MAX_SLEEP_AVG - MAX_USER_PRIO/2;
+       prio = NICE_TO_PRIO(p->__nice) - bonus;
+       if (prio < MAX_RT_PRIO)
+               prio = MAX_RT_PRIO;
+       if (prio > MAX_PRIO-1)
+               prio = MAX_PRIO-1;
+       return prio;
+}
+
 static inline void activate_task(task_t *p, runqueue_t *rq)
 {
        prio_array_t *array = rq->active;
 
        if (!rt_task(p)) {
-               unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
-
-               if (prio_bonus > MAX_PRIO)
-                       prio_bonus = MAX_PRIO;
-               p->prio -= prio_bonus;
-               if (p->prio < MAX_RT_PRIO)
-                       p->prio = MAX_RT_PRIO;
+               /*
+                * This code gives a bonus to interactive tasks. We update
+                * an 'average sleep time' value here, based on
+                * sleep_timestamp. The more time a task spends sleeping,
+                * the higher the average gets - and the higher the priority
+                * boost gets as well.
+                */
+               p->sleep_avg += jiffies - p->sleep_timestamp;
+               if (p->sleep_avg > MAX_SLEEP_AVG)
+                       p->sleep_avg = MAX_SLEEP_AVG;
+               p->prio = effective_prio(p);
        }
        enqueue_task(p, array);
        rq->nr_running++;
@@ -116,7 +154,7 @@ static inline void deactivate_task(struct task_struct *p, runqueue_t *rq)
        rq->nr_running--;
        dequeue_task(p, p->array);
        p->array = NULL;
-       p->sleep_jtime = jiffies;
+       p->sleep_timestamp = jiffies;
 }
 
 static inline void resched_task(task_t *p)
@@ -206,13 +244,13 @@ void wake_up_forked_process(task_t * p)
 {
        runqueue_t *rq = this_rq();
 
-       spin_lock_irq(&rq->lock);
        p->state = TASK_RUNNING;
        if (!rt_task(p)) {
                p->prio += MAX_USER_PRIO/10;
                if (p->prio > MAX_PRIO-1)
                        p->prio = MAX_PRIO-1;
        }
+       spin_lock_irq(&rq->lock);
        activate_task(p, rq);
        spin_unlock_irq(&rq->lock);
 }
@@ -287,59 +325,98 @@ static inline unsigned long max_rq_len(void)
 }
 
 /*
- * Current runqueue is empty, try to find work on
- * other runqueues.
+ * Current runqueue is empty, or rebalance tick: if there is an
+ * inbalance (current runqueue is too short) then pull from
+ * busiest runqueue(s).
  *
  * We call this with the current runqueue locked,
  * irqs disabled.
  */
-static void load_balance(runqueue_t *this_rq)
+static void load_balance(runqueue_t *this_rq, int idle)
 {
-       int nr_tasks, load, prev_max_load, max_load, idx, i;
+       int imbalance, nr_running, load, prev_max_load,
+               max_load, idx, i, this_cpu = smp_processor_id();
        task_t *next = this_rq->idle, *tmp;
-       runqueue_t *busiest, *rq_tmp;
+       runqueue_t *busiest, *rq_src;
        prio_array_t *array;
        list_t *head, *curr;
 
-       prev_max_load = max_rq_len();
-       nr_tasks = prev_max_load - this_rq->nr_running;
-       /*
-        * It needs an at least ~10% imbalance to trigger balancing:
-        */
-       if (nr_tasks <= 1 + prev_max_load/8)
-               return;
-       prev_max_load++;
-
-repeat_search:
        /*
         * We search all runqueues to find the most busy one.
         * We do this lockless to reduce cache-bouncing overhead,
-        * we re-check the source CPU with the lock held.
+        * we re-check the 'best' source CPU later on again, with
+        * the lock held.
+        *
+        * We fend off statistical fluctuations in runqueue lengths by
+        * saving the runqueue length during the previous load-balancing
+        * operation and using the smaller one the current and saved lengths.
+        * If a runqueue is long enough for a longer amount of time then
+        * we recognize it and pull tasks from it.
+        *
+        * The 'current runqueue length' is a statistical maximum variable,
+        * for that one we take the longer one - to avoid fluctuations in
+        * the other direction. So for a load-balance to happen it needs
+        * stable long runqueue on the target CPU and stable short runqueue
+        * on the local runqueue.
+        *
+        * We make an exception if this CPU is about to become idle - in
+        * that case we are less picky about moving a task across CPUs and
+        * take what can be taken.
         */
+       if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+               nr_running = this_rq->nr_running;
+       else
+               nr_running = this_rq->prev_nr_running[this_cpu];
+       prev_max_load = 1000000000;
+
        busiest = NULL;
        max_load = 0;
        for (i = 0; i < smp_num_cpus; i++) {
-               rq_tmp = cpu_rq(i);
-               load = rq_tmp->nr_running;
+               rq_src = cpu_rq(i);
+               if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i]))
+                       load = rq_src->nr_running;
+               else
+                       load = this_rq->prev_nr_running[i];
+               this_rq->prev_nr_running[i] = rq_src->nr_running;
+
                if ((load > max_load) && (load < prev_max_load) &&
-                                               (rq_tmp != this_rq)) {
-                       busiest = rq_tmp;
+                                               (rq_src != this_rq)) {
+                       busiest = rq_src;
                        max_load = load;
                }
        }
 
        if (likely(!busiest))
                return;
-       if (max_load <= this_rq->nr_running)
+
+       imbalance = (max_load - nr_running) / 2;
+
+       /*
+        * It needs an at least ~25% imbalance to trigger balancing.
+        *
+        * prev_max_load makes sure that we do not try to balance
+        * ad infinitum - certain tasks might be impossible to be
+        * pulled into this runqueue.
+        */
+       if (!idle && (imbalance < (max_load + 3)/4))
                return;
        prev_max_load = max_load;
-       if (busiest->cpu < this_rq->cpu) {
+
+       /*
+        * Ok, lets do some actual balancing:
+        */
+
+       if (rq_cpu(busiest) < this_cpu) {
                spin_unlock(&this_rq->lock);
                spin_lock(&busiest->lock);
                spin_lock(&this_rq->lock);
        } else
                spin_lock(&busiest->lock);
-       if (busiest->nr_running <= this_rq->nr_running + 1)
+       /*
+        * Make sure nothing changed since we checked the
+        * runqueue length.
+        */
+       if (busiest->nr_running <= nr_running + 1)
                goto out_unlock;
 
        /*
@@ -365,15 +442,14 @@ skip_bitmap:
                        array = busiest->active;
                        goto new_array;
                }
-               spin_unlock(&busiest->lock);
-               goto repeat_search;
+               goto out_unlock;
        }
 
        head = array->queue + idx;
        curr = head->next;
 skip_queue:
        tmp = list_entry(curr, task_t, run_list);
-       if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << smp_processor_id()))) {
+       if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) {
                curr = curr->next;
                if (curr != head)
                        goto skip_queue;
@@ -387,64 +463,96 @@ skip_queue:
         */
        dequeue_task(next, array);
        busiest->nr_running--;
-       next->cpu = smp_processor_id();
+       next->cpu = this_cpu;
        this_rq->nr_running++;
        enqueue_task(next, this_rq->active);
        if (next->prio < current->prio)
                current->need_resched = 1;
-       if (--nr_tasks) {
+       if (!idle && --imbalance) {
                if (array == busiest->expired) {
                        array = busiest->active;
                        goto new_array;
                }
-               spin_unlock(&busiest->lock);
-               goto repeat_search;
        }
 out_unlock:
        spin_unlock(&busiest->lock);
 }
 
-/* Rebalance every 250 msecs */
-#define REBALANCE_TICK (HZ/4)
+/*
+ * One of the idle_cpu_tick() or the busy_cpu_tick() function will
+ * gets called every timer tick, on every CPU. Our balancing action
+ * frequency and balancing agressivity depends on whether the CPU is
+ * idle or not.
+ *
+ * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on
+ * systems with HZ=100, every 10 msecs.)
+ */
+#define BUSY_REBALANCE_TICK (HZ/4 ?: 1)
+#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
 
-void idle_tick(void)
+static inline void idle_tick(void)
 {
-       unsigned long flags;
-
-       if (!(jiffies % REBALANCE_TICK) && likely(this_rq()->curr != NULL)) {
-               spin_lock_irqsave(&this_rq()->lock, flags);
-               load_balance(this_rq());
-               spin_unlock_irqrestore(&this_rq()->lock, flags);
-       }
+       if ((jiffies % IDLE_REBALANCE_TICK) ||
+                       likely(this_rq()->curr == NULL))
+               return;
+       spin_lock(&this_rq()->lock);
+       load_balance(this_rq(), 1);
+       spin_unlock(&this_rq()->lock);
 }
 
-void expire_task(task_t *p)
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ */
+void scheduler_tick(task_t *p)
 {
+       unsigned long now = jiffies;
        runqueue_t *rq = this_rq();
-       unsigned long flags;
 
+       if (p == rq->idle || !rq->idle)
+               return idle_tick();
+       /* Task might have expired already, but not scheduled off yet */
        if (p->array != rq->active) {
                p->need_resched = 1;
                return;
        }
+       spin_lock(&rq->lock);
+       if (unlikely(rt_task(p))) {
+               /*
+                * RR tasks need a special form of timeslice management.
+                * FIFO tasks have no timeslices.
+                */
+               if ((p->policy == SCHED_RR) && !--p->time_slice) {
+                       p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+                       p->need_resched = 1;
+
+                       /* put it at the end of the queue: */
+                       dequeue_task(p, rq->active);
+                       enqueue_task(p, rq->active);
+               }
+               goto out;
+       }
        /*
-        * The task cannot change CPUs because it's the current task.
+        * The task was running during this tick - update the
+        * time slice counter and the sleep average. Note: we
+        * do not update a process's priority until it either
+        * goes to sleep or uses up its timeslice. This makes
+        * it possible for interactive tasks to use up their
+        * timeslices at their high priority levels.
         */
-       spin_lock_irqsave(&rq->lock, flags);
-       if ((p->policy != SCHED_FIFO) && !--p->time_slice) {
-               prio_array_t *array = rq->active;
-               p->need_resched = 1;
+       if (p->sleep_avg)
+               p->sleep_avg--;
+       if (!--p->time_slice) {
                dequeue_task(p, rq->active);
-               if (!rt_task(p)) {
-                       if (++p->prio >= MAX_PRIO)
-                               p->prio = MAX_PRIO - 1;
-                       if (!TASK_INTERACTIVE(p))
-                               array = rq->expired;
-               }
-               enqueue_task(p, array);
+               p->need_resched = 1;
+               p->prio = effective_prio(p);
                p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+               enqueue_task(p, TASK_INTERACTIVE(p) ? rq->active : rq->expired);
        }
-       spin_unlock_irqrestore(&rq->lock, flags);
+out:
+       if (!(now % BUSY_REBALANCE_TICK))
+               load_balance(rq, 0);
+       spin_unlock(&rq->lock);
 }
 
 void scheduling_functions_start_here(void) { }
@@ -469,18 +577,18 @@ need_resched_back:
        spin_lock_irq(&rq->lock);
 
        switch (prev->state) {
-       case TASK_INTERRUPTIBLE:
-               if (unlikely(signal_pending(prev))) {
-                       prev->state = TASK_RUNNING;
-                       break;
-               }
-       default:
-               deactivate_task(prev, rq);
-       case TASK_RUNNING:
+               case TASK_INTERRUPTIBLE:
+                       if (unlikely(signal_pending(prev))) {
+                               prev->state = TASK_RUNNING;
+                               break;
+                       }
+               default:
+                       deactivate_task(prev, rq);
+               case TASK_RUNNING:
        }
 pick_next_task:
        if (unlikely(!rq->nr_running)) {
-               load_balance(rq);
+               load_balance(rq, 1);
                if (rq->nr_running)
                        goto pick_next_task;
                next = rq->idle;
@@ -520,7 +628,7 @@ switch_tasks:
        spin_unlock_irq(&rq->lock);
 
        reacquire_kernel_lock(current);
-       if (unlikely(current->need_resched))
+       if (need_resched())
                goto need_resched_back;
        return;
 }
@@ -1015,7 +1123,7 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
        p = find_process_by_pid(pid);
        if (p)
                jiffies_to_timespec(p->policy & SCHED_FIFO ?
-                                        0 : NICE_TO_TIMESLICE(p->__nice), &t);
+                                        0 : NICE_TO_TIMESLICE(p->prio), &t);
        read_unlock(&tasklist_lock);
        if (p)
                retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1123,7 +1231,7 @@ static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
        if (rq1 == rq2)
                spin_lock(&rq1->lock);
        else {
-               if (rq1->cpu < rq2->cpu) {
+               if (rq_cpu(rq1) < rq_cpu(rq2)) {
                        spin_lock(&rq1->lock);
                        spin_lock(&rq2->lock);
                } else {
@@ -1152,7 +1260,7 @@ void __init init_idle(void)
        this_rq->curr = this_rq->idle = current;
        deactivate_task(current, rq);
        current->array = NULL;
-       current->prio = MAX_PRIO;
+       current->prio = MAX_PRIO-1;
        current->state = TASK_RUNNING;
        clear_bit(smp_processor_id(), &wait_init_idle);
        double_rq_unlock(this_rq, rq);
@@ -1181,17 +1289,17 @@ void __init sched_init(void)
                rq->active = rq->arrays + 0;
                rq->expired = rq->arrays + 1;
                spin_lock_init(&rq->lock);
-               rq->cpu = i;
 
                for (j = 0; j < 2; j++) {
                        array = rq->arrays + j;
                        array->rq = rq;
                        array->lock = &rq->lock;
-                       for (k = 0; k < MAX_PRIO; k++)
+                       for (k = 0; k < MAX_PRIO; k++) {
                                INIT_LIST_HEAD(array->queue + k);
-                       memset(array->bitmap, 0xff, BITMAP_SIZE);
+                               __set_bit(k, array->bitmap);
+                       }
                        // zero delimiter for bitsearch
-                       clear_bit(MAX_PRIO, array->bitmap);
+                       __clear_bit(MAX_PRIO, array->bitmap);
                }
        }
        /*
@@ -1203,9 +1311,6 @@ void __init sched_init(void)
        rq->idle = NULL;
        wake_up_process(current);
 
-       for (i = 0; i < PIDHASH_SZ; i++)
-               pidhash[i] = NULL;
-
        init_timervecs();
        init_bh(TIMER_BH, timer_bh);
        init_bh(TQUEUE_BH, tqueue_bh);
index 4d8bb7b9795d73e235e50da7abc0263a95a4863c..5b665bd72a11181c25ac3ae9384f236bbc321d28 100644 (file)
@@ -387,8 +387,7 @@ static int ksoftirqd(void * __bind_cpu)
 
                while (softirq_pending(cpu)) {
                        do_softirq();
-                       if (current->need_resched)
-                               schedule();
+                       cond_resched();
                }
 
                __set_current_state(TASK_INTERRUPTIBLE);
index ce3945cda7990ac289a11f479353ef3f13805111..da17ae4acdd8069e5c009c1abe191fa173a175f9 100644 (file)
@@ -585,17 +585,16 @@ void update_process_times(int user_tick)
 
        update_one_process(p, user_tick, system, cpu);
        if (p->pid) {
-               expire_task(p);
                if (p->__nice > 0)
                        kstat.per_cpu_nice[cpu] += user_tick;
                else
                        kstat.per_cpu_user[cpu] += user_tick;
                kstat.per_cpu_system[cpu] += system;
        } else {
-               idle_tick();
                if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
                        kstat.per_cpu_system[cpu] += system;
        }
+       scheduler_tick(p);
 }
 
 /*
index 89968606f946494d31dfa6c61d15138aa5c64797..7fdfbdf974eed0b7e515276217fa4f07d9aa0224 100644 (file)
@@ -290,7 +290,7 @@ static int truncate_list_pages(struct list_head *head, unsigned long start, unsi
 
                        page_cache_release(page);
 
-                       if (current->need_resched) {
+                       if (need_resched()) {
                                __set_current_state(TASK_RUNNING);
                                schedule();
                        }
@@ -400,7 +400,7 @@ static int invalidate_list_pages2(struct list_head *head)
                }
 
                page_cache_release(page);
-               if (current->need_resched) {
+               if (need_resched()) {
                        __set_current_state(TASK_RUNNING);
                        schedule();
                }
index 672500e52b46e0be0781047c0262565bafe86726..3abe1c093efb46d39026104b757ae79de8afea08 100644 (file)
@@ -367,12 +367,6 @@ void create_bounce(unsigned long pfn, int gfp, struct bio **bio_orig)
                if (pfn >= blk_max_pfn)
                        return;
 
-#ifndef CONFIG_HIGHMEM
-               /*
-                * should not hit for non-highmem case
-                */
-               BUG();
-#endif
                bio_gfp = GFP_NOHIGHIO;
                pool = page_pool;
        } else {
index ede841b15f6f90e51bef8272a2413bb5489155d1..ba70b95369321b4c11f1e4cb8b4dd6d9b4273bcd 100644 (file)
@@ -696,7 +696,7 @@ static int try_to_unuse(unsigned int type)
                 * interactive performance.  Interruptible check on
                 * signal_pending() would be nice, but changes the spec?
                 */
-               if (current->need_resched)
+               if (need_resched())
                        schedule();
        }
 
index 8d6d9ffa1cc8b4077bd3055545c92d9d361608ad..fb6d468d3734db4af599a350b397b4d52ec241a2 100644 (file)
@@ -300,7 +300,7 @@ static int swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * class
 
        counter = mmlist_nr;
        do {
-               if (unlikely(current->need_resched)) {
+               if (need_resched()) {
                        __set_current_state(TASK_RUNNING);
                        schedule();
                }
@@ -345,7 +345,7 @@ static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask,
        while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) {
                struct page * page;
 
-               if (unlikely(current->need_resched)) {
+               if (need_resched()) {
                        spin_unlock(&pagemap_lru_lock);
                        __set_current_state(TASK_RUNNING);
                        schedule();
@@ -625,8 +625,7 @@ static int kswapd_balance_pgdat(pg_data_t * pgdat)
 
        for (i = pgdat->nr_zones-1; i >= 0; i--) {
                zone = pgdat->node_zones + i;
-               if (unlikely(current->need_resched))
-                       schedule();
+               cond_resched();
                if (!zone->need_balance)
                        continue;
                if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
index 6760147c4611519cabd38cfe7590f4fa3bb3d13f..1b11391683e190c4d3728d53a7b05e429dce6a68 100644 (file)
@@ -270,8 +270,10 @@ check_for_redirect(struct sk_buff *skb)
        if (redir) {
                DEBUGP("Doing tcp redirect again.\n");
                do_tcp_redir(skb, redir);
-               if (del_timer(&redir->destroyme))
-                       add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT);
+               if (del_timer(&redir->destroyme)) {
+                       redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+                       add_timer(&redir->destroyme);
+               }
        }
        UNLOCK_BH(&redir_lock);
 }
@@ -296,8 +298,10 @@ check_for_unredirect(struct sk_buff *skb)
        if (redir) {
                DEBUGP("Doing tcp unredirect.\n");
                do_tcp_unredir(skb, redir);
-               if (del_timer(&redir->destroyme))
-                       add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT);
+               if (del_timer(&redir->destroyme)) {
+                       redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+                       add_timer(&redir->destroyme);
+               }
        }
        UNLOCK_BH(&redir_lock);
 }
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 58ac533d03f849642f9d42920555409691d87b97..8c9b4fa99d0e448d2645958242f28e3bcb758cf2 100644 (file)
@@ -437,11 +437,11 @@ struct socket *sock_alloc(void)
        struct inode * inode;
        struct socket * sock;
 
-       inode = get_empty_inode();
+       inode = new_inode(sock_mnt->mnt_sb);
        if (!inode)
                return NULL;
 
-       inode->i_sb = sock_mnt->mnt_sb;
+       inode->i_dev = NODEV;
        sock = socki_lookup(inode);
 
        inode->i_mode = S_IFSOCK|S_IRWXUGO;
index 7ca2e8d46b0f7ac332bc1183bc32b8d2581d5d65..804b66208c6df2d55dcacac3494ba31d0f6e1c20 100644 (file)
@@ -721,7 +721,7 @@ __rpc_schedule(void)
 
                __rpc_execute(task);
 
-               if (++count >= 200 || current->need_resched) {
+               if (++count >= 200 || need_resched()) {
                        count = 0;
                        schedule();
                }