]> git.neil.brown.name Git - history.git/commitdiff
Import 2.4.0-test6pre2 2.4.0-test6pre2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:37:20 +0000 (15:37 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:37:20 +0000 (15:37 -0500)
84 files changed:
MAINTAINERS
Makefile
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/irq.c
drivers/char/drm/Config.in
drivers/char/drm/Makefile
drivers/char/drm/drmP.h
drivers/char/drm/gamma_drv.c
drivers/char/drm/i810_context.c
drivers/char/drm/i810_dma.c
drivers/char/drm/i810_drv.c
drivers/char/drm/mga_context.c
drivers/char/drm/mga_drv.c
drivers/char/drm/r128_context.c
drivers/char/drm/r128_drv.c
drivers/char/drm/tdfx_context.c
drivers/char/drm/tdfx_drv.c
drivers/char/drm/vm.c
drivers/char/keyboard.c
drivers/char/sysrq.c
drivers/ide/ide-features.c
drivers/ide/ide-probe.c
drivers/net/pcmcia/ray_cs.c
drivers/pci/pci.ids
drivers/pcmcia/Makefile
drivers/pcmcia/yenta.c
drivers/sbus/char/sunkbd.c
drivers/usb/bluetooth.c
drivers/usb/storage/protocol.c
drivers/usb/storage/protocol.h
drivers/usb/storage/scsiglue.c
drivers/usb/storage/sddr09.c
drivers/usb/storage/sddr09.h
drivers/usb/storage/transport.c
drivers/usb/storage/usb.c
drivers/usb/storage/usb.h
drivers/usb/usb-uhci.c
drivers/usb/usb.c
fs/autofs4/root.c
fs/buffer.c
fs/dcache.c
fs/exec.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/ioctl.c
fs/namei.c
fs/nfs/inode.c
fs/stat.c
fs/umsdos/emd.c
fs/umsdos/inode.c
fs/umsdos/ioctl.c
fs/umsdos/namei.c
include/asm-alpha/fpu.h
include/asm-arm/stat.h
include/asm-i386/stat.h
include/asm-i386/system.h
include/asm-ia64/system.h
include/asm-m68k/stat.h
include/asm-m68k/system.h
include/asm-mips/system.h
include/asm-mips64/system.h
include/asm-ppc/stat.h
include/asm-ppc/system.h
include/asm-s390/stat.h
include/asm-s390/system.h
include/asm-sh/system.h
include/asm-sparc/stat.h
include/asm-sparc/system.h
include/asm-sparc64/stat.h
include/asm-sparc64/system.h
include/linux/fs.h
include/linux/list.h
include/linux/sysrq.h
include/linux/umsdos_fs.p
include/linux/usb.h
kernel/kmod.c
kernel/sched.c
kernel/softirq.c
kernel/sysctl.c
mm/filemap.c
mm/highmem.c
mm/page_alloc.c
mm/swapfile.c

index f521bc0d52d7bacc4e2dc41c21bdcf14f8df74bd..6db8aad316204d6623f0735cbcfae3ff2431fcb4 100644 (file)
@@ -1142,7 +1142,7 @@ UMSDOS FILESYSTEM
 P:     Matija Nalis
 M:     Matija Nalis <mnalis-umsdos@voyager.hr>
 L:     linux-kernel@vger.rutgers.edu
-W:     http://www.voyager.hr/~mnalis/umsdos/
+W:     http://linux.voyager.hr/umsdos/
 S:     Maintained
 
 UNIFORM CDROM DRIVER
index 8d2689a29018f17cd04cc96388085ca66026adb6..8f2b707c6e0969ae84b8b8e200fef304b0a911ea 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -177,8 +177,6 @@ include arch/$(ARCH)/Makefile
 
 # use '-fno-strict-aliasing', but only if the compiler can take it
 CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
-# likewise for -fno-delete-null-pointer-checks
-CFLAGS += $(shell if $(CC) -fno-delete-null-pointer-checks -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-delete-null-pointer-checks"; fi)
 
 export CPPFLAGS CFLAGS AFLAGS
 
index 5f6ae670db8baf1b396197686048403e7fc81457..d9fcd91db9a757a912a941fa7ae957b662daeceb 100644 (file)
@@ -344,5 +344,5 @@ mainmenu_option next_comment
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_VT
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
index 4ead92e81cb94e4df05004ff990eb83ee463ea05..38dd1d25154caa592f91d0c358f9223b82e827b4 100644 (file)
@@ -15,8 +15,8 @@ CONFIG_UID16=y
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
 
 #
 # Processor type and features
index bfb2a6841fdd69c7678b64bef092787203ba1666..fcc0a72f5df7156b5b5c09372a301e961b77d026 100644 (file)
@@ -536,7 +536,7 @@ void enable_irq(unsigned int irq)
                desc->depth--;
                break;
        case 0:
-               printk("enable_irq() unbalanced from %p\n",
+               printk("enable_irq(%u) unbalanced from %p\n", irq,
                       __builtin_return_address(0));
        }
        spin_unlock_irqrestore(&desc->lock, flags);
@@ -775,6 +775,8 @@ void free_irq(unsigned int irq, void *dev_id)
  * disabled.
  */
 
+static DECLARE_MUTEX(probe_sem);
+
 /**
  *     probe_irq_on    - begin an interrupt autodetect
  *
@@ -790,6 +792,7 @@ unsigned long probe_irq_on(void)
        unsigned long val;
        unsigned long delay;
 
+       down(&probe_sem);
        /* 
         * something may have generated an irq long ago and we want to
         * flush such a longstanding irq before considering it as spurious. 
@@ -868,15 +871,18 @@ unsigned long probe_irq_on(void)
  *     Scan the ISA bus interrupt lines and return a bitmap of
  *     active interrupts. The interrupt probe logic state is then
  *     returned to its previous value.
+ *
+ *     Note: we need to scan all the irq's even though we will
+ *     only return ISA irq numbers - just so that we reset them
+ *     all to a known state.
  */
 unsigned int probe_irq_mask(unsigned long val)
 {
        int i;
        unsigned int mask;
 
        mask = 0;
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < NR_IRQS; i++) {
                irq_desc_t *desc = irq_desc + i;
                unsigned int status;
 
@@ -884,7 +890,7 @@ unsigned int probe_irq_mask(unsigned long val)
                status = desc->status;
 
                if (status & IRQ_AUTODETECT) {
-                       if (!(status & IRQ_WAITING))
+                       if (i < 16 && !(status & IRQ_WAITING))
                                mask |= 1 << i;
 
                        desc->status = status & ~IRQ_AUTODETECT;
@@ -892,6 +898,7 @@ unsigned int probe_irq_mask(unsigned long val)
                }
                spin_unlock_irq(&desc->lock);
        }
+       up(&probe_sem);
 
        return mask & val;
 }
@@ -943,6 +950,7 @@ int probe_irq_off(unsigned long val)
                }
                spin_unlock_irq(&desc->lock);
        }
+       up(&probe_sem);
 
        if (nr_irqs > 1)
                irq_found = -irq_found;
@@ -998,7 +1006,7 @@ int setup_irq(unsigned int irq, struct irqaction * new)
 
        if (!shared) {
                desc->depth = 0;
-               desc->status &= ~IRQ_DISABLED;
+               desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
                desc->handler->startup(irq);
        }
        spin_unlock_irqrestore(&desc->lock,flags);
index c2e91ef8380e91beafe4799e62414ea9fa5b12d3..d24d6597004dd612d9c11412b033cdfcca4994c6 100644 (file)
@@ -6,7 +6,7 @@
 #
 
 tristate 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
-if [ "$CONFIG_DRM" = "y" ]; then
+if [ "$CONFIG_DRM" != "n" ]; then
     tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX
     tristate '  3dlabs GMX 2000' CONFIG_DRM_GAMMA
     tristate '  ATI Rage 128' CONFIG_DRM_R128
index 5ae783f3ef433beb5757a2da6614a8ef8ebe8bf7..b1b8d9768ee1307aede9263b3212c03aa405c94f 100644 (file)
@@ -3,58 +3,69 @@
 # the Direct Rendering Infrastructure (DRI) in XFree86 4.x.
 #
 
-O_TARGET =     drm.o
-
-export-objs =  drm_syms.o      
-list-multi =   drm.o gamma.o tdfx.o r128.o ffb.o mga.o i810.o
-drm-objs =     init.o memory.o proc.o auth.o context.o \
-               drawable.o bufs.o lists.o lock.o ioctl.o \
-               fops.o vm.o dma.o ctxbitmap.o drm_syms.o
-gamma-objs =   gamma_drv.o                     gamma_dma.o
-tdfx-objs =    tdfx_drv.o      tdfx_context.o
-r128-objs =    r128_drv.o      r128_context.o  r128_dma.o      r128_bufs.o
-ffb-objs =     ffb_drv.o       ffb_context.o
-mga-objs =     mga_drv.o       mga_context.o   mga_dma.o mga_bufs.o mga_state.o
-i810-objs =    i810_drv.o      i810_context.o  i810_dma.o      i810_bufs.o
-
-ifeq ($(CONFIG_AGP), y)
-   drm-objs += agpsupport.o
+# drm.o is a fake target -- it is never built
+# The real targets are in the module-list
+O_TARGET       := drm.o
+module-list     := gamma.o tdfx.o r128.o ffb.o mga.o i810.o
+export-objs     := $(patsubst %.o,%_drv.o,$(module-list))
+
+# libs-objs are included in every module so that radical changes to the
+# architecture of the DRM support library can be made at a later time.
+#
+# The downside is that each module is larger, and a system that uses
+# more than one module (i.e., a dual-head system) will use more memory
+# (but a system that uses exactly one module will use the same amount of
+# memory).
+#
+# The upside is that if the DRM support library ever becomes insufficient
+# for new families of cards, a new library can be implemented for those new
+# cards without impacting the drivers for the old cards.  This is significant,
+# because testing architectural changes to old cards may be impossible, and
+# may delay the implementation of a better architecture.  We've traded slight
+# memory waste (in the dual-head case) for greatly improved long-term
+# maintainability.
+#
+lib-objs   := init.o memory.o proc.o auth.o context.o drawable.o bufs.o
+lib-objs   += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o
+
+ifeq ($(CONFIG_AGP),y)
+ lib-objs  += agpsupport.o
 else
- ifeq ($(CONFIG_AGP), m)
-   drm-objs += agpsupport.o
+ ifeq ($(CONFIG_AGP),m)
+  lib-objs  += agpsupport.o
  endif
 endif
 
-obj-$(CONFIG_DRM)      += drm.o
-obj-$(CONFIG_DRM_GAMMA) += gamma.o 
-obj-$(CONFIG_DRM_TDFX)  += tdfx.o
-obj-$(CONFIG_DRM_R128)  += r128.o
-obj-$(CONFIG_DRM_FFB)   += ffb.o
-obj-$(CONFIG_DRM_MGA)   += mga.o
-obj-$(CONFIG_DRM_I810)  += i810.o
-
-
-# Extract lists of the multi-part drivers.
-# The 'int-*' lists are the intermediate files used to build the multi's.
-multi-y                := $(filter $(list-multi), $(obj-y))
-multi-m                := $(filter $(list-multi), $(obj-m))
-int-y          := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-int-m          := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+gamma-objs := $(lib-objs) gamma_drv.o gamma_dma.o
+tdfx-objs  := $(lib-objs) tdfx_drv.o                tdfx_context.o
+r128-objs  := $(lib-objs) r128_drv.o  r128_dma.o    r128_context.o r128_bufs.o
+ffb-objs   := $(lib-objs) ffb_drv.o                 ffb_context.o
+mga-objs   := $(lib-objs) mga_drv.o   mga_dma.o     mga_context.o  mga_bufs.o \
+             mga_state.o
+i810-objs  := $(lib-objs) i810_drv.o  i810_dma.o    i810_context.o i810_bufs.o
+
+obj-$(CONFIG_DRM_GAMMA) += gamma.o $(gamma-objs)
+obj-$(CONFIG_DRM_TDFX)  += tdfx.o  $(tdfx-objs)
+obj-$(CONFIG_DRM_R128)  += r128.o  $(r128-objs)
+obj-$(CONFIG_DRM_FFB)   += ffb.o   $(ffb-objs)
+
+ifneq ($CONFIG_AGP),)
+obj-$(CONFIG_DRM_MGA)   += mga.o   $(mga-objs)
+obj-$(CONFIG_DRM_I810)  += i810.o  $(i810-objs)
+endif
 
-# Files that are both resident and modular: remove from modular.
-obj-m          := $(filter-out $(obj-y), $(obj-m))
-int-m          := $(filter-out $(int-y), $(int-m))
+# Take module names out of obj-y and int-m
 
-# Take multi-part drivers out of obj-y and put components in.
-obj-y          := $(filter-out $(list-multi), $(obj-y)) $(int-y)
+obj-y           := $(filter-out $(module-list), $(obj-y))
+int-m           := $(filter-out $(module-list), $(obj-m))
 
 # Translate to Rules.make lists.
-O_OBJS         := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS                := $(filter     $(export-objs), $(obj-y))
-M_OBJS         := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS                := $(sort $(filter     $(export-objs), $(obj-m)))
-MI_OBJS                := $(sort $(filter-out $(export-objs), $(int-m)))
-MIX_OBJS       := $(sort $(filter     $(export-objs), $(int-m)))
+
+O_OBJS          := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS         := $(filter     $(export-objs), $(obj-y))
+M_OBJS          := $(sort $(filter     $(module-list), $(obj-m)))
+MI_OBJS         := $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS        := $(sort $(filter     $(export-objs), $(int-m)))
 
 include $(TOPDIR)/Rules.make
 
index afc4fd43e254c4e997da1aa3e9d9059d6f691548..3e5149c910e6349dcf7b63ccf11d81aab12e2a3e 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/pci.h>
 #include <linux/wrapper.h>
 #include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>    /* For (un)lock_kernel */
 #include <asm/io.h>
 #include <asm/mman.h>
 #include <asm/uaccess.h>
@@ -497,8 +499,8 @@ typedef struct drm_device {
                                /* Context support */
        int               irq;          /* Interrupt used by board         */
        __volatile__ long context_flag; /* Context swapping flag           */
-       __volatile__ long  interrupt_flag; /* Interruption handler flag    */
-       __volatile__ long  dma_flag;    /* DMA dispatch flag               */
+       __volatile__ long interrupt_flag; /* Interruption handler flag     */
+       __volatile__ long dma_flag;     /* DMA dispatch flag               */
        struct timer_list timer;        /* Timer for delaying ctx switch   */
        wait_queue_head_t context_wait; /* Processes waiting on ctx switch */
        int               last_checked; /* Last context checked for DMA    */
index 850cc511845f941ad293a60a947f665a4fcd6ede..32b2ba2b9c3c17a4aac9495f16acb94d32c805d5 100644 (file)
@@ -30,9 +30,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>    /* For (un)lock_kernel */
 #include "drmP.h"
 #include "gamma_drv.h"
 
@@ -342,7 +339,7 @@ int gamma_find_devices(void)
 /* gamma_init is called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported). */
 
-int gamma_init(void)
+static int gamma_init(void)
 {
        int                   retcode;
        drm_device_t          *dev = &gamma_device;
@@ -383,7 +380,7 @@ int gamma_init(void)
 
 /* gamma_cleanup is called via cleanup_module at module unload time. */
 
-void gamma_cleanup(void)
+static void gamma_cleanup(void)
 {
        drm_device_t          *dev = &gamma_device;
 
@@ -443,6 +440,9 @@ int gamma_open(struct inode *inode, struct file *filp)
        
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_open);
                spin_lock(&dev->count_lock);
                if (!dev->open_count++) {
@@ -465,6 +465,9 @@ int gamma_release(struct inode *inode, struct file *filp)
 
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_release(inode, filp))) {
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_close);
                spin_lock(&dev->count_lock);
                if (!--dev->open_count) {
@@ -477,9 +480,8 @@ int gamma_release(struct inode *inode, struct file *filp)
                                return -EBUSY;
                        }
                        spin_unlock(&dev->count_lock);
-                       retcode = gamma_takedown(dev);
                        unlock_kernel();
-                       return retcode;
+                       return gamma_takedown(dev);
                }
                spin_unlock(&dev->count_lock);
        }
index 689814db5ad50a04504d1af012c1ccc645eab6fa..85c0877b6bfe827fae02c840e2dcbc563fd54428 100644 (file)
@@ -29,8 +29,6 @@
  *
  */
 
-#include <linux/sched.h>
-
 #define __NO_VERSION__
 #include "drmP.h"
 #include "i810_drv.h"
index 2882ca09cb26b12d67b042703fdd2a5426077d14..f3d9db43ee0edc0be5b9cf9ae54f17bc9388578d 100644 (file)
 #define __NO_VERSION__
 #include "drmP.h"
 #include "i810_drv.h"
-
 #include <linux/interrupt.h>   /* For task queue support */
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 /* in case we don't have a 2.3.99-pre6 kernel or later: */
 #ifndef VM_DONTCOPY
@@ -158,16 +155,16 @@ static struct file_operations i810_buffer_fops = {
 
 int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 {
-       drm_file_t        *priv   = filp->private_data;
-       drm_device_t      *dev;
-       drm_i810_private_t *dev_priv;
-       drm_buf_t *buf;
+       drm_file_t          *priv         = filp->private_data;
+       drm_device_t        *dev;
+       drm_i810_private_t  *dev_priv;
+       drm_buf_t           *buf;
        drm_i810_buf_priv_t *buf_priv;
 
        lock_kernel();
-       dev       = priv->dev;
+       dev      = priv->dev;
        dev_priv = dev->dev_private;
-       buf = dev_priv->mmap_buffer;
+       buf      = dev_priv->mmap_buffer;
        buf_priv = buf->dev_private;
    
        vma->vm_flags |= (VM_IO | VM_DONTCOPY);
index eaa71a66b837be8d37fe51b55706548075014f43..5cab071e4ab87196779a6f47eb5bc5b72a0163f8 100644 (file)
@@ -32,8 +32,6 @@
 #include <linux/config.h>
 #include "drmP.h"
 #include "i810_drv.h"
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 #define I810_NAME       "i810"
 #define I810_DESC       "Intel I810"
@@ -340,7 +338,7 @@ static int i810_takedown(drm_device_t *dev)
 /* i810_init is called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported). */
 
-int i810_init(void)
+static int i810_init(void)
 {
        int                   retcode;
        drm_device_t          *dev = &i810_device;
@@ -399,7 +397,7 @@ int i810_init(void)
 
 /* i810_cleanup is called via cleanup_module at module unload time. */
 
-void i810_cleanup(void)
+static void i810_cleanup(void)
 {
        drm_device_t          *dev = &i810_device;
 
@@ -465,6 +463,9 @@ int i810_open(struct inode *inode, struct file *filp)
        
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_open);
                spin_lock(&dev->count_lock);
                if (!dev->open_count++) {
@@ -545,6 +546,9 @@ int i810_release(struct inode *inode, struct file *filp)
        up(&dev->struct_sem);
        
        drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+#if LINUX_VERSION_CODE < 0x020333
+       MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
        atomic_inc(&dev->total_close);
        spin_lock(&dev->count_lock);
        if (!--dev->open_count) {
@@ -557,9 +561,10 @@ int i810_release(struct inode *inode, struct file *filp)
                        return -EBUSY;
                }
                spin_unlock(&dev->count_lock);
-               retcode = i810_takedown(dev);
-       } else
-               spin_unlock(&dev->count_lock);
+               unlock_kernel();
+               return i810_takedown(dev);
+       }
+       spin_unlock(&dev->count_lock);
        unlock_kernel();
        return retcode;
 }
index d02592740d475af0db73a5be860e4689e8fc035e..9a73e6c14f5834c27479c35236c4137ef5c30214 100644 (file)
@@ -29,8 +29,6 @@
  *
  */
 
-#include <linux/sched.h>
-
 #define __NO_VERSION__
 #include "drmP.h"
 #include "mga_drv.h"
index 45653aa56e6eba8462adc2432f329106e8df87d4..7aae6f3e9a29fd7dfa35e1d2ed26637ec87df876 100644 (file)
@@ -33,8 +33,6 @@
 #include <linux/config.h>
 #include "drmP.h"
 #include "mga_drv.h"
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 #define MGA_NAME        "mga"
 #define MGA_DESC        "Matrox g200/g400"
@@ -339,7 +337,7 @@ static int mga_takedown(drm_device_t *dev)
 /* mga_init is called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported). */
 
-int mga_init(void)
+static int mga_init(void)
 {
        int                   retcode;
        drm_device_t          *dev = &mga_device;
@@ -404,7 +402,7 @@ int mga_init(void)
 
 /* mga_cleanup is called via cleanup_module at module unload time. */
 
-void mga_cleanup(void)
+static void mga_cleanup(void)
 {
        drm_device_t          *dev = &mga_device;
 
@@ -481,6 +479,9 @@ int mga_open(struct inode *inode, struct file *filp)
        
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_open);
                spin_lock(&dev->count_lock);
                if (!dev->open_count++) {
@@ -561,6 +562,9 @@ int mga_release(struct inode *inode, struct file *filp)
        up(&dev->struct_sem);
        
        drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+#if LINUX_VERSION_CODE < 0x020333
+       MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
        atomic_inc(&dev->total_close);
        spin_lock(&dev->count_lock);
        if (!--dev->open_count) {
@@ -573,9 +577,10 @@ int mga_release(struct inode *inode, struct file *filp)
                        return -EBUSY;
                }
                spin_unlock(&dev->count_lock);
-               retcode = mga_takedown(dev);
-       } else
-               spin_unlock(&dev->count_lock);
+               unlock_kernel();
+               return mga_takedown(dev);
+       }
+       spin_unlock(&dev->count_lock);
        unlock_kernel();
        return retcode;
 }
index f11453ba1b55da4e57839a92ac4160f75b08eff0..2dd716d4b9a818ef37d9950950b4ccbc91a568d6 100644 (file)
@@ -28,8 +28,6 @@
  *
  */
 
-#include <linux/sched.h>
-
 #define __NO_VERSION__
 #include "drmP.h"
 #include "r128_drv.h"
