summaryrefslogtreecommitdiffstats
path: root/drivers
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 /drivers
parentb62a3d8e8a9d02ff6f9103358b7a9c2c3d56c653 (diff)
Merge with Linux 2.4.0-test6-pre2.
Diffstat (limited to 'drivers')
-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
34 files changed, 1309 insertions, 495 deletions
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);