summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-08 18:02:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-08 18:02:00 +0000
commit02f8110d6a247d53b489b29eec8a35c85e713c6b (patch)
tree9cb65032a35c2d1af581deaac73dfa2540b2fbdd
parentb62a3d8e8a9d02ff6f9103358b7a9c2c3d56c653 (diff)
Merge with Linux 2.4.0-test6-pre2.
-rw-r--r--MAINTAINERS2
-rw-r--r--Makefile4
-rw-r--r--arch/i386/config.in2
-rw-r--r--arch/i386/defconfig4
-rw-r--r--arch/i386/kernel/irq.c18
-rw-r--r--drivers/char/drm/Config.in2
-rw-r--r--drivers/char/drm/Makefile99
-rw-r--r--drivers/char/drm/drmP.h6
-rw-r--r--drivers/char/drm/gamma_drv.c16
-rw-r--r--drivers/char/drm/i810_context.c2
-rw-r--r--drivers/char/drm/i810_dma.c15
-rw-r--r--drivers/char/drm/i810_drv.c19
-rw-r--r--drivers/char/drm/mga_context.c2
-rw-r--r--drivers/char/drm/mga_drv.c19
-rw-r--r--drivers/char/drm/r128_context.c6
-rw-r--r--drivers/char/drm/r128_drv.c23
-rw-r--r--drivers/char/drm/tdfx_context.c2
-rw-r--r--drivers/char/drm/tdfx_drv.c12
-rw-r--r--drivers/char/drm/vm.c10
-rw-r--r--drivers/char/keyboard.c3
-rw-r--r--drivers/char/sysrq.c6
-rw-r--r--drivers/ide/ide-features.c6
-rw-r--r--drivers/ide/ide-probe.c67
-rw-r--r--drivers/net/pcmcia/ray_cs.c12
-rw-r--r--drivers/pci/pci.ids2
-rw-r--r--drivers/pcmcia/Makefile8
-rw-r--r--drivers/pcmcia/yenta.c6
-rw-r--r--drivers/sbus/char/sunkbd.c5
-rw-r--r--drivers/usb/bluetooth.c669
-rw-r--r--drivers/usb/storage/protocol.c75
-rw-r--r--drivers/usb/storage/protocol.h3
-rw-r--r--drivers/usb/storage/scsiglue.c3
-rw-r--r--drivers/usb/storage/sddr09.c534
-rw-r--r--drivers/usb/storage/sddr09.h7
-rw-r--r--drivers/usb/storage/transport.c13
-rw-r--r--drivers/usb/storage/usb.c20
-rw-r--r--drivers/usb/storage/usb.h4
-rw-r--r--drivers/usb/usb-uhci.c78
-rw-r--r--drivers/usb/usb.c50
-rw-r--r--fs/autofs4/root.c2
-rw-r--r--fs/buffer.c47
-rw-r--r--fs/dcache.c13
-rw-r--r--fs/exec.c16
-rw-r--r--fs/ext2/ialloc.c2
-rw-r--r--fs/ext2/inode.c545
-rw-r--r--fs/ext2/ioctl.c8
-rw-r--r--fs/namei.c2
-rw-r--r--fs/nfs/inode.c4
-rw-r--r--fs/stat.c3
-rw-r--r--fs/umsdos/emd.c20
-rw-r--r--fs/umsdos/inode.c26
-rw-r--r--fs/umsdos/ioctl.c10
-rw-r--r--fs/umsdos/namei.c13
-rw-r--r--include/asm-alpha/fpu.h2
-rw-r--r--include/asm-arm/stat.h6
-rw-r--r--include/asm-i386/stat.h7
-rw-r--r--include/asm-i386/system.h3
-rw-r--r--include/asm-ia64/system.h1
-rw-r--r--include/asm-m68k/stat.h5
-rw-r--r--include/asm-m68k/system.h3
-rw-r--r--include/asm-mips/system.h3
-rw-r--r--include/asm-mips64/system.h3
-rw-r--r--include/asm-ppc/stat.h3
-rw-r--r--include/asm-ppc/system.h1
-rw-r--r--include/asm-s390/stat.h4
-rw-r--r--include/asm-s390/system.h1
-rw-r--r--include/asm-sh/system.h3
-rw-r--r--include/asm-sparc/stat.h4
-rw-r--r--include/asm-sparc/system.h1
-rw-r--r--include/asm-sparc64/stat.h4
-rw-r--r--include/asm-sparc64/system.h2
-rw-r--r--include/linux/fs.h29
-rw-r--r--include/linux/list.h11
-rw-r--r--include/linux/sysrq.h2
-rw-r--r--include/linux/umsdos_fs.p3
-rw-r--r--include/linux/usb.h1
-rw-r--r--kernel/kmod.c7
-rw-r--r--kernel/sched.c1
-rw-r--r--kernel/softirq.c11
-rw-r--r--kernel/sysctl.c1
-rw-r--r--mm/filemap.c8
-rw-r--r--mm/highmem.c5
-rw-r--r--mm/page_alloc.c2
-rw-r--r--mm/swapfile.c2
84 files changed, 1775 insertions, 909 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index f521bc0d5..6db8aad31 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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
diff --git a/Makefile b/Makefile
index a26e90178..6cf982aef 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test6-pre1
+EXTRAVERSION = -test6-pre2
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -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
diff --git a/arch/i386/config.in b/arch/i386/config.in
index 5f6ae670d..d9fcd91db 100644
--- a/arch/i386/config.in
+++ b/arch/i386/config.in
@@ -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
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 4ead92e81..38dd1d251 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -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
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index bfb2a6841..fcc0a72f5 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -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);
diff --git a/drivers/char/drm/Config.in b/drivers/char/drm/Config.in
index c2e91ef83..d24d65970 100644
--- a/drivers/char/drm/Config.in
+++ b/drivers/char/drm/Config.in
@@ -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
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index 5ae783f3e..b1b8d9768 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -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
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index afc4fd43e..3e5149c91 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -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 */
diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c
index 850cc5118..32b2ba2b9 100644
--- a/drivers/char/drm/gamma_drv.c
+++ b/drivers/char/drm/gamma_drv.c
@@ -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);
}
diff --git a/drivers/char/drm/i810_context.c b/drivers/char/drm/i810_context.c
index 689814db5..85c0877b6 100644
--- a/drivers/char/drm/i810_context.c
+++ b/drivers/char/drm/i810_context.c
@@ -29,8 +29,6 @@
*
*/
-#include <linux/sched.h>
-
#define __NO_VERSION__
#include "drmP.h"
#include "i810_drv.h"
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 2882ca09c..f3d9db43e 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -33,10 +33,7 @@
#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);
diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c
index eaa71a66b..5cab071e4 100644
--- a/drivers/char/drm/i810_drv.c
+++ b/drivers/char/drm/i810_drv.c
@@ -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;
}
diff --git a/drivers/char/drm/mga_context.c b/drivers/char/drm/mga_context.c
index d02592740..9a73e6c14 100644
--- a/drivers/char/drm/mga_context.c
+++ b/drivers/char/drm/mga_context.c
@@ -29,8 +29,6 @@
*
*/
-#include <linux/sched.h>
-
#define __NO_VERSION__
#include "drmP.h"
#include "mga_drv.h"
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index 45653aa56..7aae6f3e9 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -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;
}
diff --git a/drivers/char/drm/r128_context.c b/drivers/char/drm/r128_context.c
index f11453ba1..2dd716d4b 100644
--- a/drivers/char/drm/r128_context.c
+++ b/drivers/char/drm/r128_context.c
@@ -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);
}
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index b382a13c5..6b1b19d5e 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -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;
}
diff --git a/drivers/char/drm/tdfx_context.c b/drivers/char/drm/tdfx_context.c
index c8d6e50ea..d6903c0ae 100644
--- a/drivers/char/drm/tdfx_context.c
+++ b/drivers/char/drm/tdfx_context.c
@@ -30,8 +30,6 @@
*
*/
-#include <linux/sched.h>
-
#define __NO_VERSION__
#include "drmP.h"
#include "tdfx_drv.h"
diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c
index 896705e97..ba8c40ceb 100644
--- a/drivers/char/drm/tdfx_drv.c
+++ b/drivers/char/drm/tdfx_drv.c
@@ -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) {
diff --git a/drivers/char/drm/vm.c b/drivers/char/drm/vm.c
index 01487f965..5ee9e3242 100644
--- a/drivers/char/drm/vm.c
+++ b/drivers/char/drm/vm.c
@@ -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
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 7e5a654c2..f889378a3 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -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;
}
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 67deb7f27..9650457c0 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -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;
diff --git a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
index e46d16e7f..fa765d76f 100644
--- a/drivers/ide/ide-features.c
+++ b/drivers/ide/ide-features.c
@@ -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 */
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 168895fb5..decbc9f8d 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -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
diff --git a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c
index aeee5e561..36b11f907 100644
--- a/drivers/net/pcmcia/ray_cs.c
+++ b/drivers/net/pcmcia/ray_cs.c
@@ -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);
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 288caf5ce..96b4ba97c 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -1910,6 +1910,7 @@
1105 Sigma Designs, Inc.
8300 REALmagic Hollywood Plus DVD Decoder
1106 VIA Technologies, Inc.
+ 0305 VT8363 [KT133]
0391 VT8371 [KX133]
0501 VT8501
0505 VT82C505
@@ -1953,6 +1954,7 @@
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]
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 649e50a14..b1ac19022 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -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
diff --git a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c
index 6b0a9e1ae..4d3aa947e 100644
--- a/drivers/pcmcia/yenta.c
+++ b/drivers/pcmcia/yenta.c
@@ -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 */
}
/*
diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c
index 191194287..cc71cab7e 100644
--- a/drivers/sbus/char/sunkbd.c
+++ b/drivers/sbus/char/sunkbd.c
@@ -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;
}
diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c
index bd7be69e8..4ee29a702 100644
--- a/drivers/usb/bluetooth.c
+++ b/drivers/usb/bluetooth.c
@@ -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.
@@ -49,17 +62,16 @@
#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;
}
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 5e7a5a23b..aee6b420e 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -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)
@@ -50,9 +50,58 @@
#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);
}
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
index 1a343af41..239d37983 100644
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -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*);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 25328669b..7517d63bc 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -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)
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 275712961..6bf9f1477 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -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);
diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
index 76a749528..ecd9b7611 100644
--- a/drivers/usb/storage/sddr09.h
+++ b/drivers/usb/storage/sddr09.h
@@ -28,4 +28,11 @@
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
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 69dfcfde8..a0fb2407c 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -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,
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index c82d7e914..fc70bc72a 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -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 */
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 8c7008fa9..b376d39ee 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -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 */
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index e82fa78a0..bd721cba2 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -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);
}
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 0154d7f48..777e2d650 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -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);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index f3c3e9e12..72b5e1b27 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -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);
diff --git a/fs/buffer.c b/fs/buffer.c
index 341dfe591..ad0a04e68 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -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;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 9be3e8cdc..e2bcbe6a3 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -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? */
diff --git a/fs/exec.c b/fs/exec.c
index f7745f9de..d162f8852 100644
--- 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;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 3c95ccd70..c99f7f2c8 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -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);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index c7234e7b5..678eb4d28 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -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) {
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 0b456820a..6528f1f74 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -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;
diff --git a/fs/namei.c b/fs/namei.c
index 55658cd6b..97d9e2d22 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -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;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 993dcc1a4..db7c110e5 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -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);
diff --git a/fs/stat.c b/fs/stat.c
index 3ca996ed1..18d1f7a88 100644
--- 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;
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index 84e8ca99f..9e4ace724 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -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;
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index bb48b6bf2..12b34e849 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -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);
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c
index 17d38c2dd..8731f8ecd 100644
--- a/fs/umsdos/ioctl.c
+++ b/fs/umsdos/ioctl.c
@@ -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)
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 4102ce6e0..c29387f3c 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -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.
*/
diff --git a/include/asm-alpha/fpu.h b/include/asm-alpha/fpu.h
index b9d8faa61..b02a78594 100644
--- a/include/asm-alpha/fpu.h
+++ b/include/asm-alpha/fpu.h
@@ -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"
diff --git a/include/asm-arm/stat.h b/include/asm-arm/stat.h
index 5346b0223..77a16fa5c 100644
--- a/include/asm-arm/stat.h
+++ b/include/asm-arm/stat.h
@@ -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
diff --git a/include/asm-i386/stat.h b/include/asm-i386/stat.h
index cb2fa6f4d..ef16311fe 100644
--- a/include/asm-i386/stat.h
+++ b/include/asm-i386/stat.h
@@ -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
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index ec9f33ba6..563e53b77 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -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.. */
diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h
index 689be6df6..abffefa01 100644
--- a/include/asm-ia64/system.h
+++ b/include/asm-ia64/system.h
@@ -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)
/*
diff --git a/include/asm-m68k/stat.h b/include/asm-m68k/stat.h
index b28ce37c5..1d5b008e0 100644
--- a/include/asm-m68k/stat.h
+++ b/include/asm-m68k/stat.h
@@ -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;
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
index 7b6ae7d16..64dab98d8 100644
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -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)
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 91a7b05fb..c057c0925 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -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)
diff --git a/include/asm-mips64/system.h b/include/asm-mips64/system.h
index 47e90aec4..4b9d9f551 100644
--- a/include/asm-mips64/system.h
+++ b/include/asm-mips64/system.h
@@ -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)
diff --git a/include/asm-ppc/stat.h b/include/asm-ppc/stat.h
index 538da77bb..204b07e6e 100644
--- a/include/asm-ppc/stat.h
+++ b/include/asm-ppc/stat.h
@@ -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. */
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index 162a09a1d..153e1c49d 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -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 *);
diff --git a/include/asm-s390/stat.h b/include/asm-s390/stat.h
index e3e5907e9..be52ef679 100644
--- a/include/asm-s390/stat.h
+++ b/include/asm-s390/stat.h
@@ -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;
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index 26910ac1f..afced6af1 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -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.. */
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index 3bb876274..c3ca3b467 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -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 */
diff --git a/include/asm-sparc/stat.h b/include/asm-sparc/stat.h
index 4b0dd7fa4..a70d4df3c 100644
--- a/include/asm-sparc/stat.h
+++ b/include/asm-sparc/stat.h
@@ -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;
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index 69cc06de2..4174294ca 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -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");
diff --git a/include/asm-sparc64/stat.h b/include/asm-sparc64/stat.h
index 0fd68589b..4a4fabac0 100644
--- a/include/asm-sparc64/stat.h
+++ b/include/asm-sparc64/stat.h
@@ -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;
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 257bca48d..cf5cd0b02 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -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)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a33f33768..d0e5c6267 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -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)
diff --git a/include/linux/list.h b/include/linux/list.h
index 4fbe523ab..99ab9c44e 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -85,6 +85,7 @@ 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)
{
@@ -92,6 +93,16 @@ static __inline__ void list_del(struct list_head *entry)
}
/**
+ * 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.
*/
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
index 6c080adba..e630aba70 100644
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -36,5 +36,3 @@ void do_emergency_sync(void);
#else
#define CHECK_EMERGENCY_SYNC
#endif
-
-extern int sysrq_enabled;
diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p
index 93ad4d11d..2752cb004 100644
--- a/include/linux/umsdos_fs.p
+++ b/include/linux/umsdos_fs.p
@@ -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 *);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 27e6fe7df..b50c5890c 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -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 **);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 3f59386e5..8fc459453 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -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;
diff --git a/kernel/sched.c b/kernel/sched.c
index 68d786e89..6d99e08ab 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -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);
diff --git a/kernel/softirq.c b/kernel/softirq.c
index e8afe0919..19e068c65 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -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);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 4290619d0..b475af7ed 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -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;
diff --git a/mm/filemap.c b/mm/filemap.c
index 688682aad..43f1de720 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -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 */
diff --git a/mm/highmem.c b/mm/highmem.c
index 91b45ae5a..834968569 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -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
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7843d553b..1e19a9109 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -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;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 5d3a7f23e..a84e73f2f 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -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;
}