@@ -38,10 +36,6 @@ extern drm_ctx_t r128_res_ctx;
 
 static int r128_alloc_queue(drm_device_t *dev)
 {
-#if 0
-       static int context = 0;
-#endif
-
        return drm_ctxbitmap_next(dev);
 }
 
index b382a13c5a652a737eb7842ab6db3bf2835712ab..6b1b19d5e28272328f2b0b526418ce1cea799441 100644 (file)
@@ -32,8 +32,6 @@
 #include <linux/config.h>
 #include "drmP.h"
 #include "r128_drv.h"
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 #define R128_NAME       "r128"
 #define R128_DESC       "ATI Rage 128"
@@ -325,7 +323,7 @@ static int r128_takedown(drm_device_t *dev)
 /* r128_init is called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported). */
 
-int r128_init(void)
+static int r128_init(void)
 {
        int                   retcode;
        drm_device_t          *dev = &r128_device;
@@ -389,7 +387,7 @@ int r128_init(void)
 
 /* r128_cleanup is called via cleanup_module at module unload time. */
 
-void r128_cleanup(void)
+static void r128_cleanup(void)
 {
        drm_device_t          *dev = &r128_device;
 
@@ -457,6 +455,9 @@ int r128_open(struct inode *inode, struct file *filp)
 
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_open);
                spin_lock(&dev->count_lock);
                if (!dev->open_count++) {
@@ -476,10 +477,12 @@ int r128_release(struct inode *inode, struct file *filp)
        int           retcode = 0;
 
        lock_kernel();
-       dev    = priv->dev;
+       dev = priv->dev;
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_release(inode, filp))) {
-               MOD_DEC_USE_COUNT;
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_close);
                spin_lock(&dev->count_lock);
                if (!--dev->open_count) {
@@ -492,10 +495,12 @@ int r128_release(struct inode *inode, struct file *filp)
                                return -EBUSY;
                        }
                        spin_unlock(&dev->count_lock);
-                       retcode = r128_takedown(dev);
-               } else
-                       spin_unlock(&dev->count_lock);
+                       unlock_kernel();
+                       return r128_takedown(dev);
+               }
+               spin_unlock(&dev->count_lock);
        }
+       
        unlock_kernel();
        return retcode;
 }
index c8d6e50ea98ec0c9af7abc88cb087291dbea2964..d6903c0ae9e0c7bdd0ecbaef802d96c7a7ea7552 100644 (file)
@@ -30,8 +30,6 @@
  * 
  */
 
-#include <linux/sched.h>
-
 #define __NO_VERSION__
 #include "drmP.h"
 #include "tdfx_drv.h"
index 896705e9711f16fd3e3342b6c43e4359647c5ae4..ba8c40ceb849c21199d81b21ce9183dc94368f66 100644 (file)
@@ -31,8 +31,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include "drmP.h"
 #include "tdfx_drv.h"
 
@@ -300,7 +298,7 @@ static int tdfx_takedown(drm_device_t *dev)
 /* tdfx_init is called via init_module at module load time, or via
  * linux/init/main.c (this is not currently supported). */
 
-int tdfx_init(void)
+static int tdfx_init(void)
 {
        int                   retcode;
        drm_device_t          *dev = &tdfx_device;
@@ -348,7 +346,7 @@ int tdfx_init(void)
 
 /* tdfx_cleanup is called via cleanup_module at module unload time. */
 
-void tdfx_cleanup(void)
+static void tdfx_cleanup(void)
 {
        drm_device_t          *dev = &tdfx_device;
 
@@ -416,6 +414,9 @@ int tdfx_open(struct inode *inode, struct file *filp)
        
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_open);
                spin_lock(&dev->count_lock);
                if (!dev->open_count++) {
@@ -438,6 +439,9 @@ int tdfx_release(struct inode *inode, struct file *filp)
 
        DRM_DEBUG("open_count = %d\n", dev->open_count);
        if (!(retcode = drm_release(inode, filp))) {
+#if LINUX_VERSION_CODE < 0x020333
+               MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
                atomic_inc(&dev->total_close);
                spin_lock(&dev->count_lock);
                if (!--dev->open_count) {
index 01487f96529143e55cfea4a3f81973ebae9d5736..5ee9e3242f8e04fa8e92debaab11ccc67073d463 100644 (file)
@@ -31,8 +31,6 @@
 
 #define __NO_VERSION__
 #include "drmP.h"
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 struct vm_operations_struct   drm_vm_ops = {
        nopage:  drm_vm_nopage,
@@ -147,6 +145,11 @@ void drm_vm_open(struct vm_area_struct *vma)
        DRM_DEBUG("0x%08lx,0x%08lx\n",
                  vma->vm_start, vma->vm_end - vma->vm_start);
        atomic_inc(&dev->vma_count);
+#if LINUX_VERSION_CODE < 0x020333
+                               /* The map can exist after the fd is closed. */
+       MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+
 
 #if DRM_DEBUG_CODE
        vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
@@ -171,6 +174,9 @@ void drm_vm_close(struct vm_area_struct *vma)
 
        DRM_DEBUG("0x%08lx,0x%08lx\n",
                  vma->vm_start, vma->vm_end - vma->vm_start);
+#if LINUX_VERSION_CODE < 0x020333
+       MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
        atomic_dec(&dev->vma_count);
 
 #if DRM_DEBUG_CODE
index a065669d040b9fe8d22b497d6b304060355975f8..edb5caadf316c51ef2d236964a9bf1f094b6a946 100644 (file)
@@ -158,7 +158,6 @@ struct pt_regs * kbd_pt_regs;
 
 #ifdef CONFIG_MAGIC_SYSRQ
 static int sysrq_pressed;
-int sysrq_enabled = 1;
 #endif
 
 static struct pm_dev *pm_kbd = NULL;
@@ -255,7 +254,7 @@ void handle_scancode(unsigned char scancode, int down)
                sysrq_pressed = !up_flag;
                return;
        } else if (sysrq_pressed) {
-               if (!up_flag && sysrq_enabled) {
+               if (!up_flag) {
                        handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
                        return;
                }
index 67deb7f2721a7229a72679b80e3ffa6828d0b504..9650457c0cf3334475387271ef4300ac60013fce 100644 (file)
@@ -30,6 +30,9 @@ extern void reset_vc(unsigned int);
 extern int console_loglevel;
 extern struct list_head super_blocks;
 
+/* Whether we react on sysrq keys or just ignore them */
+int sysrq_enabled = 1;
+
 /* Machine specific power off function */
 void (*sysrq_power_off)(void) = NULL;
 
@@ -60,6 +63,9 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
 {
        int orig_log_level = console_loglevel;
 
+       if (!sysrq_enabled)
+               return;
+
        if (!key)
                return;
 
index e46d16e7fa6604094d0cfa06ff95fcfd1c493a2e..fa765d76f21f4095fcbab3ddc5fd20e1a3fa0629 100644 (file)
@@ -164,10 +164,8 @@ int ide_driveid_update (ide_drive_t *drive)
         * change (copied from ide-probe.c)
         */
        struct hd_driveid *id;
-       unsigned long timeout, irqs, flags;
+       unsigned long timeout, flags;
 
-       probe_irq_off(probe_irq_on());
-       irqs = probe_irq_on();
        SELECT_MASK(HWIF(drive), drive, 1);
        if (IDE_CONTROL_REG)
                OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
@@ -176,8 +174,6 @@ int ide_driveid_update (ide_drive_t *drive)
        timeout = jiffies + WAIT_WORSTCASE;
        do {
                if (0 < (signed long)(jiffies - timeout)) {
-                       if (irqs)
-                               (void) probe_irq_off(irqs);
                        SELECT_MASK(HWIF(drive), drive, 0);
                        return 0;       /* drive timed-out */
                }
index 168895fb59efdf49644d672e81911b0700abbd7e..decbc9f8d5294f03c738572ac3f2f77f83b477b3 100644 (file)
@@ -184,22 +184,16 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
  *             1  device timed-out (no response to identify request)
  *             2  device aborted the command (refused to identify itself)
  */
-static int try_to_identify (ide_drive_t *drive, byte cmd)
+static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
 {
        int rc;
        ide_ioreg_t hd_status;
        unsigned long timeout;
-       unsigned long irqs = 0;
        byte s, a;
 
        if (IDE_CONTROL_REG) {
-               if (!HWIF(drive)->irq) {                /* already got an IRQ? */
-                       probe_irq_off(probe_irq_on());  /* clear dangling irqs */
-                       irqs = probe_irq_on();          /* start monitoring irqs */
-                       OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* enable device irq */
-               }
-
-               ide_delay_50ms();                               /* take a deep breath */
+               /* take a deep breath */
+               ide_delay_50ms();
                a = IN_BYTE(IDE_ALTSTATUS_REG);
                s = IN_BYTE(IDE_STATUS_REG);
                if ((a ^ s) & ~INDEX_STAT) {
@@ -222,8 +216,6 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
                /* DC4030 hosted drives need their own identify... */
                extern int pdc4030_identify(ide_drive_t *);
                if (pdc4030_identify(drive)) {
-                       if (irqs)
-                               (void) probe_irq_off(irqs);
                        return 1;
                }
        } else
@@ -233,8 +225,6 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
        timeout += jiffies;
        do {
                if (0 < (signed long)(jiffies - timeout)) {
-                       if (irqs)
-                               (void) probe_irq_off(irqs);
                        return 1;       /* drive timed-out */
                }
                ide_delay_50ms();               /* give drive a breather */
@@ -251,32 +241,49 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
                __restore_flags(flags); /* local CPU only */
        } else
                rc = 2;                 /* drive refused ID */
+       return rc;
+}
+
+static int try_to_identify (ide_drive_t *drive, byte cmd)
+{
+       int retval;
+       int autoprobe = 0;
+       unsigned long cookie = 0;
+
        if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
-               irqs = probe_irq_off(irqs);     /* get our irq number */
-               if (irqs > 0) {
-                       HWIF(drive)->irq = irqs; /* save it for later */
-                       irqs = probe_irq_on();
-                       OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
-                       udelay(5);
-                       (void) probe_irq_off(irqs);
-                       (void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */
-                       (void) GET_STAT();      /* clear drive IRQ */
-
-               } else {        /* Mmmm.. multiple IRQs.. don't know which was ours */
-                       printk("%s: IRQ probe failed (%ld)\n", drive->name, irqs);
+               autoprobe = 1;
+               cookie = probe_irq_on();
+               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);   /* enable device irq */
+       }
+
+       retval = actual_try_to_identify(drive, cmd);
+
+       if (autoprobe) {
+               int irq;
+               OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
+               (void) GET_STAT();                      /* clear drive IRQ */
+               udelay(5);
+               irq = probe_irq_off(cookie);
+               if (!HWIF(drive)->irq) {
+                       if (irq > 0) {
+                               HWIF(drive)->irq = irq;
+                       } else {        /* Mmmm.. multiple IRQs.. don't know which was ours */
+                               printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
-                       if (HWIF(drive)->chipset == ide_cmd640) {
-                               printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
-                               CMD640_DUMP_REGS;
-                       }
+                               if (HWIF(drive)->chipset == ide_cmd640) {
+                                       printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+                                       CMD640_DUMP_REGS;
+                               }
 #endif /* CMD640_DUMP_REGS */
 #endif /* CONFIG_BLK_DEV_CMD640 */
+                       }
                }
        }
-       return rc;
+       return retval;
 }
 
+
 /*
  * do_probe() has the difficult job of finding a drive if it exists,
  * without getting hung up if it doesn't exist, without trampling on
index aeee5e561e845d3cf346632ec33d48cc49393fca..36b11f907e049a78208125758cad24bfc4694215 100644 (file)
@@ -2663,7 +2663,7 @@ static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
 } /* End build_auth_frame */
 
 /*===========================================================================*/
-
+#ifdef CONFIG_PROC_FS
 static void raycs_write(const char *name, write_proc_t *w, void *data)
 {
        struct proc_dir_entry * entry = create_proc_entry(name, S_IFREG | S_IWUSR, NULL);
@@ -2713,6 +2713,7 @@ static int write_int(struct file *file, const char *buffer, unsigned long count,
        *(int *)data = nr;
        return count;
 }
+#endif
 
 static int __init init_ray_cs(void)
 {
@@ -2722,12 +2723,14 @@ static int __init init_ray_cs(void)
     rc = register_pcmcia_driver(&dev_info, &ray_attach, &ray_detach);
     DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc);
 
+#ifdef CONFIG_PROC_FS
     proc_mkdir("driver/ray_cs", 0);
 
-    create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_read);
+    create_proc_info_entry("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_read);
     raycs_write("driver/ray_cs/essid", write_essid, NULL);
     raycs_write("driver/ray_cs/net_type", write_int, &net_type);
     raycs_write("driver/ray_cs/translate", write_int, &translate);
+#endif
     if (translate != 0) translate = 1;
     return 0;
 } /* init_ray_cs */
@@ -2739,17 +2742,22 @@ static void __exit exit_ray_cs(void)
     DEBUG(0, "ray_cs: cleanup_module\n");
 
 
+#ifdef CONFIG_PROC_FS
     remove_proc_entry("ray_cs", proc_root_driver);
+#endif
+
     unregister_pcmcia_driver(&dev_info);
     while (dev_list != NULL) {
         if (dev_list->state & DEV_CONFIG) ray_release((u_long)dev_list);
         ray_detach(dev_list);
     }
+#ifdef CONFIG_PROC_FS
     remove_proc_entry("driver/ray_cs/ray_cs", NULL);
     remove_proc_entry("driver/ray_cs/essid", NULL);
     remove_proc_entry("driver/ray_cs/net_type", NULL);
     remove_proc_entry("driver/ray_cs/translate", NULL);
     remove_proc_entry("driver/ray_cs", NULL);
+#endif
 } /* exit_ray_cs */
 
 module_init(init_ray_cs);
index 288caf5cef8fec64a5c935113cd3da83a32d3345..96b4ba97cbfdafffc27a5f86e93e4b859702db16 100644 (file)
 1105  Sigma Designs, Inc.
        8300  REALmagic Hollywood Plus DVD Decoder
 1106  VIA Technologies, Inc.
+       0305  VT8363 [KT133]
        0391  VT8371 [KX133]
        0501  VT8501
        0505  VT82C505
        5030  VT82C596 ACPI [Apollo PRO]
        6100  VT85C100A [Rhine II]
        8231  VT8231 [PCI-to-ISA Bridge]
+       8305  VT8363 [PCI-PCI Bridge]
        8391  VT8371 [PCI-PCI Bridge]
        8501  VT8501
        8596  VT82C596 [Apollo PRO AGP]
index 649e50a1454d675f3f45d03df34e20acfb29f2ca..b1ac19022df6b1b4ebb849fbdfa4d7852daadf18 100644 (file)
@@ -41,8 +41,11 @@ else
       M_OBJS += tcic.o
     endif
      ifeq ($(CONFIG_CARDBUS),y)
+       M_OBJS += yenta_socket.o
        CORE_OBJS += cardbus.o
-       MX_OBJS += cb_enabler.o yenta.o pci_socket.o
+       CARDBUS_OBJS := pci_socket.o yenta.o
+       OX_OBJS += pci_socket.o yenta.o
+       MX_OBJS += cb_enabler.o
      endif
   endif
 endif
@@ -51,3 +54,6 @@ include $(TOPDIR)/Rules.make
 
 pcmcia_core.o:  $(CORE_OBJS)
        $(LD) $(LD_RFLAG) -r -o $@ $(CORE_OBJS)
+
+yenta_socket.o: $(CARDBUS_OBJS)
+       $(LD) $(LD_RFLAG) -r -o $@ yenta.o pci_socket.o
index 6b0a9e1ae1cf01d00a5fc4040777321506d39af0..4d3aa947e850eb1f4711c8d736d55c86db697b98 100644 (file)
@@ -500,6 +500,7 @@ static unsigned int yenta_probe_irq(pci_socket_t *socket, u32 isa_irq_mask)
         */
        cb_writel(socket, CB_SOCKET_EVENT, -1);
        cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
+       exca_writeb(socket, I365_CSCINT, 0);
        val = probe_irq_on() & isa_irq_mask;
        for (i = 1; i < 16; i++) {
                if (!((val >> i) & 1))
@@ -547,6 +548,7 @@ static int yenta_socket_thread(void * data)
        pci_socket_t * socket = (pci_socket_t *) data;
        DECLARE_WAITQUEUE(wait, current);
 
+       MOD_INC_USE_COUNT;
        daemonize();
        strcpy(current->comm, "CardBus Watcher");
 
@@ -572,6 +574,7 @@ static int yenta_socket_thread(void * data)
                        schedule_timeout(HZ);
                remove_wait_queue(&socket->wait, &wait);
        } while (!signal_pending(current));
+       MOD_DEC_USE_COUNT;
        return 0;
 }
 
@@ -699,7 +702,7 @@ static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
        min = PCIBIOS_MIN_MEM; max = ~0U;
        if (type & IORESOURCE_IO) {
                align = 1024;
-               size = 1024;
+               size = 256;
                min = PCIBIOS_MIN_IO;
                max = 0xffff;
        }
@@ -719,6 +722,7 @@ static void yenta_allocate_resources(pci_socket_t *socket)
        yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH);
        yenta_allocate_res(socket, 1, IORESOURCE_MEM);
        yenta_allocate_res(socket, 2, IORESOURCE_IO);
+       yenta_allocate_res(socket, 3, IORESOURCE_IO);   /* PCI isn't clever enough to use this one yet */
 }
 
 /*
index 1911942879e04f86bd7b7f011db2760b263caa89..cc71cab7e0d6a17a696ba5ab31fc145e72ae82eb 100644 (file)
@@ -177,9 +177,6 @@ static unsigned char handle_diacr(unsigned char);
 static struct pt_regs * pt_regs;
 
 #ifdef CONFIG_MAGIC_SYSRQ
-#ifndef CONFIG_PCI
-int sysrq_enabled = 1;
-#endif
 unsigned char sun_sysrq_xlate[128] =
        "\0\0\0\0\0\201\202\212\203\213\204\214\205\0\206\0"    /* 0x00 - 0x0f */
        "\207\210\211\0\0\0\0\0\0\0\0\0\0\03312"                /* 0x10 - 0x1f */
@@ -556,7 +553,7 @@ static void __sunkbd_inchar(unsigned char ch, struct pt_regs *regs)
 
 #ifdef CONFIG_MAGIC_SYSRQ                      /* Handle the SysRq hack */
        if (l1a_state.l1_down) {
-               if (!up_flag && sysrq_enabled)
+               if (!up_flag)
                        handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, kbd, tty);
                goto out;
        }
index bd7be69e893d03530a126b0d84fe40f6027a9ba8..4ee29a70214211f5c4bd9e29b89375a7e15da6b4 100644 (file)
@@ -1,11 +1,24 @@
 /*
- * bluetooth.c   Version 0.2
+ * bluetooth.c   Version 0.3
  *
  * Copyright (c) 2000 Greg Kroah-Hartman       <greg@kroah.com>
+ * Copyright (c) 2000 Mark Douglas Corner      <mcorner@umich.edu>
  *
  * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
  *
  *
+ * (08/03/2000) Version 0.3 gkh mdc
+ *     Merged in Mark's changes to make the driver play nice with the Axis
+ *     stack.
+ *     Made the write bulk use an urb pool to enable larger transfers with
+ *     fewer calls to the driver.
+ *     Fixed off by one bug in acl pkt receive
+ *     Made packet counters specific to each bluetooth device 
+ *     Added checks for zero length callbacks
+ *     Added buffers for int and bulk packets.  Had to do this otherwise 
+ *     packet types could intermingle.
+ *     Made a control urb pool for the control messages.
+ *
  * (07/11/2000) Version 0.2 gkh
  *     Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe 
  *     function.
 #include <linux/tty_flip.h>
 #include <linux/tty.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/smp_lock.h>
 
 #define DEBUG
 #include <linux/usb.h>
 
 /* Module information */
-MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
+MODULE_AUTHOR("Greg Kroah-Hartman, Mark Douglas Corner");
 MODULE_DESCRIPTION("USB Bluetooth driver");
 
+/* define this if you have hardware that is not good */
+/*#define      BTBUGGYHARDWARE */
 
 /* Class, SubClass, and Protocol codes that describe a Bluetooth device */
 #define WIRELESS_CLASS_CODE                    0xe0
@@ -72,19 +84,47 @@ MODULE_DESCRIPTION("USB Bluetooth driver");
 
 #define USB_BLUETOOTH_MAGIC    0x6d02  /* magic number for bluetooth struct */
 
+#define BLUETOOTH_CONTROL_REQUEST_TYPE 0x20
+
+/* Bluetooth packet types */
+#define CMD_PKT                        0x01
+#define ACL_PKT                        0x02
+#define SCO_PKT                        0x03
+#define EVENT_PKT              0x04
+#define ERROR_PKT              0x05
+#define NEG_PKT                        0x06
+
+/* Message sizes */
+#define MAX_EVENT_SIZE         0xFF
+#define EVENT_HDR_SIZE         3       /* 2 for the header + 1 for the type indicator */
+#define EVENT_BUFFER_SIZE      (MAX_EVENT_SIZE + EVENT_HDR_SIZE)
+
+#define MAX_ACL_SIZE           0xFFFF
+#define ACL_HDR_SIZE           5       /* 4 for the header + 1 for the type indicator */
+#define ACL_BUFFER_SIZE                (MAX_ACL_SIZE + ACL_HDR_SIZE)
+
 /* parity check flag */
 #define RELEVANT_IFLAG(iflag)  (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
+#define CHAR2INT16(c1,c0)      (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
+#define MIN(a,b)               (((a)<(b))?(a):(b))
 
+#define NUM_BULK_URBS          24
+#define NUM_CONTROL_URBS       16
 
 struct usb_bluetooth {
        int                     magic;
        struct usb_device *     dev;
        struct tty_driver *     tty_driver;     /* the tty_driver for this device */
        struct tty_struct *     tty;            /* the coresponding tty for this port */
-       
+
        unsigned char           minor;          /* the starting minor number for this device */
        char                    active;         /* someone has this device open */
+       int                     throttle;       /* throttled by tty layer */
+       
+       __u8                    control_out_bInterfaceNum;
+       struct urb *            control_urb_pool[NUM_CONTROL_URBS];
+       devrequest              dr[NUM_CONTROL_URBS];
 
        unsigned char *         interrupt_in_buffer;
        struct urb *            interrupt_in_urb;
@@ -92,17 +132,21 @@ struct usb_bluetooth {
        unsigned char *         bulk_in_buffer;
        struct urb *            read_urb;
 
-       unsigned char *         bulk_out_buffer;
        int                     bulk_out_size;
-       struct urb *            write_urb;
+       struct urb *            write_urb_pool[NUM_BULK_URBS];
+       __u8                    bulk_out_endpointAddress;
 
        wait_queue_head_t       write_wait;
 
        struct tq_struct        tqueue;         /* task queue for line discipline waking up */
+       
+       unsigned int            int_packet_pos;
+       unsigned char           int_buffer[EVENT_BUFFER_SIZE];
+       unsigned int            bulk_packet_pos;
+       unsigned char           bulk_buffer[ACL_BUFFER_SIZE];   /* 64k preallocated, fix? */
 };
 
 
-
 /* local function prototypes */
 static int  bluetooth_open             (struct tty_struct *tty, struct file *filp);
 static void bluetooth_close            (struct tty_struct *tty, struct file *filp);
@@ -114,9 +158,15 @@ static void bluetooth_unthrottle   (struct tty_struct *tty);
 static int  bluetooth_ioctl            (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
 static void bluetooth_set_termios      (struct tty_struct *tty, struct termios *old);
 
+static void bluetooth_int_callback             (struct urb *urb);
+static void bluetooth_ctrl_callback            (struct urb *urb);
+static void bluetooth_read_bulk_callback       (struct urb *urb);
+static void bluetooth_write_bulk_callback      (struct urb *urb);
+
 static void * usb_bluetooth_probe      (struct usb_device *dev, unsigned int ifnum);
 static void usb_bluetooth_disconnect   (struct usb_device *dev, void *ptr);
 
+
 static struct usb_driver usb_bluetooth_driver = {
        name:           "bluetooth",
        probe:          usb_bluetooth_probe,
@@ -131,6 +181,7 @@ static struct termios *             bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
 static struct usb_bluetooth    *bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, };
 
 
+
 static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
 {
        if (!bluetooth) {
@@ -141,17 +192,17 @@ static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, con
                dbg("%s - bad magic number for bluetooth", function);
                return -1;
        }
-       
+
        return 0;
 }
 
 
-static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function) 
-{ 
+static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function)
+{
        if (!bluetooth || 
-               bluetooth_paranoia_check (bluetooth, function)) {
+           bluetooth_paranoia_check (bluetooth, function)) { 
                /* then say that we dont have a valid usb_bluetooth thing, which will
-                * end up genrating -ENODEV return values */ 
+                * end up generating -ENODEV return values */
                return NULL;
        }
 
@@ -165,6 +216,54 @@ static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor)
 }
 
 
+static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, void *buf, int len)
+{
+       struct urb *urb = NULL;
+       devrequest *dr = NULL;
+       int i;
+       int status;
+
+       dbg (__FUNCTION__);
+
+       /* try to find a free urb in our list */
+       for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+               if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) {
+                       urb = bluetooth->control_urb_pool[i];
+                       dr = &bluetooth->dr[i];
+                       break;
+               }
+       }
+       if (urb == NULL) {
+               dbg (__FUNCTION__ " - no free urbs");
+               return -ENOMEM;
+       }
+
+       /* free up the last buffer that this urb used */
+       if (urb->transfer_buffer != NULL) {
+               kfree(urb->transfer_buffer);
+               urb->transfer_buffer = NULL;
+       }
+
+       dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE;
+       dr->request = request;
+       dr->value = cpu_to_le16p(&value);
+       dr->index = cpu_to_le16p(&bluetooth->control_out_bInterfaceNum);
+       dr->length = cpu_to_le16p(&len);
+       
+       FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
+                         (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, 0);
+
+       /* send it down the pipe */
+       status = usb_submit_urb(urb);
+       if (status)
+               dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
+       
+       return 0;
+}
+
+
+
+
 
 /*****************************************************************************
  * Driver tty interface functions
@@ -172,7 +271,8 @@ static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor)
 static int bluetooth_open (struct tty_struct *tty, struct file * filp)
 {
        struct usb_bluetooth *bluetooth;
-       
+       int result;
+
        dbg(__FUNCTION__);
 
        /* initialize the pointer incase something fails */
@@ -189,16 +289,26 @@ static int bluetooth_open (struct tty_struct *tty, struct file * filp)
                dbg (__FUNCTION__ " - device already open");
                return -EINVAL;
        }
-       
+
        /* set up our structure making the tty driver remember our object, and us it */
        tty->driver_data = bluetooth;
        bluetooth->tty = tty;
-        
+
        bluetooth->active = 1;
-       /*Start reading from the device*/
-       if (usb_submit_urb(bluetooth->read_urb))
-               dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+
+       /* Reset the packet position counters */
+       bluetooth->int_packet_pos = 0;
+       bluetooth->bulk_packet_pos = 0;
+
+#ifndef BTBUGGYHARDWARE
+       /* Start reading from the device */
+       result = usb_submit_urb(bluetooth->read_urb);
+       if (result)
+               dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result);
+#endif
+       result = usb_submit_urb(bluetooth->interrupt_in_urb);
+       if (result)
+               dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result);
 
        return 0;
 }
@@ -207,20 +317,22 @@ static int bluetooth_open (struct tty_struct *tty, struct file * filp)
 static void bluetooth_close (struct tty_struct *tty, struct file * filp)
 {
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+       int i;
 
        if (!bluetooth) {
                return;
        }
 
        dbg(__FUNCTION__);
-       
+
        if (!bluetooth->active) {
                dbg (__FUNCTION__ " - device not opened");
                return;
        }
 
-       /* shutdown any bulk reads that might be going on */
-       usb_unlink_urb (bluetooth->write_urb);
+       /* shutdown any bulk reads and writes that might be going on */
+       for (i = 0; i < NUM_BULK_URBS; ++i)
+               usb_unlink_urb (bluetooth->write_urb_pool[i]);
        usb_unlink_urb (bluetooth->read_urb);
 
        bluetooth->active = 0;
@@ -230,55 +342,137 @@ static void bluetooth_close (struct tty_struct *tty, struct file * filp)
 static int bluetooth_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-       
+       struct urb *urb = NULL;
+       unsigned char *new_buffer;
+       const unsigned char *current_position;
+       int status;
+       int bytes_sent;
+       int buffer_size;
+       int i;
+
        if (!bluetooth) {
                return -ENODEV;
        }
-       
+
        dbg(__FUNCTION__ " - %d byte(s)", count);
 
        if (!bluetooth->active) {
                dbg (__FUNCTION__ " - device not opened");
                return -EINVAL;
        }
-       
+
        if (count == 0) {
                dbg(__FUNCTION__ " - write request of 0 bytes");
-               return (0);
+               return 0;
        }
-
-       if (bluetooth->write_urb->status == -EINPROGRESS) {
-               dbg (__FUNCTION__ " - already writing");
-               return (0);
+       if (count == 1) {
+               dbg(__FUNCTION__ " - write request only included type %d", buf[0]);
+               return 1;
        }
 
-       count = (count > bluetooth->bulk_out_size) ? bluetooth->bulk_out_size : count;
-
 #ifdef DEBUG
-       {
-               int i;
-               printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
-               for (i = 0; i < count; ++i) {
-                       printk ("%.2x ", buf[i]);
-               }
-               printk ("\n");
+       printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+       for (i = 0; i < count; ++i) {
+               printk ("%.2x ", buf[i]);
        }
+       printk ("\n");
 #endif
 
-       if (from_user) {
-               copy_from_user(bluetooth->write_urb->transfer_buffer, buf, count);
-       }
-       else {
-               memcpy (bluetooth->write_urb->transfer_buffer, buf, count);
-       }  
-
-       /* send the data out the bulk bluetooth */
-       bluetooth->write_urb->transfer_buffer_length = count;
+       switch (*buf) {
+               /* First byte indicates the type of packet */
+               case CMD_PKT:
+                       /* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/
+
+                       if (in_interrupt()){
+                               printk("cmd_pkt from interrupt!\n");
+                               return count;
+                       }
+
+                       new_buffer = kmalloc (count-1, GFP_KERNEL);
+
+                       if (!new_buffer) {
+                               err (__FUNCTION__ "- out of memory.");
+                               return -ENOMEM;
+                       }
+
+                       if (from_user)
+                               copy_from_user (new_buffer, buf+1, count-1);
+                       else
+                               memcpy (new_buffer, buf+1, count-1);
+
+                       bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1);
+
+                       /* need to free new_buffer somehow... FIXME */
+                       return count;
+
+               case ACL_PKT:
+                       current_position = buf;
+                       ++current_position;
+                       --count;
+                       bytes_sent = 0;
+
+                       while (count > 0) {
+                               urb = NULL;
+
+                               /* try to find a free urb in our list */
+                               for (i = 0; i < NUM_BULK_URBS; ++i) {
+                                       if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+                                               urb = bluetooth->write_urb_pool[i];
+                                               break;
+                                       }
+                               }
+                               if (urb == NULL) {
+                                       dbg (__FUNCTION__ " - no free urbs");
+                                       return bytes_sent;
+                               }
+                               
+                               /* free up the last buffer that this urb used */
+                               if (urb->transfer_buffer != NULL) {
+                                       kfree(urb->transfer_buffer);
+                                       urb->transfer_buffer = NULL;
+                               }
+
+                               buffer_size = MIN (count, bluetooth->bulk_out_size);
+                               
+                               new_buffer = kmalloc (buffer_size, GFP_KERNEL);
+                               if (new_buffer == NULL) {
+                                       err(__FUNCTION__" no more kernel memory...");
+                                       return bytes_sent;
+                               }
+
+                               if (from_user)
+                                       copy_from_user(new_buffer, current_position, buffer_size);
+                               else
+                                       memcpy (new_buffer, current_position, buffer_size);
+
+                               /* build up our urb */
+                               FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress),
+                                               new_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
+                               urb->transfer_flags |= USB_QUEUE_BULK;
+
+                               /* send it down the pipe */
+                               status = usb_submit_urb(urb);
+                               if (status)
+                                       dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+#ifdef BTBUGGYHARDWARE
+                               /* A workaround for the stalled data bug */
+                               /* May or may not be needed...*/
+                               if (count != 0) {
+                                       udelay(500);
+                               }
+#endif
+                               current_position += buffer_size;
+                               bytes_sent += buffer_size;
+                               count -= buffer_size;
+                       }
 
-       if (usb_submit_urb(bluetooth->write_urb))
-               dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed");
+                       return bytes_sent + 1;
+               
+               default :
+                       dbg(__FUNCTION__" - unsupported (at this time) write type");
+       }
 
-       return count;
+       return 0;
 } 
 
 
@@ -286,21 +480,25 @@ static int bluetooth_write_room (struct tty_struct *tty)
 {
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
        int room = 0;
+       int i;
 
        if (!bluetooth) {
                return -ENODEV;
        }
 
        dbg(__FUNCTION__);
-       
+
        if (!bluetooth->active) {
                dbg (__FUNCTION__ " - device not open");
                return -EINVAL;
        }
 
-       if (bluetooth->write_urb->status != -EINPROGRESS)
-               room = bluetooth->bulk_out_size;
-       
+       for (i = 0; i < NUM_BULK_URBS; ++i) {
+               if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+                       room += bluetooth->bulk_out_size;
+               }
+       }
+
        dbg(__FUNCTION__ " - returns %d", room);
        return room;
 }
@@ -310,6 +508,7 @@ static int bluetooth_chars_in_buffer (struct tty_struct *tty)
 {
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
        int chars = 0;
+       int i;
 
        if (!bluetooth) {
                return -ENODEV;
@@ -320,9 +519,11 @@ static int bluetooth_chars_in_buffer (struct tty_struct *tty)
                return -EINVAL;
        }
 
-
-       if (bluetooth->write_urb->status == -EINPROGRESS)
-               chars = bluetooth->write_urb->transfer_buffer_length;
+       for (i = 0; i < NUM_BULK_URBS; ++i) {
+               if (bluetooth->write_urb_pool[i]->status == -EINPROGRESS) {
+                       chars += bluetooth->write_urb_pool[i]->transfer_buffer_length;
+               }
+       }
 
        dbg (__FUNCTION__ " - returns %d", chars);
        return chars;
@@ -343,9 +544,9 @@ static void bluetooth_throttle (struct tty_struct * tty)
                dbg (__FUNCTION__ " - device not open");
                return;
        }
-
-       /* FIXME!!! */
        
+       dbg(__FUNCTION__ " unsupported (at this time)");
+
        return;
 }
 
@@ -365,9 +566,7 @@ static void bluetooth_unthrottle (struct tty_struct * tty)
                return;
        }
 
-       /* FIXME!!! */
-
-       return;
+       dbg(__FUNCTION__ " unsupported (at this time)");
 }
 
 
@@ -387,7 +586,6 @@ static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned
        }
 
        /* FIXME!!! */
-       
        return -ENOIOCTLCMD;
 }
 
@@ -408,59 +606,184 @@ static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old)
        }
 
        /* FIXME!!! */
-       
+
        return;
 }
 
 
+#ifdef BTBUGGYHARDWARE
+void btusb_enable_bulk_read(struct tty_struct *tty){
+       struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+       if (!bluetooth) {
+               return;
+       }
+
+       dbg(__FUNCTION__);
+
+       if (!bluetooth->active) {
+               dbg (__FUNCTION__ " - device not open");
+               return;
+       }
+
+       if (bluetooth->read_urb)
+               if (usb_submit_urb(bluetooth->read_urb))
+                       dbg (__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+}
+
+void btusb_disable_bulk_read(struct tty_struct *tty){
+       struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+       if (!bluetooth) {
+               return;
+       }
+
+       dbg(__FUNCTION__);
+
+       if (!bluetooth->active) {
+               dbg (__FUNCTION__ " - device not open");
+               return;
+       }
+
+       if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length))
+               usb_unlink_urb(bluetooth->read_urb);
+}
+#endif
+
+
 /*****************************************************************************
  * urb callback functions
  *****************************************************************************/
 
+
 static void bluetooth_int_callback (struct urb *urb)
 {
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
        unsigned char *data = urb->transfer_buffer;
-       int i;
+       unsigned int i;
+       unsigned int count = urb->actual_length;
+       unsigned int packet_size;
 
        dbg(__FUNCTION__);
-       
+
        if (!bluetooth) {
                dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
                return;
        }
 
        if (urb->status) {
-               dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+               dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status);
                return;
        }
 
+       if (!count) {
+               dbg(__FUNCTION__ " - zero length int");
+               return;
+       }
+
+
 #ifdef DEBUG
-       if (urb->actual_length) {
-               printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
-               for (i = 0; i < urb->actual_length; ++i) {
+       if (count) {
+               printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+               for (i = 0; i < count; ++i) {
                        printk ("%.2x ", data[i]);
                }
                printk ("\n");
        }
 #endif
 
-       /* Don't really know what else to do with this data yet. */
-       /* FIXME!!! */
+#ifdef BTBUGGYHARDWARE
+       if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) {
+               data += 2;
+               count -= 2;
+       }
+       if (count == 0) {
+               urb->actual_length = 0;
+               return;
+       }
+#endif
+       /* We add  a packet type identifier to the beginning of each
+          HCI frame.  This makes the data in the tty look like a
+          serial USB devices.  Each HCI frame can be broken across
+          multiple URBs so we buffer them until we have a full hci
+          packet */
+
+       if (!bluetooth->int_packet_pos) {
+               bluetooth->int_buffer[0] = EVENT_PKT;
+               bluetooth->int_packet_pos++;
+       }
        
-       return;
+       if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) {
+               err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE");
+               bluetooth->int_packet_pos = 0;
+               return;
+       }
+
+       memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos],
+               urb->transfer_buffer, count);
+       bluetooth->int_packet_pos += count;
+       urb->actual_length = 0;
+
+       if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE)
+               packet_size = bluetooth->int_buffer[2];
+       else
+               return;
+
+       if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) {
+               err(__FUNCTION__ " - packet was too long");
+               bluetooth->int_packet_pos = 0;
+               return;
+       }
+
+       if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){
+               for (i = 0; i < bluetooth->int_packet_pos; ++i)
+                       tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
+               tty_flip_buffer_push(bluetooth->tty);
+
+               bluetooth->int_packet_pos = 0;
+       }
+}
+
+
+static void bluetooth_ctrl_callback (struct urb *urb)
+{
+       struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+
+       dbg(__FUNCTION__);
+
+       if (!bluetooth) {
+               dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+               return;
+       }
+
+       if (urb->status) {
+               dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+               return;
+       }
 }
 
 
 static void bluetooth_read_bulk_callback (struct urb *urb)
 {
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-       struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
-       int i;
+       unsigned int count = urb->actual_length;
+       unsigned int i;
+       uint packet_size;
+
+#ifdef BTBUGGYHARDWARE
+       if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
+           && (data[2] == 0x00) && (data[3] == 0x00)) {
+               urb->actual_length = 0;
+               if (usb_submit_urb(urb))
+                       dbg(__FUNCTION__ " - failed resubmitting read urb");
+
+               return;
+       }
+#endif
 
        dbg(__FUNCTION__);
-       
+
        if (!bluetooth) {
                dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
                return;
@@ -471,25 +794,67 @@ static void bluetooth_read_bulk_callback (struct urb *urb)
                return;
        }
 
+       if (!count) {
+               dbg(__FUNCTION__ " - zero length read bulk");
+               return;
+       }
+
 #ifdef DEBUG
-       if (urb->actual_length) {
-               printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
-               for (i = 0; i < urb->actual_length; ++i) {
+       if (count) {
+               printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+               for (i = 0; i < count; ++i) {
                        printk ("%.2x ", data[i]);
                }
                printk ("\n");
        }
 #endif
+       /* We add  a packet type identifier to the beginning of each
+          HCI frame.  This makes the data in the tty look like a
+          serial USB devices.  Each HCI frame can be broken across
+          multiple URBs so we buffer them until we have a full hci
+          packet */
+       
+       if (!bluetooth->bulk_packet_pos) {
+               bluetooth->bulk_buffer[0] = ACL_PKT;
+               bluetooth->bulk_packet_pos++;
+       }
 
-       tty = bluetooth->tty;
-       if (urb->actual_length) {
-               for (i = 0; i < urb->actual_length ; ++i) {
-                        tty_insert_flip_char(tty, data[i], 0);
-               }
-               tty_flip_buffer_push(tty);
+       if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
+               err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE");
+               bluetooth->bulk_packet_pos = 0;
+               if (usb_submit_urb(urb))
+                       dbg(__FUNCTION__ " - failed resubmitting read urb");
+               return;
+       }
+
+       memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos],
+               urb->transfer_buffer, count);
+       bluetooth->bulk_packet_pos += count;
+       urb->actual_length = 0;
+
+       if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) {
+               packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]);
+       } else {
+               if (usb_submit_urb(urb))
+                       dbg(__FUNCTION__ " - failed resubmitting read urb");
+               return;
        }
 
-       /* Continue trying to always read  */
+       if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
+               err(__FUNCTION__ " - packet was too long");
+               bluetooth->bulk_packet_pos = 0;
+               if (usb_submit_urb(urb))
+                       dbg(__FUNCTION__ " - failed resubmitting read urb");
+               return;
+       }
+
+       if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
+               for (i = 0; i < bluetooth->bulk_packet_pos; ++i)
+                       tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
+               tty_flip_buffer_push(bluetooth->tty);
+               bluetooth->bulk_packet_pos = 0;
+       }       
+
        if (usb_submit_urb(urb))
                dbg(__FUNCTION__ " - failed resubmitting read urb");
 
@@ -502,7 +867,7 @@ static void bluetooth_write_bulk_callback (struct urb *urb)
        struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
 
        dbg(__FUNCTION__);
-       
+
        if (!bluetooth) {
                dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
                return;
@@ -513,9 +878,9 @@ static void bluetooth_write_bulk_callback (struct urb *urb)
                return;
        }
 
+       /* wake up our little function to let the tty layer know that something happened */
        queue_task(&bluetooth->tqueue, &tq_immediate);
        mark_bh(IMMEDIATE_BH);
-       
        return;
 }
 
@@ -526,11 +891,11 @@ static void bluetooth_softint(void *private)
        struct tty_struct *tty;
 
        dbg(__FUNCTION__);
-       
+
        if (!bluetooth) {
                return;
        }
-       
+
        tty = bluetooth->tty;
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
                dbg(__FUNCTION__ " - write wakeup call.");
@@ -549,28 +914,32 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
        struct usb_endpoint_descriptor *interrupt_in_endpoint[8];
        struct usb_endpoint_descriptor *bulk_in_endpoint[8];
        struct usb_endpoint_descriptor *bulk_out_endpoint[8];
+       int control_out_endpoint;
+
        int minor;
        int buffer_size;
        int i;
        int num_interrupt_in = 0;
        int num_bulk_in = 0;
        int num_bulk_out = 0;
-       
+
        /* see if this device has the proper class signature */
        if ((dev->descriptor.bDeviceClass != WIRELESS_CLASS_CODE) || 
            (dev->descriptor.bDeviceSubClass != RF_SUBCLASS_CODE) ||
            (dev->descriptor.bDeviceProtocol != BLUETOOTH_PROGRAMMING_PROTOCOL_CODE)) {
                dbg (__FUNCTION__ " - class signature %d, %d, %d did not match", 
-                       dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass,
-                       dev->descriptor.bDeviceProtocol);
+                    dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass,
+                    dev->descriptor.bDeviceProtocol);
                return NULL;
        }
 
-       /* find the endpoints that we need */
        interface = &dev->actconfig->interface[ifnum].altsetting[0];
+       control_out_endpoint = interface->bInterfaceNumber;
+
+       /* find the endpoints that we need */
        for (i = 0; i < interface->bNumEndpoints; ++i) {
                endpoint = &interface->endpoint[i];
-               
+
                if ((endpoint->bEndpointAddress & 0x80) &&
                    ((endpoint->bmAttributes & 3) == 0x02)) {
                        /* we found a bulk in endpoint */
@@ -586,7 +955,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
                        bulk_out_endpoint[num_bulk_out] = endpoint;
                        ++num_bulk_out;
                }
-               
+
                if ((endpoint->bEndpointAddress & 0x80) &&
                    ((endpoint->bmAttributes & 3) == 0x03)) {
                        /* we found a interrupt in endpoint */
@@ -595,7 +964,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
                        ++num_interrupt_in;
                }
        }
-       
+
        /* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */
        if ((num_bulk_in != 1) ||
            (num_bulk_out != 1) ||
@@ -603,7 +972,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
                dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound.");
                return NULL;
        }
-       
+
        MOD_INC_USE_COUNT;
        info("USB Bluetooth converter detected");
 
@@ -620,15 +989,29 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
                MOD_DEC_USE_COUNT;
                return NULL;
        }
-       
+
        memset(bluetooth, 0, sizeof(struct usb_bluetooth));
-       
+
        bluetooth->magic = USB_BLUETOOTH_MAGIC;
        bluetooth->dev = dev;
        bluetooth->minor = minor;
        bluetooth->tqueue.routine = bluetooth_softint;
        bluetooth->tqueue.data = bluetooth;
 
+       /* record the interface number for the control out */
+       bluetooth->control_out_bInterfaceNum = control_out_endpoint;
+       
+       /* create our control out urb pool */ 
+       for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+               struct urb  *urb = usb_alloc_urb(0);
+               if (urb == NULL) {
+                       err("No free urbs available");
+                       goto probe_error;
+               }
+               urb->transfer_buffer = NULL;
+               bluetooth->control_urb_pool[i] = urb;
+       }
+
        /* set up the endpoint information */
        endpoint = bulk_in_endpoint[0];
        bluetooth->read_urb = usb_alloc_urb (0);
@@ -646,20 +1029,20 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
                      bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth);
 
        endpoint = bulk_out_endpoint[0];
-       bluetooth->write_urb = usb_alloc_urb(0);
-       if (!bluetooth->write_urb) {
-               err("No free urbs available");
-               goto probe_error;
-       }
-       buffer_size = endpoint->wMaxPacketSize;
-       bluetooth->bulk_out_size = buffer_size;
-       bluetooth->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
-       if (!bluetooth->bulk_out_buffer) {
-               err("Couldn't allocate bulk_out_buffer");
-               goto probe_error;
+       bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
+       
+       /* create our write urb pool */ 
+       for (i = 0; i < NUM_BULK_URBS; ++i) {
+               struct urb  *urb = usb_alloc_urb(0);
+               if (urb == NULL) {
+                       err("No free urbs available");
+                       goto probe_error;
+               }
+               urb->transfer_buffer = NULL;
+               bluetooth->write_urb_pool[i] = urb;
        }
-       FILL_BULK_URB(bluetooth->write_urb, dev, usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
-                     bluetooth->bulk_out_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
+       
+       bluetooth->bulk_out_size = endpoint->wMaxPacketSize * 2;
 
        endpoint = interrupt_in_endpoint[0];
        bluetooth->interrupt_in_urb = usb_alloc_urb(0);
@@ -680,9 +1063,9 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
        /* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
        tty_register_devfs (&bluetooth_tty_driver, 0, minor);
        info("Bluetooth converter now attached to ttyBLUE%d (or usb/ttblue/%d for devfs)", minor, minor);
-       
+
        bluetooth_table[minor] = bluetooth;
-       
+
        return bluetooth; /* success */
 
 probe_error:
@@ -690,15 +1073,17 @@ probe_error:
                usb_free_urb (bluetooth->read_urb);
        if (bluetooth->bulk_in_buffer)
                kfree (bluetooth->bulk_in_buffer);
-       if (bluetooth->write_urb)
-               usb_free_urb (bluetooth->write_urb);
-       if (bluetooth->bulk_out_buffer)
-               kfree (bluetooth->bulk_out_buffer);
        if (bluetooth->interrupt_in_urb)
                usb_free_urb (bluetooth->interrupt_in_urb);
        if (bluetooth->interrupt_in_buffer)
                kfree (bluetooth->interrupt_in_buffer);
-               
+       for (i = 0; i < NUM_BULK_URBS; ++i)
+               if (bluetooth->write_urb_pool[i])
+                       usb_free_urb (bluetooth->write_urb_pool[i]);
+       for (i = 0; i < NUM_CONTROL_URBS; ++i) 
+               if (bluetooth->control_urb_pool[i])
+                       usb_free_urb (bluetooth->control_urb_pool[i]);
+
        bluetooth_table[minor] = NULL;
 
        /* free up any memory that we allocated */
@@ -711,6 +1096,7 @@ probe_error:
 static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
 {
        struct usb_bluetooth *bluetooth = (struct usb_bluetooth *) ptr;
+       int i;
 
        if (bluetooth) {
                bluetooth->active = 0;
@@ -721,14 +1107,7 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
                }
                if (bluetooth->bulk_in_buffer)
                        kfree (bluetooth->bulk_in_buffer);
-                       
-               if (bluetooth->write_urb) {
-                       usb_unlink_urb (bluetooth->write_urb);
-                       usb_free_urb (bluetooth->write_urb);
-               }
-               if (bluetooth->bulk_out_buffer)
-                       kfree (bluetooth->bulk_out_buffer);
-               
+
                if (bluetooth->interrupt_in_urb) {
                        usb_unlink_urb (bluetooth->interrupt_in_urb);
                        usb_free_urb (bluetooth->interrupt_in_urb);
@@ -737,6 +1116,26 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
                        kfree (bluetooth->interrupt_in_buffer);
 
                tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor);
+
+               if (bluetooth->tty)
+                       tty_hangup(bluetooth->tty);
+
+               for (i = 0; i < NUM_BULK_URBS; ++i) {
+                       if (bluetooth->write_urb_pool[i]) {
+                               usb_unlink_urb (bluetooth->write_urb_pool[i]);
+                               if (bluetooth->write_urb_pool[i]->transfer_buffer)
+                                       kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
+                               usb_free_urb (bluetooth->write_urb_pool[i]);
+                       }
+               }
+               for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+                       if (bluetooth->control_urb_pool[i]) {
+                               usb_unlink_urb (bluetooth->control_urb_pool[i]);
+                               if (bluetooth->control_urb_pool[i]->transfer_buffer)
+                                       kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
+                               usb_free_urb (bluetooth->control_urb_pool[i]);
+                       }
+               }
                
                info("Bluetooth converter now disconnected from ttyBLUE%d", bluetooth->minor);
 
@@ -748,7 +1147,7 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
        } else {
                info("device disconnected");
        }
-       
+
        MOD_DEC_USE_COUNT;
 }
 
@@ -763,12 +1162,12 @@ static struct tty_driver bluetooth_tty_driver = {
        type:                   TTY_DRIVER_TYPE_SERIAL,
        subtype:                SERIAL_TYPE_NORMAL,
        flags:                  TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-       
+
        refcount:               &bluetooth_refcount,
        table:                  bluetooth_tty,
        termios:                bluetooth_termios,
        termios_locked:         bluetooth_termios_locked,
-       
+
        open:                   bluetooth_open,
        close:                  bluetooth_close,
        write:                  bluetooth_write,
@@ -808,7 +1207,7 @@ int usb_bluetooth_init(void)
                err("usb_register failed for the USB bluetooth driver. Error number %d", result);
                return -1;
        }
-       
+
        return 0;
 }
 
index 5e7a5a23be63b3f19058763fd90df58dda94680e..aee6b420e0fbc424e1a14f7aba18e4d43598c0e7 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.2 2000/07/19 17:21:39 groovyjava Exp $
+ * $Id: protocol.c,v 1.4 2000/08/01 22:01:19 mdharm Exp $
  *
  * Current development and maintainance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
 #include "scsiglue.h"
 #include "transport.h"
 
+/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+/* Fix-up the return data from an INQUIRY command to show 
+ * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+ */
+void fix_inquiry_data(Scsi_Cmnd *srb)
+{
+       unsigned char *data_ptr;
+
+       /* verify that it's an INQUIRY command */
+       if (srb->cmnd[0] != INQUIRY)
+               return;
+
+       US_DEBUGP("Fixing INQUIRY data to show SCSI rev 2\n");
+
+       /* find the location of the data */
+       if (srb->use_sg) {
+               struct scatterlist *sg;
+
+               sg = (struct scatterlist *) srb->request_buffer;
+               data_ptr = (unsigned char *) sg[0].address;
+       } else
+               data_ptr = (unsigned char *)srb->request_buffer;
+
+       /* Change the SCSI revision number */
+       data_ptr[2] |= 0x2;
+}
+
 /***********************************************************************
  * Protocol routines
  ***********************************************************************/
 
+void usb_stor_qic157_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+       /* Pad the ATAPI command with zeros 
+        * NOTE: This only works because a Scsi_Cmnd struct field contains
+        * a unsigned char cmnd[12], so we know we have storage available
+        */
+       for (; srb->cmd_len<12; srb->cmd_len++)
+               srb->cmnd[srb->cmd_len] = 0;
+
+       /* set command length to 12 bytes */
+       srb->cmd_len = 12;
+
+       /* send the command to the transport layer */
+       usb_stor_invoke_transport(srb, us);
+
+       /* fix the INQUIRY data if necessary */
+       fix_inquiry_data(srb);
+}
+
 void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
 {
        int old_cmnd = 0;
@@ -65,7 +114,6 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
         */
 
        /* Pad the ATAPI command with zeros */
-
        for (; srb->cmd_len<12; srb->cmd_len++)
                srb->cmnd[srb->cmd_len] = 0;
 
@@ -125,12 +173,8 @@ void usb_stor_ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
        if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
                usb_stor_scsiSense10to6(srb);
 
-       /* Fix-up the return data from an INQUIRY command to show 
-        * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
-        */
-       if (srb->cmnd[0] == INQUIRY) {
-               ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
-       }
+       /* fix the INQUIRY data if necessary */
+       fix_inquiry_data(srb);
 }
 
 
@@ -224,12 +268,8 @@ void usb_stor_ufi_command(Scsi_Cmnd *srb, struct us_data *us)
        if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
                usb_stor_scsiSense10to6(srb);
 
-       /* Fix-up the return data from an INQUIRY command to show 
-        * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
-        */
-       if (srb->cmnd[0] == INQUIRY) {
-               ((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
-       }
+       /* Fix the data for an INQUIRY, if necessary */
+       fix_inquiry_data(srb);
 }
 
 void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
@@ -300,10 +340,7 @@ void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
        /* send the command to the transport layer */
        usb_stor_invoke_transport(srb, us);
 
-       /* fix the results of an INQUIRY */
-       if (srb->cmnd[0] == INQUIRY) {
-               US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
-               ((unsigned char*)us->srb->request_buffer)[2] |= 2;
-       }
+       /* fix the INQUIRY data if necessary */
+       fix_inquiry_data(srb);
 }
 
index 1a343af415336e20fb032c8a43736e0a132a8e5d..239d37983caa86883a39dcaab1ba675a5b5a23b9 100644 (file)
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Protocol Functions Header File
  *
- * $Id: protocol.h,v 1.1 2000/06/27 01:25:28 mdharm Exp $
+ * $Id: protocol.h,v 1.2 2000/08/01 22:01:19 mdharm Exp $
  *
  * Current development and maintainance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -57,6 +57,7 @@
 #define US_SC_MAX      US_SC_SCSI
 
 extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*);
+extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*);
 extern void usb_stor_ufi_command(Scsi_Cmnd*, struct us_data*);
 extern void usb_stor_transparent_scsi_command(Scsi_Cmnd*, struct us_data*);
 
index 25328669b793b2693646a18d00e41d20b209ba39..7517d63bce5285ca05451c53bbd68840bedc7601 100644 (file)
@@ -1,13 +1,14 @@
 /* Driver for USB Mass Storage compliant devices
  * SCSI layer glue code
  *
- * $Id: scsiglue.c,v 1.6 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $
  *
  * Current development and maintainance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
  *
  * Developed with the assistance of:
  *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
  *
  * Initial work by:
  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
index 27571296124379db9527f2eb39093234090911a8..6bf9f147778823f1337de6fb096c442c9c7c6838 100644 (file)
@@ -44,7 +44,7 @@ extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
 extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
        unsigned int len, unsigned int *act_len);
 
-#define short_pack(b1,b2) ( ((u16)(b1)) | ( ((u16)(b2))<<8 ) )
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
 #define LSB_of(s) ((s)&0xFF)
 #define MSB_of(s) ((s)>>8)
 
@@ -132,7 +132,7 @@ static int sddr09_send_control(struct us_data *us,
 static int sddr09_raw_bulk(struct us_data *us, 
                int direction,
                unsigned char *data,
-               unsigned short len) {
+               unsigned int len) {
 
        int result;
        int act_len;
@@ -196,64 +196,38 @@ static int sddr09_raw_bulk(struct us_data *us,
  */
 
 static int sddr09_bulk_transport(struct us_data *us,
-                         unsigned char *command,
-                         unsigned short command_len,
                          int direction,
                          unsigned char *data,
-                         unsigned short len,
+                         unsigned int len,
                          int use_sg) {
 
        int result = USB_STOR_TRANSPORT_GOOD;
        int transferred = 0;
-       unsigned char execute[8] = {
-               0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-       };
        int i;
        struct scatterlist *sg;
        char string[64];
-/*
-       if (command_len != 0) {
-
-               // Fix up the command's data length
 
-               command[6] = len&0xFF;
-               command[7] = (len>>8)&0xFF;
-
-               result = sddr09_send_control(us, 
-                                         execute,
-                                         command,
-                                         command_len);
-
-               if (result != USB_STOR_TRANSPORT_GOOD)
-                       return result;
-       }
-*/
        if (len==0)
                return USB_STOR_TRANSPORT_GOOD;
 
 
-       /* transfer the data payload for the command, if there is any */
-
-
-       if (command_len != 0)
-               direction = (command[0]&0x80) ? SCSI_DATA_READ :
-                       SCSI_DATA_WRITE;
+       /* transfer the data */
 
        if (direction == SCSI_DATA_WRITE) {
 
                /* Debug-print the first 48 bytes of the write transfer */
 
                if (!use_sg) {
-                       string[0] = 0;
+                       strcpy(string, "wr: ");
                        for (i=0; i<len && i<48; i++) {
                                sprintf(string+strlen(string), "%02X ",
                                  data[i]);
                                if ((i%16)==15) {
                                        US_DEBUGP("%s\n", string);
-                                       string[0] = 0;
+                                       strcpy(string, "wr: ");
                                }
                        }
-                       if (string[0]!=0)
+                       if ((i%16)!=0)
                                US_DEBUGP("%s\n", string);
                }
        }
@@ -278,6 +252,25 @@ static int sddr09_bulk_transport(struct us_data *us,
                }
        }
 
+       if (direction == SCSI_DATA_READ) {
+
+               /* Debug-print the first 48 bytes of the read transfer */
+
+               if (!use_sg) {
+                       strcpy(string, "rd: ");
+                       for (i=0; i<len && i<48; i++) {
+                               sprintf(string+strlen(string), "%02X ",
+                                 data[i]);
+                               if ((i%16)==15) {
+                                       US_DEBUGP("%s\n", string);
+                                       strcpy(string, "rd: ");
+                               }
+                       }
+                       if ((i%16)!=0)
+                               US_DEBUGP("%s\n", string);
+               }
+       }
+
        return result;
 }
 
@@ -289,45 +282,142 @@ int sddr09_read_data(struct us_data *us,
 
        int result;
        unsigned char command[12] = {
-               0xe8, 0x20, MSB_of(address>>16),
-               LSB_of(address>>16), MSB_of(address&0xFFFF),
-               LSB_of(address&0xFFFF), 0, 0, 0, 0,
-               MSB_of(sectors), LSB_of(sectors)
+               0xe8, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        };
+       struct sddr09_card_info *info = (struct sddr09_card_info *)us->extra;
+       unsigned int lba;
+       unsigned int pba;
+       unsigned short page;
+       unsigned short pages;
+       unsigned char *buffer = NULL;
+       unsigned char *ptr;
+       struct scatterlist *sg = NULL;
+       int i;
+       int len;
+       int transferred;
 
-       result = sddr09_send_control(us,
-               usb_sndctrlpipe(us->pusb_dev,0),
-               0,
-               0x41,
-               0,
-               0,
-               command,
-               12);
+       // If we're using scatter-gather, we have to create a new
+       // buffer to read all of the data in first, since a
+       // scatter-gather buffer could in theory start in the middle
+       // of a page, which would be bad. A developer who wants a
+       // challenge might want to write a limited-buffer
+       // version of this code.
+
+       len = sectors*info->pagesize;
+
+       if (use_sg) {
+               sg = (struct scatterlist *)content;
+               buffer = kmalloc(len, GFP_KERNEL);
+               if (buffer == NULL)
+                       return USB_STOR_TRANSPORT_ERROR;
+               ptr = buffer;
+       } else
+               ptr = content;
+
+       // Figure out the initial LBA and page
+
+       pba = (address/info->pagesize)>>4;
+       lba = info->pba_to_lba[pba];
+       page = (address/info->pagesize)&0x0F;
+
+       // This could be made much more efficient by checking for
+       // contiguous LBA's. Another exercise left to the student.
+
+       while (sectors>0) {
+
+               pba = info->lba_to_pba[lba];
+
+               // Read as many sectors as possible in this block
+
+               pages = 0x10-page;
+               if (pages > sectors)
+                       pages = sectors;
+
+               US_DEBUGP("Read %01X pages, from PBA %04X"
+                       " (LBA %04X) page %01X\n",
+                       pages, pba, lba, page);
+
+               address = ((pba<<4)+page)*info->pagesize;
+
+               // Unlike in the documentation, the address is in
+               // words of 2 bytes.
+
+               command[2] = MSB_of(address>>17);
+               command[3] = LSB_of(address>>17); 
+               command[4] = MSB_of((address>>1)&0xFFFF);
+               command[5] = LSB_of((address>>1)&0xFFFF); 
+
+               command[10] = MSB_of(pages);
+               command[11] = LSB_of(pages);
+
+               result = sddr09_send_control(us,
+                       usb_sndctrlpipe(us->pusb_dev,0),
+                       0,
+                       0x41,
+                       0,
+                       0,
+                       command,
+                       12);
                
-       if (result != USB_STOR_TRANSPORT_GOOD)
-               return result;
+               US_DEBUGP("Result for send_control in read_data %d\n",
+                       result);
+               
+               if (result != USB_STOR_TRANSPORT_GOOD) {
+                       if (use_sg)
+                               kfree(buffer);
+                       return result;
+               }
 
-       result = sddr09_bulk_transport(us,
-               NULL, 0, SCSI_DATA_READ, content,
-               sectors*512, use_sg);
+               result = sddr09_bulk_transport(us,
+                       SCSI_DATA_READ, ptr,
+                       pages*info->pagesize, 0);
 
-       return result;
+               if (result != USB_STOR_TRANSPORT_GOOD) {
+                       if (use_sg)
+                               kfree(buffer);
+                       return result;
+               }
+
+               page = 0;
+               lba++;
+               sectors -= pages;
+               ptr += pages*info->pagesize;
+       }
+
+       if (use_sg) {
+               transferred = 0;
+               for (i=0; i<use_sg && transferred<len; i++) {
+                       memcpy(sg[i].address, buffer+transferred,
+                               len-transferred > sg[i].length ?
+                                       sg[i].length : len-transferred);
+                       transferred += sg[i].length;
+               }
+               kfree(buffer);
+       }
+
+       return USB_STOR_TRANSPORT_GOOD;
 }
 
 int sddr09_read_control(struct us_data *us,
                unsigned long address,
-               unsigned short sectors,
+               unsigned short blocks,
                unsigned char *content,
                int use_sg) {
 
+       // Unlike in the documentation, the last two bytes are the
+       // number of blocks, not sectors.
+
        int result;
        unsigned char command[12] = {
                0xe8, 0x21, MSB_of(address>>16),
                LSB_of(address>>16), MSB_of(address&0xFFFF),
                LSB_of(address&0xFFFF), 0, 0, 0, 0,
-               MSB_of(sectors), LSB_of(sectors)
+               MSB_of(blocks), LSB_of(blocks)
        };
 
+       US_DEBUGP("Read control address %08X blocks %04X\n",
+               address, blocks);
+
        result = sddr09_send_control(us,
                usb_sndctrlpipe(us->pusb_dev,0),
                0,
@@ -336,13 +426,19 @@ int sddr09_read_control(struct us_data *us,
                0,
                command,
                12);
+
+       US_DEBUGP("Result for send_control in read_control %d\n",
+               result);
                
        if (result != USB_STOR_TRANSPORT_GOOD)
                return result;
 
        result = sddr09_bulk_transport(us,
-               NULL, 0, SCSI_DATA_READ, content,
-               sectors*64, use_sg);
+               SCSI_DATA_READ, content,
+               blocks*0x40, use_sg);
+
+       US_DEBUGP("Result for bulk read in read_control %d\n",
+               result);
 
        return result;
 }
@@ -373,7 +469,7 @@ int sddr09_read_deviceID(struct us_data *us,
                return result;
 
        result = sddr09_bulk_transport(us,
-               NULL, 0, SCSI_DATA_READ, content,
+               SCSI_DATA_READ, content,
                64, 0);
 
        *manufacturerID = content[0];
@@ -389,7 +485,6 @@ int sddr09_read_status(struct us_data *us,
        unsigned char command[12] = {
                0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        };
-       unsigned char content[2];
 
        result = sddr09_send_control(us,
                usb_sndctrlpipe(us->pusb_dev,0),
@@ -404,7 +499,7 @@ int sddr09_read_status(struct us_data *us,
                return result;
 
        result = sddr09_bulk_transport(us,
-               NULL, 0, SCSI_DATA_READ, status,
+               SCSI_DATA_READ, status,
                1, 0);
 
        return result;
@@ -429,6 +524,154 @@ int sddr09_reset(struct us_data *us) {
        return result;
 }
 
+unsigned long sddr09_get_capacity(struct us_data *us,
+               unsigned int *pagesize) {
+
+       unsigned char manufacturerID;
+       unsigned char deviceID;
+       int result;
+
+       US_DEBUGP("Reading capacity...\n");
+
+       result = sddr09_read_deviceID(us,
+               &manufacturerID,
+               &deviceID);
+
+       US_DEBUGP("Result of read_deviceID is %d\n",
+               result);
+
+       if (result != USB_STOR_TRANSPORT_GOOD)
+               return 0;
+
+       US_DEBUGP("Device ID = %02X\n", deviceID);
+       US_DEBUGP("Manuf  ID = %02X\n", manufacturerID);
+
+       *pagesize = 512;
+
+       switch (deviceID) {
+
+       case 0x6e: // 1MB
+       case 0xe8:
+       case 0xec:
+               *pagesize = 256;
+               return 0x00100000;
+
+       case 0x5d: // 2MB
+       case 0xea: 
+       case 0x64:
+               if (deviceID!=0x5D)
+                       *pagesize = 256;
+               return 0x00200000;
+
+       case 0xe3: // 4MB
+       case 0xe5:
+       case 0x6b:
+       case 0xd5:
+               return 0x00400000;
+
+       case 0xe6: // 8MB
+       case 0xd6:
+               return 0x00800000;
+
+       case 0x73: // 16MB
+               return 0x01000000;
+
+       case 0x75: // 32MB
+               return 0x02000000;
+
+       default: // unknown
+               return 0;
+
+       }
+}
+
+int sddr09_read_map(struct us_data *us) {
+
+       unsigned char *control;
+       struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
+       int numblocks;
+       int i;
+       unsigned char *ptr;
+       unsigned short lba;
+       unsigned char parity;
+       unsigned char fast_parity[16] = {
+               0, 1, 1, 0, 1, 0, 0, 1,
+               1, 0, 0, 1, 0, 1, 1, 0
+       };
+       int result;
+
+       if (!info->capacity)
+               return -1;
+
+       /* read 64 (2^6) bytes for every block (8192 (2^13) bytes)
+                of capacity:
+          64*(capacity/8192) = capacity*(2^6)*(2^-13) =
+          capacity*2^(6-13) = capacity*(2^-7)
+        */
+
+       control = kmalloc(info->capacity>>7, GFP_KERNEL);
+
+
+       numblocks = info->capacity>>13;
+
+       if ( (result = sddr09_read_control(us, 0, numblocks,
+                       control, 0)) !=
+                       USB_STOR_TRANSPORT_GOOD) {
+               kfree(control);
+               return -1;
+       }
+
+       
+
+       if (info->lba_to_pba)
+               kfree(info->lba_to_pba);
+       if (info->pba_to_lba)
+               kfree(info->pba_to_lba);
+       info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+       info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_KERNEL);
+       memset(info->lba_to_pba, 0, numblocks*sizeof(int));
+       memset(info->pba_to_lba, 0, numblocks*sizeof(int));
+
+       for (i=0; i<numblocks; i++) {
+               ptr = control+64*i;
+               if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF ||
+                   ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF)
+                       continue;
+               if ((ptr[6]>>4)!=0x01)
+                       continue;
+               
+               /* ensure even parity */
+
+               lba = short_pack(ptr[7], ptr[6]);
+               parity = 1; // the parity of 0x1000
+               parity ^= fast_parity[lba & 0x000F];
+               parity ^= fast_parity[(lba>>4) & 0x000F];
+               parity ^= fast_parity[(lba>>8) & 0x000F];
+
+               if (parity) { /* bad parity bit */
+                       US_DEBUGP("Bad parity in LBA for block %04X\n", i);
+                       continue;
+               }
+
+               lba = (lba&0x07FF)>>1;
+
+               if (lba>=numblocks) {
+                       US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i);
+                       continue;
+               }
+
+               if (i<0x10)
+                       US_DEBUGP("LBA %04X <-> PBA %04X\n",
+                               lba, i);
+
+               info->pba_to_lba[i] = lba;
+               info->lba_to_pba[lba] = i;
+       }
+
+       kfree(control);
+       return 0;
+}
+
 /*
 static int init_sddr09(struct us_data *us) {
 
@@ -477,15 +720,24 @@ static int init_sddr09(struct us_data *us) {
 }
 */
 
+void sddr09_card_info_destructor(void *extra) {
+       struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
+
+       if (!extra)
+               return;
+
+       if (info->lba_to_pba)
+               kfree(info->lba_to_pba);
+       if (info->pba_to_lba)
+               kfree(info->pba_to_lba);
+}
+
 /*
  * Transport for the Sandisk SDDR-09
  */
 int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
        int result;
-       unsigned char send_scsi_command[8] = {
-               0x41, 0, 0, 0, 0, 0, 0, 0
-       };
        int i;
        char string[64];
        unsigned char inquiry_response[36] = {
@@ -495,9 +747,16 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
                'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
                ' ', ' ', ' ', ' '
        };
-       unsigned char deviceID;
-       unsigned char manufacturerID;
+       unsigned char mode_page_01[12] = {
+               0x01, 0x0a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+       };
        unsigned char *ptr;
+       unsigned long capacity;
+       unsigned int lba;
+       unsigned int pba;
+       unsigned int page;
+       unsigned short pages;
+       struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra);
 
 /*
        if (us->flags & US_FL_NEED_INIT) {
@@ -507,85 +766,116 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
        }
 */
 
+       if (!us->extra) {
+               us->extra = kmalloc(
+                       sizeof(struct sddr09_card_info), GFP_KERNEL);
+               memset(us->extra, 0, sizeof(struct sddr09_card_info));
+               us->extra_destructor = sddr09_card_info_destructor;
+       }
+
        ptr = (unsigned char *)srb->request_buffer;
 
        /* Dummy up a response for INQUIRY since SDDR09 doesn't
           respond to INQUIRY commands */
 
        if (srb->cmnd[0] == INQUIRY) {
-               memcpy(srb->request_buffer, inquiry_response, 36);
+               memcpy(ptr, inquiry_response, 36);
                return USB_STOR_TRANSPORT_GOOD;
        }
 
        if (srb->cmnd[0] == READ_CAPACITY) {
 
-               US_DEBUGP("Reading capacity...\n");
+               capacity = sddr09_get_capacity(us, &info->pagesize);
+               info->capacity = capacity;
 
-               result = sddr09_read_deviceID(us,
-                       &manufacturerID,
-                       &deviceID);
+               // Last page in the card
 
-               US_DEBUGP("Result of read_deviceID is %d\n",
-                       result);
+               capacity /= info->pagesize;
+               capacity--;
 
-               if (result != USB_STOR_TRANSPORT_GOOD)
-                       return result;
+               ptr[0] = MSB_of(capacity>>16);
+               ptr[1] = LSB_of(capacity>>16);
+               ptr[2] = MSB_of(capacity&0xFFFF);
+               ptr[3] = LSB_of(capacity&0xFFFF);
 
-               US_DEBUGP("Device ID = %02X\n", deviceID);
-               US_DEBUGP("Manuf  ID = %02X\n", manufacturerID);
-
-               ptr[0] = 0;
-               ptr[1] = 0;
-               ptr[2] = 0;
-               ptr[3] = 0;
-
-               switch (deviceID) {
-
-               case 0x6e: // 1MB
-               case 0xe8:
-               case 0xec:
-                       ptr[4] = 0;
-                       ptr[5] = 0x10;
-                       break;
-
-               case 0xea: // 2MB
-               case 0x64:
-               case 0x5d:
-                       ptr[4] = 0;
-                       ptr[5] = 0x20;
-                       break;
-
-               case 0xe3: // 4MB
-               case 0xe5:
-               case 0x6b:
-               case 0xd5:
-                       ptr[4] = 0;
-                       ptr[5] = 0x40;
-                       break;
-
-               case 0xe6: // 8MB
-               case 0xd6:
-                       ptr[4] = 0;
-                       ptr[5] = 0x80;
-                       break;
-
-               case 0x75: // 32MB
-                       ptr[4] = 0x02;
-                       ptr[5] = 0;
-                       break;
-
-               default: // unknown
-                       ptr[4] = 0;
-                       ptr[5] = 0;
+               // The page size
 
-               }
+               ptr[4] = MSB_of(info->pagesize>>16);
+               ptr[5] = LSB_of(info->pagesize>>16);
+               ptr[6] = MSB_of(info->pagesize&0xFFFF);
+               ptr[7] = LSB_of(info->pagesize&0xFFFF);
 
-               ptr[6] = 0;
-               ptr[7] = 0;
+               sddr09_read_map(us);
                
                return USB_STOR_TRANSPORT_GOOD;
        }
 
+       if (srb->cmnd[0] == MODE_SENSE) {
+       
+                       // Read-write error recovery page: there needs to
+                       // be a check for write-protect here
+
+               if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
+                       if (ptr==NULL || srb->request_bufflen<12)
+                               return USB_STOR_TRANSPORT_ERROR;
+                       memcpy(ptr, mode_page_01, 12);
+                       return USB_STOR_TRANSPORT_GOOD;
+               }
+
+               // FIXME: sense buffer?
+
+               return USB_STOR_TRANSPORT_ERROR;
+       }
+
+       if (srb->cmnd[0] == READ_10) {
+
+               page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+               page <<= 16;
+               page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+               pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+               // convert page to block and page-within-block
+
+               lba = page>>4;
+               page = page&0x0F;
+
+               // locate physical block corresponding to logical block
+
+               if (lba>=(info->capacity>>13)) {
+
+                       // FIXME: sense buffer?
+
+                       return USB_STOR_TRANSPORT_ERROR;
+               }
+
+               pba = info->lba_to_pba[lba];
+
+               // if pba is 0, either it's really 0, in which case
+               // the pba-to-lba map for pba 0 will be the lba,
+               // or that lba doesn't exist.
+
+               if (pba==0 && info->pba_to_lba[0] != lba) {
+
+                       // FIXME: sense buffer?
+
+                       return USB_STOR_TRANSPORT_ERROR;
+               }
+
+               US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
+                       " pages %d\n",
+                       pba, lba, page, pages);
+
+               return sddr09_read_data(us,
+                       ((pba<<4)+page)*info->pagesize, pages,
+                       ptr, srb->use_sg);
+       }
+
+       // Pass TEST_UNIT_READY and REQUEST_SENSE through
+
+       if (srb->cmnd[0] != TEST_UNIT_READY &&
+           srb->cmnd[0] != REQUEST_SENSE)
+               return USB_STOR_TRANSPORT_ERROR; // FIXME: sense buffer?
+
        for (; srb->cmd_len<12; srb->cmd_len++)
                srb->cmnd[srb->cmd_len] = 0;
 
@@ -622,7 +912,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
                        srb->request_bufflen);
 
                result = sddr09_bulk_transport(us,
-                       NULL, 0, srb->sc_data_direction,
+                       srb->sc_data_direction,
                        srb->request_buffer, 
                        srb->request_bufflen, srb->use_sg);
 
index 76a7495286333f83fca9e6c83014e78a3af0afef..ecd9b761129185b8b9b1dbef6887dacde61d2f5e 100644 (file)
 
 extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us);
 
+struct sddr09_card_info {
+       unsigned long           capacity; /* Size of card in bytes */
+       int                     pagesize;  /* Size of page in bytes */
+       int                     *lba_to_pba; /* logical to physical map */
+       int                     *pba_to_lba; /* physical to logical map */
+};
+
 #endif
index 69dfcfde88f8ceabe2e37a0f9eba106f816618ac..a0fb2407cafd0fd1ef8b3748e325f48ea6f06598 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: transport.c,v 1.4 2000/07/25 23:04:47 mdharm Exp $
+ * $Id: transport.c,v 1.5 2000/07/28 22:40:20 mdharm Exp $
  *
  * Current development and maintainance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -717,6 +717,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
        return 0;
 }
 
+int usb_stor_Bulk_reset(struct us_data *us);
+
 int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
        struct bulk_cb_wrap bcb;
@@ -820,7 +822,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
        }
        
        /* check bulk status */
-       US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+       US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
                  le32_to_cpu(bcs.Signature), bcs.Tag, 
                  bcs.Residue, bcs.Status);
        if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
@@ -842,6 +844,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
                
        case US_BULK_STAT_PHASE:
                /* phase error */
+               usb_stor_Bulk_reset(us);
                return USB_STOR_TRANSPORT_ERROR;
        }
        
@@ -883,11 +886,15 @@ int usb_stor_CB_reset(struct us_data *us)
        return 0;
 }
 
-/* FIXME: Does this work? */
+/* This issues a Bulk-only Reset to the device in question, including
+ * clearing the subsequent endpoint halts that may occur.
+ */
 int usb_stor_Bulk_reset(struct us_data *us)
 {
        int result;
 
+       US_DEBUGP("Bulk reset requested\n");
+
        result = usb_control_msg(us->pusb_dev, 
                                 usb_sndctrlpipe(us->pusb_dev,0), 
                                 US_BULK_RESET_REQUEST, 
index c82d7e914d32f0738533255d374cfb36a2dc00da..fc70bc72a1737709128d0b0730046c4986f2dc47 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.14 2000/07/27 14:42:43 groovyjava Exp $
+ * $Id: usb.c,v 1.16 2000/08/01 22:01:19 mdharm Exp $
  *
  * Current development and maintainance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -685,13 +685,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
 
                case US_SC_QIC:
                        ss->protocol_name = "QIC-157";
-                       US_DEBUGP("Sorry, device not supported.  Please\n");
-                       US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
-                       US_DEBUGP("if you see this message.\n");
-                       up(&us_list_semaphore);
-                       kfree(ss->current_urb);
-                       kfree(ss);
-                       return NULL;
+                       ss->proto_handler = usb_stor_qic157_command;
                        break;
 
                case US_SC_8070:
@@ -862,6 +856,16 @@ void __exit usb_stor_exit(void)
                 /* Now that scsi_unregister_module is done with the host
                  * template, we can free the us_data structure (the host
                  * template is inline in this structure). */
+
+               /* If there's extra data in the us_data structure then
+                * free that first */
+
+               if (us_list->extra) {
+                       if (us_list->extra_destructor)
+                               (*us_list->extra_destructor)(
+                                       us_list->extra);
+                       kfree(us_list->extra);
+               }
                 kfree (us_list);
 
                /* advance the list pointer */
index 8c7008fa920450205041508b2badec836e114dd4..b376d39eebc8e114cb84c0d734f148d616d5858a 100644 (file)
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Main Header File
  *
- * $Id: usb.h,v 1.3 2000/07/20 01:14:56 mdharm Exp $
+ * $Id: usb.h,v 1.4 2000/07/28 20:14:49 groovyjava Exp $
  *
  * Current development and maintainance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -176,6 +176,8 @@ struct us_data {
        /* mutual exclusion structures */
        struct semaphore        notify;          /* thread begin/end        */
        struct semaphore        queue_exclusion; /* to protect data structs */
+       void                    *extra;          /* Any extra data          */
+       void (*extra_destructor)(void *);        /* extra data destructor   */
 };
 
 /* The list of structures and the protective lock for them */
index e82fa78a08aaac8f8e623324938b37b955b3bf5e..bd721cba20fe301ca7e9686265df82493a36b23d 100644 (file)
@@ -1,10 +1,10 @@
 /* 
  * Universal Host Controller Interface driver for USB (take II).
  *
- * (c) 1999 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
- *          Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
- *          Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
- *          Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
+ * (c) 1999-2000 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ *               Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+ *               Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+ *               Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
  *          
  * HW-initalization based on material of
  *
@@ -12,7 +12,7 @@
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Randy Dunlap
  *
- * $Id: usb-uhci.c,v 1.232 2000/06/11 13:18:30 acher Exp $
+ * $Id: usb-uhci.c,v 1.236 2000/08/02 20:28:28 acher Exp $
  */
 
 #include <linux/config.h>
@@ -48,7 +48,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.232 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.236 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -791,7 +791,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
        char *data;
        unsigned int pipe = urb->pipe;
        int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-       int info, len;
+       int info, len, last;
        int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
        urb_priv_t *upriv, *bpriv;
 
@@ -888,13 +888,15 @@ _static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
                data += pktsze;
                len -= pktsze;
 
-               if (!len)
+               last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || (urb->transfer_flags & USB_DISABLE_SPD)));
+
+               if (last)
                        td->hw.td.status |= TD_CTRL_IOC;        // last one generates INT
 
                insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
                usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
 
-       } while (len > 0);
+       } while (!last);
 
        list_add (&qh->desc_list, &urb_priv->desc_list);
 
@@ -1036,11 +1038,18 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
 
        spin_lock_irqsave (&s->urb_list_lock, flags);
 
+       if (!in_interrupt())            // shouldn't be called from interrupt at all...
+               spin_lock(&urb->lock); 
+       
        if (urb->status == -EINPROGRESS) {
                // URB probably still in work
                dequeue_urb (s, urb);
                uhci_switch_timer_int(s);
                s->unlink_urb_done=1;
+
+               if (!in_interrupt())    
+                       spin_unlock(&urb->lock); 
+
                spin_unlock_irqrestore (&s->urb_list_lock, flags);              
                
                urb->status = -ENOENT;  // mark urb as killed           
@@ -1076,10 +1085,13 @@ _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
                        urb->complete ((struct urb *) urb);
                }
                usb_dec_dev_use (urb->dev);
-               return 0;
        }
-       else
+       else {
+               if (!in_interrupt())    
+                       spin_unlock(&urb->lock); 
                spin_unlock_irqrestore (&s->urb_list_lock, flags);
+       }
+
        return 0;
 }
 /*-------------------------------------------------------------------*/
@@ -1198,9 +1210,10 @@ _static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
                        break;
                }
                ((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
+               return -EINPROGRESS;  // completion will follow
        }               
 
-       return -EINPROGRESS;
+       return 0;    // URB already dead
 }
 /*-------------------------------------------------------------------*/
 _static int uhci_unlink_urb (urb_t *urb)
@@ -1222,9 +1235,20 @@ _static int uhci_unlink_urb (urb_t *urb)
        if (urb->transfer_flags & USB_ASYNC_UNLINK) {
                int ret;
 
-               spin_lock_irqsave (&s->urb_list_lock, flags);
+                       spin_lock_irqsave (&s->urb_list_lock, flags);
+
+               // The URB needs to be locked if called outside completion context
+
+               if (!in_interrupt())
+                       spin_lock(&urb->lock);
+
                ret = uhci_unlink_urb_async(s, urb);
-               spin_unlock_irqrestore (&s->urb_list_lock, flags);
+
+               if (!in_interrupt())
+                       spin_unlock(&urb->lock);
+
+               spin_unlock_irqrestore (&s->urb_list_lock, flags);      
+
                return ret;
        }
        else
@@ -1427,10 +1451,10 @@ _static int uhci_submit_iso_urb (urb_t *urb)
 
 #ifdef ISO_SANITY_CHECK
                if(urb->iso_frame_desc[n].length > maxsze) {
+
                        err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
                        tdm[n] = 0;
-                       ret=-EINVAL;
-                       goto inval;
+                       ret=-EINVAL;            
                }
                else
 #endif
@@ -2177,10 +2201,9 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
                        usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
                }
 
-               if (status != 0) {              // if any error occured stop processing of further TDs
+               if (status && (status != -EPIPE)) {     // if any error occurred stop processing of further TDs
                        // only set ret if status returned an error
-                       if (status != -EPIPE) 
-                               uhci_show_td (desc);
+  is_error:
                        ret = status;
                        urb->error_count++;
                        break;
@@ -2212,6 +2235,8 @@ _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
                        data_toggle = uhci_toggle (desc->hw.td.info);
                        break;
                }
+               else if (status)
+                       goto is_error;
 
                data_toggle = uhci_toggle (desc->hw.td.info);
                queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, desc->hw.td.status,status, data_toggle);      
@@ -2457,10 +2482,11 @@ _static int process_urb (uhci_t *s, struct list_head *p)
                                        is_ring = 1;
                        }
 
+                       spin_lock(&urb->lock);
                        spin_unlock(&s->urb_list_lock);
 
-                       // In case you need the current URB status for your completion handler
-                       if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
+                       // In case you need the current URB status for your completion handler (before resubmit)
+                       if (urb->complete && (!proceed )) {
                                dbg("process_transfer: calling early completion");
                                urb->complete ((struct urb *) urb);
                                if (!proceed && is_ring && (urb->status != -ENOENT))
@@ -2478,15 +2504,15 @@ _static int process_urb (uhci_t *s, struct list_head *p)
                                }
                                while (tmp != NULL && tmp != urb->next);        // submit until we reach NULL or our own pointer or submit fails
 
-                               if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE)) {
+                               if (urb->complete) {
                                        dbg("process_transfer: calling completion");
                                        urb->complete ((struct urb *) urb);
                                }
                        }
 
-                       spin_lock(&s->urb_list_lock);
-
                        usb_dec_dev_use (urb->dev);
+                       spin_unlock(&urb->lock);                
+                       spin_lock(&s->urb_list_lock);
                }
        }
 
@@ -2790,10 +2816,6 @@ _static int __init start_uhci (struct pci_dev *dev)
                        break;
                /* disable legacy emulation */
                pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-               if(dev->vendor==0x8086) {
-                       info("Intel USB controller: setting latency timer to %d", UHCI_LATENCY_TIMER);
-                       pci_write_config_byte(dev, PCI_LATENCY_TIMER, UHCI_LATENCY_TIMER);
-               }
        
                return alloc_uhci(dev, dev->irq, io_addr, io_size);
        }
index 0154d7f4885573776cbc775081e151ee02ff581e..777e2d650204aa79302b6abdb0c0cb0f46c1557c 100644 (file)
@@ -775,8 +775,8 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
 void usb_free_dev(struct usb_device *dev)
 {
        if (atomic_dec_and_test(&dev->refcnt)) {
-               usb_destroy_configuration(dev);
                dev->bus->op->deallocate(dev);
+               usb_destroy_configuration(dev);
                kfree(dev);
        }
 }
@@ -819,7 +819,7 @@ int usb_submit_urb(urb_t *urb)
        if (urb && urb->dev)
                return urb->dev->bus->op->submit_urb(urb);
        else
-               return -1;
+               return -ENODEV;
 }
 
 /*-------------------------------------------------------------------*/
@@ -828,7 +828,7 @@ int usb_unlink_urb(urb_t *urb)
        if (urb && urb->dev)
                return urb->dev->bus->op->unlink_urb(urb);
        else
-               return -1;
+               return -ENODEV;
 }
 /*-------------------------------------------------------------------*
  *                     COMPLETION HANDLERS                           *
@@ -1330,13 +1330,6 @@ void usb_destroy_configuration(struct usb_device *dev)
        }
        kfree(dev->config);
 }
-                       
-void usb_init_root_hub(struct usb_device *dev)
-{
-       dev->devnum = -1;
-       dev->slow = 0;
-       dev->actconfig = NULL;
-}
 
 /* for returning string descriptors in UTF-16LE */
 static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
@@ -1451,13 +1444,13 @@ void usb_disconnect(struct usb_device **pdev)
                        usb_disconnect(child);
        }
 
-       /* remove /proc/bus/usb entry */
-       usbdevfs_remove_device(dev);
-
-       /* Free up the device itself, including its device number */
-       if (dev->devnum > 0)
+       /* Free the device number and remove the /proc/bus/usb entry */
+       if (dev->devnum > 0) {
                clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+               usbdevfs_remove_device(dev);
+       }
 
+       /* Free up the device itself */
        usb_free_dev(dev);
 }
 
@@ -1631,7 +1624,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
        if (result < 0)
                return result;
 
-       if (status & 1)
+       if (le16_to_cpu(status) & 1)
                return -EPIPE;          /* still halted */
 
        usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
@@ -1679,7 +1672,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
        }
        if (!cp) {
                warn("selecting invalid configuration %d", configuration);
-               return -1;
+               return -EINVAL;
        }
 
        if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -1719,12 +1712,12 @@ int usb_get_configuration(struct usb_device *dev)
 
        if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
                warn("too many configurations");
-               return -1;
+               return -EINVAL;
        }
 
        if (dev->descriptor.bNumConfigurations < 1) {
                warn("not enough configurations");
-               return -1;
+               return -EINVAL;
        }
 
        dev->config = (struct usb_config_descriptor *)
@@ -1732,7 +1725,7 @@ int usb_get_configuration(struct usb_device *dev)
                sizeof(struct usb_config_descriptor), GFP_KERNEL);
        if (!dev->config) {
                err("out of memory");
-               return -1;      
+               return -ENOMEM; 
        }
        memset(dev->config, 0, dev->descriptor.bNumConfigurations *
                sizeof(struct usb_config_descriptor));
@@ -1741,7 +1734,7 @@ int usb_get_configuration(struct usb_device *dev)
                dev->descriptor.bNumConfigurations, GFP_KERNEL);
        if (!dev->rawdescriptors) {
                err("out of memory");
-               return -1;
+               return -ENOMEM;
        }
 
        for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
@@ -1751,8 +1744,10 @@ int usb_get_configuration(struct usb_device *dev)
                if (result < 8) {
                        if (result < 0)
                                err("unable to get descriptor");
-                       else
+                       else {
                                err("config descriptor too short (expected %i, got %i)", 8, result);
+                               result = -EINVAL;
+                       }
                        goto err;
                }
 
@@ -1776,6 +1771,7 @@ int usb_get_configuration(struct usb_device *dev)
        
                if (result < length) {
                        err("config descriptor too short (expected %i, got %i)", length, result);
+                       result = -EINVAL;
                        kfree(bigbuffer);
                        goto err;
                }
@@ -1786,7 +1782,7 @@ int usb_get_configuration(struct usb_device *dev)
                if (result > 0)
                        dbg("descriptor data left");
                else if (result < 0) {
-                       result = -1;
+                       result = -EINVAL;
                        goto err;
                }
        }
@@ -1921,14 +1917,13 @@ int usb_new_device(struct usb_device *dev)
                return 1;
        }
 
-       dev->actconfig = dev->config;
-       usb_set_maxpacket(dev);
-
        /* we set the default configuration here */
        err = usb_set_configuration(dev, dev->config[0].bConfigurationValue);
        if (err) {
                err("failed to set default configuration (error=%d)", err);
-               return -1;
+               clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+               dev->devnum = -1;
+               return 1;
        }
 
        dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
@@ -2035,7 +2030,6 @@ EXPORT_SYMBOL(usb_driver_claim_interface);
 EXPORT_SYMBOL(usb_interface_claimed);
 EXPORT_SYMBOL(usb_driver_release_interface);
 
-EXPORT_SYMBOL(usb_init_root_hub);
 EXPORT_SYMBOL(usb_root_hub_string);
 EXPORT_SYMBOL(usb_new_device);
 EXPORT_SYMBOL(usb_reset_device);
index f3c3e9e1258b536a8fef6095370365596524b647..72b5e1b27e1f4c11b644785c4f7c0483ceeb921b 100644 (file)
@@ -400,7 +400,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
                spin_unlock(&dcache_lock);
                return -ENOTEMPTY;
        }
-       list_del(&dentry->d_hash);
+       list_del_init(&dentry->d_hash);
        spin_unlock(&dcache_lock);
 
        dput(ino->dentry);
index 341dfe5917fcd915068f73f96ca2099ca037730f..ad0a04e686425e005e23887c42c8ba88e551c7d8 100644 (file)
@@ -482,16 +482,12 @@ static void __remove_from_queues(struct buffer_head *bh)
        __remove_from_lru_list(bh, bh->b_list);
 }
 
-static void insert_into_queues(struct buffer_head *bh)
+static void __insert_into_queues(struct buffer_head *bh)
 {
        struct buffer_head **head = &hash(bh->b_dev, bh->b_blocknr);
 
-       spin_lock(&lru_list_lock);
-       write_lock(&hash_table_lock);
        __hash_link(bh, head);
        __insert_into_lru_list(bh, bh->b_list);
-       write_unlock(&hash_table_lock);
-       spin_unlock(&lru_list_lock);
 }
 
 /* This function must only run if there are no other
@@ -524,19 +520,27 @@ static void put_last_free(struct buffer_head * bh)
  * will force it bad). This shouldn't really happen currently, but
  * the code is ready.
  */
-struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
+static inline struct buffer_head * __get_hash_table(kdev_t dev, int block, int size)
 {
-       struct buffer_head **head = &hash(dev, block);
-       struct buffer_head *bh;
+       struct buffer_head *bh = hash(dev, block);
 
-       read_lock(&hash_table_lock);
-       for(bh = *head; bh; bh = bh->b_next)
+       for (; bh; bh = bh->b_next)
                if (bh->b_blocknr == block      &&
                    bh->b_size    == size       &&
                    bh->b_dev     == dev)
                        break;
        if (bh)
                atomic_inc(&bh->b_count);
+
+       return bh;
+}
+
+struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
+{
+       struct buffer_head *bh;
+
+       read_lock(&hash_table_lock);
+       bh = __get_hash_table(dev, block, size);
        read_unlock(&hash_table_lock);
 
        return bh;
@@ -804,7 +808,9 @@ struct buffer_head * getblk(kdev_t dev, int block, int size)
        int isize;
 
 repeat:
-       bh = get_hash_table(dev, block, size);
+       spin_lock(&lru_list_lock);
+       write_lock(&hash_table_lock);
+       bh = __get_hash_table(dev, block, size);
        if (bh)
                goto out;
 
@@ -829,9 +835,10 @@ repeat:
                bh->b_state = 1 << BH_Mapped;
 
                /* Insert the buffer into the regular lists */
-               insert_into_queues(bh);
+               __insert_into_queues(bh);
        out:
-               touch_buffer(bh);
+               write_unlock(&hash_table_lock);
+               spin_unlock(&lru_list_lock);
                return bh;
        }
 
@@ -839,6 +846,8 @@ repeat:
         * If we block while refilling the free list, somebody may
         * create the buffer first ... search the hashes again.
         */
+       write_unlock(&hash_table_lock);
+       spin_unlock(&lru_list_lock);
        refill_freelist(size);
        goto repeat;
 }
@@ -2118,6 +2127,11 @@ out:
  *
  * This all is required so that we can free up memory
  * later.
+ *
+ * Wait:
+ *     0 - no wait (this does not get called - see try_to_free_buffers below)
+ *     1 - start IO for dirty buffers
+ *     2 - wait for completion of locked buffers
  */
 static void sync_page_buffers(struct buffer_head *bh, int wait)
 {
@@ -2127,7 +2141,7 @@ static void sync_page_buffers(struct buffer_head *bh, int wait)
                struct buffer_head *p = tmp;
                tmp = tmp->b_this_page;
                if (buffer_locked(p)) {
-                       if (wait)
+                       if (wait > 1)
                                __wait_on_buffer(p);
                } else if (buffer_dirty(p))
                        ll_rw_block(WRITE, 1, &p);
@@ -2200,8 +2214,9 @@ busy_buffer_page:
        /* Uhhuh, start writeback so that we don't end up with all dirty pages */
        spin_unlock(&free_list[index].lock);
        write_unlock(&hash_table_lock);
-       spin_unlock(&lru_list_lock);    
-       sync_page_buffers(bh, wait);
+       spin_unlock(&lru_list_lock);
+       if (wait)
+               sync_page_buffers(bh, wait);
        return 0;
 }
 
index 9be3e8cdc934fdcfeaa9faaa6838d3be8de6b217..e2bcbe6a3345c8b4e760a06ae2d4f27784ae035d 100644 (file)
@@ -81,8 +81,7 @@ static inline void dentry_iput(struct dentry * dentry)
        struct inode *inode = dentry->d_inode;
        if (inode) {
                dentry->d_inode = NULL;
-               list_del(&dentry->d_alias);
-               INIT_LIST_HEAD(&dentry->d_alias);
+               list_del_init(&dentry->d_alias);
                spin_unlock(&dcache_lock);
                if (dentry->d_op && dentry->d_op->d_iput)
                        dentry->d_op->d_iput(dentry, inode);
@@ -153,7 +152,7 @@ repeat:
        return;
 
 unhash_it:
-       list_del(&dentry->d_hash);
+       list_del_init(&dentry->d_hash);
 
 kill_it: {
                struct dentry *parent;
@@ -218,8 +217,7 @@ int d_invalidate(struct dentry * dentry)
                }
        }
 
-       list_del(&dentry->d_hash);
-       INIT_LIST_HEAD(&dentry->d_hash);
+       list_del_init(&dentry->d_hash);
        spin_unlock(&dcache_lock);
        return 0;
 }
@@ -307,7 +305,7 @@ static inline void prune_one_dentry(struct dentry * dentry)
 {
        struct dentry * parent;
 
-       list_del(&dentry->d_hash);
+       list_del_init(&dentry->d_hash);
        list_del(&dentry->d_child);
        dentry_iput(dentry);
        parent = dentry->d_parent;
@@ -342,8 +340,7 @@ void prune_dcache(int count)
                if (tmp == &dentry_unused)
                        break;
                dentry_stat.nr_unused--;
-               list_del(tmp);
-               INIT_LIST_HEAD(tmp);
+               list_del_init(tmp);
                dentry = list_entry(tmp, struct dentry, d_lru);
 
                /* Unused dentry with a count? */
index f7745f9de2ab116ed3bb390e81bab810932d0f25..d162f885255a01c7b44309f471dab0dbdd0e862f 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -320,9 +320,11 @@ int setup_arg_pages(struct linux_binprm *bprm)
        } 
 
        for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-               if (bprm->page[i]) {
+               struct page *page = bprm->page[i];
+               if (page) {
+                       bprm->page[i] = NULL;
                        current->mm->rss++;
-                       put_dirty_page(current,bprm->page[i],stack_base);
+                       put_dirty_page(current,page,stack_base);
                }
                stack_base += PAGE_SIZE;
        }
@@ -873,11 +875,11 @@ out:
        if (bprm.file)
                fput(bprm.file);
 
-       /* Assumes that free_page() can take a NULL argument. */ 
-       /* I hope this is ok for all architectures */ 
-       for (i = 0 ; i < MAX_ARG_PAGES ; i++)
-               if (bprm.page[i])
-                       __free_page(bprm.page[i]);
+       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+               struct page * page = bprm.page[i];
+               if (page)
+                       __free_page(page);
+       }
 
        return retval;
 }
index 3c95ccd70c4ff91f27461924d54c9a34e5a3a32f..c99f7f2c89377757d7baa11addfec066e3ab11cf 100644 (file)
@@ -453,7 +453,7 @@ repeat:
        inode->u.ext2_i.i_dtime = 0;
        inode->u.ext2_i.i_block_group = i;
        if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
-               inode->i_flags |= MS_SYNCHRONOUS;
+               inode->i_flags |= S_SYNC;
        insert_inode_hash(inode);
        inode->i_generation = event++;
        mark_inode_dirty(inode);
index c7234e7b5e25090759c1d7d5b5c85debd3ba2fcb..678eb4d285c958330a621540fb5e77d489bfa03e 100644 (file)
@@ -18,6 +18,8 @@
  *        David S. Miller (davem@caip.rutgers.edu), 1995
  *  64-bit file support on 64-bit platforms by Jakub Jelinek
  *     (jj@sunsite.ms.mff.cuni.cz)
+ *
+ *  Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000
  */
 
 #include <linux/fs.h>
@@ -26,8 +28,6 @@
 #include <linux/sched.h>
 #include <linux/highuid.h>
 
-
-
 static int ext2_update_inode(struct inode * inode, int do_sync);
 
 /*
@@ -64,23 +64,18 @@ no_delete:
        clear_inode(inode);     /* We must guarantee clearing of inode... */
 }
 
-/* 
- * ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the
- * superblock in the same manner as are ext2_free_blocks and
- * ext2_new_block.  We just wait on the super rather than locking it
- * here, since ext2_new_block will do the necessary locking and we
- * can't block until then.
- */
 void ext2_discard_prealloc (struct inode * inode)
 {
 #ifdef EXT2_PREALLOCATE
-       unsigned short total;
-
        lock_kernel();
+       /* Writer: ->i_prealloc* */
        if (inode->u.ext2_i.i_prealloc_count) {
-               total = inode->u.ext2_i.i_prealloc_count;
+               unsigned short total = inode->u.ext2_i.i_prealloc_count;
+               unsigned long block = inode->u.ext2_i.i_prealloc_block;
                inode->u.ext2_i.i_prealloc_count = 0;
-               ext2_free_blocks (inode, inode->u.ext2_i.i_prealloc_block, total);
+               inode->u.ext2_i.i_prealloc_block = 0;
+               /* Writer: end */
+               ext2_free_blocks (inode, block, total);
        }
        unlock_kernel();
 #endif
@@ -93,22 +88,26 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
 #endif
        unsigned long result;
 
-       wait_on_super (inode->i_sb);
 
 #ifdef EXT2_PREALLOCATE
+       /* Writer: ->i_prealloc* */
        if (inode->u.ext2_i.i_prealloc_count &&
            (goal == inode->u.ext2_i.i_prealloc_block ||
             goal + 1 == inode->u.ext2_i.i_prealloc_block))
        {               
                result = inode->u.ext2_i.i_prealloc_block++;
                inode->u.ext2_i.i_prealloc_count--;
+               /* Writer: end */
+#ifdef EXT2FS_DEBUG
                ext2_debug ("preallocation hit (%lu/%lu).\n",
                            ++alloc_hits, ++alloc_attempts);
-
+#endif
        } else {
                ext2_discard_prealloc (inode);
+#ifdef EXT2FS_DEBUG
                ext2_debug ("preallocation miss (%lu/%lu).\n",
                            alloc_hits, ++alloc_attempts);
+#endif
                if (S_ISREG(inode->i_mode))
                        result = ext2_new_block (inode, goal, 
                                 &inode->u.ext2_i.i_prealloc_count,
@@ -299,307 +298,307 @@ no_block:
        return p;
 }
 
-static struct buffer_head * inode_getblk (struct inode * inode, int nr,
-       int new_block, int * err, int metadata, long *phys, int *new)
+/**
+ *     ext2_find_near - find a place for allocation with sufficient locality
+ *     @inode: owner
+ *     @ind: descriptor of indirect block.
+ *
+ *     This function returns the prefered place for block allocation.
+ *     It is used when heuristic for sequential allocation fails.
+ *     Rules are:
+ *       + if there is a block to the left of our position - allocate near it.
+ *       + if pointer will live in indirect block - allocate near that block.
+ *       + if pointer will live in inode - allocate in the same cylinder group.
+ *     Caller must make sure that @ind is valid and will stay that way.
+ */
+
+static inline unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
 {
-       u32 * p;
-       int tmp, goal = 0;
-       struct buffer_head * result;
-       int blocksize = inode->i_sb->s_blocksize;
+       u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.ext2_i.i_data;
+       u32 *p;
 
-       p = inode->u.ext2_i.i_data + nr;
-repeat:
-       tmp = le32_to_cpu(*p);
-       if (tmp) {
-               if (metadata) {
-                       result = getblk (inode->i_dev, tmp, blocksize);
-                       if (tmp == le32_to_cpu(*p))
-                               return result;
-                       brelse (result);
-                       goto repeat;
-               } else {
-                       *phys = tmp;
-                       return NULL;
-               }
-       }
+       /* Try to find previous block */
+       for (p = ind->p - 1; p >= start; p--)
+               if (*p)
+                       return le32_to_cpu(*p);
 
-       if (inode->u.ext2_i.i_next_alloc_block == new_block)
-               goal = inode->u.ext2_i.i_next_alloc_goal;
+       /* No such thing, so let's try location of indirect block */
+       if (ind->bh)
+               return ind->bh->b_blocknr;
 
-       ext2_debug ("hint = %d,", goal);
+       /*
+        * It is going to be refered from inode itself? OK, just put it into
+        * the same cylinder group then.
+        */
+       return (inode->u.ext2_i.i_block_group * 
+               EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
+              le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_first_data_block);
+}
 
-       if (!goal) {
-               for (tmp = nr - 1; tmp >= 0; tmp--) {
-                       if (inode->u.ext2_i.i_data[tmp]) {
-                               goal = le32_to_cpu(inode->u.ext2_i.i_data[tmp]);
-                               break;
-                       }
-               }
-               if (!goal)
-                       goal = (inode->u.ext2_i.i_block_group * 
-                               EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
-                              le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_first_data_block);
-       }
+/**
+ *     ext2_find_goal - find a prefered place for allocation.
+ *     @inode: owner
+ *     @block:  block we want
+ *     @chain:  chain of indirect blocks
+ *     @partial: pointer to the last triple within a chain.
+ *
+ *     This function returns the prefered place for block allocation.
+ */
 
-       ext2_debug ("goal = %d.\n", goal);
-
-       tmp = ext2_alloc_block (inode, goal, err);
-       if (!tmp)
-               return NULL;
-
-       if (metadata) {
-               result = getblk (inode->i_dev, tmp, blocksize);
-               if (!buffer_uptodate(result))
-                       wait_on_buffer(result);
-               memset(result->b_data, 0, blocksize);
-               mark_buffer_uptodate(result, 1);
-               mark_buffer_dirty(result, 1);
-               if (*p) {
-                       ext2_free_blocks (inode, tmp, 1);
-                       bforget (result);
-                       goto repeat;
-               }
-       } else {
-               if (*p) {
-                       /*
-                        * Nobody is allowed to change block allocation
-                        * state from under us:
-                        */
-                       ext2_error (inode->i_sb, "block_getblk",
-                                   "data block filled under us");
-                       BUG();
-                       ext2_free_blocks (inode, tmp, 1);
-                       goto repeat;
-               }
-               *phys = tmp;
-               result = NULL;
-               *err = 0;
-               *new = 1;
-       }
-       *p = cpu_to_le32(tmp);
+static inline unsigned long ext2_find_goal(struct inode *inode,
+                                          long block,
+                                          Indirect chain[4],
+                                          Indirect *partial)
+{
+       unsigned long goal = 0;
 
-       inode->u.ext2_i.i_next_alloc_block = new_block;
-       inode->u.ext2_i.i_next_alloc_goal = tmp;
-       inode->i_ctime = CURRENT_TIME;
-       inode->i_blocks += blocksize/512;
-       if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
-               ext2_sync_inode (inode);
-       else
-               mark_inode_dirty(inode);
-       return result;
+       /* Writer: ->i_next_alloc* */
+       if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
+               inode->u.ext2_i.i_next_alloc_block++;
+               inode->u.ext2_i.i_next_alloc_goal++;
+       } 
+       /* Writer: end */
+       /* Reader: pointers, ->i_next_alloc* */
+       if (verify_chain(chain, partial)) {
+               /*
+                * try the heuristic for sequential allocation,
+                * failing that at least try to get decent locality.
+                */
+               if (block == inode->u.ext2_i.i_next_alloc_block)
+                       goal = inode->u.ext2_i.i_next_alloc_goal;
+               if (!goal)
+                       goal = ext2_find_near(inode, partial);
+       }
+       /* Reader: end */
+       return goal;
 }
 
-/*
- *   metadata / data
- *   possibly create / access
- *   can fail due to: - not present
- *                    - out of space
+/**
+ *     ext2_alloc_branch - allocate and set up a chain of blocks.
+ *     @inode: owner
+ *     @num: depth of the chain (number of blocks to allocate)
+ *     @offsets: offsets (in the blocks) to store the pointers to next.
+ *     @branch: place to store the chain in.
  *
- *   NULL return in the data case is mandatory.
+ *     This function allocates @num blocks, zeroes out all but the last one,
+ *     links them into chain and (if we are synchronous) writes them to disk.
+ *     In other words, it prepares a branch that can be spliced onto the
+ *     inode. It stores the information about that chain in the branch[], in
+ *     the same format as ext2_get_branch() would do. We are calling it after
+ *     we had read the existing part of chain and partial points to the last
+ *     triple of that (one with zero ->key). Upon the exit we have the same
+ *     picture as after the successful ext2_get_block(), excpet that in one
+ *     place chain is disconnected - *branch->p is still zero (we did not
+ *     set the last link), but branch->key contains the number that should
+ *     be placed into *branch->p to fill that gap.
+ *
+ *     If allocation fails we free all blocks we've allocated (and forget
+ *     ther buffer_heads) and return the error value the from failed
+ *     ext2_alloc_block() (normally -ENOSPC). Otherwise we set the chain
+ *     as described above and return 0.
  */
-static struct buffer_head * block_getblk (struct inode * inode,
-         struct buffer_head * bh, int nr,
-         int new_block, int * err, int metadata, long *phys, int *new)
+
+static int ext2_alloc_branch(struct inode *inode,
+                            int num,
+                            unsigned long goal,
+                            int *offsets,
+                            Indirect *branch)
 {
-       int tmp, goal = 0;
-       u32 * p;
-       struct buffer_head * result;
        int blocksize = inode->i_sb->s_blocksize;
+       int n = 0;
+       int err;
+       int i;
+       int parent = ext2_alloc_block(inode, goal, &err);
 
-       result = NULL;  
-       if (!bh)
-               goto out;
-       if (!buffer_uptodate(bh)) {
-               ll_rw_block (READ, 1, &bh);
-               wait_on_buffer (bh);
+       branch[0].key = cpu_to_le32(parent);
+       if (parent) for (n = 1; n < num; n++) {
+               struct buffer_head *bh;
+               /* Allocate the next block */
+               int nr = ext2_alloc_block(inode, parent, &err);
+               if (!nr)
+                       break;
+               branch[n].key = cpu_to_le32(nr);
+               /*
+                * Get buffer_head for parent block, zero it out and set 
+                * the pointer to new one, then send parent to disk.
+                */
+               bh = getblk(inode->i_dev, parent, blocksize);
                if (!buffer_uptodate(bh))
-                       goto out;
-       }
-       p = (u32 *) bh->b_data + nr;
-repeat:
-       tmp = le32_to_cpu(*p);
-       if (tmp) {
-               if (metadata) {
-                       result = getblk (bh->b_dev, tmp, blocksize);
-                       if (tmp == le32_to_cpu(*p))
-                               goto out;
-                       brelse (result);
-                       goto repeat;
-               } else {
-                       *phys = tmp;
-                       /* result == NULL */
-                       goto out;
+                       wait_on_buffer(bh);
+               memset(bh->b_data, 0, blocksize);
+               branch[n].bh = bh;
+               branch[n].p = (u32*) bh->b_data + offsets[n];
+               *branch[n].p = branch[n].key;
+               mark_buffer_uptodate(bh, 1);
+               mark_buffer_dirty(bh, 1);
+               if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
+                       ll_rw_block (WRITE, 1, &bh);
+                       wait_on_buffer (bh);
                }
+               parent = nr;
        }
+       if (n == num)
+               return 0;
 
-       if (inode->u.ext2_i.i_next_alloc_block == new_block)
-               goal = inode->u.ext2_i.i_next_alloc_goal;
-       if (!goal) {
-               for (tmp = nr - 1; tmp >= 0; tmp--) {
-                       if (le32_to_cpu(((u32 *) bh->b_data)[tmp])) {
-                               goal = le32_to_cpu(((u32 *)bh->b_data)[tmp]);
-                               break;
-                       }
-               }
-               if (!goal)
-                       goal = bh->b_blocknr;
-       }
-       tmp = ext2_alloc_block (inode, goal, err);
-       if (!tmp)
-               goto out;
-       if (metadata) {
-               result = getblk (bh->b_dev, tmp, blocksize);
-               if (!buffer_uptodate(result))
-                       wait_on_buffer(result);
-               memset(result->b_data, 0, inode->i_sb->s_blocksize);
-               mark_buffer_uptodate(result, 1);
-               mark_buffer_dirty(result, 1);
-               if (*p) {
-                       ext2_free_blocks (inode, tmp, 1);
-                       bforget (result);
-                       goto repeat;
-               }
-       } else {
-               if (*p) {
-                       /*
-                        * Nobody is allowed to change block allocation
-                        * state from under us:
-                        */
-                       ext2_error (inode->i_sb, "block_getblk",
-                                   "data block filled under us");
-                       BUG();
-                       ext2_free_blocks (inode, tmp, 1);
-                       goto repeat;
+       /* Allocation failed, free what we already allocated */
+       for (i = 1; i < n; i++)
+               bforget(branch[i].bh);
+       for (i = 0; i < n; i++)
+               ext2_free_blocks(inode, le32_to_cpu(branch[i].key), 1);
+       return err;
+}
+
+/**
+ *     ext2_splice_branch - splice the allocated branch onto inode.
+ *     @inode: owner
+ *     @block: (logical) number of block we are adding
+ *     @chain: chain of indirect blocks (with a missing link - see
+ *             ext2_alloc_branch)
+ *     @where: location of missing link
+ *     @num:   number of blocks we are adding
+ *
+ *     This function verifies that chain (up to the missing link) had not
+ *     changed, fills the missing link and does all housekeeping needed in
+ *     inode (->i_blocks, etc.). In case of success we end up with the full
+ *     chain to new block and return 0. Otherwise (== chain had been changed)
+ *     we free the new blocks (forgetting their buffer_heads, indeed) and
+ *     return -EAGAIN.
+ */
+
+static inline int ext2_splice_branch(struct inode *inode,
+                                    long block,
+                                    Indirect chain[4],
+                                    Indirect *where,
+                                    int num)
+{
+       int i;
+
+       /* Verify that place we are splicing to is still there and vacant */
+
+       /* Writer: pointers, ->i_next_alloc*, ->i_blocks */
+       if (!verify_chain(chain, where-1) || *where->p)
+               /* Writer: end */
+               goto changed;
+
+       /* That's it */
+
+       *where->p = where->key;
+       inode->u.ext2_i.i_next_alloc_block = block;
+       inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);
+       inode->i_blocks += num * inode->i_sb->s_blocksize/512;
+
+       /* Writer: end */
+
+       /* We are done with atomic stuff, now do the rest of housekeeping */
+
+       inode->i_ctime = CURRENT_TIME;
+
+       /* had we spliced it onto indirect block? */
+       if (where->bh) {
+               mark_buffer_dirty(where->bh, 1);
+               if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
+                       ll_rw_block (WRITE, 1, &where->bh);
+                       wait_on_buffer(where->bh);
                }
-               *phys = tmp;
-               *new = 1;
-       }
-       *p = le32_to_cpu(tmp);
-       mark_buffer_dirty(bh, 1);
-       if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
-               ll_rw_block (WRITE, 1, &bh);
-               wait_on_buffer (bh);
        }
-       inode->i_ctime = CURRENT_TIME;
-       inode->i_blocks += blocksize/512;
-       mark_inode_dirty(inode);
-       inode->u.ext2_i.i_next_alloc_block = new_block;
-       inode->u.ext2_i.i_next_alloc_goal = tmp;
-       *err = 0;
-out:
-       brelse (bh);
-       return result;
+
+       if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
+               ext2_sync_inode (inode);
+       else
+               mark_inode_dirty(inode);
+       return 0;
+
+changed:
+       for (i = 1; i < num; i++)
+               bforget(where[i].bh);
+       for (i = 0; i < num; i++)
+               ext2_free_blocks(inode, le32_to_cpu(where[i].key), 1);
+       return -EAGAIN;
 }
 
+/*
+ * Allocation strategy is simple: if we have to allocate something, we will
+ * have to go the whole way to leaf. So let's do it before attaching anything
+ * to tree, set linkage between the newborn blocks, write them if sync is
+ * required, recheck the path, free and repeat if check fails, otherwise
+ * set the last missing link (that will protect us from any truncate-generated
+ * removals - all blocks on the path are immune now) and possibly force the
+ * write on the parent block.
+ * That has a nice additional property: no special recovery from the failed
+ * allocations is needed - we simply release blocks and do not touch anything
+ * reachable from inode.
+ */
+
 static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
 {
-       int ret, err, new;
-       struct buffer_head *bh;
-       unsigned long phys;
+       int err = -EIO;
        int offsets[4];
-       int *p;
        Indirect chain[4];
        Indirect *partial;
-       int depth;
+       unsigned long goal;
+       int left;
+       int depth = ext2_block_to_path(inode, iblock, offsets);
 
-       depth = ext2_block_to_path(inode, iblock, offsets);
        if (depth == 0)
-               goto abort;
+               goto out;
 
        lock_kernel();
+reread:
        partial = ext2_get_branch(inode, depth, offsets, chain, &err);
 
+       /* Simplest case - block found, no allocation needed */
        if (!partial) {
-               unlock_kernel();
-               for (partial = chain + depth - 1; partial > chain; partial--)
-                       brelse(partial->bh);
+got_it:
                bh_result->b_dev = inode->i_dev;
                bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key);
                bh_result->b_state |= (1UL << BH_Mapped);
-               return 0;
+               /* Clean up and exit */
+               partial = chain+depth-1; /* the whole chain */
+               goto cleanup;
        }
 
-       while (partial > chain) {
-               brelse(partial->bh);
-               partial--;
-       }
-
-       if (!create) {
+       /* Next simple case - plain lookup or failed read of indirect block */
+       if (!create || err == -EIO) {
+cleanup:
+               while (partial > chain) {
+                       brelse(partial->bh);
+                       partial--;
+               }
                unlock_kernel();
-               return 0;
+out:
+               return err;
        }
 
-       err = -EIO;
-       new = 0;
-       ret = 0;
-       bh = NULL;
-
        /*
-        * If this is a sequential block allocation, set the next_alloc_block
-        * to this block now so that all the indblock and data block
-        * allocations use the same goal zone
+        * Indirect block might be removed by truncate while we were
+        * reading it. Handling of that case (forget what we've got and
+        * reread) is taken out of the main path.
         */
+       if (err == -EAGAIN)
+               goto changed;
 
-       ext2_debug ("block %lu, next %lu, goal %lu.\n", iblock, 
-                   inode->u.ext2_i.i_next_alloc_block,
-                   inode->u.ext2_i.i_next_alloc_goal);
-
-       if (iblock == inode->u.ext2_i.i_next_alloc_block + 1) {
-               inode->u.ext2_i.i_next_alloc_block++;
-               inode->u.ext2_i.i_next_alloc_goal++;
-       }
+       goal = ext2_find_goal(inode, iblock, chain, partial);
+       if (!goal)
+               goto changed;
 
-       err = 0;
+       left = (chain + depth) - partial;
+       err = ext2_alloc_branch(inode, left, goal,
+                                       offsets+(partial-chain), partial);
+       if (err)
+               goto cleanup;
 
-       /*
-        * ok, these macros clean the logic up a bit and make
-        * it much more readable:
-        */
-#define GET_INODE_DATABLOCK(x) \
-               inode_getblk(inode, x, iblock, &err, 0, &phys, &new)
-#define GET_INODE_PTR(x) \
-               inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
-#define GET_INDIRECT_DATABLOCK(x) \
-               block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
-#define GET_INDIRECT_PTR(x) \
-               block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
-
-       p = offsets;
-       if (depth == 1) {
-               bh = GET_INODE_DATABLOCK(*p);
-               goto out;
-       }
-       bh = GET_INODE_PTR(*p);
-       switch (depth) {
-               default: /* case 4: */
-                       bh = GET_INDIRECT_PTR(*++p);
-               case 3:
-                       bh = GET_INDIRECT_PTR(*++p);
-               case 2:
-                       bh = GET_INDIRECT_DATABLOCK(*++p);
-       }
+       if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
+               goto changed;
 
-#undef GET_INODE_DATABLOCK
-#undef GET_INODE_PTR
-#undef GET_INDIRECT_DATABLOCK
-#undef GET_INDIRECT_PTR
+       bh_result->b_state |= (1UL << BH_New);
+       goto got_it;
 
-out:
-       if (bh)
-               BUG();  // temporary debugging check
-       if (err)
-               goto abort;
-       if (!phys)
-               BUG();  // must not happen either
-
-       bh_result->b_dev = inode->i_dev;
-       bh_result->b_blocknr = phys;
-       bh_result->b_state |= (1UL << BH_Mapped); /* safe */
-       if (new)
-               bh_result->b_state |= (1UL << BH_New);
-       unlock_kernel();
-abort:
-       return err;
+changed:
+       while (partial > chain) {
+               bforget(partial->bh);
+               partial--;
+       }
+       goto reread;
 }
 
 struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
@@ -833,7 +832,7 @@ void ext2_read_inode (struct inode * inode)
        inode->i_attr_flags = 0;
        if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
                inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
-               inode->i_flags |= MS_SYNCHRONOUS;
+               inode->i_flags |= S_SYNC;
        }
        if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {
                inode->i_attr_flags |= ATTR_FLAG_APPEND;
@@ -845,7 +844,7 @@ void ext2_read_inode (struct inode * inode)
        }
        if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
                inode->i_attr_flags |= ATTR_FLAG_NOATIME;
-               inode->i_flags |= MS_NOATIME;
+               inode->i_flags |= S_NOATIME;
        }
        return;
        
@@ -999,17 +998,17 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
        
        flags = iattr->ia_attr_flags;
        if (flags & ATTR_FLAG_SYNCRONOUS) {
-               inode->i_flags |= MS_SYNCHRONOUS;
+               inode->i_flags |= S_SYNC;
                inode->u.ext2_i.i_flags |= EXT2_SYNC_FL;
        } else {
-               inode->i_flags &= ~MS_SYNCHRONOUS;
+               inode->i_flags &= ~S_SYNC;
                inode->u.ext2_i.i_flags &= ~EXT2_SYNC_FL;
        }
        if (flags & ATTR_FLAG_NOATIME) {
-               inode->i_flags |= MS_NOATIME;
+               inode->i_flags |= S_NOATIME;
                inode->u.ext2_i.i_flags |= EXT2_NOATIME_FL;
        } else {
-               inode->i_flags &= ~MS_NOATIME;
+               inode->i_flags &= ~S_NOATIME;
                inode->u.ext2_i.i_flags &= ~EXT2_NOATIME_FL;
        }
        if (flags & ATTR_FLAG_APPEND) {
index 0b456820aeb33f54e11c4fd7a4f7ec354a28608c..6528f1f741b1916173166ef392d7c3d2342958c4 100644 (file)
@@ -53,9 +53,9 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                inode->u.ext2_i.i_flags = flags;
 
                if (flags & EXT2_SYNC_FL)
-                       inode->i_flags |= MS_SYNCHRONOUS;
+                       inode->i_flags |= S_SYNC;
                else
-                       inode->i_flags &= ~MS_SYNCHRONOUS;
+                       inode->i_flags &= ~S_SYNC;
                if (flags & EXT2_APPEND_FL)
                        inode->i_flags |= S_APPEND;
                else
@@ -65,9 +65,9 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
                else
                        inode->i_flags &= ~S_IMMUTABLE;
                if (flags & EXT2_NOATIME_FL)
-                       inode->i_flags |= MS_NOATIME;
+                       inode->i_flags |= S_NOATIME;
                else
-                       inode->i_flags &= ~MS_NOATIME;
+                       inode->i_flags &= ~S_NOATIME;
                inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
                return 0;
index 55658cd6b8c3eeecd07c8e02ff75ec990a3488e9..97d9e2d22184cff0e11974875a7c42a138f067fb 100644 (file)
@@ -1739,7 +1739,7 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
        if (error)
                return error;
        /* The following d_move() should become unconditional */
-       if (!(old_dir->i_sb->s_flags & MS_ODD_RENAME)) {
+       if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) {
                d_move(old_dentry, new_dentry);
        }
        return 0;
index 993dcc1a4879d1747436fb68d16d6387b88d3bf3..db7c110e5466c830e86e9d39cd2fb811044f1177 100644 (file)
@@ -275,8 +275,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
        if (srvaddr.sin_addr.s_addr == INADDR_ANY)
                goto out_no_remote;
 
-       sb->s_flags |= MS_ODD_RENAME; /* This should go away */
-
        sb->s_magic      = NFS_SUPER_MAGIC;
        sb->s_op         = &nfs_sops;
        sb->s_blocksize_bits = 0;
@@ -1164,7 +1162,7 @@ out_changed:
 /*
  * File system information
  */
-static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, 0);
+static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME);
 
 extern int nfs_init_fhcache(void);
 extern void nfs_destroy_fhcache(void);
index 3ca996ed15822bd3a5af3884393dff8b62e8d2c6..18d1f7a887ea4ea1182317b5f775d2c6fd9c4997 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -269,6 +269,9 @@ static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
        memset(&tmp, 0, sizeof(tmp));
        tmp.st_dev = kdev_t_to_nr(inode->i_dev);
        tmp.st_ino = inode->i_ino;
+#ifdef STAT64_HAS_BROKEN_ST_INO
+       tmp.__st_ino = inode->i_ino;
+#endif
        tmp.st_mode = inode->i_mode;
        tmp.st_nlink = inode->i_nlink;
        tmp.st_uid = inode->i_uid;
index 84e8ca99f476e37f7f125dbf68da48d8a98aef07..9e4ace724d788afe79c700b68556461f27c62bd2 100644 (file)
@@ -22,6 +22,7 @@
 static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q)
 {
        p->name_len = q->name_len;
+       p->name[p->name_len]='\0';
        p->flags = q->flags;
        p->nlink = le16_to_cpu (q->nlink);
        /* FIXME -- 32bit UID/GID issues */
@@ -119,6 +120,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di
        struct umsdos_dirent *p;
        int offs = *pos & ~PAGE_CACHE_MASK;
        int recsize;
+       int ret = 0;
 
        page = read_cache_page(mapping, *pos>>PAGE_CACHE_SHIFT,
                        (filler_t*)mapping->a_ops->readpage, NULL);
@@ -128,6 +130,15 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di
        if (!Page_Uptodate(page))
                goto async_fail;
        p = (struct umsdos_dirent*)((char*)kmap(page)+offs);
+
+       /* if this is an invalid entry (invalid name length), ignore it */
+       if( p->name_len > UMSDOS_MAXNAME )
+       {
+               printk (KERN_WARNING "Ignoring invalid EMD entry with size %d\n", entry->name_len);
+               p->name_len = 0; 
+               ret = -ENAMETOOLONG; /* notify umssync(8) code that something is wrong */
+       }
+
        recsize = umsdos_evalrecsize(p->name_len);
        if (offs + recsize > PAGE_CACHE_SIZE) {
                struct page *page2;
@@ -157,7 +168,7 @@ int umsdos_emd_dir_readentry (struct dentry *demd, loff_t *pos, struct umsdos_di
        kunmap(page);
        page_cache_release(page);
        *pos += recsize;
-       return 0;
+       return ret;
 async_fail:
        page_cache_release(page);
        page = ERR_PTR(-EIO);
@@ -172,7 +183,7 @@ sync_fail:
  *
  * Note: the caller must hold a lock on the parent directory.
  */
-static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
+int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
                                int free_entry)
 {
        struct inode *dir = parent->d_inode;
@@ -266,7 +277,7 @@ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
                        goto out_unlock;
        } else {
                ret = mapping->a_ops->prepare_write(NULL,page,offs,
-                                       info->recsize);
+                                       offs + info->recsize);
                if (ret)
                        goto out_unlock;
                p->name_len = entry->name_len;
@@ -281,7 +292,7 @@ static int umsdos_writeentry (struct dentry *parent, struct umsdos_info *info,
                p->mode = cpu_to_le16(entry->mode);
                memcpy(p->spare,entry->spare,((char*)p+info->recsize)-p->spare);
                ret = mapping->a_ops->commit_write(NULL,page,offs,
-                                       info->recsize);
+                                       offs + info->recsize);
                if (ret)
                        goto out_unlock;
        }
@@ -373,6 +384,7 @@ static int umsdos_find (struct dentry *demd, struct umsdos_info *info)
                        if (page) {
                                kunmap(page);
                                page_cache_release(page);
+                               page = NULL;
                        }
                        if (pos >= emd_dir->i_size) {
                                info->f_pos = empty.posok;
index bb48b6bf27d702856224443dc4f6b93b5a4cb706..12b34e849ee016256c4d30a5b356ad51c6796e75 100644 (file)
@@ -38,8 +38,7 @@ void UMSDOS_put_inode (struct inode *inode)
                 ,atomic_read(&inode->i_count)));
 
        if (inode == pseudo_root) {
-               printk (KERN_ERR "Umsdos: Oops releasing pseudo_root."
-                       " Notify jacques@solucorp.qc.ca\n");
+               printk (KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count));
        }
 
        if (atomic_read(&inode->i_count) == 1)
@@ -203,15 +202,15 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched)
        ret = PTR_ERR(demd);
        if (IS_ERR(demd))
                goto out;
-       ret = -EPERM;
-       if (!demd->d_inode) {
-               printk(KERN_WARNING
+       ret = 0;
+       /* don't do anything if directory is not promoted to umsdos yet */
+       if (!demd->d_inode) { 
+               Printk((KERN_DEBUG
                        "UMSDOS_notify_change: no EMD file %s/%s\n",
-                       demd->d_parent->d_name.name, demd->d_name.name);
+                       demd->d_parent->d_name.name, demd->d_name.name));
                goto out_dput;
        }
 
-       ret = 0;
        /* don't do anything if this is the EMD itself */
        if (inode == demd->d_inode)
                goto out_dput;
@@ -295,10 +294,19 @@ static struct super_operations umsdos_sops =
        put_inode:      UMSDOS_put_inode,
        delete_inode:   fat_delete_inode,
        put_super:      UMSDOS_put_super,
-       statfs:         fat_statfs,
+       statfs:         UMSDOS_statfs,
        clear_inode:    fat_clear_inode,
 };
 
+int UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
+{
+       int ret;
+       ret = fat_statfs (sb, buf);
+       if (!ret)       
+               buf->f_namelen = UMSDOS_MAXNAME;
+       return ret;
+}
+
 /*
  * Read the super block of an Extended MS-DOS FS.
  */
@@ -317,7 +325,7 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
        if (!res)
                goto out_fail;
 
-       printk (KERN_INFO "UMSDOS 0.86 "
+       printk (KERN_INFO "UMSDOS 0.86i "
                "(compatibility level %d.%d, fast msdos)\n", 
                UMSDOS_VERSION, UMSDOS_RELEASE);
 
index 17d38c2dd2e386055343236798f12988bc41ddf6..8731f8ecddcf2536fcaf6aacf328ce92b22d32d7 100644 (file)
@@ -177,6 +177,16 @@ dentry->d_parent->d_name.name, dentry->d_name.name, cmd, data_ptr));
                        struct umsdos_info info;
 
                        ret = umsdos_emd_dir_readentry (demd, &pos, &entry);
+
+                       if (ret == -ENAMETOOLONG) {
+                               printk (KERN_INFO "Fixing EMD entry with invalid size -- zeroing out\n");
+                               memset (&info, 0, sizeof (info));
+                               info.f_pos = f_pos;
+                               info.recsize = UMSDOS_REC_SIZE;
+                               ret = umsdos_writeentry (dentry, &info, 1);
+                               continue;
+                       }
+
                        if (ret)
                                break;
                        if (entry.name_len <= 0)
index 4102ce6e05dd416521ba4f57f89a1d02afb51e89..c29387f3c759dfbf70c13eaaa6a963cc9c8a9e6e 100644 (file)
@@ -335,19 +335,6 @@ static void umsdos_ren_init (struct umsdos_info *new_info,
        new_info->entry.nlink = old_info->entry.nlink;
 }
 
-#ifdef OBSOLETE
-#define chkstk() \
-if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
-    printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
-          , current->comm,STACK_MAGIC \
-          ,*(unsigned long *)current->kernel_stack_page \
-          ,__LINE__); \
-}
-
-#undef chkstk
-#define chkstk() do { } while (0);
-#endif
-
 /*
  * Rename a file (move) in the file system.
  */
index b9d8faa61163f713715bc4a406465f9b648401bf..b02a78594624cc3d3ade1c548379e8c048f5b3d0 100644 (file)
@@ -153,7 +153,7 @@ wrfpcr(unsigned long val)
        unsigned long tmp;
 
 #if defined(__alpha_cix__) || defined(__alpha_fix__)
-       __asm__ ("ftoit $f0,%0\n\t"
+       __asm__ __volatile__ ("ftoit $f0,%0\n\t"
                 "itoft %1,$f0\n\t"
                 "mt_fpcr $f0\n\t"
                 "itoft %0,$f0"
index 5346b02236876007fc5c315f7e9d1b44d6964b4a..77a16fa5cfb5e5a9bb20198f4908c8261eace138 100644 (file)
@@ -45,7 +45,8 @@ struct stat64 {
        unsigned short  st_dev;
        unsigned char   __pad0[10];
 
-       unsigned long   st_ino;
+#define STAT64_HAS_BROKEN_ST_INO       1
+       unsigned long   __st_ino;
        unsigned int    st_mode;
        unsigned int    st_nlink;
 
@@ -70,8 +71,7 @@ struct stat64 {
        unsigned long   st_ctime;
        unsigned long   __pad7;         /* will be high 32 bits of ctime someday */
 
-       unsigned long   __unused1;
-       unsigned long   __unused2;
+       unsigned long long      st_ino;
 };
 
 #endif
index cb2fa6f4d0a2b5b54d2444206147ed964034f8fd..ef16311fe0ab7bc28405dc5cec94a3c1e68a9686 100644 (file)
@@ -45,7 +45,9 @@ struct stat64 {
        unsigned short  st_dev;
        unsigned char   __pad0[10];
 
-       unsigned long   st_ino;
+#define STAT64_HAS_BROKEN_ST_INO       1
+       unsigned long   __st_ino;
+
        unsigned int    st_mode;
        unsigned int    st_nlink;
 
@@ -70,8 +72,7 @@ struct stat64 {
        unsigned long   st_ctime;
        unsigned long   __pad7;         /* will be high 32 bits of ctime someday */
 
-       unsigned long   __unused1;
-       unsigned long   __unused2;
+       unsigned long long      st_ino;
 };
 
 #endif
index ec9f33ba65bbc7c88ba1c25cc52f254a5b46a484..563e53b77df787954a6f70dfac360ba2ea915410 100644 (file)
@@ -271,8 +271,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 #define mb()   __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
 #define rmb()  mb()
 #define wmb()  __asm__ __volatile__ ("": : :"memory")
-#define set_rmb(var, value) do { xchg(&var, value); } while (0)
-#define set_mb(var, value) set_rmb(var, value)
+#define set_mb(var, value) do { xchg(&var, value); } while (0)
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
 /* interrupt control.. */
index 689be6df6f9610cc7bb4396c285048808f0822b1..abffefa016a9235599c473aeb32540189c119bd1 100644 (file)
@@ -96,7 +96,6 @@ ia64_insn_group_barrier (void)
  * Linus just yet.  Grrr...
  */
 #define set_mb(var, value)     do { (var) = (value); mb(); } while (0)
-#define set_rmb(var, value)    do { (var) = (value); mb(); } while (0)
 #define set_wmb(var, value)    do { (var) = (value); mb(); } while (0)
 
 /*
index b28ce37c5f96bc15b6b75f3083181015b911b36c..1d5b008e09d7d40e914c9a4295b0a18b34cdd62d 100644 (file)
@@ -42,10 +42,11 @@ struct stat {
  * insane amounts of padding around dev_t's.
  */
 struct stat64 {
+       unsigned char   __pad0[6];
        unsigned short  st_dev;
-       unsigned char   __pad0[10];
 
-       unsigned long   st_ino;
+       unsigned long long      st_ino;
+
        unsigned int    st_mode;
        unsigned int    st_nlink;
 
index 7b6ae7d16f32273a4065bbed0e492e7b307100ad..64dab98d8ec9f90cd295c0b32a0dc81273857c96 100644 (file)
@@ -80,8 +80,7 @@ asmlinkage void resume(void);
 #define mb()   asm volatile (""   : : :"memory")
 #define rmb()  asm volatile (""   : : :"memory")
 #define wmb()  asm volatile (""   : : :"memory")
-#define set_rmb(var, value)    do { xchg(&var, value); } while (0)
-#define set_mb(var, value)     set_rmb(var, value)
+#define set_mb(var, value)    do { xchg(&var, value); } while (0)
 #define set_wmb(var, value)    do { var = value; wmb(); } while (0)
 
 
index 91a7b05fb2493886684c8234321c911fb9b0e583..c057c09255063e5a6793f7a310922b23409913a1 100644 (file)
@@ -153,9 +153,6 @@ __asm__ __volatile__(                                       \
 #define set_mb(var, value) \
 do { var = value; mb(); } while (0)
 
-#define set_rmb(var, value) \
-do { var = value; rmb(); } while (0)
-
 #define set_wmb(var, value) \
 do { var = value; wmb(); } while (0)
 
index 47e90aec4619bc6fd44747b38e5b91ee44721b08..4b9d9f551a9aeebc3120ff5ca17fcfcb27bd2166 100644 (file)
@@ -154,9 +154,6 @@ __asm__ __volatile__(                                       \
 #define set_mb(var, value) \
 do { var = value; mb(); } while (0)
 
-#define set_rmb(var, value) \
-do { var = value; rmb(); } while (0)
-
 #define set_wmb(var, value) \
 do { var = value; wmb(); } while (0)
 
index 538da77bbe81b42bb60ee4d12ce1be35ab843b66..204b07e6e771e98786e95b45665e5c962fa236fc 100644 (file)
@@ -42,8 +42,7 @@ struct stat {
  */
 struct stat64 {
        unsigned long long st_dev;      /* Device.  */
-       unsigned short int __pad1;
-       unsigned long st_ino;           /* File serial number.  */
+       unsigned long long st_ino;      /* File serial number.  */
        unsigned int st_mode;           /* File mode.  */
        unsigned int st_nlink;          /* Link count.  */
        unsigned int st_uid;            /* User ID of the file's owner.  */
index 162a09a1d181dd9d247f4d9acfa93f884bac3166..153e1c49d29dcb5343836b96fbc5a478877a269e 100644 (file)
@@ -34,7 +34,6 @@
 #define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")
 
 #define set_mb(var, value)     do { var = value; mb(); } while (0)
-#define set_rmb(var, value)    do { var = value; rmb(); } while (0)
 #define set_wmb(var, value)    do { var = value; wmb(); } while (0)
 
 extern void xmon_irq(int, void *, struct pt_regs *);
index e3e5907e9c232c0b2963d1752be04e918da5dad4..be52ef6797bd5fb1a2889dc1d47d022d2887a7ec 100644 (file)
@@ -51,9 +51,9 @@ struct stat {
  */
 struct stat64 {
         unsigned short  st_dev;
-        unsigned char   __pad0[10];
+        unsigned char   __pad0[6];
 
-        unsigned long   st_ino;
+        unsigned long long st_ino;
         unsigned int    st_mode;
         unsigned int    st_nlink;
 
index 26910ac1f571fe12d3e6b0d05f5834b8942aba01..afced6af1f44c51382ef03aadc05fedba81d3eb0 100644 (file)
@@ -117,7 +117,6 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 #define wmb()   eieio()
 
 #define set_mb(var, value)      do { var = value; mb(); } while (0)
-#define set_rmb(var, value)     do { var = value; rmb(); } while (0)
 #define set_wmb(var, value)     do { var = value; wmb(); } while (0)
 
 /* interrupt control.. */
index 3bb876274f934d6f73e7f23a40889d4af903661c..c3ca3b467c68f7f1c47cf8def7ea6e894c7c5e3a 100644 (file)
@@ -88,8 +88,7 @@ extern void __xchg_called_with_bad_pointer(void);
 #define mb()   __asm__ __volatile__ ("": : :"memory")
 #define rmb()  mb()
 #define wmb()  __asm__ __volatile__ ("": : :"memory")
-#define set_rmb(var, value) do { xchg(&var, value); } while (0)
-#define set_mb(var, value) set_rmb(var, value)
+#define set_mb(var, value) do { xchg(&var, value); } while (0)
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
 /* Interrupt Control */
index 4b0dd7fa4d6b9a48103319c18e81fd9b8f17b1d7..a70d4df3c779c863f376267dc20c31970b543a21 100644 (file)
@@ -41,9 +41,9 @@ struct stat {
 struct stat64 {
        unsigned char   __pad0[6];
        unsigned short  st_dev;
-       unsigned char   __pad1[4];
 
-       unsigned int    st_ino;
+       unsigned long long      st_ino;
+
        unsigned int    st_mode;
        unsigned int    st_nlink;
 
index 69cc06de2307c28d3c95407dae9c6a173a02c681..4174294ca1349433d51adccb90529d03199ce85f 100644 (file)
@@ -279,7 +279,6 @@ extern void __global_restore_flags(unsigned long flags);
 #define rmb()  mb()
 #define wmb()  mb()
 #define set_mb(__var, __value)  do { __var = __value; mb(); } while(0)
-#define set_rmb(__var, __value) set_mb(__var, __value)
 #define set_wmb(__var, __value) set_mb(__var, __value)
 
 #define nop() __asm__ __volatile__ ("nop");
index 0fd68589b48ceabe1e95017e615af519b2d35362..4a4fabac05b70b9c97bdf96c3f56c49b8dd222ef 100644 (file)
@@ -48,9 +48,9 @@ struct stat {
 struct stat64 {
        unsigned char   __pad0[6];
        unsigned short  st_dev;
-       unsigned char   __pad1[4];
 
-       unsigned int    st_ino;
+       unsigned long long      st_ino;
+
        unsigned int    st_mode;
        unsigned int    st_nlink;
 
index 257bca48d4036e2733298ae941eedcb39748400c..cf5cd0b0235dcfa6a604b972907ec0e4f6b5a929 100644 (file)
@@ -104,8 +104,6 @@ extern void __global_restore_flags(unsigned long flags);
 #define wmb()          membar("#StoreLoad | #StoreStore")
 #define set_mb(__var, __value) \
        do { __var = __value; membar("#StoreLoad | #StoreStore"); } while(0)
-#define set_rmb(__var, __value) \
-       do { __var = __value; membar("#StoreLoad"); } while(0)
 #define set_wmb(__var, __value) \
        do { __var = __value; membar("#StoreStore"); } while(0)
 
index a33f33768e42df0c21225fcbdbd27c36d1297f6f..d0e5c62670998ad1bc72e30c66642ecd23b70c6e 100644 (file)
@@ -91,6 +91,9 @@ extern int max_super_blocks, nr_super_blocks;
                           */
 #define FS_NOMOUNT     16 /* Never mount from userland */
 #define FS_LITTER      32 /* Keeps the tree in dcache */
+#define FS_ODD_RENAME  32768   /* Temporary stuff; will go away as soon
+                                 * as nfs_rename() will be cleaned up
+                                 */
 /*
  * These are the fs-independent mount-flags: up to 16 flags are supported
  */
@@ -101,17 +104,9 @@ extern int max_super_blocks, nr_super_blocks;
 #define MS_SYNCHRONOUS 16      /* Writes are synced at once */
 #define MS_REMOUNT     32      /* Alter flags of a mounted FS */
 #define MS_MANDLOCK    64      /* Allow mandatory locks on an FS */
-#define S_QUOTA                128     /* Quota initialized for file/directory/symlink */
-#define S_APPEND       256     /* Append-only file */
-#define S_IMMUTABLE    512     /* Immutable file */
 #define MS_NOATIME     1024    /* Do not update access times. */
 #define MS_NODIRATIME  2048    /* Do not update directory access times */
 
-#define MS_ODD_RENAME  32768   /* Temporary stuff; will go away as soon
-                                 * as nfs_rename() will be cleaned up
-                                 */
-#define S_DEAD         (1<<16) /* removed, but still open directory */
-
 /*
  * Flags that can be altered by MS_REMOUNT
  */
@@ -124,6 +119,15 @@ extern int max_super_blocks, nr_super_blocks;
 #define MS_MGC_VAL 0xC0ED0000  /* magic flag number to indicate "new" flags */
 #define MS_MGC_MSK 0xffff0000  /* magic flag number mask */
 
+/* Inode flags - they have nothing to superblock flags now */
+
+#define S_SYNC         1       /* Writes are synced at once */
+#define S_NOATIME      2       /* Do not update access times */
+#define S_QUOTA                4       /* Quota initialized for file */
+#define S_APPEND       8       /* Append-only file */
+#define S_IMMUTABLE    16      /* Immutable file */
+#define S_DEAD         32      /* removed, but still open directory */
+
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
  * flags just means all the inodes inherit those flags by default. It might be
@@ -137,20 +141,19 @@ extern int max_super_blocks, nr_super_blocks;
  * i_flags updated.  Hence, i_flags no longer inherit the superblock mount
  * flags, so these have to be checked separately. -- rmk@arm.uk.linux.org
  */
-#define __IS_FLG(inode,flg) (((inode)->i_sb && (inode)->i_sb->s_flags & (flg)) \
-                               || (inode)->i_flags & (flg))
+#define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg))
 
-#define IS_RDONLY(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & MS_RDONLY))
+#define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY)
 #define IS_NOSUID(inode)       __IS_FLG(inode, MS_NOSUID)
 #define IS_NODEV(inode)                __IS_FLG(inode, MS_NODEV)
 #define IS_NOEXEC(inode)       __IS_FLG(inode, MS_NOEXEC)
-#define IS_SYNC(inode)         __IS_FLG(inode, MS_SYNCHRONOUS)
+#define IS_SYNC(inode)         (__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC))
 #define IS_MANDLOCK(inode)     __IS_FLG(inode, MS_MANDLOCK)
 
 #define IS_QUOTAINIT(inode)    ((inode)->i_flags & S_QUOTA)
 #define IS_APPEND(inode)       ((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode)    ((inode)->i_flags & S_IMMUTABLE)
-#define IS_NOATIME(inode)      __IS_FLG(inode, MS_NOATIME)
+#define IS_NOATIME(inode)      (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
 #define IS_NODIRATIME(inode)   __IS_FLG(inode, MS_NODIRATIME)
 
 #define IS_DEADDIR(inode)      ((inode)->i_flags & S_DEAD)
index 4fbe523ab45abf765cac55f93a9146e3fa8469ff..99ab9c44ec7aae70e226a3448b4c34b722eadd41 100644 (file)
@@ -85,12 +85,23 @@ static __inline__ void __list_del(struct list_head * prev,
 /**
  * list_del - deletes entry from list.
  * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
  */
 static __inline__ void list_del(struct list_head *entry)
 {
        __list_del(entry->prev, entry->next);
 }
 
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.n 
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       INIT_LIST_HEAD(entry); 
+}
+
 /**
  * list_empty - tests whether a list is empty
  * @head: the list to test.
index 6c080adba18e04ef66a8a0bcd0c455a4c91bcd13..e630aba706f5806faaba20746abccdc5a430477d 100644 (file)
@@ -36,5 +36,3 @@ void do_emergency_sync(void);
 #else
 #define CHECK_EMERGENCY_SYNC
 #endif
-
-extern int sysrq_enabled;
index 93ad4d11d15a65ce948543560c9eae5b30673e96..2752cb004c0f6cd2a4701b434f410c3e50b6e83a 100644 (file)
@@ -26,6 +26,7 @@ int umsdos_newhidden (struct dentry *, struct umsdos_info *);
 int umsdos_delentry (struct dentry *, struct umsdos_info *, int);
 int umsdos_findentry (struct dentry *, struct umsdos_info *, int);
 int umsdos_isempty (struct dentry *);
+int umsdos_writeentry (struct dentry *, struct umsdos_info *, int);
 
 /* file.c 25/01/95 02.25.38 */
 
@@ -36,7 +37,7 @@ void UMSDOS_write_inode (struct inode *, int);
 int UMSDOS_notify_change (struct dentry *, struct iattr *attr);
 int umsdos_notify_change_locked(struct dentry *, struct iattr *attr);
 void UMSDOS_put_inode (struct inode *);
-int UMSDOS_statfs (struct super_block *, struct statfs *, int);
+int UMSDOS_statfs (struct super_block *, struct statfs *);
 struct super_block *UMSDOS_read_super (struct super_block *, void *, int);
 void UMSDOS_put_super (struct super_block *);
 
index 27e6fe7df7eaa3caee78ffc3957ed768c05ed4c0..b50c5890c70a7f37e434ba83ba8f8d214e8a4351 100644 (file)
@@ -576,7 +576,6 @@ extern void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int i
 
 extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
 
-extern void usb_init_root_hub(struct usb_device *dev);
 extern int usb_root_hub_string(int id, int serial, char *type, __u8 *data, int len);
 extern void usb_connect(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
index 3f59386e5fb68e1c809adf2653bfb096e2e8b7d8..8fc459453a542639851cada57754ae1a66a9bfb0 100644 (file)
@@ -108,7 +108,12 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
        }
 
        /* Drop the "current user" thing */
-       free_uid(current);
+       {
+               struct user_struct *user = current->user;
+               current->user = INIT_USER;
+               atomic_inc(&current->user->__count);
+               free_uid(user);
+       }
 
        /* Give kmod all effective privileges.. */
        current->uid = current->euid = current->fsuid = 0;
index 68d786e89c636a4b908381f77f40143a5a3ef05d..6d99e08ab9336835b1d17122fae9cf40ec5643c2 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
-
 extern void timer_bh(void);
 extern void tqueue_bh(void);
 extern void immediate_bh(void);
index e8afe0919e6e0ab59b4c3477437325d702f76cdc..19e068c65f79b97f22e2b4de870bfaea1a5859d5 100644 (file)
@@ -198,10 +198,15 @@ void tasklet_init(struct tasklet_struct *t,
 
 void tasklet_kill(struct tasklet_struct *t)
 {
+       if (in_interrupt())
+               printk("Attempt to kill tasklet from interrupt\n");
+
        while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-               if (in_interrupt())
-                       panic("Attempt to kill tasklet from interrupt\n");
-               schedule();
+               current->state = TASK_RUNNING;
+               do {
+                       current->policy |= SCHED_YIELD;
+                       schedule();
+               } while (test_bit(TASKLET_STATE_SCHED, &t->state));
        }
        tasklet_unlock_wait(t);
        clear_bit(TASKLET_STATE_SCHED, &t->state);
index 4290619d092129e9562dcb42d2903cc956ae781f..b475af7ed4f5b8eeefaacff8cdd27c17f93776c7 100644 (file)
@@ -46,6 +46,7 @@ extern int bdf_prm[], bdflush_min[], bdflush_max[];
 extern int sysctl_overcommit_memory;
 extern int max_threads;
 extern int nr_queued_signals, max_queued_signals;
+extern int sysrq_enabled;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
index 688682aad0c3b61a41874bf907ff6743522fabca..43f1de720f7f18481c4df1c3856963bb46d4deb7 100644 (file)
@@ -294,7 +294,13 @@ int shrink_mmap(int priority, int gfp_mask)
                 * of zone - it's old.
                 */
                if (page->buffers) {
-                       int wait = ((gfp_mask & __GFP_IO) && (nr_dirty-- < 0));
+                       int wait;
+                       /*
+                        * 0 - free it if can do so without IO
+                        * 1 - start write-out of dirty buffers
+                        * 2 - wait for locked buffers
+                        */
+                       wait = (gfp_mask & __GFP_IO) ? (nr_dirty-- < 0) ? 2 : 1 : 0;
                        if (!try_to_free_buffers(page, wait))
                                goto unlock_continue;
                        /* page was locked, inode can't go away under us */
index 91b45ae5a3bc5150d150d932cf236a7d4b998bb0..834968569a4a4761331489baf0a3a51726a0a0ea 100644 (file)
@@ -86,9 +86,8 @@ struct page * replace_with_highmem(struct page * page)
        copy_page((void *)vaddr, (void *)page_address(page));
        kunmap(highpage);
 
-       /* Preserve the caching of the swap_entry. */
-       highpage->index = page->index;
-       highpage->mapping = page->mapping;
+       if (page->mapping)
+               BUG();
 
        /*
         * We can just forget the old page since 
index 7843d553b0d6f69c419438b513ddd465bf47e422..1e19a9109c2dff9102bc7319d646ba8e4a2ad865 100644 (file)
@@ -385,7 +385,7 @@ unsigned int nr_free_buffer_pages (void)
        zone_t *zone;
        int i;
 
-       sum = nr_lru_pages;
+       sum = nr_lru_pages / 3;
        for (i = 0; i < NUMNODES; i++)
                for (zone = NODE_DATA(i)->node_zones; zone <= NODE_DATA(i)->node_zones+ZONE_NORMAL; zone++)
                        sum += zone->free_pages;
index 5d3a7f23e80232122e8c509dcacc2f0e10b59101..a84e73f2fe72bad88217d93186de51239250b4fa 100644 (file)
@@ -315,10 +315,12 @@ static void unuse_process(struct mm_struct * mm,
         */
        if (!mm)
                return;
+       vmlist_access_lock(mm);
        for (vma = mm->mmap; vma; vma = vma->vm_next) {
                pgd_t * pgd = pgd_offset(mm, vma->vm_start);
                unuse_vma(vma, pgd, entry, page);
        }
+       vmlist_access_unlock(mm);
        return;
 }