summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-08-28 22:00:09 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-08-28 22:00:09 +0000
commit1a1d77dd589de5a567fa95e36aa6999c704ceca4 (patch)
tree141e31f89f18b9fe0831f31852e0435ceaccafc5 /drivers/usb
parentfb9c690a18b3d66925a65b17441c37fa14d4370b (diff)
Merge with 2.4.0-test7.
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Config.in28
-rw-r--r--drivers/usb/Makefile60
-rw-r--r--drivers/usb/bluetooth.c22
-rw-r--r--drivers/usb/dc2xx.c134
-rw-r--r--drivers/usb/devio.c3
-rw-r--r--drivers/usb/evdev.c356
-rw-r--r--drivers/usb/hid.c69
-rw-r--r--drivers/usb/hid.h23
-rw-r--r--drivers/usb/iforce.c336
-rw-r--r--drivers/usb/inode.c14
-rw-r--r--drivers/usb/input.c426
-rw-r--r--drivers/usb/joydev.c497
-rw-r--r--drivers/usb/keybdev.c200
-rw-r--r--drivers/usb/mousedev.c486
-rw-r--r--drivers/usb/pegasus.c385
-rw-r--r--drivers/usb/printer.c108
-rw-r--r--drivers/usb/serial/digi_acceleport.c723
-rw-r--r--drivers/usb/serial/keyspan_pda.c188
-rw-r--r--drivers/usb/serial/usb-serial.h4
-rw-r--r--drivers/usb/serial/visor.c70
-rw-r--r--drivers/usb/storage/Makefile6
-rw-r--r--drivers/usb/storage/dpcm.c83
-rw-r--r--drivers/usb/storage/dpcm.h34
-rw-r--r--drivers/usb/storage/scsiglue.c8
-rw-r--r--drivers/usb/storage/shuttle_usbat.c2
-rw-r--r--drivers/usb/storage/shuttle_usbat.h2
-rw-r--r--drivers/usb/storage/transport.c435
-rw-r--r--drivers/usb/storage/transport.h5
-rw-r--r--drivers/usb/storage/usb.c285
-rw-r--r--drivers/usb/storage/usb.h20
-rw-r--r--drivers/usb/usb-core.c13
-rw-r--r--drivers/usb/usb-ohci.c171
-rw-r--r--drivers/usb/usb-ohci.h6
-rw-r--r--drivers/usb/usb-uhci.c6
-rw-r--r--drivers/usb/usb.c59
-rw-r--r--drivers/usb/usbkbd.c37
36 files changed, 2084 insertions, 3220 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 1edbfcb44..496faba61 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -68,31 +68,23 @@ comment 'USB Devices'
dep_tristate ' DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate ' PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET
- dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
+ dep_tristate ' USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV
dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
fi
-comment 'USB HID'
- dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
- if [ "$CONFIG_USB_HID" != "y" ]; then
- dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB
- dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB
- fi
- dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB
- dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_USB
- if [ "$CONFIG_INPUT_IFORCE_USB" != "n" ]; then
- define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_USB
+ comment 'USB Human Interface Devices (HID)'
+ if [ "$CONFIG_INPUT" = "n" ]; then
+ comment ' Input core support is needed for USB HID'
+ else
+ dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
+ if [ "$CONFIG_USB_HID" != "y" ]; then
+ dep_tristate ' USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
+ dep_tristate ' USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
fi
- dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB
- dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
- if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
- int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
- int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
+ dep_tristate ' Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
fi
- dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB
- dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB
fi
endmenu
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 5831dd1d9..7112ae635 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -17,7 +17,7 @@ O_OBJS :=
# Objects that export symbols.
-export-objs := usb.o input.o
+export-objs := usb.o
# Multipart objects.
@@ -37,27 +37,6 @@ obj-m :=
obj-n :=
obj- :=
-# Object files in subdirectories
-
-ifeq ($(CONFIG_USB_SERIAL),y)
- SUB_DIRS += serial
- obj-y += serial/usb-serial.o
-else
- ifeq ($(CONFIG_USB_SERIAL),m)
- MOD_IN_SUB_DIRS += serial
- endif
-endif
-
-ifeq ($(CONFIG_USB_STORAGE),y)
- SUB_DIRS += storage
- obj-y += storage/usb-storage.o
-else
- ifeq ($(CONFIG_USB_STORAGE),m)
- MOD_IN_SUB_DIRS += storage
- endif
-endif
-
-
# Each configuration option enables a list of files.
obj-$(CONFIG_USB) += usbcore.o
@@ -65,15 +44,10 @@ obj-$(CONFIG_USB_UHCI) += usb-uhci.o
obj-$(CONFIG_USB_UHCI_ALT) += uhci.o
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
-obj-$(CONFIG_USB_MOUSE) += usbmouse.o input.o
-obj-$(CONFIG_USB_HID) += hid.o input.o
-obj-$(CONFIG_USB_KBD) += usbkbd.o input.o
-obj-$(CONFIG_USB_WACOM) += wacom.o input.o
-obj-$(CONFIG_INPUT_IFORCE) += iforce.o input.o
-obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o input.o
-obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o input.o
-obj-$(CONFIG_INPUT_JOYDEV) += joydev.o input.o
-obj-$(CONFIG_INPUT_EVDEV) += evdev.o input.o
+obj-$(CONFIG_USB_MOUSE) += usbmouse.o
+obj-$(CONFIG_USB_HID) += hid.o
+obj-$(CONFIG_USB_KBD) += usbkbd.o
+obj-$(CONFIG_USB_WACOM) += wacom.o
obj-$(CONFIG_USB_SCANNER) += scanner.o
obj-$(CONFIG_USB_ACM) += acm.o
@@ -92,6 +66,26 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_USB_MICROTEK) += microtek.o
obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o
+# Object files in subdirectories
+
+ifeq ($(CONFIG_USB_SERIAL),y)
+ SUB_DIRS += serial
+ obj-y += serial/usb-serial.o
+else
+ ifeq ($(CONFIG_USB_SERIAL),m)
+ MOD_IN_SUB_DIRS += serial
+ endif
+endif
+
+ifeq ($(CONFIG_USB_STORAGE),y)
+ SUB_DIRS += storage
+ obj-y += storage/usb-storage.o
+else
+ ifeq ($(CONFIG_USB_STORAGE),m)
+ MOD_IN_SUB_DIRS += storage
+ endif
+endif
+
# Extract lists of the multi-part drivers.
# The 'int-*' lists are the intermediate files used to build the multi's.
@@ -111,8 +105,8 @@ obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y)
# Translate to Rules.make lists.
-O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
-OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+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)))
diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c
index 4ee29a702..fd239671b 100644
--- a/drivers/usb/bluetooth.c
+++ b/drivers/usb/bluetooth.c
@@ -1,5 +1,5 @@
/*
- * bluetooth.c Version 0.3
+ * bluetooth.c Version 0.4
*
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
@@ -7,6 +7,13 @@
* USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
*
*
+ * (07/11/2000) Version 0.4 gkh
+ * Fixed bug in disconnect for when we call tty_hangup
+ * Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not
+ * getting attached to the control urb properly.
+ * Fixed bug in bluetooth_write where we pay attention to the result
+ * of bluetooth_ctrl_msg.
+ *
* (08/03/2000) Version 0.3 gkh mdc
* Merged in Mark's changes to make the driver play nice with the Axis
* stack.
@@ -251,7 +258,7 @@ static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int
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);
+ (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, bluetooth);
/* send it down the pipe */
status = usb_submit_urb(urb);
@@ -400,7 +407,10 @@ static int bluetooth_write (struct tty_struct * tty, int from_user, const unsign
else
memcpy (new_buffer, buf+1, count-1);
- bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1);
+ if (bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1) != 0) {
+ kfree (new_buffer);
+ return 0;
+ }
/* need to free new_buffer somehow... FIXME */
return count;
@@ -1099,6 +1109,9 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
int i;
if (bluetooth) {
+ if ((bluetooth->active) && (bluetooth->tty))
+ tty_hangup(bluetooth->tty);
+
bluetooth->active = 0;
if (bluetooth->read_urb) {
@@ -1117,9 +1130,6 @@ static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
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]);
diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c
index bb960a4af..67a55ab46 100644
--- a/drivers/usb/dc2xx.c
+++ b/drivers/usb/dc2xx.c
@@ -43,6 +43,7 @@
* added timeouts to bulk_msg calls. Minor updates, docs.
* 03 Nov, 1999 -- update for 2.3.25 kernel API changes.
* 08 Jan, 2000 .. multiple camera support
+ * 12 Aug, 2000 .. add some real locking, remove an Oops
*
* Thanks to: the folk who've provided USB product IDs, sent in
* patches, and shared their sucesses!
@@ -60,7 +61,6 @@
#include <linux/module.h>
#undef DEBUG
#include <linux/usb.h>
-#include <linux/smp_lock.h>
@@ -114,7 +114,7 @@ struct camera_state {
int outEP; /* write endpoint */
const struct camera *info; /* DC-240, etc */
int subminor; /* which minor dev #? */
- int isActive; /* I/O taking place? */
+ struct semaphore sem; /* locks this struct */
/* this is non-null iff the device is open */
char *buf; /* buffer for I/O */
@@ -127,21 +127,25 @@ struct camera_state {
/* Support multiple cameras, possibly of different types. */
static struct camera_state *minor_data [MAX_CAMERAS];
+/* make this an rwlock if contention becomes an issue */
+static DECLARE_MUTEX (state_table_mutex);
static ssize_t camera_read (struct file *file,
char *buf, size_t len, loff_t *ppos)
{
struct camera_state *camera;
int retries;
+ int retval = 0;
if (len > MAX_PACKET_SIZE)
return -EINVAL;
camera = (struct camera_state *) file->private_data;
- if (!camera->dev)
+ down (&camera->sem);
+ if (!camera->dev) {
+ up (&camera->sem);
return -ENODEV;
- if (camera->isActive++)
- return -EBUSY;
+ }
/* Big reads are common, for image downloading. Smaller ones
* are also common (even "directory listing" commands don't
@@ -150,37 +154,33 @@ static ssize_t camera_read (struct file *file,
*/
for (retries = 0; retries < MAX_READ_RETRY; retries++) {
int count;
- int result;
if (signal_pending (current)) {
- camera->isActive = 0;
- return -EINTR;
- }
- if (!camera->dev) {
- camera->isActive = 0;
- return -ENODEV;
+ retval = -EINTR;
+ break;
}
- result = usb_bulk_msg (camera->dev,
+ retval = usb_bulk_msg (camera->dev,
usb_rcvbulkpipe (camera->dev, camera->inEP),
camera->buf, len, &count, HZ*10);
- dbg ("read (%d) - 0x%x %d", len, result, count);
+ dbg ("read (%d) - 0x%x %d", len, retval, count);
- if (!result) {
+ if (!retval) {
if (copy_to_user (buf, camera->buf, count))
- return -EFAULT;
- camera->isActive = 0;
- return count;
+ retval = -EFAULT;
+ else
+ retval = count;
+ break;
}
- if (result != USB_ST_TIMEOUT)
+ if (retval != USB_ST_TIMEOUT)
break;
interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT);
dbg ("read (%d) - retry", len);
}
- camera->isActive = 0;
- return -EIO;
+ up (&camera->sem);
+ return retval;
}
static ssize_t camera_write (struct file *file,
@@ -193,10 +193,11 @@ static ssize_t camera_write (struct file *file,
return -EINVAL;
camera = (struct camera_state *) file->private_data;
- if (!camera->dev)
+ down (&camera->sem);
+ if (!camera->dev) {
+ up (&camera->sem);
return -ENODEV;
- if (camera->isActive++)
- return -EBUSY;
+ }
/* most writes will be small: simple commands, sometimes with
* parameters. putting images (like borders) into the camera
@@ -224,18 +225,13 @@ static ssize_t camera_write (struct file *file,
bytes_written = -EINTR;
goto done;
}
- if (!camera->dev) {
- if (!bytes_written)
- bytes_written = -ENODEV;
- goto done;
- }
result = usb_bulk_msg (camera->dev,
usb_sndbulkpipe (camera->dev, camera->outEP),
obuf, thistime, &count, HZ*10);
if (result)
- dbg ("write USB err - %x", result);
+ dbg ("write USB err - %d", result);
if (count) {
obuf += count;
@@ -264,49 +260,69 @@ static ssize_t camera_write (struct file *file,
buf += copy_size;
}
done:
- camera->isActive = 0;
+ up (&camera->sem);
dbg ("wrote %d", bytes_written);
return bytes_written;
}
static int camera_open (struct inode *inode, struct file *file)
{
- struct camera_state *camera;
+ struct camera_state *camera = NULL;
int subminor;
+ int value = 0;
+ down (&state_table_mutex);
subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
if (subminor < 0 || subminor >= MAX_CAMERAS
|| !(camera = minor_data [subminor])) {
+ up (&state_table_mutex);
return -ENODEV;
}
+ down (&camera->sem);
+ up (&state_table_mutex);
+
+ if (camera->buf) {
+ value = -EBUSY;
+ goto done;
+ }
if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) {
- return -ENOMEM;
+ value = -ENOMEM;
+ goto done;
}
- dbg ("open");
+ dbg ("open #%d", subminor);
- camera->isActive = 0;
file->private_data = camera;
- return 0;
+done:
+ up (&camera->sem);
+ return value;
}
static int camera_release (struct inode *inode, struct file *file)
{
- struct camera_state *camera;
+ struct camera_state *camera;
+ int subminor;
camera = (struct camera_state *) file->private_data;
- kfree (camera->buf);
+ down (&state_table_mutex);
+ down (&camera->sem);
+
+ if (camera->buf) {
+ kfree (camera->buf);
+ camera->buf = 0;
+ }
+ subminor = camera->subminor;
/* If camera was unplugged with open file ... */
- lock_kernel();
if (!camera->dev) {
- minor_data [camera->subminor] = NULL;
+ minor_data [subminor] = NULL;
kfree (camera);
}
- unlock_kernel();
+ up (&camera->sem);
+ up (&state_table_mutex);
- dbg ("close");
+ dbg ("close #%d", subminor);
return 0;
}
@@ -333,7 +349,7 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
int direction, ep;
- struct camera_state *camera;
+ struct camera_state *camera = NULL;
/* Is it a supported camera? */
for (i = 0; i < sizeof (cameras) / sizeof (struct camera); i++) {
@@ -368,27 +384,30 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
/* select "subminor" number (part of a minor number) */
+ down (&state_table_mutex);
for (i = 0; i < MAX_CAMERAS; i++) {
if (!minor_data [i])
break;
}
if (i >= MAX_CAMERAS) {
info ("Ignoring additional USB Camera");
- return NULL;
+ up (&state_table_mutex);
+ goto bye;
}
/* allocate & init camera state */
camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL);
if (!camera) {
err ("no memory!");
- return NULL;
+ up (&state_table_mutex);
+ goto bye;
}
+
+ init_MUTEX (&camera->sem);
camera->info = camera_info;
camera->subminor = i;
- camera->isActive = 0;
camera->buf = NULL;
init_waitqueue_head (&camera->wait);
- info ("USB Camera #%d connected", camera->subminor);
/* get input and output endpoints (either order) */
@@ -417,19 +436,19 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
goto error;
}
-
- if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) {
- err ("Failed usb_set_configuration");
- goto error;
- }
+ info ("USB Camera #%d connected", camera->subminor);
camera->dev = dev;
- return camera;
+ usb_inc_dev_use (dev);
+ goto bye;
error:
minor_data [camera->subminor] = NULL;
kfree (camera);
- return NULL;
+ camera = NULL;
+bye:
+ up (&state_table_mutex);
+ return camera;
}
static void camera_disconnect(struct usb_device *dev, void *ptr)
@@ -437,6 +456,9 @@ static void camera_disconnect(struct usb_device *dev, void *ptr)
struct camera_state *camera = (struct camera_state *) ptr;
int subminor = camera->subminor;
+ down (&state_table_mutex);
+ down (&camera->sem);
+
/* If camera's not opened, we can clean up right away.
* Else apps see a disconnect on next I/O; the release cleans.
*/
@@ -447,6 +469,10 @@ static void camera_disconnect(struct usb_device *dev, void *ptr)
camera->dev = NULL;
info ("USB Camera #%d disconnected", subminor);
+ usb_dec_dev_use (dev);
+
+ up (&camera->sem);
+ up (&state_table_mutex);
}
static /* const */ struct usb_driver camera_driver = {
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index 5609ae1c2..00bd135e8 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -733,8 +733,7 @@ static int proc_clearhalt(struct dev_state *ps, void *arg)
else
pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
- usb_clear_halt(ps->dev, pipe);
- return 0;
+ return usb_clear_halt(ps->dev, pipe);
}
diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c
deleted file mode 100644
index 65109e9ca..000000000
--- a/drivers/usb/evdev.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Event char devices, giving access to raw input device events.
- *
- * Sponsored by SuSE
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#define EVDEV_MINOR_BASE 64
-#define EVDEV_MINORS 32
-#define EVDEV_BUFFER_SIZE 64
-
-#include <linux/poll.h>
-#include <linux/malloc.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/smp_lock.h>
-
-struct evdev {
- int exist;
- int open;
- int minor;
- struct input_handle handle;
- wait_queue_head_t wait;
- devfs_handle_t devfs;
- struct evdev_list *list;
-};
-
-struct evdev_list {
- struct input_event buffer[EVDEV_BUFFER_SIZE];
- int head;
- int tail;
- struct fasync_struct *fasync;
- struct evdev *evdev;
- struct evdev_list *next;
-};
-
-static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ };
-
-static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
-{
- struct evdev *evdev = handle->private;
- struct evdev_list *list = evdev->list;
-
- while (list) {
-
- get_fast_time(&list->buffer[list->head].time);
- list->buffer[list->head].type = type;
- list->buffer[list->head].code = code;
- list->buffer[list->head].value = value;
- list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
-
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
-
- list = list->next;
- }
-
- wake_up_interruptible(&evdev->wait);
-}
-
-static int evdev_fasync(int fd, struct file *file, int on)
-{
- int retval;
- struct evdev_list *list = file->private_data;
- retval = fasync_helper(fd, file, on, &list->fasync);
- return retval < 0 ? retval : 0;
-}
-
-static int evdev_release(struct inode * inode, struct file * file)
-{
- struct evdev_list *list = file->private_data;
- struct evdev_list **listptr;
-
- lock_kernel();
- listptr = &list->evdev->list;
- evdev_fasync(-1, file, 0);
-
- while (*listptr && (*listptr != list))
- listptr = &((*listptr)->next);
- *listptr = (*listptr)->next;
-
- if (!--list->evdev->open) {
- if (list->evdev->exist) {
- input_close_device(&list->evdev->handle);
- } else {
- input_unregister_minor(list->evdev->devfs);
- evdev_table[list->evdev->minor] = NULL;
- kfree(list->evdev);
- }
- }
-
- kfree(list);
- unlock_kernel();
-
- return 0;
-}
-
-static int evdev_open(struct inode * inode, struct file * file)
-{
- struct evdev_list *list;
- int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
-
- if (i > EVDEV_MINORS || !evdev_table[i])
- return -ENODEV;
-
- if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
- return -ENOMEM;
- memset(list, 0, sizeof(struct evdev_list));
-
- list->evdev = evdev_table[i];
- list->next = evdev_table[i]->list;
- evdev_table[i]->list = list;
-
- file->private_data = list;
-
- if (!list->evdev->open++)
- if (list->evdev->exist)
- input_open_device(&list->evdev->handle);
-
- return 0;
-}
-
-static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
-{
- return -EINVAL;
-}
-
-static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct evdev_list *list = file->private_data;
- int retval = 0;
-
- if (list->head == list->tail) {
-
- add_wait_queue(&list->evdev->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (list->head == list->tail) {
-
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-
- schedule();
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&list->evdev->wait, &wait);
- }
-
- if (retval)
- return retval;
-
- while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
- if (copy_to_user(buffer + retval, list->buffer + list->tail,
- sizeof(struct input_event))) return -EFAULT;
- list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
- retval += sizeof(struct input_event);
- }
-
- return retval;
-}
-
-/* No kernel lock - fine */
-static unsigned int evdev_poll(struct file *file, poll_table *wait)
-{
- struct evdev_list *list = file->private_data;
- poll_wait(file, &list->evdev->wait, wait);
- if (list->head != list->tail)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct evdev_list *list = file->private_data;
- struct evdev *evdev = list->evdev;
- struct input_dev *dev = evdev->handle.dev;
- int retval;
-
- switch (cmd) {
-
- case EVIOCGVERSION:
- return put_user(EV_VERSION, (int *) arg);
-
- case EVIOCGID:
- if ((retval = put_user(dev->idbus, ((short *) arg) + 0))) return retval;
- if ((retval = put_user(dev->idvendor, ((short *) arg) + 1))) return retval;
- if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval;
- if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval;
- return 0;
-
- default:
-
- if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
- return -EINVAL;
-
- if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
-
- long *bits;
- int len;
-
- switch (_IOC_NR(cmd) & EV_MAX) {
- case 0: bits = dev->evbit; len = EV_MAX; break;
- case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
- case EV_REL: bits = dev->relbit; len = REL_MAX; break;
- case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
- case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
- case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
- default: return -EINVAL;
- }
- len = NBITS(len) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) {
- printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n",
- len, _IOC_SIZE(cmd));
- len = _IOC_SIZE(cmd);
- }
- return copy_to_user((char *) arg, bits, len) ? -EFAULT : len;
- }
-
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
- int len;
- if (!dev->name) return 0;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
- }
-
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
-
- int t = _IOC_NR(cmd) & ABS_MAX;
-
- if ((retval = put_user(dev->abs[t], ((int *) arg) + 0))) return retval;
- if ((retval = put_user(dev->absmin[t], ((int *) arg) + 1))) return retval;
- if ((retval = put_user(dev->absmax[t], ((int *) arg) + 2))) return retval;
- if ((retval = put_user(dev->absfuzz[t], ((int *) arg) + 3))) return retval;
- if ((retval = put_user(dev->absflat[t], ((int *) arg) + 4))) return retval;
-
- return 0;
- }
- }
- return -EINVAL;
-}
-
-static struct file_operations evdev_fops = {
- owner: THIS_MODULE,
- read: evdev_read,
- write: evdev_write,
- poll: evdev_poll,
- open: evdev_open,
- release: evdev_release,
- ioctl: evdev_ioctl,
- fasync: evdev_fasync,
-};
-
-static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
-{
- struct evdev *evdev;
- int minor;
-
- for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
- if (evdev_table[minor]) {
- printk(KERN_ERR "evdev: no more free evdev devices\n");
- return NULL;
- }
-
- if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
- return NULL;
- memset(evdev, 0, sizeof(struct evdev));
-
- init_waitqueue_head(&evdev->wait);
-
- evdev->minor = minor;
- evdev_table[minor] = evdev;
-
- evdev->handle.dev = dev;
- evdev->handle.handler = handler;
- evdev->handle.private = evdev;
-
- evdev->exist = 1;
-
- evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
-
- printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);
-
- return &evdev->handle;
-}
-
-static void evdev_disconnect(struct input_handle *handle)
-{
- struct evdev *evdev = handle->private;
-
- evdev->exist = 0;
-
- if (evdev->open) {
- input_close_device(handle);
- } else {
- input_unregister_minor(evdev->devfs);
- evdev_table[evdev->minor] = NULL;
- kfree(evdev);
- }
-}
-
-static struct input_handler evdev_handler = {
- event: evdev_event,
- connect: evdev_connect,
- disconnect: evdev_disconnect,
- fops: &evdev_fops,
- minor: EVDEV_MINOR_BASE,
-};
-
-static int __init evdev_init(void)
-{
- input_register_handler(&evdev_handler);
- return 0;
-}
-
-static void __exit evdev_exit(void)
-{
- input_unregister_handler(&evdev_handler);
-}
-
-module_init(evdev_init);
-module_exit(evdev_exit);
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Event character device driver");
diff --git a/drivers/usb/hid.c b/drivers/usb/hid.c
index 68a981e27..189cbbdfc 100644
--- a/drivers/usb/hid.c
+++ b/drivers/usb/hid.c
@@ -1,5 +1,5 @@
/*
- * $Id: hid.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: hid.c,v 1.14 2000/08/14 21:05:26 vojtech Exp $
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000 Vojtech Pavlik
@@ -65,8 +65,8 @@ static unsigned char hid_keyboard[256] = {
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
- 115,114,unk,unk,unk,unk,unk,124,unk,unk,unk,unk,unk,unk,unk,unk,
- unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+ 115,114,unk,unk,unk,124,unk,181,182,183,184,185,186,187,188,189,
+ 190,191,192,193,194,195,196,197,198,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
@@ -149,7 +149,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
usage = parser->local.usage[0];
- if (type == HID_COLLECTION_APPLICATION)
+ if (type == HID_COLLECTION_APPLICATION && !parser->device->application)
parser->device->application = usage;
if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */
@@ -197,7 +197,7 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
static int hid_add_usage(struct hid_parser *parser, unsigned usage)
{
- if (parser->local.usage_index >= MAX_USAGES) {
+ if (parser->local.usage_index >= HID_MAX_USAGES) {
dbg("usage index exceeded");
return -1;
}
@@ -346,7 +346,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
return 0;
case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
- if ((parser->global.report_count = item_udata(item)) > MAX_USAGES) {
+ if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
dbg("invalid report_count %d", parser->global.report_count);
return -1;
}
@@ -1224,10 +1224,31 @@ static int hid_find_field(struct hid_device *hid, unsigned int type, unsigned in
return -1;
}
+static int hid_submit_out(struct hid_device *hid)
+{
+ hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length;
+ hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
+ hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
+
+ if (usb_submit_urb(&hid->urbout)) {
+ err("usb_submit_urb(out) failed");
+ return -1;
+ }
+
+ return 0;
+}
+
static void hid_ctrl(struct urb *urb)
{
+ struct hid_device *hid = urb->context;
+
if (urb->status)
- warn("ctrl urb status %d received", urb->status);
+ warn("ctrl urb status %d received", urb->status);
+
+ hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+
+ if (hid->outhead != hid->outtail)
+ hid_submit_out(hid);
}
static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
@@ -1242,22 +1263,18 @@ static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code
}
hid_set_field(field, offset, value);
+ hid_output_report(field->report, hid->out[hid->outhead].buffer);
- if (hid->urbout.status == -EINPROGRESS) {
- warn("had to kill output urb");
- usb_unlink_urb(&hid->urbout);
- }
+ hid->out[hid->outhead].dr.value = 0x200 | field->report->id;
+ hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1;
- hid_output_report(field->report, hid->bufout);
+ hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
- hid->dr.value = 0x200 | field->report->id;
- hid->dr.length = ((field->report->size - 1) >> 3) + 1;
- hid->urbout.transfer_buffer_length = hid->dr.length;
+ if (hid->outhead == hid->outtail)
+ hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
- if (usb_submit_urb(&hid->urbout)) {
- err("usb_submit_urb(out) failed");
- return -1;
- }
+ if (hid->urbout.status != -EINPROGRESS)
+ hid_submit_out(hid);
return 0;
}
@@ -1364,7 +1381,7 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c
if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT)
rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
- if (!rsize || rsize > 1024) {
+ if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
dbg("weird size of report descriptor (%u)", rsize);
return NULL;
}
@@ -1420,11 +1437,11 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c
hid->dev = dev;
hid->ifnum = interface->bInterfaceNumber;
- hid->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- hid->dr.request = USB_REQ_SET_REPORT;
- hid->dr.value = 0x200;
- hid->dr.index = hid->ifnum;
- hid->dr.length = 1;
+ for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
+ hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ hid->out[n].dr.request = USB_REQ_SET_REPORT;
+ hid->out[n].dr.index = hid->ifnum;
+ }
hid->input.name = hid->name;
hid->input.idbus = BUS_USB;
@@ -1441,7 +1458,7 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, c
hid->input.idvendor, hid->input.idproduct);
FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),
- (void*) &hid->dr, hid->bufout, 1, hid_ctrl, hid);
+ (void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid);
if (interface->bInterfaceSubClass == 1)
usb_set_protocol(dev, hid->ifnum, 1);
diff --git a/drivers/usb/hid.h b/drivers/usb/hid.h
index 88ab5eaca..98abc8a76 100644
--- a/drivers/usb/hid.h
+++ b/drivers/usb/hid.h
@@ -2,7 +2,7 @@
#define __HID_H
/*
- * $Id: hid.h,v 1.4 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: hid.h,v 1.7 2000/05/31 22:57:48 vojtech Exp $
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000 Vojtech Pavlik
@@ -208,10 +208,11 @@ struct hid_global {
* This is the local enviroment. It is resistent up the the next main-item.
*/
-#define MAX_USAGES 1024
+#define HID_MAX_DESCRIPTOR_SIZE 4096
+#define HID_MAX_USAGES 1024
struct hid_local {
- unsigned usage[MAX_USAGES]; /* usage array */
+ unsigned usage[HID_MAX_USAGES]; /* usage array */
unsigned usage_index;
unsigned usage_minimum;
unsigned delimiter_depth;
@@ -275,6 +276,14 @@ struct hid_report_enum {
#define HID_REPORT_TYPES 3
+#define HID_BUFFER_SIZE 32
+#define HID_CONTROL_FIFO_SIZE 8
+
+struct hid_control_fifo {
+ devrequest dr;
+ char buffer[HID_BUFFER_SIZE];
+};
+
struct hid_device { /* device report descriptor */
__u8 *rdesc;
unsigned rsize;
@@ -286,11 +295,13 @@ struct hid_device { /* device report descriptor */
struct usb_device *dev; /* USB device */
int ifnum; /* USB interface number */
- char buffer[32]; /* Receive buffer */
- char bufout[32]; /* Transmit buffer */
- devrequest dr; /* Startup packet */
struct urb urb; /* USB URB structure */
+ char buffer[HID_BUFFER_SIZE]; /* Rx buffer */
+
struct urb urbout; /* Output URB */
+ struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE]; /* Transmit buffer */
+ unsigned char outhead, outtail; /* Tx buffer head & tail */
+
struct input_dev input; /* input device structure */
int open; /* is the device open by input? */
int quirks; /* Various nasty tricks the device can pull on us */
diff --git a/drivers/usb/iforce.c b/drivers/usb/iforce.c
deleted file mode 100644
index d70bfd90e..000000000
--- a/drivers/usb/iforce.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * $Id: iforce.c,v 1.7 2000/06/04 14:03:36 vojtech Exp $
- *
- * Copyright (c) 2000 Vojtech Pavlik
- *
- * USB/RS232 I-Force joysticks and wheels.
- *
- * Sponsored by SuSE
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb.h>
-#include <linux/serio.h>
-#include <linux/config.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
-
-#define USB_VENDOR_ID_LOGITECH 0x046d
-#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281
-
-#define IFORCE_MAX_LENGTH 16
-
-#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE)
-#define IFORCE_232
-#endif
-#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE)
-#define IFORCE_USB
-#endif
-
-struct iforce {
- signed char data[IFORCE_MAX_LENGTH];
- struct input_dev dev;
- struct urb irq;
- int open;
- int idx, pkt, len, id;
- unsigned char csum;
-};
-
-static struct {
- __s32 x;
- __s32 y;
-} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-static char *iforce_name = "I-Force joystick/wheel";
-
-static void iforce_process_packet(struct input_dev *dev, unsigned char id, int idx, unsigned char *data)
-{
- switch (id) {
-
- case 1: /* joystick position data */
- case 3: /* wheel position data */
-
- if (id == 1) {
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
- input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
- } else {
- input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_GAS, 255 - data[2]);
- input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
- }
-
- input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
- input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
-
- input_report_key(dev, BTN_TRIGGER, data[5] & 0x01);
- input_report_key(dev, BTN_TOP, data[5] & 0x02);
- input_report_key(dev, BTN_THUMB, data[5] & 0x04);
- input_report_key(dev, BTN_TOP2, data[5] & 0x08);
- input_report_key(dev, BTN_BASE, data[5] & 0x10);
- input_report_key(dev, BTN_BASE2, data[5] & 0x20);
- input_report_key(dev, BTN_BASE3, data[5] & 0x40);
- input_report_key(dev, BTN_BASE4, data[5] & 0x80);
- input_report_key(dev, BTN_BASE5, data[6] & 0x01);
- input_report_key(dev, BTN_A, data[6] & 0x02);
- input_report_key(dev, BTN_B, data[6] & 0x04);
- input_report_key(dev, BTN_C, data[6] & 0x08);
- break;
-
- case 2: /* force feedback effect status */
- break;
- }
-}
-
-
-static int iforce_open(struct input_dev *dev)
-{
- struct iforce *iforce = dev->private;
-
- if (dev->idbus == BUS_USB && !iforce->open++)
- if (usb_submit_urb(&iforce->irq))
- return -EIO;
-
- return 0;
-}
-
-static void iforce_close(struct input_dev *dev)
-{
- struct iforce *iforce = dev->private;
-
- if (dev->idbus == BUS_USB && !--iforce->open)
- usb_unlink_urb(&iforce->irq);
-}
-
-static void iforce_input_setup(struct iforce *iforce)
-{
- int i;
-
- iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- iforce->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) |
- BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5);
- iforce->dev.keybit[LONG(BTN_GAMEPAD)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C);
- iforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y)
- | BIT(ABS_WHEEL) | BIT(ABS_GAS) | BIT(ABS_BRAKE);
-
- for (i = ABS_X; i <= ABS_Y; i++) {
- iforce->dev.absmax[i] = 1920;
- iforce->dev.absmin[i] = -1920;
- iforce->dev.absflat[i] = 128;
- iforce->dev.absfuzz[i] = 16;
- }
-
- for (i = ABS_THROTTLE; i <= ABS_RUDDER; i++) {
- iforce->dev.absmax[i] = 255;
- iforce->dev.absmin[i] = 0;
- }
-
- for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) {
- iforce->dev.absmax[i] = 1;
- iforce->dev.absmin[i] = -1;
- }
-
- iforce->dev.private = iforce;
- iforce->dev.open = iforce_open;
- iforce->dev.close = iforce_close;
-
- input_register_device(&iforce->dev);
-}
-
-#ifdef IFORCE_USB
-
-static void iforce_usb_irq(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- iforce_process_packet(&iforce->dev, iforce->data[0], 8, iforce->data + 1);
-}
-
-static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_endpoint_descriptor *endpoint;
- struct iforce *iforce;
-
- if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH ||
- dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE)
- return NULL;
-
- endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
-
- if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return NULL;
- memset(iforce, 0, sizeof(struct iforce));
-
- iforce->dev.name = iforce_name;
- iforce->dev.idbus = BUS_USB;
- iforce->dev.idvendor = dev->descriptor.idVendor;
- iforce->dev.idproduct = dev->descriptor.idProduct;
- iforce->dev.idversion = dev->descriptor.bcdDevice;
-
- FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- iforce->data, 8, iforce_usb_irq, iforce, endpoint->bInterval);
-
- iforce_input_setup(iforce);
-
- printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
- iforce->dev.number, iforce_name, dev->bus->busnum, dev->devnum, ifnum);
-
- return iforce;
-}
-
-static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
-{
- struct iforce *iforce = ptr;
- usb_unlink_urb(&iforce->irq);
- input_unregister_device(&iforce->dev);
- kfree(iforce);
-}
-
-static struct usb_driver iforce_usb_driver = {
- name: "iforce",
- probe: iforce_usb_probe,
- disconnect: iforce_usb_disconnect,
-};
-
-#endif
-
-#ifdef IFORCE_232
-
-static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct iforce* iforce = serio->private;
-
- if (!iforce->pkt) {
- if (data != 0x2b) {
- return;
- }
- iforce->pkt = 1;
- return;
- }
-
- if (!iforce->id) {
- if (data > 3) {
- iforce->pkt = 0;
- return;
- }
- iforce->id = data;
- return;
- }
-
- if (!iforce->len) {
- if (data > IFORCE_MAX_LENGTH) {
- iforce->pkt = 0;
- iforce->id = 0;
- return;
- }
- iforce->len = data;
- return;
- }
-
- if (iforce->idx < iforce->len) {
- iforce->csum += iforce->data[iforce->idx++] = data;
- return;
- }
-
- if (iforce->idx == iforce->len) {
- iforce_process_packet(&iforce->dev, iforce->id, iforce->idx, iforce->data);
- iforce->pkt = 0;
- iforce->id = 0;
- iforce->len = 0;
- iforce->idx = 0;
- iforce->csum = 0;
- }
-}
-
-static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
-{
- struct iforce *iforce;
-
- if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
- return;
-
- if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
- memset(iforce, 0, sizeof(struct iforce));
-
- iforce->dev.name = iforce_name;
- iforce->dev.idbus = BUS_RS232;
- iforce->dev.idvendor = SERIO_IFORCE;
- iforce->dev.idproduct = 0x0001;
- iforce->dev.idversion = 0x0100;
-
- serio->private = iforce;
-
- if (serio_open(serio, dev)) {
- kfree(iforce);
- return;
- }
-
- iforce_input_setup(iforce);
-
- printk(KERN_INFO "input%d: %s on serio%d\n",
- iforce->dev.number, iforce_name, serio->number);
-}
-
-static void iforce_serio_disconnect(struct serio *serio)
-{
- struct iforce* iforce = serio->private;
- input_unregister_device(&iforce->dev);
- serio_close(serio);
- kfree(iforce);
-}
-
-static struct serio_dev iforce_serio_dev = {
- interrupt: iforce_serio_irq,
- connect: iforce_serio_connect,
- disconnect: iforce_serio_disconnect,
-};
-
-#endif
-
-static int __init iforce_init(void)
-{
-#ifdef IFORCE_USB
- usb_register(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
- serio_register_device(&iforce_serio_dev);
-#endif
- return 0;
-}
-
-static void __exit iforce_exit(void)
-{
-#ifdef IFORCE_USB
- usb_deregister(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
- serio_unregister_device(&iforce_serio_dev);
-#endif
-}
-
-module_init(iforce_init);
-module_exit(iforce_exit);
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index 50970155b..b55073398 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -290,14 +290,14 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill
i = filp->f_pos;
switch (i) {
case 0:
- if (filldir(dirent, ".", 1, i, IROOT) < 0)
+ if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0)
return 0;
filp->f_pos++;
i++;
/* fall through */
case 1:
- if (filldir(dirent, "..", 2, i, IROOT) < 0)
+ if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0)
return 0;
filp->f_pos++;
i++;
@@ -307,7 +307,7 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill
while (i >= 2 && i < 2+NRSPECIAL) {
spec = &special[filp->f_pos-2];
- if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0)
+ if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0)
return 0;
filp->f_pos++;
i++;
@@ -323,7 +323,7 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill
}
bus = list_entry(list, struct usb_bus, bus_list);
sprintf(numbuf, "%03d", bus->busnum);
- if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0)
+ if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0)
break;
filp->f_pos++;
}
@@ -343,7 +343,7 @@ static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struc
if (pos > 0)
pos--;
else {
- if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0)
+ if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0)
return -1;
filp->f_pos++;
}
@@ -368,13 +368,13 @@ static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filld
return -EINVAL;
switch ((unsigned int)filp->f_pos) {
case 0:
- if (filldir(dirent, ".", 1, filp->f_pos, ino) < 0)
+ if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0)
return 0;
filp->f_pos++;
/* fall through */
case 1:
- if (filldir(dirent, "..", 2, filp->f_pos, IROOT) < 0)
+ if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0)
return 0;
filp->f_pos++;
/* fall through */
diff --git a/drivers/usb/input.c b/drivers/usb/input.c
deleted file mode 100644
index f3701965e..000000000
--- a/drivers/usb/input.c
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * $Id: input.c,v 1.7 2000/05/28 17:31:36 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * The input layer module itself
- *
- * Sponsored by SuSE
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/random.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Input layer module");
-
-EXPORT_SYMBOL(input_register_device);
-EXPORT_SYMBOL(input_unregister_device);
-EXPORT_SYMBOL(input_register_handler);
-EXPORT_SYMBOL(input_unregister_handler);
-EXPORT_SYMBOL(input_register_minor);
-EXPORT_SYMBOL(input_unregister_minor);
-EXPORT_SYMBOL(input_open_device);
-EXPORT_SYMBOL(input_close_device);
-EXPORT_SYMBOL(input_event);
-
-#define INPUT_MAJOR 13
-#define INPUT_DEVICES 256
-
-static struct input_dev *input_dev = NULL;
-static struct input_handler *input_handler = NULL;
-static struct input_handler *input_table[8] = { NULL, /* ... */ };
-static devfs_handle_t input_devfs_handle = NULL;
-static int input_number = 0;
-static long input_devices[NBITS(INPUT_DEVICES)] = { 0, /* ... */ };
-
-void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- struct input_handle *handle = dev->handle;
-
-/*
- * Filter non-events, and bad input values out.
- */
-
- if (type > EV_MAX || !test_bit(type, dev->evbit))
- return;
-
- switch (type) {
-
- case EV_KEY:
-
- if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
- return;
-
- if (value == 2) break;
-
- change_bit(code, dev->key);
-
- if (test_bit(EV_REP, dev->evbit) && dev->timer.function) {
- if (value) {
- mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]);
- dev->repeat_key = code;
- break;
- }
- if (dev->repeat_key == code)
- del_timer(&dev->timer);
- }
-
- break;
-
- case EV_ABS:
-
- if (code > ABS_MAX || !test_bit(code, dev->absbit))
- return;
-
- if (dev->absfuzz[code]) {
- if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
- (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
- return;
-
- if ((value > dev->abs[code] - dev->absfuzz[code]) &&
- (value < dev->abs[code] + dev->absfuzz[code]))
- value = (dev->abs[code] * 3 + value) >> 2;
-
- if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
- (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
- value = (dev->abs[code] + value) >> 1;
- }
-
- if (dev->abs[code] == value)
- return;
-
- dev->abs[code] = value;
- break;
-
- case EV_REL:
-
- if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
- return;
-
- break;
-
- case EV_LED:
-
- if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
- return;
-
- change_bit(code, dev->led);
- if (dev->event) dev->event(dev, type, code, value);
-
- break;
-
- case EV_SND:
-
- if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value)
- return;
-
- change_bit(code, dev->snd);
- if (dev->event) dev->event(dev, type, code, value);
-
- break;
-
- case EV_REP:
-
- if (code > REP_MAX || dev->rep[code] == value) return;
-
- dev->rep[code] = value;
- if (dev->event) dev->event(dev, type, code, value);
-
- break;
- }
-/*
- * Add randomness.
- */
-
-#if 0 /* BUG */
- add_input_randomness(((unsigned long) dev) ^ (type << 24) ^ (code << 16) ^ value);
-#endif
-
-/*
- * Distribute the event to handler modules.
- */
-
- while (handle) {
- if (handle->open)
- handle->handler->event(handle, type, code, value);
- handle = handle->dnext;
- }
-}
-
-static void input_repeat_key(unsigned long data)
-{
- struct input_dev *dev = (void *) data;
- input_event(dev, EV_KEY, dev->repeat_key, 2);
- mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]);
-}
-
-int input_open_device(struct input_handle *handle)
-{
- handle->open++;
- if (handle->dev->open)
- return handle->dev->open(handle->dev);
- return 0;
-}
-
-void input_close_device(struct input_handle *handle)
-{
- if (handle->dev->close)
- handle->dev->close(handle->dev);
- handle->open--;
-}
-
-static void input_link_handle(struct input_handle *handle)
-{
- handle->dnext = handle->dev->handle;
- handle->hnext = handle->handler->handle;
- handle->dev->handle = handle;
- handle->handler->handle = handle;
-}
-
-static void input_unlink_handle(struct input_handle *handle)
-{
- struct input_handle **handleptr;
-
- handleptr = &handle->dev->handle;
- while (*handleptr && (*handleptr != handle))
- handleptr = &((*handleptr)->dnext);
- *handleptr = (*handleptr)->dnext;
-
- handleptr = &handle->handler->handle;
- while (*handleptr && (*handleptr != handle))
- handleptr = &((*handleptr)->hnext);
- *handleptr = (*handleptr)->hnext;
-}
-
-void input_register_device(struct input_dev *dev)
-{
- struct input_handler *handler = input_handler;
- struct input_handle *handle;
-
-/*
- * Initialize repeat timer to default values.
- */
-
- init_timer(&dev->timer);
- dev->timer.data = (long) dev;
- dev->timer.function = input_repeat_key;
- dev->rep[REP_DELAY] = HZ/4;
- dev->rep[REP_PERIOD] = HZ/33;
-
-/*
- * Add the device.
- */
-
- if (input_number >= INPUT_DEVICES) {
- printk(KERN_WARNING "input: ran out of input device numbers!\n");
- dev->number = input_number;
- } else {
- dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
- set_bit(dev->number, input_devices);
- }
-
- dev->next = input_dev;
- input_dev = dev;
- input_number++;
-
-/*
- * Notify handlers.
- */
-
- while (handler) {
- if ((handle = handler->connect(handler, dev)))
- input_link_handle(handle);
- handler = handler->next;
- }
-}
-
-void input_unregister_device(struct input_dev *dev)
-{
- struct input_handle *handle = dev->handle;
- struct input_dev **devptr = &input_dev;
- struct input_handle *dnext;
-
-/*
- * Kill any pending repeat timers.
- */
-
- del_timer(&dev->timer);
-
-/*
- * Notify handlers.
- */
-
- while (handle) {
- dnext = handle->dnext;
- input_unlink_handle(handle);
- handle->handler->disconnect(handle);
- handle = dnext;
- }
-
-/*
- * Remove the device.
- */
-
- while (*devptr && (*devptr != dev))
- devptr = &((*devptr)->next);
- *devptr = (*devptr)->next;
-
- input_number--;
-
- if (dev->number < INPUT_DEVICES)
- clear_bit(dev->number, input_devices);
-}
-
-void input_register_handler(struct input_handler *handler)
-{
- struct input_dev *dev = input_dev;
- struct input_handle *handle;
-
-/*
- * Add minors if needed.
- */
-
- if (handler->fops != NULL)
- input_table[handler->minor >> 5] = handler;
-
-/*
- * Add the handler.
- */
-
- handler->next = input_handler;
- input_handler = handler;
-
-/*
- * Notify it about all existing devices.
- */
-
- while (dev) {
- if ((handle = handler->connect(handler, dev)))
- input_link_handle(handle);
- dev = dev->next;
- }
-}
-
-void input_unregister_handler(struct input_handler *handler)
-{
- struct input_handler **handlerptr = &input_handler;
- struct input_handle *handle = handler->handle;
- struct input_handle *hnext;
-
-/*
- * Tell the handler to disconnect from all devices it keeps open.
- */
-
- while (handle) {
- hnext = handle->hnext;
- input_unlink_handle(handle);
- handler->disconnect(handle);
- handle = hnext;
- }
-
-/*
- * Remove it.
- */
-
- while (*handlerptr && (*handlerptr != handler))
- handlerptr = &((*handlerptr)->next);
-
- *handlerptr = (*handlerptr)->next;
-
-/*
- * Remove minors.
- */
-
- if (handler->fops != NULL)
- input_table[handler->minor >> 5] = NULL;
-}
-
-static int input_open_file(struct inode *inode, struct file *file)
-{
- struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];
- struct file_operations *old_fops, *new_fops = NULL;
- int err;
-
- /* No load-on-demand here? */
- if (!handler || !(new_fops = fops_get(handler->fops)))
- return -ENODEV;
-
- /*
- * That's _really_ odd. Usually NULL ->open means "nothing special",
- * not "no device". Oh, well...
- */
- if (!new_fops->open) {
- fops_put(new_fops);
- return -ENODEV;
- }
- old_fops = file->f_op;
- file->f_op = new_fops;
- err = new_fops->open(inode, file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
- fops_put(old_fops);
- return err;
-}
-
-static struct file_operations input_fops = {
- owner: THIS_MODULE,
- open: input_open_file,
-};
-
-devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
-{
- char devfs_name[16];
- sprintf(devfs_name, name, minor);
- return devfs_register(input_devfs_handle, devfs_name, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
- S_IFCHR | S_IRUGO | S_IWUSR, &input_fops, NULL);
-}
-
-void input_unregister_minor(devfs_handle_t handle)
-{
- devfs_unregister(handle);
-}
-
-static int __init input_init(void)
-{
- if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
- printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
- return -EBUSY;
- }
- input_devfs_handle = devfs_mk_dir(NULL, "input", NULL);
- return 0;
-}
-
-static void __exit input_exit(void)
-{
- devfs_unregister(input_devfs_handle);
- if (devfs_unregister_chrdev(INPUT_MAJOR, "input"))
- printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
-}
-
-module_init(input_init);
-module_exit(input_exit);
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
deleted file mode 100644
index 99b17a3cd..000000000
--- a/drivers/usb/joydev.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * $Id: joydev.c,v 1.11 2000/06/23 09:23:00 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- * Copyright (c) 1999 Colin Van Dyke
- *
- * Joystick device driver for the input driver suite.
- *
- * Sponsored by SuSE and Intel
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/input.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-
-#define JOYDEV_MINOR_BASE 0
-#define JOYDEV_MINORS 32
-#define JOYDEV_BUFFER_SIZE 64
-
-struct joydev {
- int exist;
- int open;
- int minor;
- struct input_handle handle;
- wait_queue_head_t wait;
- devfs_handle_t devfs;
- struct joydev *next;
- struct joydev_list *list;
- struct js_corr corr[ABS_MAX];
- struct JS_DATA_SAVE_TYPE glue;
- int nabs;
- int nkey;
- __u16 keymap[KEY_MAX - BTN_MISC];
- __u16 keypam[KEY_MAX - BTN_MISC];
- __u8 absmap[ABS_MAX];
- __u8 abspam[ABS_MAX];
- __s16 abs[ABS_MAX];
-};
-
-struct joydev_list {
- struct js_event buffer[JOYDEV_BUFFER_SIZE];
- int head;
- int tail;
- int startup;
- struct fasync_struct *fasync;
- struct joydev *joydev;
- struct joydev_list *next;
-};
-
-static struct joydev *joydev_table[JOYDEV_MINORS];
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Joystick device driver");
-MODULE_SUPPORTED_DEVICE("input/js");
-
-static int joydev_correct(int value, struct js_corr *corr)
-{
- switch (corr->type) {
- case JS_CORR_NONE:
- break;
- case JS_CORR_BROKEN:
- value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
- ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
- ((corr->coef[2] * (value - corr->coef[0])) >> 14);
- break;
- default:
- return 0;
- }
-
- if (value < -32767) return -32767;
- if (value > 32767) return 32767;
-
- return value;
-}
-
-static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
-{
- struct joydev *joydev = handle->private;
- struct joydev_list *list = joydev->list;
- struct js_event event;
-
- switch (type) {
-
- case EV_KEY:
- if (code < BTN_MISC || value == 2) return;
- event.type = JS_EVENT_BUTTON;
- event.number = joydev->keymap[code - BTN_MISC];
- event.value = value;
- break;
-
- case EV_ABS:
- event.type = JS_EVENT_AXIS;
- event.number = joydev->absmap[code];
- event.value = joydev_correct(value, joydev->corr + event.number);
- if (event.value == joydev->abs[event.number]) return;
- joydev->abs[event.number] = event.value;
- break;
-
- default:
- return;
- }
-
- event.time = jiffies * (1000 / HZ);
-
- while (list) {
-
- memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
-
- if (list->startup == joydev->nabs + joydev->nkey)
- if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
- list->startup = 0;
-
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
-
- list = list->next;
- }
-
- wake_up_interruptible(&joydev->wait);
-}
-
-static int joydev_fasync(int fd, struct file *file, int on)
-{
- int retval;
- struct joydev_list *list = file->private_data;
- retval = fasync_helper(fd, file, on, &list->fasync);
- return retval < 0 ? retval : 0;
-}
-
-static int joydev_release(struct inode * inode, struct file * file)
-{
- struct joydev_list *list = file->private_data;
- struct joydev_list **listptr;
-
- lock_kernel();
- listptr = &list->joydev->list;
- joydev_fasync(-1, file, 0);
-
- while (*listptr && (*listptr != list))
- listptr = &((*listptr)->next);
- *listptr = (*listptr)->next;
-
- if (!--list->joydev->open) {
- if (list->joydev->exist) {
- input_close_device(&list->joydev->handle);
- } else {
- input_unregister_minor(list->joydev->devfs);
- joydev_table[list->joydev->minor] = NULL;
- kfree(list->joydev);
- }
- }
-
- kfree(list);
- unlock_kernel();
-
- return 0;
-}
-
-static int joydev_open(struct inode *inode, struct file *file)
-{
- struct joydev_list *list;
- int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
-
- if (i > JOYDEV_MINORS || !joydev_table[i])
- return -ENODEV;
-
- if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
- return -ENOMEM;
- memset(list, 0, sizeof(struct joydev_list));
-
- list->joydev = joydev_table[i];
- list->next = joydev_table[i]->list;
- joydev_table[i]->list = list;
-
- file->private_data = list;
-
- if (!list->joydev->open++)
- if (list->joydev->exist)
- input_open_device(&list->joydev->handle);
-
- return 0;
-}
-
-static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
-{
- return -EINVAL;
-}
-
-static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
- struct input_dev *input = joydev->handle.dev;
- int retval = 0;
-
- if (count < sizeof(struct js_event))
- return -EINVAL;
-
- if (count == sizeof(struct JS_DATA_TYPE)) {
-
- struct JS_DATA_TYPE data;
-
- data.buttons = ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) |
- ((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0);
- data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
- data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
-
- if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
- return -EFAULT;
-
- list->startup = 0;
- list->tail = list->head;
-
- return sizeof(struct JS_DATA_TYPE);
- }
-
- if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) {
-
- add_wait_queue(&list->joydev->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (list->head == list->tail) {
-
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-
- schedule();
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&list->joydev->wait, &wait);
- }
-
- if (retval)
- return retval;
-
- while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
-
- struct js_event event;
-
- event.time = jiffies * (1000/HZ);
-
- if (list->startup < joydev->nkey) {
- event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- event.number = list->startup;
- event.value = !!test_bit(joydev->keypam[event.number], input->key);
- } else {
- event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- event.number = list->startup - joydev->nkey;
- event.value = joydev->abs[event.number];
- }
-
- if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
- return -EFAULT;
-
- list->startup++;
- retval += sizeof(struct js_event);
- }
-
- while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
-
- if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
- return -EFAULT;
-
- list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
- retval += sizeof(struct js_event);
- }
-
- return retval;
-}
-
-/* No kernel lock - fine */
-static unsigned int joydev_poll(struct file *file, poll_table *wait)
-{
- struct joydev_list *list = file->private_data;
- poll_wait(file, &list->joydev->wait, wait);
- if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
- struct input_dev *dev = joydev->handle.dev;
-
-
- switch (cmd) {
-
- case JS_SET_CAL:
- return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_GET_CAL:
- return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (int *) arg);
- case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (int *) arg);
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
-
- case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 *) arg);
- case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 *) arg);
- case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 *) arg);
- case JSIOCSCORR:
- return copy_from_user(joydev->corr, (struct js_corr *) arg,
- sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
- case JSIOCGCORR:
- return copy_to_user((struct js_corr *) arg, joydev->corr,
- sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
- default:
- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
- int len;
- if (!dev->name) return 0;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT;
- return len;
- }
- }
- return -EINVAL;
-}
-
-static struct file_operations joydev_fops = {
- owner: THIS_MODULE,
- read: joydev_read,
- write: joydev_write,
- poll: joydev_poll,
- open: joydev_open,
- release: joydev_release,
- ioctl: joydev_ioctl,
- fasync: joydev_fasync,
-};
-
-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
-{
- struct joydev *joydev;
- int i, j, minor;
-
- if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
- test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) &&
- (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
- || test_bit(BTN_1, dev->keybit)))) return NULL;
-
- for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
- if (joydev_table[minor]) {
- printk(KERN_ERR "joydev: no more free joydev devices\n");
- return NULL;
- }
-
- if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
- return NULL;
- memset(joydev, 0, sizeof(struct joydev));
-
- init_waitqueue_head(&joydev->wait);
-
- joydev->minor = minor;
- joydev_table[minor] = joydev;
-
- joydev->handle.dev = dev;
- joydev->handle.handler = handler;
- joydev->handle.private = joydev;
-
- joydev->exist = 1;
-
- for (i = 0; i < ABS_MAX; i++)
- if (test_bit(i, dev->absbit)) {
- joydev->absmap[i] = joydev->nabs;
- joydev->abspam[joydev->nabs] = i;
- joydev->nabs++;
- }
-
- for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
- if (test_bit(i + BTN_MISC, dev->keybit)) {
- joydev->keymap[i] = joydev->nkey;
- joydev->keypam[joydev->nkey] = i + BTN_MISC;
- joydev->nkey++;
- }
-
- for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
- if (test_bit(i + BTN_MISC, dev->keybit)) {
- joydev->keymap[i] = joydev->nkey;
- joydev->keypam[joydev->nkey] = i + BTN_MISC;
- joydev->nkey++;
- }
-
- for (i = 0; i < joydev->nabs; i++) {
- j = joydev->abspam[i];
- if (dev->absmax[j] == dev->absmin[j]) {
- joydev->corr[i].type = JS_CORR_NONE;
- continue;
- }
- joydev->corr[i].type = JS_CORR_BROKEN;
- joydev->corr[i].prec = dev->absfuzz[j];
- joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
- joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
- joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
- joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
-
- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
- }
-
- joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
-
- printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number);
-
- return &joydev->handle;
-}
-
-static void joydev_disconnect(struct input_handle *handle)
-{
- struct joydev *joydev = handle->private;
-
- joydev->exist = 0;
-
- if (joydev->open) {
- input_close_device(handle);
- } else {
- input_unregister_minor(joydev->devfs);
- joydev_table[joydev->minor] = NULL;
- kfree(joydev);
- }
-}
-
-static struct input_handler joydev_handler = {
- event: joydev_event,
- connect: joydev_connect,
- disconnect: joydev_disconnect,
- fops: &joydev_fops,
- minor: JOYDEV_MINOR_BASE,
-};
-
-static int __init joydev_init(void)
-{
- input_register_handler(&joydev_handler);
- return 0;
-}
-
-static void __exit joydev_exit(void)
-{
- input_unregister_handler(&joydev_handler);
-}
-
-module_init(joydev_init);
-module_exit(joydev_exit);
diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c
deleted file mode 100644
index 95fce5e80..000000000
--- a/drivers/usb/keybdev.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * $Id: keybdev.c,v 1.3 2000/05/28 17:31:36 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Input driver to keyboard driver binding.
- *
- * Sponsored by SuSE
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/config.h>
-#include <linux/kbd_ll.h>
-#include <linux/input.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kbd_kern.h>
-
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || defined(__mips__)
-
-static int x86_sysrq_alt = 0;
-
-static unsigned short x86_keycodes[256] =
- { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90,
- 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
- 367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
- 360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
- 103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
- 291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
- 118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269,
- 271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
- 308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
- 332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
-
-static int emulate_raw(unsigned int keycode, int down)
-{
- if (keycode > 255 || !x86_keycodes[keycode])
- return -1;
-
- if (keycode == KEY_PAUSE) {
- handle_scancode(0xe1, 1);
- handle_scancode(0x1d, down);
- handle_scancode(0x45, down);
- return 0;
- }
-
- if (keycode == KEY_SYSRQ && x86_sysrq_alt) {
- handle_scancode(0x54, down);
- return 0;
- }
-
- if (x86_keycodes[keycode] & 0x100)
- handle_scancode(0xe0, 1);
-
- handle_scancode(x86_keycodes[keycode] & 0x7f, down);
-
- if (keycode == KEY_SYSRQ) {
- handle_scancode(0xe0, 1);
- handle_scancode(0x37, down);
- }
-
- if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
- x86_sysrq_alt = down;
-
- return 0;
-}
-
-#elif defined(CONFIG_ADB_KEYBOARD)
-
-static unsigned char mac_keycodes[128] =
- { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
- 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1,
- 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
- 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
- 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
- 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0,
- 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117,
- 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 };
-
-static int emulate_raw(unsigned int keycode, int down)
-{
- if (keycode > 127 || !mac_keycodes[keycode])
- return -1;
-
- handle_scancode(mac_keycodes[keycode] & 0x7f, down);
-
- return 0;
-}
-
-#endif
-
-static struct input_handler keybdev_handler;
-
-void keybdev_ledfunc(unsigned int led)
-{
- struct input_handle *handle;
-
- for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
-
- input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
- input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02));
- input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04));
-
- }
-}
-
-void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
-{
- if (type != EV_KEY) return;
-
- if (emulate_raw(code, down))
- printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
-
- tasklet_schedule(&keyboard_tasklet);
-}
-
-static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev)
-{
- struct input_handle *handle;
- int i;
-
- if (!test_bit(EV_KEY, dev->evbit))
- return NULL;
-
- for (i = KEY_RESERVED; i < BTN_MISC; i++)
- if (test_bit(i, dev->keybit)) break;
-
- if (i == BTN_MISC)
- return NULL;
-
- if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
- return NULL;
- memset(handle, 0, sizeof(struct input_handle));
-
- handle->dev = dev;
- handle->handler = handler;
-
- input_open_device(handle);
-
- printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
-
- return handle;
-}
-
-static void keybdev_disconnect(struct input_handle *handle)
-{
- printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
- input_close_device(handle);
- kfree(handle);
-}
-
-static struct input_handler keybdev_handler = {
- event: keybdev_event,
- connect: keybdev_connect,
- disconnect: keybdev_disconnect,
-};
-
-static int __init keybdev_init(void)
-{
- input_register_handler(&keybdev_handler);
- kbd_ledfunc = keybdev_ledfunc;
- return 0;
-}
-
-static void __exit keybdev_exit(void)
-{
- kbd_ledfunc = NULL;
- input_unregister_handler(&keybdev_handler);
-}
-
-module_init(keybdev_init);
-module_exit(keybdev_exit);
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Input driver to keyboard driver binding");
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
deleted file mode 100644
index ccb118520..000000000
--- a/drivers/usb/mousedev.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * $Id: mousedev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Input driver to PS/2 or ImPS/2 device driver module.
- *
- * Sponsored by SuSE
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#define MOUSEDEV_MINOR_BASE 32
-#define MOUSEDEV_MINORS 32
-#define MOUSEDEV_MIX 31
-
-#include <linux/malloc.h>
-#include <linux/poll.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/config.h>
-#include <linux/smp_lock.h>
-
-#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
-#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
-#endif
-#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
-#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
-#endif
-
-struct mousedev {
- int exist;
- int open;
- int minor;
- wait_queue_head_t wait;
- struct mousedev_list *list;
- struct input_handle handle;
- devfs_handle_t devfs;
-};
-
-struct mousedev_list {
- struct fasync_struct *fasync;
- struct mousedev *mousedev;
- struct mousedev_list *next;
- int dx, dy, dz, oldx, oldy;
- char ps2[6];
- unsigned long buttons;
- unsigned char ready, buffer, bufsiz;
- unsigned char mode, genseq, impseq;
-};
-
-#define MOUSEDEV_GENIUS_LEN 5
-#define MOUSEDEV_IMPS_LEN 6
-
-static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
-static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
-
-static struct input_handler mousedev_handler;
-
-static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
-static struct mousedev mousedev_mix;
-
-static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
-{
- struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
- struct mousedev **mousedev = mousedevs;
- struct mousedev_list *list;
- int index, size;
-
- while (*mousedev) {
- list = (*mousedev)->list;
- while (list) {
- switch (type) {
- case EV_ABS:
- switch (code) {
- case ABS_X:
- size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
- list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size;
- list->oldx += list->dx * size;
- break;
- case ABS_Y:
- size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
- list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size;
- list->oldy -= list->dy * size;
- break;
- }
- break;
- case EV_REL:
- switch (code) {
- case REL_X: list->dx += value; break;
- case REL_Y: list->dy -= value; break;
- case REL_WHEEL: if (list->mode) list->dz -= value; break;
- }
- break;
-
- case EV_KEY:
- switch (code) {
- case BTN_0:
- case BTN_TOUCH:
- case BTN_LEFT: index = 0; break;
- case BTN_4:
- case BTN_EXTRA: if (list->mode > 1) { index = 4; break; }
- case BTN_STYLUS:
- case BTN_1:
- case BTN_RIGHT: index = 1; break;
- case BTN_3:
- case BTN_SIDE: if (list->mode > 1) { index = 3; break; }
- case BTN_2:
- case BTN_STYLUS2:
- case BTN_MIDDLE: index = 2; break;
- default: return;
- }
- switch (value) {
- case 0: clear_bit(index, &list->buttons); break;
- case 1: set_bit(index, &list->buttons); break;
- case 2: return;
- }
- break;
- }
-
- list->ready = 1;
-
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
-
- list = list->next;
- }
-
- wake_up_interruptible(&((*mousedev)->wait));
- mousedev++;
- }
-}
-
-static int mousedev_fasync(int fd, struct file *file, int on)
-{
- int retval;
- struct mousedev_list *list = file->private_data;
- retval = fasync_helper(fd, file, on, &list->fasync);
- return retval < 0 ? retval : 0;
-}
-
-static int mousedev_release(struct inode * inode, struct file * file)
-{
- struct mousedev_list *list = file->private_data;
- struct mousedev_list **listptr;
-
- lock_kernel();
- listptr = &list->mousedev->list;
- mousedev_fasync(-1, file, 0);
-
- while (*listptr && (*listptr != list))
- listptr = &((*listptr)->next);
- *listptr = (*listptr)->next;
-
- if (!--list->mousedev->open) {
- if (list->mousedev->minor == MOUSEDEV_MIX) {
- struct input_handle *handle = mousedev_handler.handle;
- while (handle) {
- struct mousedev *mousedev = handle->private;
- if (!mousedev->open) {
- if (mousedev->exist) {
- input_close_device(&mousedev->handle);
- } else {
- input_unregister_minor(mousedev->devfs);
- mousedev_table[mousedev->minor] = NULL;
- kfree(mousedev);
- }
- }
- handle = handle->hnext;
- }
- } else {
- if (!mousedev_mix.open) {
- if (list->mousedev->exist) {
- input_close_device(&list->mousedev->handle);
- } else {
- input_unregister_minor(list->mousedev->devfs);
- mousedev_table[list->mousedev->minor] = NULL;
- kfree(list->mousedev);
- }
- }
- }
- }
-
- kfree(list);
- unlock_kernel();
-
- return 0;
-}
-
-static int mousedev_open(struct inode * inode, struct file * file)
-{
- struct mousedev_list *list;
- int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
-
- if (i > MOUSEDEV_MINORS || !mousedev_table[i])
- return -ENODEV;
-
- if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
- return -ENOMEM;
- memset(list, 0, sizeof(struct mousedev_list));
-
- list->mousedev = mousedev_table[i];
- list->next = mousedev_table[i]->list;
- mousedev_table[i]->list = list;
- file->private_data = list;
-
- if (!list->mousedev->open++) {
- if (list->mousedev->minor == MOUSEDEV_MIX) {
- struct input_handle *handle = mousedev_handler.handle;
- while (handle) {
- struct mousedev *mousedev = handle->private;
- if (!mousedev->open)
- if (mousedev->exist)
- input_open_device(handle);
- handle = handle->hnext;
- }
- } else {
- if (!mousedev_mix.open)
- if (list->mousedev->exist)
- input_open_device(&list->mousedev->handle);
- }
- }
-
- return 0;
-}
-
-static void mousedev_packet(struct mousedev_list *list, unsigned char off)
-{
- list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
- list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
- list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
- list->dx -= list->ps2[off + 1];
- list->dy -= list->ps2[off + 2];
- list->bufsiz = off + 3;
-
- if (list->mode > 1)
- list->ps2[off] |= ((list->buttons & 0x30) << 2);
-
- if (list->mode) {
- list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
- list->bufsiz++;
- list->dz -= list->ps2[off + 3];
- }
- if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
- list->buffer = list->bufsiz;
-}
-
-
-static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
-{
- struct mousedev_list *list = file->private_data;
- unsigned char c;
- int i;
-
- for (i = 0; i < count; i++) {
-
- c = buffer[i];
-
- if (c == mousedev_genius_seq[list->genseq]) {
- if (++list->genseq == MOUSEDEV_GENIUS_LEN) {
- list->genseq = 0;
- list->ready = 1;
- list->mode = 2;
- }
- } else list->genseq = 0;
-
- if (c == mousedev_imps_seq[list->impseq]) {
- if (++list->impseq == MOUSEDEV_IMPS_LEN) {
- list->impseq = 0;
- list->ready = 1;
- list->mode = 1;
- }
- } else list->impseq = 0;
-
- list->ps2[0] = 0xfa;
- list->bufsiz = 1;
-
- switch (c) {
-
- case 0xeb: /* Poll */
- mousedev_packet(list, 1);
- break;
-
- case 0xf2: /* Get ID */
- list->ps2[1] = (list->mode == 1) ? 3 : 0;
- list->bufsiz = 2;
- break;
-
- case 0xe9: /* Get info */
- if (list->mode == 2) {
- list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55;
- } else {
- list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
- }
- list->bufsiz = 4;
- break;
- }
-
- list->buffer = list->bufsiz;
- }
-
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
-
- wake_up_interruptible(&list->mousedev->wait);
-
- return count;
-}
-
-static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct mousedev_list *list = file->private_data;
- int retval = 0;
-
- if (!list->ready && !list->buffer) {
-
- add_wait_queue(&list->mousedev->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (!list->ready) {
-
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-
- schedule();
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&list->mousedev->wait, &wait);
- }
-
- if (retval)
- return retval;
-
- if (!list->buffer)
- mousedev_packet(list, 0);
-
- if (count > list->buffer)
- count = list->buffer;
-
- if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count))
- return -EFAULT;
-
- list->buffer -= count;
-
- return count;
-}
-
-/* No kernel lock - fine */
-static unsigned int mousedev_poll(struct file *file, poll_table *wait)
-{
- struct mousedev_list *list = file->private_data;
- poll_wait(file, &list->mousedev->wait, wait);
- if (list->ready || list->buffer)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-struct file_operations mousedev_fops = {
- owner: THIS_MODULE,
- read: mousedev_read,
- write: mousedev_write,
- poll: mousedev_poll,
- open: mousedev_open,
- release: mousedev_release,
- fasync: mousedev_fasync,
-};
-
-static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
-{
- struct mousedev *mousedev;
- int minor = 0;
-
- if (!test_bit(EV_KEY, dev->evbit) ||
- (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
- return NULL;
-
- if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
- (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
- return NULL;
-
- for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
- if (mousedev_table[minor]) {
- printk(KERN_ERR "mousedev: no more free mousedev devices\n");
- return NULL;
- }
-
- if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
- return NULL;
- memset(mousedev, 0, sizeof(struct mousedev));
- init_waitqueue_head(&mousedev->wait);
-
- mousedev->exist = 1;
- mousedev->minor = minor;
- mousedev_table[minor] = mousedev;
-
- mousedev->handle.dev = dev;
- mousedev->handle.handler = handler;
- mousedev->handle.private = mousedev;
-
- mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
-
- if (mousedev_mix.open)
- input_open_device(&mousedev->handle);
-
- printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
-
- return &mousedev->handle;
-}
-
-static void mousedev_disconnect(struct input_handle *handle)
-{
- struct mousedev *mousedev = handle->private;
-
- mousedev->exist = 0;
-
- if (mousedev->open) {
- input_close_device(handle);
- } else {
- if (mousedev_mix.open)
- input_close_device(handle);
- input_unregister_minor(mousedev->devfs);
- mousedev_table[mousedev->minor] = NULL;
- kfree(mousedev);
- }
-}
-
-static struct input_handler mousedev_handler = {
- event: mousedev_event,
- connect: mousedev_connect,
- disconnect: mousedev_disconnect,
- fops: &mousedev_fops,
- minor: MOUSEDEV_MINOR_BASE,
-};
-
-static int __init mousedev_init(void)
-{
- input_register_handler(&mousedev_handler);
-
- memset(&mousedev_mix, 0, sizeof(struct mousedev));
- init_waitqueue_head(&mousedev_mix.wait);
- mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
- mousedev_mix.exist = 1;
- mousedev_mix.minor = MOUSEDEV_MIX;
- mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
-
- printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
-
- return 0;
-}
-
-static void __exit mousedev_exit(void)
-{
- input_unregister_minor(mousedev_mix.devfs);
- input_unregister_handler(&mousedev_handler);
-}
-
-module_init(mousedev_init);
-module_exit(mousedev_exit);
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver");
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 0a264faaf..96a28da5e 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -1,7 +1,7 @@
/*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
**
-** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@spct.net)
+** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg)
**
**
** ChangeLog:
@@ -42,16 +42,26 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.4.0 2000/06/15 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.4.3 2000/08/22 (C) 1999-2000 Petko Manolov (petkan@dce.bg)\n";
+
+
+#define PEGASUS_USE_WAITQ
#define PEGASUS_MTU 1500
#define PEGASUS_MAX_MTU 1536
-#define SROM_WRITE 0x01
-#define SROM_READ 0x02
-#define PEGASUS_TX_TIMEOUT (HZ*5)
-#define PEGASUS_CTRL_TIMEOUT 1000
-#define PEGASUS_RESET 1
+#define EPROM_WRITE 0x01
+#define EPROM_READ 0x02
+#define PEGASUS_TX_TIMEOUT (HZ*10)
+#define PEGASUS_CTRL_TIMEOUT (HZ*5)
+#define PEGASUS_CTRL_WAIT (1<<31)
+#define PEGASUS_RUNNING 1
+#define PEGASUS_REQT_READ 0xc0
+#define PEGASUS_REQT_WRITE 0x40
+#define PEGASUS_REQ_GET_REGS 0xf0
+#define PEGASUS_REQ_SET_REGS 0xf1
+#define PEGASUS_REQ_SET_REG PEGASUS_REQ_SET_REGS
+#define NUM_CTRL_URBS 0x10
#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
@@ -75,16 +85,26 @@ enum pegasus_registers {
};
+struct pegasus;
+struct ctrl_urb_pool {
+ struct pegasus *pegasus;
+ struct urb urb;
+ devrequest dr;
+ __u8 busy;
+};
+
+
struct pegasus {
struct usb_device *usb;
struct net_device *net;
struct net_device_stats stats;
int flags;
- spinlock_t pegasus_lock, ctrl_lock;
- struct urb rx_urb, tx_urb, intr_urb, ctrl_urb;
- devrequest dr;
- unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
- unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]);
+ struct urb rx_urb, tx_urb, intr_urb;
+ struct ctrl_urb_pool ALIGN(ctrl[NUM_CTRL_URBS]);
+ wait_queue_head_t ctrl_wait;
+ struct semaphore ctrl_sem;
+ unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]);
+ unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]);
unsigned char ALIGN(intr_buff[8]);
};
@@ -100,10 +120,11 @@ static int loopback = 0;
static int multicast_filter_limit = 32;
-MODULE_AUTHOR("Petko Manolov <petkan@spct.net>");
+MODULE_AUTHOR("Petko Manolov <petkan@dce.bg>");
MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i");
-MODULE_PARM_DESC(loopback, "Enable loopback mode (Bit 0) and ??? (Bit 1)");
+MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)");
+
static struct usb_eth_dev usb_dev_id[] = {
{"Billionton USB-100", 0x08dd, 0x0986, NULL},
@@ -112,8 +133,10 @@ static struct usb_eth_dev usb_dev_id[] = {
{"D-Link DSB-650TX", 0x2001, 0x4001, NULL},
{"D-Link DSB-650TX", 0x2001, 0x4002, NULL},
{"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL},
+ {"D-Link DSB-650", 0x2001, 0xabc1, NULL},
{"D-Link DU-E10", 0x07b8, 0xabc1, NULL},
{"D-Link DU-E100", 0x07b8, 0x4002, NULL},
+ {"Linksys USB10TX", 0x066b, 0x2202, NULL},
{"Linksys USB100TX", 0x066b, 0x2203, NULL},
{"Linksys USB100TX", 0x066b, 0x2204, NULL},
{"Linksys USB Ethernet Adapter", 0x066b, 0x2206, NULL},
@@ -122,112 +145,149 @@ static struct usb_eth_dev usb_dev_id[] = {
{"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL},
{"IO DATA USB ET/TX", 0x04bb, 0x0904, NULL},
{"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, NULL},
+ {"SOHOware NUB100 Ethernet", 0x15e8, 0x9100, NULL},
{NULL, 0, 0, NULL}
};
-
-static void pegasus_ctrl_end( urb_t *urb )
+static void pegasus_unlink_ctrl_urbs( struct pegasus *pegasus )
{
- if ( urb->status )
- warn("ctrl_urb end status %d", urb->status);
+ int i;
+
+ for ( i=0; i < NUM_CTRL_URBS; i++ ) {
+ if ( pegasus->ctrl[i].urb.status == -EINPROGRESS )
+ usb_unlink_urb( &pegasus->ctrl[i].urb );
+ }
}
-static int pegasus_ctrl_timeout( urb_t *ctrl_urb )
+static int pegasus_find_ctrl_urb( struct pegasus *pegasus )
{
- int timeout=0;
-
- while ( ctrl_urb->status == -EINPROGRESS ) {
- if ( timeout++ < PEGASUS_CTRL_TIMEOUT ) {
- udelay(100);
- continue;
- }
- err("ctrl urb busy %d", ctrl_urb->status);
- usb_unlink_urb( ctrl_urb );
- return ctrl_urb->status;
- }
- return 0;
+ int i=0;
+
+ while( i < NUM_CTRL_URBS && (pegasus->ctrl[i].busy == 1 ||
+ (pegasus->ctrl[i].urb.status == -EINPROGRESS)) )
+ i++;
+
+ return i;
}
-static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data )
+static void pegasus_ctrl_end( urb_t *urb )
{
- int ret;
+ struct ctrl_urb_pool *ctrl = urb->context;
+ struct pegasus *pegasus = ctrl->pegasus;
- spin_lock( &pegasus->ctrl_lock );
- pegasus->dr.requesttype = 0xc0;
- pegasus->dr.request = 0xf0;
- pegasus->dr.value = 0x0;
- pegasus->dr.index = indx;
- pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size;
+ if ( !pegasus )
+ return;
- FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
- usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr,
- data, size, pegasus_ctrl_end, pegasus );
+ if ( urb->status )
+ warn("ctrl_urb end status %d", urb->status);
+ ctrl->busy = 0;
+#ifdef PEGASUS_USE_WAITQ
+ wake_up_interruptible( &pegasus->ctrl_wait );
+#endif
+}
- if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
- err("BAD CTRLs %d", ret);
- else
- ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb );
- spin_unlock( &pegasus->ctrl_lock );
+static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data )
+{
+ int ret, i;
+ struct ctrl_urb_pool *ctrl;
+
+ if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) {
+ return -1;
+ }
+ ctrl = &pegasus->ctrl[i];
+ ctrl->busy = 1;
+ ctrl->pegasus = pegasus;
+
+ ctrl->dr.requesttype = PEGASUS_REQT_READ;
+ ctrl->dr.request = PEGASUS_REQ_GET_REGS;
+ ctrl->dr.value = 0;
+ ctrl->dr.index = cpu_to_le16p(&indx);
+ ctrl->dr.length =
+ ctrl->urb.transfer_buffer_length = cpu_to_le16p(&size);
+
+ FILL_CONTROL_URB( &ctrl->urb, pegasus->usb,
+ usb_rcvctrlpipe(pegasus->usb,0),
+ (char *)&ctrl->dr,
+ data, size, pegasus_ctrl_end, ctrl );
+
+ if ( (ret = usb_submit_urb( &ctrl->urb )) )
+ err( __FUNCTION__ " BAD CTRLs %d", ret);
+#ifdef PEGASUS_USE_WAITQ
+ interruptible_sleep_on( &pegasus->ctrl_wait );
+#endif
return ret;
}
static int pegasus_set_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data )
{
- int ret;
-
-
- spin_lock( &pegasus->ctrl_lock );
- pegasus->dr.requesttype = 0x40;
- pegasus->dr.request = 0xf1;
- pegasus->dr.value = 0x0;
- pegasus->dr.index = indx;
- pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = size;
-
- FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
- usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr,
- data, size, pegasus_ctrl_end, pegasus );
-
- if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
- err("BAD CTRL %d", ret);
- else
- ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb );
-
- spin_unlock( &pegasus->ctrl_lock );
+ int ret, i;
+ struct ctrl_urb_pool *ctrl;
+
+ if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) {
+ return -1;
+ }
+ ctrl = &pegasus->ctrl[i];
+ ctrl->busy = 1;
+ ctrl->pegasus = pegasus;
+
+ ctrl->dr.requesttype = PEGASUS_REQT_WRITE;
+ ctrl->dr.request = PEGASUS_REQ_SET_REGS;
+ ctrl->dr.value = 0;
+ ctrl->dr.index = cpu_to_le16p( &indx );
+ ctrl->dr.length =
+ ctrl->urb.transfer_buffer_length = cpu_to_le16p( &size );
+
+ FILL_CONTROL_URB( &ctrl->urb, pegasus->usb,
+ usb_sndctrlpipe(pegasus->usb,0),
+ (char *)&ctrl->dr,
+ data, size, pegasus_ctrl_end, ctrl );
+
+ if ( (ret = usb_submit_urb( &ctrl->urb )) )
+ err( __FUNCTION__ " BAD CTRL %d", ret);
+#ifdef PEGASUS_USE_WAITQ
+ interruptible_sleep_on( &pegasus->ctrl_wait );
+#endif
return ret;
}
static int pegasus_set_register( struct pegasus *pegasus, __u16 indx,__u8 data )
{
- int ret;
-
-
- spin_lock( &pegasus->ctrl_lock );
- pegasus->dr.requesttype = 0x40;
- pegasus->dr.request = 0xf1;
- pegasus->dr.value = data;
- pegasus->dr.index = indx;
- pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1;
-
- FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
- usb_sndctrlpipe(pegasus->usb,0), (char *)&pegasus->dr,
- &data, 1, pegasus_ctrl_end, pegasus );
-
- if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
- err("BAD CTRL %d", ret);
- else
- ret = pegasus_ctrl_timeout( &pegasus->ctrl_urb );
-
- spin_unlock( &pegasus->ctrl_lock );
+ int ret, i;
+ struct ctrl_urb_pool *ctrl;
+
+ if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) {
+ return -1;
+ }
+ ctrl = &pegasus->ctrl[i];
+ ctrl->busy = 1;
+ ctrl->pegasus = pegasus;
+
+ ctrl->dr.requesttype = PEGASUS_REQT_WRITE;
+ ctrl->dr.request = PEGASUS_REQ_SET_REG;
+ ctrl->dr.value = cpu_to_le16p( &data );
+ ctrl->dr.index = cpu_to_le16p( &indx );
+ ctrl->dr.length = ctrl->urb.transfer_buffer_length = 1;
+
+ FILL_CONTROL_URB( &ctrl->urb, pegasus->usb,
+ usb_sndctrlpipe(pegasus->usb,0),
+ (char *)&ctrl->dr,
+ &data, 1, pegasus_ctrl_end, ctrl );
+
+ if ( (ret = usb_submit_urb( &ctrl->urb )) )
+ err( __FUNCTION__ " BAD CTRL %d", ret);
+#ifdef PEGASUS_USE_WAITQ
+ interruptible_sleep_on( &pegasus->ctrl_wait );
+#endif
return ret;
}
@@ -244,10 +304,9 @@ static int pegasus_read_phy_word(struct pegasus *pegasus, __u8 index, __u16 *reg
*regdata = *(__u16 *)(data);
return 0;
}
- udelay(100);
}
-
warn("read_phy_word() failed");
+
return 1;
}
@@ -262,10 +321,9 @@ static int pegasus_write_phy_word(struct pegasus *pegasus, __u8 index, __u16 reg
pegasus_get_registers(pegasus, PhyCtrl, 1, data);
if (data[0] & 0x80)
return 0;
- udelay(100);
}
-
warn("write_phy_word() failed");
+
return 1;
}
@@ -284,8 +342,8 @@ static int pegasus_rw_eprom_word(struct pegasus *pegasus, __u8 index, __u16 *ret
return 0;
}
}
-
warn("pegasus_rw_eprom_word() failed");
+
return 1;
}
@@ -294,7 +352,7 @@ static int pegasus_get_node_id(struct pegasus *pegasus, __u8 *id)
{
int i;
for (i = 0; i < 3; i++)
- if (pegasus_rw_eprom_word(pegasus,i,(__u16 *)&id[i*2],SROM_READ))
+ if (pegasus_rw_eprom_word(pegasus, i, (__u16 *)&id[i*2], EPROM_READ))
return 1;
return 0;
}
@@ -311,8 +369,6 @@ static int pegasus_reset_mac(struct pegasus *pegasus)
if (~data & 0x08) {
if (loopback & 1)
return 0;
- if (loopback & 2)
- pegasus_write_phy_word(pegasus, 0, 0x4000);
pegasus_set_register(pegasus, Gpio0, 0x24);
pegasus_set_register(pegasus, Gpio0, 0x27);
return 0;
@@ -348,7 +404,6 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
if ((partmedia & 0x1f) != 1) {
warn("party FAIL %x", partmedia);
- /* return 5; FIXME */
}
data[0] = 0xc9;
@@ -361,15 +416,21 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
}
-static void pegasus_read_bulk(struct urb *urb)
+static void pegasus_read_bulk_callback( struct urb *urb )
{
struct pegasus *pegasus = urb->context;
- struct net_device *net = pegasus->net;
+ struct net_device *net; /* = pegasus->net;*/
int count = urb->actual_length, res;
- int rx_status = *(int *)(pegasus->rx_buff + count - 4);
+ int rx_status; /*= *(int *)(pegasus->rx_buff + count - 4);*/
struct sk_buff *skb;
__u16 pkt_len;
+ if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )
+ return;
+
+ net = pegasus->net;
+ rx_status = *(int *)(pegasus->rx_buff + count - 4);
+
if (urb->status) {
dbg("%s: RX status %d", net->name, urb->status);
goto goon;
@@ -408,31 +469,30 @@ static void pegasus_read_bulk(struct urb *urb)
pegasus->stats.rx_bytes += pkt_len;
goon:
- if ((res = usb_submit_urb(&pegasus->rx_urb)))
+ if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
warn("(prb)failed rx_urb %d", res);
}
-static void pegasus_irq(urb_t *urb)
+static void pegasus_irq_callback( urb_t *urb )
{
__u8 *d = urb->transfer_buffer;
-
+
+
if ( d[0] )
dbg("txst0=0x%2x", d[0]);
}
-static void pegasus_write_bulk(struct urb *urb)
+static void pegasus_write_bulk_callback(struct urb *urb)
{
struct pegasus *pegasus = urb->context;
+ if ( !pegasus )
+ return;
if (urb->status)
info("%s: TX status %d", pegasus->net->name, urb->status);
-#if 1 /* Should be fixed */
- if (urb->status == -ETIMEDOUT)
- pegasus_reset_mac(pegasus);
-#endif
netif_wake_queue(pegasus->net);
}
@@ -440,10 +500,11 @@ static void pegasus_tx_timeout(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
+ if ( !pegasus )
+ return;
usb_unlink_urb(&pegasus->tx_urb);
- warn("%s: Tx timed out. Reseting...", net->name);
- pegasus_reset_mac( pegasus );
+ warn("%s: Tx timed out.", net->name);
pegasus->stats.tx_errors++;
net->trans_start = jiffies;
@@ -457,13 +518,14 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;
int res;
- spin_lock(&pegasus->pegasus_lock);
-
netif_stop_queue(net);
+ if ( !(pegasus->flags & PEGASUS_RUNNING) )
+ return 0;
((__u16 *)pegasus->tx_buff)[0] = skb->len;
memcpy(pegasus->tx_buff+2, skb->data, skb->len);
- (&pegasus->tx_urb)->transfer_buffer_length = count;
+ pegasus->tx_urb.transfer_buffer_length = count;
+ pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
if ((res = usb_submit_urb(&pegasus->tx_urb))) {
warn("failed tx_urb %d", res);
@@ -477,8 +539,6 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
dev_kfree_skb(skb);
- spin_unlock(&pegasus->pegasus_lock);
-
return 0;
}
@@ -489,6 +549,15 @@ static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
}
+static inline void pegasus_stop_net( struct pegasus *pegasus )
+{
+ int tmp;
+
+ pegasus_get_registers( pegasus, EthCtrl0, 1, &tmp );
+ pegasus_set_register( pegasus, EthCtrl0, tmp & 0x3f );
+}
+
+
static int pegasus_open(struct net_device *net)
{
struct pegasus *pegasus = (struct pegasus *)net->priv;
@@ -506,8 +575,7 @@ static int pegasus_open(struct net_device *net)
warn("(open)failed intr_urb %d", res);
netif_start_queue(net);
-
- MOD_INC_USE_COUNT;
+ pegasus->flags |= PEGASUS_RUNNING;
return 0;
}
@@ -517,18 +585,15 @@ static int pegasus_close(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
+ pegasus->flags &= ~PEGASUS_RUNNING;
+ pegasus_stop_net( pegasus );
+
netif_stop_queue(net);
- if ( pegasus->ctrl_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->ctrl_urb);
- if ( pegasus->rx_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->rx_urb);
- if ( pegasus->tx_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->tx_urb);
- if ( pegasus->intr_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->intr_urb);
-
- MOD_DEC_USE_COUNT;
+ usb_unlink_urb(&pegasus->rx_urb);
+ usb_unlink_urb(&pegasus->tx_urb);
+ usb_unlink_urb(&pegasus->intr_urb);
+ pegasus_unlink_ctrl_urbs( pegasus );
return 0;
}
@@ -558,24 +623,32 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
static void pegasus_set_rx_mode(struct net_device *net)
{
+#ifndef PEGASUS_USE_WAITQ
struct pegasus *pegasus = net->priv;
__u8 tmp;
+#endif
netif_stop_queue(net);
if (net->flags & IFF_PROMISC) {
- info("%s: Promiscuous mode enabled", net->name);
+#ifndef PEGASUS_USE_WAITQ
pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp);
- pegasus_set_register(pegasus, EthCtrl2, tmp | 4);
+ pegasus_set_register(pegasus, EthCtrl2, tmp | 4);
+#endif
+ info("%s: Promiscuous mode enabled", net->name);
} else if ((net->mc_count > multicast_filter_limit) ||
(net->flags & IFF_ALLMULTI)) {
+#ifndef PEGASUS_USE_WAITQ
pegasus_set_register(pegasus, EthCtrl0, 0xfa);
pegasus_set_register(pegasus, EthCtrl2, 0);
+#endif
info("%s set allmulti", net->name);
} else {
- info("%s: set Rx mode", net->name);
+#ifndef PEGASUS_USE_WAITQ
pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp);
- pegasus_set_register(pegasus, EthCtrl2, tmp & ~4);
+ pegasus_set_register(pegasus, EthCtrl2, tmp & ~4);
+#endif
+ info("%s: set Rx mode", net->name);
}
netif_wake_queue(net);
@@ -629,27 +702,32 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
net->get_stats = pegasus_netdev_stats;
net->mtu = PEGASUS_MTU;
+ init_MUTEX( &pegasus-> ctrl_sem );
+ init_waitqueue_head( &pegasus->ctrl_wait );
+
pegasus->usb = dev;
pegasus->net = net;
- pegasus->pegasus_lock = SPIN_LOCK_UNLOCKED;
- pegasus->ctrl_lock = SPIN_LOCK_UNLOCKED;
-
- FILL_BULK_URB(&pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1),
- pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus_read_bulk,
- pegasus);
- FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2),
- pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
- pegasus);
- FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
- pegasus->intr_buff, 8, pegasus_irq, pegasus, 500);
+
+ FILL_BULK_URB( &pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1),
+ pegasus->rx_buff, PEGASUS_MAX_MTU,
+ pegasus_read_bulk_callback, pegasus );
+ FILL_BULK_URB( &pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2),
+ pegasus->tx_buff, PEGASUS_MAX_MTU,
+ pegasus_write_bulk_callback, pegasus );
+ FILL_INT_URB( &pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
+ pegasus->intr_buff, 8, pegasus_irq_callback,
+ pegasus, 128 );
if (pegasus_reset_mac(pegasus)) {
err("can't reset MAC");
kfree(pegasus);
+ pegasus = NULL;
return NULL;
}
- printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
+ info( "%s: %s\n", net->name, usb_dev_id[dev_indx].name );
+
+ MOD_INC_USE_COUNT;
return pegasus;
}
@@ -664,21 +742,18 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
return;
}
- if (pegasus->net->flags & IFF_UP)
- dev_close(pegasus->net);
-
+ pegasus->flags &= ~PEGASUS_RUNNING;
unregister_netdev(pegasus->net);
-
- if ( pegasus->ctrl_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->ctrl_urb);
- if ( pegasus->rx_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->rx_urb);
- if ( pegasus->tx_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->tx_urb);
- if ( pegasus->intr_urb.status == -EINPROGRESS )
- usb_unlink_urb(&pegasus->intr_urb);
+
+ usb_unlink_urb(&pegasus->rx_urb);
+ usb_unlink_urb(&pegasus->tx_urb);
+ usb_unlink_urb(&pegasus->intr_urb);
+ pegasus_unlink_ctrl_urbs( pegasus );
kfree(pegasus);
+ pegasus = NULL;
+
+ MOD_DEC_USE_COUNT;
}
@@ -690,7 +765,7 @@ static struct usb_driver pegasus_driver = {
int __init pegasus_init(void)
{
- printk( version );
+ info( "%s", version );
return usb_register(&pegasus_driver);
}
diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c
index 96fa971d8..bbbc05f33 100644
--- a/drivers/usb/printer.c
+++ b/drivers/usb/printer.c
@@ -1,10 +1,10 @@
/*
- * printer.c Version 0.5
+ * printer.c Version 0.6
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
- * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2000 Randy Dunlap <randy.dunlap@intel.com>
+ * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
*
* USB Printer Device Class driver for USB printers and printer cables
*
@@ -16,6 +16,7 @@
* v0.3 - cleaner again, waitqueue fixes
* v0.4 - fixes in unidirectional mode
* v0.5 - add DEVICE_ID string support
+ * v0.6 - never time out
*/
/*
@@ -71,7 +72,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
-#define USBLP_WRITE_TIMEOUT (60*60*HZ) /* 60 minutes */
+#define USBLP_WRITE_TIMEOUT (5*HZ) /* 5 seconds */
struct usblp {
struct usb_device *dev; /* USB device */
@@ -83,10 +84,10 @@ struct usblp {
unsigned char used; /* True if open */
unsigned char bidir; /* interface is bidirectional */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
- /* first 2 bytes are (big-endian) length */
+ /* first 2 bytes are (big-endian) length */
};
-static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ };
+static struct usblp *usblp_table[USBLP_MINORS];
/*
* Functions for usblp control messages.
@@ -121,7 +122,8 @@ static void usblp_bulk(struct urb *urb)
return;
if (urb->status)
- warn("nonzero read/write bulk status received: %d", urb->status);
+ warn("usblp%d: nonzero read/write bulk status received: %d",
+ usblp->minor, urb->status);
wake_up_interruptible(&usblp->wait);
}
@@ -130,29 +132,27 @@ static void usblp_bulk(struct urb *urb)
* Get and print printer errors.
*/
-static int usblp_check_status(struct usblp *usblp)
+static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
+
+static int usblp_check_status(struct usblp *usblp, int err)
{
- unsigned char status;
+ unsigned char status, newerr = 0;
if (usblp_read_status(usblp, &status)) {
- err("failed reading usblp status");
- return -EIO;
+ err("usblp%d: failed reading printer status", usblp->minor);
+ return 0;
}
if (~status & LP_PERRORP) {
- if (status & LP_POUTPA) {
- info("usblp%d: out of paper", usblp->minor);
- return -ENOSPC;
- }
- if (~status & LP_PSELECD) {
- info("usblp%d: off-line", usblp->minor);
- return -EIO;
- }
- info("usblp%d: on fire", usblp->minor);
- return -EIO;
+ newerr = 3;
+ if (status & LP_POUTPA) newerr = 1;
+ if (~status & LP_PSELECD) newerr = 2;
}
- return 0;
+ if (newerr != err)
+ info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
+
+ return newerr;
}
/*
@@ -179,8 +179,10 @@ static int usblp_open(struct inode *inode, struct file *file)
if (usblp->used)
goto out;
- if ((retval = usblp_check_status(usblp)))
+ if ((retval = usblp_check_status(usblp, 0))) {
+ retval = retval > 1 ? -EIO : -ENOSPC;
goto out;
+ }
usblp->used = 1;
file->private_data = usblp;
@@ -228,27 +230,30 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- int length;
struct usblp *usblp = file->private_data;
+ int length;
if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ))
return -EINVAL;
switch (_IOC_NR(cmd)) {
- case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
- length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
-#if 0
- dbg ("usblp_ioctl GET_DEVICE_ID: actlen=%d, user size=%d, string='%s'",
- length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
-#endif
- if (length > _IOC_SIZE(cmd))
- length = _IOC_SIZE(cmd); /* truncate */
- if (copy_to_user ((unsigned char *)arg, usblp->device_id_string, (unsigned long) length))
- return -EFAULT;
- break;
- default:
- return -EINVAL;
+ case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
+
+ length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
+
+ dbg ("usblp_ioctl GET_DEVICE_ID actlen: %d, size: %d, string: '%s'",
+ length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
+
+ if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */
+
+ if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length))
+ return -EFAULT;
+
+ break;
+
+ default:
+ return -EINVAL;
}
return 0;
@@ -257,7 +262,7 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- int retval, timeout, writecount = 0;
+ int timeout, err = 0, writecount = 0;
while (writecount < count) {
@@ -276,28 +281,17 @@ static ssize_t usblp_write(struct file *file, const char *buffer, size_t count,
}
}
- if (usblp->writeurb.status == -EINPROGRESS) {
- usb_unlink_urb(&usblp->writeurb);
- err("usblp%d: timed out", usblp->minor);
- return -EIO;
- }
-
if (!usblp->dev)
return -ENODEV;
- if (!usblp->writeurb.status) {
- writecount += usblp->writeurb.transfer_buffer_length;
- usblp->writeurb.transfer_buffer_length = 0;
- } else {
- if (!(retval = usblp_check_status(usblp))) {
- err("usblp%d: error %d writing to printer (retval=%d)",
- usblp->minor, usblp->writeurb.status, retval);
- return -EIO;
- }
-
- return retval;
+ if (usblp->writeurb.status) {
+ err = usblp_check_status(usblp, err);
+ continue;
}
+ writecount += usblp->writeurb.transfer_buffer_length;
+ usblp->writeurb.transfer_buffer_length = 0;
+
if (writecount == count)
continue;
@@ -368,14 +362,14 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
interface = &dev->actconfig->interface[ifnum].altsetting[i];
if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
- (interface->bInterfaceProtocol != 1 && interface->bInterfaceProtocol != 2) ||
- (interface->bInterfaceProtocol > interface->bNumEndpoints))
+ interface->bInterfaceProtocol < 1 || interface->bInterfaceProtocol > 3 ||
+ (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2))
continue;
if (alts == -1)
alts = i;
- if (!bidir && interface->bInterfaceProtocol == 2) {
+ if (!bidir && interface->bInterfaceProtocol > 1) {
bidir = 1;
alts = i;
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index c5c403b2b..f168b1bfc 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -14,6 +14,58 @@
* Peter Berger (pberger@brimson.com)
* Al Borchers (borchers@steinerpoint.com)
*
+* (8/8/2000) pberger and borchers
+* -- Fixed close so that
+* - it can timeout while waiting for transmit idle, if needed;
+* - it ignores interrupts when flushing the port, turning
+* of modem signalling, and so on;
+* - it waits for the flush to really complete before returning.
+* -- Read_bulk_callback and write_bulk_callback check for a closed
+* port before using the tty struct or writing to the port.
+* -- The two changes above fix the oops caused by interrupted closes.
+* -- Added interruptible args to write_oob_command and set_modem_signals
+* and added a timeout arg to transmit_idle; needed for fixes to
+* close.
+* -- Added code for rx_throttle and rx_unthrottle so that input flow
+* control works.
+* -- Added code to set overrun, parity, framing, and break errors
+* (untested).
+* -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length
+* bulk writes are done. These hung the Digi USB device. The
+* 0 length bulk writes were a new feature of usb-uhci added in
+* the 2.4.0-test6 kernels.
+* -- Fixed mod inc race in open; do mod inc before sleeping to wait
+* for a close to finish.
+*
+* (7/31/2000) pberger
+* -- Fixed bugs with hardware handshaking:
+* - Added code to set/clear tty->hw_stopped in digi_read_oob_callback()
+* and digi_set_termios()
+* -- Added code in digi_set_termios() to
+* - add conditional in code handling transition from B0 to only
+* set RTS if RTS/CTS flow control is either not in use or if
+* the port is not currently throttled.
+* - handle turning off CRTSCTS.
+*
+* (7/30/2000) borchers
+* -- Added support for more than one Digi USB device by moving
+* globals to a private structure in the pointed to from the
+* usb_serial structure.
+* -- Moved the modem change and transmit idle wait queues into
+* the port private structure, so each port has its own queue
+* rather than sharing global queues.
+* -- Added support for break signals.
+*
+* (7/25/2000) pberger
+* -- Added USB-2 support. Note: the USB-2 supports 3 devices: two
+* serial and a parallel port. The parallel port is implemented
+* as a serial-to-parallel converter. That is, the driver actually
+* presents all three USB-2 interfaces as serial ports, but the third
+* one physically connects to a parallel device. Thus, for example,
+* one could plug a parallel printer into the USB-2's third port,
+* but from the kernel's (and userland's) point of view what's
+* actually out there is a serial device.
+*
* (7/15/2000) borchers
* -- Fixed race in open when a close is in progress.
* -- Keep count of opens and dec the module use count for each
@@ -24,8 +76,8 @@
* callbacks, and no longer restart read chains if there is
* a status error or a sanity error. This fixed the seg
* faults and other errors we used to get on disconnect.
-* -- Port->active is once again a flag, not a count, as it was
-* intended by usb-serial. Since it was only a char it would
+* -- Port->active is once again a flag as usb-serial intended it
+* to be, not a count. Since it was only a char it would
* have been limited to 256 simultaneous opens. Now the open
* count is kept in the port private structure in dp_open_count.
* -- Added code for modularization of the digi_acceleport driver.
@@ -51,7 +103,7 @@
*
* (6/4/2000) pberger and borchers
* -- Replaced separate calls to spin_unlock_irqrestore and
-* interruptible_sleep_on_interruptible with a new function
+* interruptible_sleep_on_timeout with a new function
* cond_wait_interruptible_timeout_irqrestore. This eliminates
* the race condition where the wake up could happen after
* the unlock and before the sleep.
@@ -157,7 +209,7 @@
* - Following Documentation/DocBook/kernel-locking.pdf no spin locks
* are held when calling copy_to/from_user or printk.
*
-* $Id: digi_acceleport.c,v 1.5 2000/07/18 04:52:43 root Exp $
+* $Id: digi_acceleport.c,v 1.80 2000/08/09 06:36:18 root Exp $
*/
#include <linux/config.h>
@@ -188,9 +240,13 @@
/* Defines */
-/* port buffer length -- must be <= transfer buffer length - 2 */
+/* port output buffer length -- must be <= transfer buffer length - 2 */
/* so we can be sure to send the full buffer in one urb */
-#define DIGI_PORT_BUF_LEN 8
+#define DIGI_OUT_BUF_SIZE 8
+
+/* port input buffer length -- must be >= transfer buffer length - 3 */
+/* so we can be sure to hold at least one full buffer from one urb */
+#define DIGI_IN_BUF_SIZE 64
/* retry timeout while sleeping */
#define DIGI_RETRY_TIMEOUT (HZ/10)
@@ -205,7 +261,8 @@
/* ids */
#define DIGI_VENDOR_ID 0x05c5
-#define DIGI_ID 0x0004
+#define DIGI_2_ID 0x0002 /* USB-2 */
+#define DIGI_4_ID 0x0004 /* USB-4 */
/* commands
* "INB": can be used on the in-band endpoint
@@ -335,29 +392,45 @@
/* Structures */
-typedef struct digi_private {
- int dp_port_num;
+typedef struct digi_serial {
+ spinlock_t ds_serial_lock;
+ struct usb_serial_port *ds_oob_port; /* out-of-band port */
+ int ds_oob_port_num; /* index of out-of-band port */
+ int ds_device_started;
+} digi_serial_t;
+
+typedef struct digi_port {
spinlock_t dp_port_lock;
- int dp_buf_len;
- unsigned char dp_buf[DIGI_PORT_BUF_LEN];
+ int dp_port_num;
+ int dp_out_buf_len;
+ unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
+ int dp_in_buf_len;
+ unsigned char dp_in_buf[DIGI_IN_BUF_SIZE];
+ unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE];
unsigned int dp_modem_signals;
+ wait_queue_head_t dp_modem_change_wait;
int dp_open_count; /* inc on open, dec on close */
int dp_transmit_idle;
+ wait_queue_head_t dp_transmit_idle_wait;
+ int dp_throttled;
+ int dp_throttle_restart;
+ wait_queue_head_t dp_flush_wait;
int dp_in_close; /* close in progress */
wait_queue_head_t dp_close_wait; /* wait queue for close */
struct tq_struct dp_wakeup_task;
-} digi_private_t;
+} digi_port_t;
/* Local Function Declarations */
static void digi_wakeup_write( struct usb_serial_port *port );
static void digi_wakeup_write_lock( struct usb_serial_port *port );
-static int digi_write_oob_command( unsigned char *buf, int count );
+static int digi_write_oob_command( struct usb_serial_port *port,
+ unsigned char *buf, int count, int interruptible );
static int digi_write_inb_command( struct usb_serial_port *port,
- unsigned char *buf, int count ) __attribute__((unused));
+ unsigned char *buf, int count, unsigned long timeout );
static int digi_set_modem_signals( struct usb_serial_port *port,
- unsigned int modem_signals );
+ unsigned int modem_signals, int interruptible );
static int digi_transmit_idle( struct usb_serial_port *port,
unsigned long timeout );
static void digi_rx_throttle (struct usb_serial_port *port);
@@ -386,25 +459,40 @@ static int digi_read_oob_callback( struct urb *urb );
/* device info needed for the Digi serial converter */
static u16 digi_vendor_id = DIGI_VENDOR_ID;
-static u16 digi_product_id = DIGI_ID;
-
-/* out of band port */
-static int oob_port_num; /* index of out-of-band port */
-static struct usb_serial_port *oob_port; /* out-of-band port */
-static int device_startup = 0;
-
-spinlock_t startup_lock; /* used by startup_device */
-
-static wait_queue_head_t modem_change_wait;
-static wait_queue_head_t transmit_idle_wait;
+static u16 digi_product_2_id = DIGI_2_ID; /* USB 2 */
+static u16 digi_product_4_id = DIGI_4_ID; /* USB 4 */
+static struct usb_serial_device_type digi_acceleport_2_device = {
+ name: "Digi USB",
+ idVendor: &digi_vendor_id,
+ idProduct: &digi_product_2_id,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 0,
+ num_bulk_in: 4,
+ num_bulk_out: 4,
+ num_ports: 3,
+ open: digi_open,
+ close: digi_close,
+ write: digi_write,
+ write_room: digi_write_room,
+ write_bulk_callback: digi_write_bulk_callback,
+ read_bulk_callback: digi_read_bulk_callback,
+ chars_in_buffer: digi_chars_in_buffer,
+ throttle: digi_rx_throttle,
+ unthrottle: digi_rx_unthrottle,
+ ioctl: digi_ioctl,
+ set_termios: digi_set_termios,
+ break_ctl: digi_break_ctl,
+ startup: digi_startup,
+ shutdown: digi_shutdown,
+};
-/* Globals */
-
-struct usb_serial_device_type digi_acceleport_device = {
+static struct usb_serial_device_type digi_acceleport_4_device = {
name: "Digi USB",
idVendor: &digi_vendor_id,
- idProduct: &digi_product_id,
+ idProduct: &digi_product_4_id,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: MUST_HAVE,
needs_bulk_out: MUST_HAVE,
@@ -479,7 +567,7 @@ static void digi_wakeup_write_lock( struct usb_serial_port *port )
{
unsigned long flags;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
spin_lock_irqsave( &priv->dp_port_lock, flags );
@@ -515,20 +603,23 @@ static void digi_wakeup_write( struct usb_serial_port *port )
* Write commands on the out of band port. Commands are 4
* bytes each, multiple commands can be sent at once, and
* no command will be split across USB packets. Returns 0
-* if successful, -EINTR if interrupted while sleeping, or
-* a negative error returned by usb_submit_urb.
+* if successful, -EINTR if interrupted while sleeping and
+* the interruptible flag is true, or a negative error
+* returned by usb_submit_urb.
*/
-static int digi_write_oob_command( unsigned char *buf, int count )
+static int digi_write_oob_command( struct usb_serial_port *port,
+ unsigned char *buf, int count, int interruptible )
{
int ret = 0;
int len;
- digi_private_t *oob_priv = (digi_private_t *)(oob_port->private);
+ struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
+ digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
unsigned long flags = 0;
-dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count );
+dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count );
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
@@ -538,7 +629,7 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count );
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags );
- if( signal_pending(current) ) {
+ if( interruptible && signal_pending(current) ) {
return( -EINTR );
}
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
@@ -562,8 +653,8 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count );
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
if( ret ) {
- dbg( "digi_write_oob_command: usb_submit_urb failed, ret=%d",
- ret );
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
+ ret );
}
return( ret );
@@ -576,17 +667,20 @@ dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_port_num, count );
*
* Write commands on the given port. Commands are 4
* bytes each, multiple commands can be sent at once, and
-* no command will be split across USB packets. Returns 0
-* if successful, or a negative error returned by digi_write.
+* no command will be split across USB packets. If timeout
+* is non-zero, write in band command will return after
+* waiting unsuccessfully for the URB status to clear for
+* timeout ticks. Returns 0 if successful, or a negative
+* error returned by digi_write.
*/
static int digi_write_inb_command( struct usb_serial_port *port,
- unsigned char *buf, int count )
+ unsigned char *buf, int count, unsigned long timeout )
{
int ret = 0;
int len;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned char *data = port->write_urb->transfer_buffer;
unsigned long flags = 0;
@@ -594,11 +688,17 @@ static int digi_write_inb_command( struct usb_serial_port *port,
dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num,
count );
+ if( timeout )
+ timeout += jiffies;
+ else
+ timeout = ULONG_MAX;
+
spin_lock_irqsave( &priv->dp_port_lock, flags );
- while( count > 0 ) {
+ while( count > 0 && ret == 0 ) {
- while( port->write_urb->status == -EINPROGRESS ) {
+ while( port->write_urb->status == -EINPROGRESS
+ && jiffies < timeout ) {
cond_wait_interruptible_timeout_irqrestore(
&port->write_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
@@ -611,25 +711,26 @@ count );
/* len must be a multiple of 4 and small enough to */
/* guarantee the write will send buffered data first, */
/* so commands are in order with data and not split */
- len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
+ len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
if( len > 4 )
len &= ~3;
/* write any buffered data first */
- if( priv->dp_buf_len > 0 ) {
+ if( priv->dp_out_buf_len > 0 ) {
data[0] = DIGI_CMD_SEND_DATA;
- data[1] = priv->dp_buf_len;
- memcpy( data+2, priv->dp_buf, priv->dp_buf_len );
- memcpy( data+2+priv->dp_buf_len, buf, len );
+ data[1] = priv->dp_out_buf_len;
+ memcpy( data+2, priv->dp_out_buf,
+ priv->dp_out_buf_len );
+ memcpy( data+2+priv->dp_out_buf_len, buf, len );
port->write_urb->transfer_buffer_length
- = priv->dp_buf_len+2+len;
+ = priv->dp_out_buf_len+2+len;
} else {
memcpy( data, buf, len );
port->write_urb->transfer_buffer_length = len;
}
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
count -= len;
buf += len;
}
@@ -639,8 +740,8 @@ count );
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
if( ret ) {
- dbg( "digi_write_inb_command: usb_submit_urb failed, ret=%d",
- ret );
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, priv->dp_port_num );
}
return( ret );
@@ -659,13 +760,14 @@ count );
*/
static int digi_set_modem_signals( struct usb_serial_port *port,
- unsigned int modem_signals )
+ unsigned int modem_signals, int interruptible )
{
int ret;
+ digi_port_t *port_priv = (digi_port_t *)port->private;
+ struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
+ digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
unsigned char *data = oob_port->write_urb->transfer_buffer;
- digi_private_t *port_priv = (digi_private_t *)(port->private);
- digi_private_t *oob_priv = (digi_private_t *)(oob_port->private);
unsigned long flags = 0;
@@ -680,7 +782,7 @@ port_priv->dp_port_num, modem_signals );
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags );
- if( signal_pending(current) ) {
+ if( interruptible && signal_pending(current) ) {
return( -EINTR );
}
spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
@@ -711,7 +813,7 @@ port_priv->dp_port_num, modem_signals );
spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
if( ret ) {
- dbg( "digi_set_modem_signals: usb_submit_urb failed, ret=%d",
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
ret );
}
@@ -738,7 +840,7 @@ static int digi_transmit_idle( struct usb_serial_port *port,
int ret;
unsigned char buf[2];
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned long flags = 0;
@@ -749,16 +851,16 @@ static int digi_transmit_idle( struct usb_serial_port *port,
buf[0] = DIGI_CMD_TRANSMIT_IDLE;
buf[1] = 0;
- if( (ret=digi_write_inb_command( port, buf, 2 )) != 0 )
- return( ret );
-
timeout += jiffies;
+ if( (ret=digi_write_inb_command( port, buf, 2, timeout-jiffies )) != 0 )
+ return( ret );
+
spin_lock_irqsave( &priv->dp_port_lock, flags );
while( jiffies < timeout && !priv->dp_transmit_idle ) {
cond_wait_interruptible_timeout_irqrestore(
- &transmit_idle_wait, DIGI_RETRY_TIMEOUT,
+ &priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
if( signal_pending(current) ) {
return( -EINTR );
@@ -777,21 +879,18 @@ static int digi_transmit_idle( struct usb_serial_port *port,
static void digi_rx_throttle( struct usb_serial_port *port )
{
-#ifdef DEBUG
- digi_private_t *priv = (digi_private_t *)(port->private);
-#endif
+ unsigned long flags;
+ digi_port_t *priv = (digi_port_t *)(port->private);
dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
- /* stop receiving characters. We just turn off the URB request, and
- let chars pile up in the device. If we're doing hardware
- flowcontrol, the device will signal the other end when its buffer
- fills up. If we're doing XON/XOFF, this would be a good time to
- send an XOFF, although it might make sense to foist that off
- upon the device too. */
-
- // usb_unlink_urb(port->interrupt_in_urb);
+ /* stop receiving characters by not resubmitting the read urb */
+ spin_lock_irqsave( &priv->dp_port_lock, flags );
+ priv->dp_throttled = 1;
+ priv->dp_throttle_restart = 0;
+ priv->dp_in_buf_len = 0;
+ spin_unlock_irqrestore( &priv->dp_port_lock, flags );
}
@@ -799,16 +898,43 @@ dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
static void digi_rx_unthrottle( struct usb_serial_port *port )
{
-#ifdef DEBUG
- digi_private_t *priv = (digi_private_t *)(port->private);
-#endif
+ int ret = 0;
+ int len;
+ unsigned long flags;
+ digi_port_t *priv = (digi_port_t *)(port->private);
+ struct tty_struct *tty = port->tty;
dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
- /* just restart the receive interrupt URB */
- //if (usb_submit_urb(port->interrupt_in_urb))
- // dbg( "digi_rx_unthrottle: usb_submit_urb failed" );
+ spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+ /* send any buffered chars from throttle time on to tty subsystem */
+ len = MIN( priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
+ if( len > 0 ) {
+ memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len );
+ memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len );
+ tty->flip.char_buf_ptr += len;
+ tty->flip.flag_buf_ptr += len;
+ tty->flip.count += len;
+ tty_flip_buffer_push( tty );
+ }
+
+ /* restart read chain */
+ if( priv->dp_throttle_restart )
+ ret = usb_submit_urb( port->read_urb );
+
+ /* turn throttle off */
+ priv->dp_throttled = 0;
+ priv->dp_in_buf_len = 0;
+ priv->dp_throttle_restart = 0;
+
+ spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+ if( ret ) {
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, priv->dp_port_num );
+ }
}
@@ -817,12 +943,13 @@ static void digi_set_termios( struct usb_serial_port *port,
struct termios *old_termios )
{
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned int iflag = port->tty->termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_iflag = old_termios->c_iflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned char buf[32];
+ unsigned int modem_signals;
int arg,ret;
int i = 0;
@@ -837,13 +964,18 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
/* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag&CBAUD) == B0 ) {
/* don't set RTS if using hardware flow control */
- /* and throttling input -- not implemented yet */
- digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS );
+ /* and throttling input */
+ modem_signals = TIOCM_DTR;
+ if( !(port->tty->termios->c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &port->tty->flags) ) {
+ modem_signals |= TIOCM_RTS;
+ }
+ digi_set_modem_signals( port, modem_signals, 1 );
}
switch( (cflag&CBAUD) ) {
/* drop DTR and RTS on transition to B0 */
- case B0: digi_set_modem_signals( port, 0 ); break;
+ case B0: digi_set_modem_signals( port, 0, 1 ); break;
case B50: arg = DIGI_BAUD_50; break;
case B75: arg = DIGI_BAUD_75; break;
case B110: arg = DIGI_BAUD_110; break;
@@ -947,10 +1079,20 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
else
arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
- if( (cflag&CRTSCTS) )
+ if( (cflag&CRTSCTS) ) {
+
arg |= DIGI_INPUT_FLOW_CONTROL_RTS;
- else
+
+ /* On USB-4 it is necessary to assert RTS prior */
+ /* to selecting RTS input flow control. */
+ buf[i++] = DIGI_CMD_SET_RTS_SIGNAL;
+ buf[i++] = priv->dp_port_num;
+ buf[i++] = DIGI_RTS_ACTIVE;
+ buf[i++] = 0;
+
+ } else {
arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS;
+ }
buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
buf[i++] = priv->dp_port_num;
@@ -960,8 +1102,8 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
}
/* set output flow control */
- /*if( (iflag&IXON) != (old_iflag&IXON)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) )*/ {
+ if( (iflag&IXON) != (old_iflag&IXON)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
arg = 0;
@@ -970,10 +1112,12 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
else
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
- if( (cflag&CRTSCTS) )
+ if( (cflag&CRTSCTS) ) {
arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
- else
+ } else {
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
+ port->tty->hw_stopped = 0;
+ }
buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
buf[i++] = priv->dp_port_num;
@@ -997,7 +1141,7 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
}
- if( (ret=digi_write_oob_command( buf, i )) != 0 )
+ if( (ret=digi_write_oob_command( port, buf, i, 1 )) != 0 )
dbg( "digi_set_termios: write oob failed, ret=%d", ret );
}
@@ -1006,12 +1150,15 @@ dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, ol
static void digi_break_ctl( struct usb_serial_port *port, int break_state )
{
-#ifdef DEBUG
- digi_private_t *priv = (digi_private_t *)(port->private);
-#endif
+ unsigned char buf[4];
-dbg( "digi_break_ctl: TOP: port=%d", priv->dp_port_num );
+ buf[0] = DIGI_CMD_BREAK_CONTROL;
+ buf[1] = 2; /* length */
+ buf[2] = break_state ? 1 : 0;
+ buf[3] = 0; /* pad */
+
+ digi_write_inb_command( port, buf, 4, 0 );
}
@@ -1020,7 +1167,7 @@ static int digi_ioctl( struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg )
{
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned int val;
unsigned long flags = 0;
@@ -1048,7 +1195,7 @@ dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd );
else if( cmd == TIOCMBIC )
val = priv->dp_modem_signals & ~val;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
- return( digi_set_modem_signals( port, val ) );
+ return( digi_set_modem_signals( port, val, 1 ) );
case TIOCMIWAIT:
/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
@@ -1072,7 +1219,7 @@ static int digi_write( struct usb_serial_port *port, int from_user,
{
int ret,data_len,new_len;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned char *data = port->write_urb->transfer_buffer;
unsigned char user_buf[64]; /* 64 bytes is max USB bulk packet */
unsigned long flags = 0;
@@ -1098,9 +1245,10 @@ priv->dp_port_num, count, from_user, in_interrupt() );
/* buffer data if count is 1 (probably put_char) if possible */
if( count == 1 ) {
new_len = MIN( count,
- DIGI_PORT_BUF_LEN-priv->dp_buf_len );
- memcpy( priv->dp_buf+priv->dp_buf_len, buf, new_len );
- priv->dp_buf_len += new_len;
+ DIGI_OUT_BUF_SIZE-priv->dp_out_buf_len );
+ memcpy( priv->dp_out_buf+priv->dp_out_buf_len, buf,
+ new_len );
+ priv->dp_out_buf_len += new_len;
} else {
new_len = 0;
}
@@ -1113,8 +1261,8 @@ priv->dp_port_num, count, from_user, in_interrupt() );
/* allow space for any buffered data and for new data, up to */
/* transfer buffer size - 2 (for command and length bytes) */
- new_len = MIN( count, port->bulk_out_size-2-priv->dp_buf_len );
- data_len = new_len + priv->dp_buf_len;
+ new_len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
+ data_len = new_len + priv->dp_out_buf_len;
if( data_len == 0 ) {
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
@@ -1127,22 +1275,24 @@ priv->dp_port_num, count, from_user, in_interrupt() );
*data++ = data_len;
/* copy in buffered data first */
- memcpy( data, priv->dp_buf, priv->dp_buf_len );
- data += priv->dp_buf_len;
+ memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len );
+ data += priv->dp_out_buf_len;
/* copy in new data */
memcpy( data, from_user ? user_buf : buf, new_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
ret = new_len;
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
}
/* return length of new data written, or error */
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
if( ret < 0 ) {
- dbg( "digi_write: usb_submit_urb failed, ret=%d", ret );
+ err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, priv->dp_port_num );
}
+
dbg( "digi_write: returning %d", ret );
return( ret );
@@ -1154,21 +1304,27 @@ static void digi_write_bulk_callback( struct urb *urb )
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial;
- digi_private_t *priv;
+ digi_port_t *priv;
int ret = 0;
-dbg( "digi_write_bulk_callback: TOP" );
+dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
- /* port sanity check */
- if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) {
+ /* port and serial sanity check */
+ if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
err( __FUNCTION__ ": port or port->private is NULL, status=%d",
urb->status );
return;
}
+ serial = port->serial;
+ if( serial == NULL || serial->private == NULL ) {
+ err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status );
+ return;
+ }
/* handle oob callback */
- if( priv->dp_port_num == oob_port_num ) {
+ if( priv->dp_port_num
+ == ((digi_serial_t *)(serial->private))->ds_oob_port_num ) {
dbg( "digi_write_bulk_callback: oob callback" );
spin_lock( &priv->dp_port_lock );
wake_up_interruptible( &port->write_wait );
@@ -1176,29 +1332,29 @@ dbg( "digi_write_bulk_callback: TOP" );
return;
}
- /* sanity checks */
- if( port_paranoia_check( port, "digi_write_bulk_callback" ) )
- return;
- serial = port->serial;
- if( serial_paranoia_check( serial, "digi_write_bulk_callback" ) )
+ /* further sanity checks */
+ if( port_paranoia_check( port, __FUNCTION__ )
+ || serial_paranoia_check( serial, __FUNCTION__ ) )
return;
- /* try to send any buffered data on this port */
+ /* try to send any buffered data on this port, if it is open */
spin_lock( &priv->dp_port_lock );
- if( port->write_urb->status != -EINPROGRESS && priv->dp_buf_len > 0 ) {
+ if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS
+ && priv->dp_out_buf_len > 0 ) {
*((unsigned char *)(port->write_urb->transfer_buffer))
= (unsigned char)DIGI_CMD_SEND_DATA;
*((unsigned char *)(port->write_urb->transfer_buffer)+1)
- = (unsigned char)priv->dp_buf_len;
+ = (unsigned char)priv->dp_out_buf_len;
- port->write_urb->transfer_buffer_length = priv->dp_buf_len+2;
+ port->write_urb->transfer_buffer_length
+ = priv->dp_out_buf_len+2;
- memcpy( port->write_urb->transfer_buffer+2, priv->dp_buf,
- priv->dp_buf_len );
+ memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf,
+ priv->dp_out_buf_len );
if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
}
}
@@ -1224,7 +1380,7 @@ static int digi_write_room( struct usb_serial_port *port )
{
int room;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
unsigned long flags = 0;
@@ -1233,7 +1389,7 @@ static int digi_write_room( struct usb_serial_port *port )
if( port->write_urb->status == -EINPROGRESS )
room = 0;
else
- room = port->bulk_out_size - 2 - priv->dp_buf_len;
+ room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
@@ -1246,7 +1402,7 @@ dbg( "digi_write_room: port=%d, room=%d", priv->dp_port_num, room );
static int digi_chars_in_buffer( struct usb_serial_port *port )
{
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
if( port->write_urb->status == -EINPROGRESS ) {
@@ -1254,8 +1410,8 @@ dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_ou
/* return( port->bulk_out_size - 2 ); */
return( 256 );
} else {
-dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_buf_len );
- return( priv->dp_buf_len );
+dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len );
+ return( priv->dp_out_buf_len );
}
}
@@ -1266,7 +1422,7 @@ static int digi_open( struct usb_serial_port *port, struct file *filp )
int ret;
unsigned char buf[32];
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
struct termios not_termios;
unsigned long flags = 0;
@@ -1285,12 +1441,18 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por
return( -EAGAIN );
}
+ /* inc module use count before sleeping to wait for closes */
+ ++priv->dp_open_count;
+ MOD_INC_USE_COUNT;
+
/* wait for a close in progress to finish */
while( priv->dp_in_close ) {
cond_wait_interruptible_timeout_irqrestore(
&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags );
if( signal_pending(current) ) {
+ --priv->dp_open_count;
+ MOD_DEC_USE_COUNT;
return( -EINTR );
}
spin_lock_irqsave( &priv->dp_port_lock, flags );
@@ -1299,16 +1461,12 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por
/* if port is already open, just return */
/* be sure exactly one open proceeds */
if( port->active ) {
- ++priv->dp_open_count;
- MOD_INC_USE_COUNT;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
return( 0 );
}
- /* open is certain */
+ /* first open, mark port as active */
port->active = 1;
- ++priv->dp_open_count;
- MOD_INC_USE_COUNT;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
/* read modem signals automatically whenever they change */
@@ -1323,7 +1481,7 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por
buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
buf[7] = 0;
- if( (ret=digi_write_oob_command( buf, 8 )) != 0 )
+ if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 )
dbg( "digi_open: write oob failed, ret=%d", ret );
/* set termios settings */
@@ -1332,7 +1490,7 @@ dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, por
digi_set_termios( port, &not_termios );
/* set DTR and RTS */
- digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS );
+ digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 );
return( 0 );
@@ -1345,7 +1503,7 @@ static void digi_close( struct usb_serial_port *port, struct file *filp )
int ret;
unsigned char buf[32];
struct tty_struct *tty = port->tty;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)port->private;
unsigned long flags = 0;
@@ -1386,7 +1544,7 @@ dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, po
}
/* drop DTR and RTS */
- digi_set_modem_signals( port, 0 );
+ digi_set_modem_signals( port, 0, 0 );
/* disable input flow control */
buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
@@ -1406,29 +1564,24 @@ dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, po
buf[10] = DIGI_DISABLE;
buf[11] = 0;
- /* flush fifos */
- buf[12] = DIGI_CMD_IFLUSH_FIFO;
+ /* disable receive */
+ buf[12] = DIGI_CMD_RECEIVE_ENABLE;
buf[13] = priv->dp_port_num;
- buf[14] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+ buf[14] = DIGI_DISABLE;
buf[15] = 0;
- /* disable receive */
- buf[16] = DIGI_CMD_RECEIVE_ENABLE;
+ /* flush fifos */
+ buf[16] = DIGI_CMD_IFLUSH_FIFO;
buf[17] = priv->dp_port_num;
- buf[18] = DIGI_DISABLE;
+ buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
buf[19] = 0;
- if( (ret=digi_write_oob_command( buf, 20 )) != 0 )
+ if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )
dbg( "digi_close: write oob failed, ret=%d", ret );
/* wait for final commands on oob port to complete */
- while( oob_port->write_urb->status == -EINPROGRESS ) {
- interruptible_sleep_on_timeout( &oob_port->write_wait,
- DIGI_RETRY_TIMEOUT );
- if( signal_pending(current) ) {
- break;
- }
- }
+ interruptible_sleep_on_timeout( &priv->dp_flush_wait,
+ DIGI_CLOSE_TIMEOUT );
/* shutdown any outstanding bulk writes */
usb_unlink_urb (port->write_urb);
@@ -1458,23 +1611,31 @@ static int digi_startup_device( struct usb_serial *serial )
{
int i,ret = 0;
+ digi_serial_t *serial_priv = (digi_serial_t *)serial->private;
+ struct usb_serial_port *port;
/* be sure this happens exactly once */
- spin_lock( &startup_lock );
- if( device_startup ) {
- spin_unlock( &startup_lock );
+ spin_lock( &serial_priv->ds_serial_lock );
+ if( serial_priv->ds_device_started ) {
+ spin_unlock( &serial_priv->ds_serial_lock );
return( 0 );
}
- device_startup = 1;
- spin_unlock( &startup_lock );
+ serial_priv->ds_device_started = 1;
+ spin_unlock( &serial_priv->ds_serial_lock );
/* start reading from each bulk in endpoint for the device */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ /* set USB_DISABLE_SPD flag for write bulk urbs */
+ for( i=0; i<serial->type->num_ports+1; i++ ) {
- if( (ret=usb_submit_urb(serial->port[i].read_urb)) != 0 ) {
- dbg( "digi_startup_device: usb_submit_urb failed, port=%d, ret=%d",
- i, ret );
+ port = &serial->port[i];
+
+ port->write_urb->transfer_flags |= USB_DISABLE_SPD;
+
+ if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
+ err(
+ __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+ ret, i );
break;
}
@@ -1489,51 +1650,68 @@ static int digi_startup( struct usb_serial *serial )
{
int i;
- digi_private_t *priv;
+ digi_port_t *priv;
+ digi_serial_t *serial_priv;
dbg( "digi_startup: TOP" );
- spin_lock_init( &startup_lock );
- init_waitqueue_head( &modem_change_wait );
- init_waitqueue_head( &transmit_idle_wait );
-
/* allocate the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ for( i=0; i<serial->type->num_ports+1; i++ ) {
serial->port[i].active = 0;
- /* allocate private structure */
+ /* allocate port private structure */
priv = serial->port[i].private =
- (digi_private_t *)kmalloc( sizeof(digi_private_t),
+ (digi_port_t *)kmalloc( sizeof(digi_port_t),
GFP_KERNEL );
- if( priv == (digi_private_t *)0 )
+ if( priv == (digi_port_t *)0 ) {
+ while( --i >= 0 )
+ kfree( serial->port[i].private );
return( 1 ); /* error */
+ }
- /* initialize private structure */
+ /* initialize port private structure */
+ spin_lock_init( &priv->dp_port_lock );
priv->dp_port_num = i;
- priv->dp_buf_len = 0;
+ priv->dp_out_buf_len = 0;
+ priv->dp_in_buf_len = 0;
priv->dp_modem_signals = 0;
+ init_waitqueue_head( &priv->dp_modem_change_wait );
priv->dp_open_count = 0;
priv->dp_transmit_idle = 0;
+ init_waitqueue_head( &priv->dp_transmit_idle_wait );
+ priv->dp_throttled = 0;
+ priv->dp_throttle_restart = 0;
+ init_waitqueue_head( &priv->dp_flush_wait );
priv->dp_in_close = 0;
init_waitqueue_head( &priv->dp_close_wait );
priv->dp_wakeup_task.next = NULL;
priv->dp_wakeup_task.sync = 0;
priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock;
priv->dp_wakeup_task.data = (void *)(&serial->port[i]);
- spin_lock_init( &priv->dp_port_lock );
/* initialize write wait queue for this port */
- init_waitqueue_head(&serial->port[i].write_wait);
+ init_waitqueue_head( &serial->port[i].write_wait );
+
+ }
+ /* allocate serial private structure */
+ serial_priv = serial->private =
+ (digi_serial_t *)kmalloc( sizeof(digi_serial_t),
+ GFP_KERNEL );
+ if( serial_priv == (digi_serial_t *)0 ) {
+ for( i=0; i<serial->type->num_ports+1; i++ )
+ kfree( serial->port[i].private );
+ return( 1 ); /* error */
}
- /* initialize out of band port info */
- oob_port_num = digi_acceleport_device.num_ports;
- oob_port = &serial->port[oob_port_num];
- device_startup = 0;
+ /* initialize serial private structure */
+ spin_lock_init( &serial_priv->ds_serial_lock );
+ serial_priv->ds_oob_port_num = serial->type->num_ports;
+ serial_priv->ds_oob_port = &serial->port[serial_priv->ds_oob_port_num];
+ serial_priv->ds_device_started = 0;
return( 0 );
@@ -1544,22 +1722,20 @@ static void digi_shutdown( struct usb_serial *serial )
{
int i;
- digi_private_t *priv;
+ digi_port_t *priv;
unsigned long flags;
dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
/* stop reads and writes on all ports */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ ) {
+ for( i=0; i<serial->type->num_ports+1; i++ ) {
usb_unlink_urb( serial->port[i].read_urb );
usb_unlink_urb( serial->port[i].write_urb );
}
- device_startup = 0;
-
/* dec module use count */
- for( i=0; i<digi_acceleport_device.num_ports; i++ ) {
+ for( i=0; i<serial->type->num_ports; i++ ) {
priv = serial->port[i].private;
spin_lock_irqsave( &priv->dp_port_lock, flags );
while( priv->dp_open_count > 0 ) {
@@ -1571,8 +1747,9 @@ dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
/* free the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
- for( i=0; i<digi_acceleport_device.num_ports+1; i++ )
+ for( i=0; i<serial->type->num_ports+1; i++ )
kfree( serial->port[i].private );
+ kfree( serial->private );
}
@@ -1581,18 +1758,24 @@ static void digi_read_bulk_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- digi_private_t *priv;
+ digi_port_t *priv;
int ret;
dbg( "digi_read_bulk_callback: TOP" );
/* port sanity check, do not resubmit if port is not valid */
- if( port == NULL || (priv=(digi_private_t *)(port->private)) == NULL ) {
+ if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
err( __FUNCTION__ ": port or port->private is NULL, status=%d",
urb->status );
return;
}
+ if( port->serial == NULL
+ || serial_paranoia_check( port->serial, __FUNCTION__ )
+ || port->serial->private == NULL ) {
+ err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status );
+ return;
+ }
/* do not resubmit urb if it has any status error */
if( urb->status ) {
@@ -1601,7 +1784,8 @@ dbg( "digi_read_bulk_callback: TOP" );
}
/* handle oob or inb callback, do not resubmit if error */
- if( priv->dp_port_num == oob_port_num ) {
+ if( priv->dp_port_num
+ == ((digi_serial_t *)(port->serial->private))->ds_oob_port_num ) {
if( digi_read_oob_callback( urb ) != 0 )
return;
} else {
@@ -1623,45 +1807,110 @@ dbg( "digi_read_bulk_callback: TOP" );
*
* Digi Read INB Callback handles reads on the in band ports, sending
* the data on to the tty subsystem. When called we know port and
-* port->private are not NULL. It returns 0 if successful, and -1 if
-* the sanity checks failed.
+* port->private are not NULL and port->serial has been validated.
+* It returns 0 if successful, 1 if successful but the port is
+* throttled, and -1 if the sanity checks failed.
*/
static int digi_read_inb_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = port->serial;
struct tty_struct *tty = port->tty;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
int opcode = ((unsigned char *)urb->transfer_buffer)[0];
int len = ((unsigned char *)urb->transfer_buffer)[1];
int status = ((unsigned char *)urb->transfer_buffer)[2];
unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;
- int i;
+ int flag,throttled;
- /* sanity checks */
- if( port_paranoia_check( port, __FUNCTION__ )
- || serial_paranoia_check( serial, __FUNCTION__ ) )
+ /* sanity check */
+ if( port_paranoia_check( port, __FUNCTION__ ) )
return( -1 );
- /* short packet check */
+ /* do not process callbacks on closed ports */
+ /* but do continue the read chain */
+ if( priv->dp_open_count == 0 )
+ return( 0 );
+
+ /* short/multiple packet check */
if( urb->actual_length != len + 2 ) {
- err( __FUNCTION__ ": INCOMPLETE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
+ err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
return( -1 );
}
+ spin_lock( &priv->dp_port_lock );
+
+ /* check for throttle; if set, do not resubmit read urb */
+ /* indicate the read chain needs to be restarted on unthrottle */
+ throttled = priv->dp_throttled;
+ if( throttled )
+ priv->dp_throttle_restart = 1;
+
/* receive data */
- if( opcode == DIGI_CMD_RECEIVE_DATA && urb->actual_length > 3 ) {
- len = MIN( len, urb->actual_length-3 );
- for( i=0; i<len; ++i ) {
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
+ if( opcode == DIGI_CMD_RECEIVE_DATA ) {
+
+ /* get flag from status */
+ flag = 0;
+
+ /* overrun is special, not associated with a char */
+ if( status & DIGI_OVERRUN_ERROR ) {
+ tty_insert_flip_char( tty, 0, TTY_OVERRUN );
+ }
+
+ /* break takes precedence over parity, */
+ /* which takes precedence over framing errors */
+ if( status & DIGI_BREAK_ERROR ) {
+ flag = TTY_BREAK;
+ } else if( status & DIGI_PARITY_ERROR ) {
+ flag = TTY_PARITY;
+ } else if( status & DIGI_FRAMING_ERROR ) {
+ flag = TTY_FRAME;
+ }
+
+ /* data length is len-1 (one byte of len is status) */
+ --len;
+
+ if( throttled ) {
+
+ len = MIN( len,
+ DIGI_IN_BUF_SIZE - priv->dp_in_buf_len );
+
+ if( len > 0 ) {
+ memcpy( priv->dp_in_buf + priv->dp_in_buf_len,
+ data, len );
+ memset( priv->dp_in_flag_buf
+ + priv->dp_in_buf_len, flag, len );
+ priv->dp_in_buf_len += len;
+ }
+
+ } else {
+
+ len = MIN( len, TTY_FLIPBUF_SIZE - tty->flip.count );
+
+ if( len > 0 ) {
+ memcpy( tty->flip.char_buf_ptr, data, len );
+ memset( tty->flip.flag_buf_ptr, flag, len );
+ tty->flip.char_buf_ptr += len;
+ tty->flip.flag_buf_ptr += len;
+ tty->flip.count += len;
+ tty_flip_buffer_push( tty );
+ }
+
+ }
+
}
- return( 0 );
+ spin_unlock( &priv->dp_port_lock );
+
+ if( opcode == DIGI_CMD_RECEIVE_DISABLE ) {
+ dbg( __FUNCTION__ ": got RECEIVE_DISABLE" );
+ } else if( opcode != DIGI_CMD_RECEIVE_DATA ) {
+ dbg( __FUNCTION__ ": unknown opcode: %d", opcode );
+ }
+
+ return( throttled ? 1 : 0 );
}
@@ -1670,8 +1919,9 @@ static int digi_read_inb_callback( struct urb *urb )
* Digi Read OOB Callback
*
* Digi Read OOB Callback handles reads on the out of band port.
-* When called we know port and port->private are not NULL. It
-* returns 0 if successful, and -1 if the sanity checks failed.
+* When called we know port and port->private are not NULL and
+* the port->serial is valid. It returns 0 if successful, and
+* -1 if the sanity checks failed.
*/
static int digi_read_oob_callback( struct urb *urb )
@@ -1679,19 +1929,13 @@ static int digi_read_oob_callback( struct urb *urb )
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
- digi_private_t *priv = (digi_private_t *)(port->private);
+ digi_port_t *priv = (digi_port_t *)(port->private);
int opcode, line, status, val;
int i;
-dbg( "digi_read_oob_callback: len=%d", urb->actual_length );
-
- /* sanity check */
- if( serial == NULL ) {
- err( __FUNCTION__ ": port->serial is NULL, status=%d, port=%d",
- urb->status, priv->dp_port_num );
- return( -1 );
- }
+dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num,
+urb->actual_length );
/* handle each oob command */
for( i=0; i<urb->actual_length-3; ) {
@@ -1701,25 +1945,39 @@ dbg( "digi_read_oob_callback: len=%d", urb->actual_length );
status = ((unsigned char *)urb->transfer_buffer)[i++];
val = ((unsigned char *)urb->transfer_buffer)[i++];
-dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, line, status, val );
+dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
+opcode, line, status, val );
- if( status != 0 )
+ if( status != 0 || line >= serial->type->num_ports )
continue;
- if( (priv=serial->port[line].private) == NULL ) {
- dbg( __FUNCTION__ ": port[%d].private is NULL!", line );
- continue;
- }
+ port = &serial->port[line];
+
+ if( port_paranoia_check( port, __FUNCTION__ )
+ || (priv=port->private) == NULL )
+ return( -1 );
if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) {
spin_lock( &priv->dp_port_lock );
/* convert from digi flags to termiox flags */
- if( val & DIGI_READ_INPUT_SIGNALS_CTS )
+ if( val & DIGI_READ_INPUT_SIGNALS_CTS ) {
priv->dp_modem_signals |= TIOCM_CTS;
- else
+ /* port must be open to use tty struct */
+ if( priv->dp_open_count
+ && port->tty->termios->c_cflag & CRTSCTS ) {
+ port->tty->hw_stopped = 0;
+ digi_wakeup_write( port );
+ }
+ } else {
priv->dp_modem_signals &= ~TIOCM_CTS;
+ /* port must be open to use tty struct */
+ if( priv->dp_open_count
+ && port->tty->termios->c_cflag & CRTSCTS ) {
+ port->tty->hw_stopped = 1;
+ }
+ }
if( val & DIGI_READ_INPUT_SIGNALS_DSR )
priv->dp_modem_signals |= TIOCM_DSR;
else
@@ -1733,16 +1991,20 @@ dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, li
else
priv->dp_modem_signals &= ~TIOCM_CD;
- wake_up_interruptible( &modem_change_wait );
+ wake_up_interruptible( &priv->dp_modem_change_wait );
spin_unlock( &priv->dp_port_lock );
} else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) {
spin_lock( &priv->dp_port_lock );
priv->dp_transmit_idle = 1;
- wake_up_interruptible( &transmit_idle_wait );
+ wake_up_interruptible( &priv->dp_transmit_idle_wait );
spin_unlock( &priv->dp_port_lock );
+ } else if( opcode == DIGI_CMD_IFLUSH_FIFO ) {
+
+ wake_up_interruptible( &priv->dp_flush_wait );
+
}
}
@@ -1754,20 +2016,23 @@ dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", opcode, li
int digi_init (void)
{
- usb_serial_register (&digi_acceleport_device);
+ usb_serial_register (&digi_acceleport_2_device);
+ usb_serial_register (&digi_acceleport_4_device);
return 0;
}
void digi_exit (void)
{
- usb_serial_deregister (&digi_acceleport_device);
+ usb_serial_deregister (&digi_acceleport_2_device);
+ usb_serial_deregister (&digi_acceleport_4_device);
}
module_init(digi_init);
module_exit(digi_exit);
+
MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>");
MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver");
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 675764ad4..e118e29b8 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -1,8 +1,9 @@
/*
* USB Keyspan PDA Converter driver
*
- * Copyright (C) 1999, 2000
- * Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 1999, 2000 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 1999, 2000 Brian Warner <warner@lothar.com>
+ * Copyright (c) 2000 Al Borchers <borchers@steinerpoint.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -11,6 +12,24 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (07/20/2000) borchers
+ * - keyspan_pda_write no longer sleeps if it is called on interrupt time;
+ * PPP and the line discipline with stty echo on can call write on
+ * interrupt time and this would cause an oops if write slept
+ * - if keyspan_pda_write is in an interrupt, it will not call
+ * usb_control_msg (which sleeps) to query the room in the device
+ * buffer, it simply uses the current room value it has
+ * - if the urb is busy or if it is throttled keyspan_pda_write just
+ * returns 0, rather than sleeping to wait for this to change; the
+ * write_chan code in n_tty.c will sleep if needed before calling
+ * keyspan_pda_write again
+ * - if the device needs to be unthrottled, write now queues up the
+ * call to usb_control_msg (which sleeps) to unthrottle the device
+ * - the wakeups from keyspan_pda_write_bulk_callback are queued rather
+ * than done directly from the callback to avoid the race in write_chan
+ * - keyspan_pda_chars_in_buffer also indicates its buffer is full if the
+ * urb status is -EINPROGRESS, meaning it cannot write at the moment
+ *
* (07/19/2000) gkh
* Added module_init and module_exit functions to handle the fact that this
* driver is a loadable module now.
@@ -35,6 +54,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/tqueue.h>
#ifdef CONFIG_USB_SERIAL_DEBUG
#define DEBUG
@@ -56,6 +76,8 @@ struct ezusb_hex_record {
struct keyspan_pda_private {
int tx_room;
int tx_throttled;
+ struct tq_struct wakeup_task;
+ struct tq_struct unthrottle_task;
};
#define KEYSPAN_VENDOR_ID 0x06cd
@@ -69,6 +91,45 @@ static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID;
+static void keyspan_pda_wakeup_write( struct usb_serial_port *port )
+{
+
+ struct tty_struct *tty = port->tty;
+
+ /* wake up port processes */
+ wake_up_interruptible( &port->write_wait );
+
+ /* wake up line discipline */
+ if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup )
+ (tty->ldisc.write_wakeup)(tty);
+
+ /* wake up other tty processes */
+ wake_up_interruptible( &tty->write_wait );
+ /* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
+
+}
+
+static void keyspan_pda_request_unthrottle( struct usb_serial *serial )
+{
+
+ dbg(" request_unthrottle");
+ /* ask the device to tell us when the tx buffer becomes
+ sufficiently empty */
+ usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ 7, /* request_unthrottle */
+ USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+ | USB_DIR_OUT,
+ 16, /* value: threshold */
+ 0, /* index */
+ NULL,
+ 0,
+ 2*HZ);
+
+}
+
+
static void keyspan_pda_rx_interrupt (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -113,8 +174,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
case 2: /* tx unthrottle interrupt */
tty = serial->port[0].tty;
priv->tx_throttled = 0;
- wake_up(&port->write_wait); /* wake up writer */
- wake_up(&tty->write_wait); /* them too */
+ /* queue up a wakeup at scheduler time */
+ queue_task( &priv->wakeup_task, &tq_scheduler );
break;
default:
break;
@@ -355,7 +416,6 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
int request_unthrottle = 0;
int rc = 0;
struct keyspan_pda_private *priv;
- DECLARE_WAITQUEUE(wait, current);
priv = (struct keyspan_pda_private *)(port->private);
/* guess how much room is left in the device's ring buffer, and if we
@@ -376,53 +436,22 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- while (port->write_urb->status == -EINPROGRESS) {
- if (0 /* file->f_flags & O_NONBLOCK */) {
- rc = -EAGAIN;
- goto err;
- }
- interruptible_sleep_on(&port->write_wait);
- if (signal_pending(current)) {
- rc = -ERESTARTSYS;
- goto err;
- }
+ if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
+ return( 0 );
}
- /* at this point the URB is in our control, nobody else can submit it
+ /* At this point the URB is in our control, nobody else can submit it
again (the only sudden transition was the one from EINPROGRESS to
- finished) */
-
- /* the next potential block is that our TX process might be throttled.
- The transition from throttled->not happens because of an Rx
- interrupt, and the wake_up occurs during the same interrupt, so we
- have to be careful to avoid a race that would cause us to sleep
- forever. */
-
- add_wait_queue(&port->write_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- while (priv->tx_throttled) {
- /* device can't accomodate any more characters. Sleep until it
- can. Woken up by an Rx interrupt message, which clears
- tx_throttled first. */
- dbg(" tx_throttled, going to sleep");
- if (signal_pending(current)) {
- current->state = TASK_RUNNING;
- remove_wait_queue(&port->write_wait, &wait);
- dbg(" woke up because of signal");
- rc = -ERESTARTSYS;
- goto err;
- }
- schedule();
- dbg(" woke up");
- }
- remove_wait_queue(&port->write_wait, &wait);
- set_current_state(TASK_RUNNING);
+ finished). Also, the tx process is not throttled. So we are
+ ready to write. */
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
- if (count > priv->tx_room) {
+
+ /* Check if we might overrun the Tx buffer. If so, ask the
+ device how much room it really has. This is done only on
+ scheduler time, since usb_control_msg() sleeps. */
+ if (count > priv->tx_room && !in_interrupt()) {
unsigned char room;
- /* Looks like we might overrun the Tx buffer. Ask the device
- how much room it really has */
rc = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
6, /* write_room */
@@ -443,19 +472,20 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
}
dbg(" roomquery says %d", room);
priv->tx_room = room;
- if (count > priv->tx_room) {
- /* we're about to completely fill the Tx buffer, so
- we'll be throttled afterwards. */
- count = priv->tx_room;
- request_unthrottle = 1;
- }
}
- priv->tx_room -= count;
+ if (count > priv->tx_room) {
+ /* we're about to completely fill the Tx buffer, so
+ we'll be throttled afterwards. */
+ count = priv->tx_room;
+ request_unthrottle = 1;
+ }
if (count) {
/* now transfer data */
if (from_user) {
- copy_from_user(port->write_urb->transfer_buffer, buf, count);
+ if( copy_from_user(port->write_urb->transfer_buffer,
+ buf, count) )
+ return( -EFAULT );
}
else {
memcpy (port->write_urb->transfer_buffer, buf, count);
@@ -463,6 +493,8 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
/* send the data out the bulk port */
port->write_urb->transfer_buffer_length = count;
+ priv->tx_room -= count;
+
if (usb_submit_urb(port->write_urb))
dbg(" usb_submit_urb(write bulk) failed");
}
@@ -473,25 +505,11 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
}
if (request_unthrottle) {
- dbg(" request_unthrottle");
- /* ask the device to tell us when the tx buffer becomes
- sufficiently empty */
priv->tx_throttled = 1; /* block writers */
- rc = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- 7, /* request_unthrottle */
- USB_TYPE_VENDOR | USB_RECIP_INTERFACE
- | USB_DIR_OUT,
- 16, /* value: threshold */
- 0, /* index */
- NULL,
- 0,
- 2*HZ);
+ queue_task( &priv->unthrottle_task, &tq_scheduler );
}
return (count);
- err:
- return (rc);
}
@@ -499,7 +517,9 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial;
- struct tty_struct *tty;
+ struct keyspan_pda_private *priv;
+
+ priv = (struct keyspan_pda_private *)(port->private);
if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
return;
@@ -510,14 +530,9 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
return;
}
- wake_up_interruptible(&port->write_wait);
+ /* queue up a wakeup at scheduler time */
+ queue_task( &priv->wakeup_task, &tq_scheduler );
- tty = port->tty;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
-
- wake_up_interruptible(&tty->write_wait);
}
@@ -541,7 +556,7 @@ static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
- if (priv->tx_throttled)
+ if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
return 256;
return 0;
}
@@ -644,14 +659,25 @@ static int keyspan_pda_fake_startup (struct usb_serial *serial)
static int keyspan_pda_startup (struct usb_serial *serial)
{
+
+ struct keyspan_pda_private *priv;
+
/* allocate the private data structures for all ports. Well, for all
one ports. */
- serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private),
- GFP_KERNEL);
- if (!serial->port[0].private)
+ priv = serial->port[0].private
+ = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL);
+ if (!priv)
return (1); /* error */
init_waitqueue_head(&serial->port[0].write_wait);
+ priv->wakeup_task.next = NULL;
+ priv->wakeup_task.sync = 0;
+ priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write;
+ priv->wakeup_task.data = (void *)(&serial->port[0]);
+ priv->unthrottle_task.next = NULL;
+ priv->unthrottle_task.sync = 0;
+ priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle;
+ priv->unthrottle_task.data = (void *)(serial);
return (0);
}
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index fe63007b8..10d57076c 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -11,6 +11,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (08/08/2000) gkh
+ * Added open_count to port structure.
+ *
* (07/23/2000) gkh
* Added bulk_out_endpointAddress to port structure.
*
@@ -59,6 +62,7 @@ struct usb_serial_port {
wait_queue_head_t write_wait;
struct tq_struct tqueue; /* task queue for line discipline waking up */
+ int open_count; /* number of times this port has been opened */
void * private; /* data private to the specific port */
};
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 568f2b5cd..bc0ea807a 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -11,6 +11,11 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (08/08/2000) gkh
+ * Fixed endian problem in visor_startup.
+ * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
+ * than once.
+ *
* (07/23/2000) gkh
* Added pool of write urbs to speed up transfers to the visor.
*
@@ -71,6 +76,7 @@ static int visor_write (struct usb_serial_port *port, int from_user, const uns
static void visor_throttle (struct usb_serial_port *port);
static void visor_unthrottle (struct usb_serial_port *port);
static int visor_startup (struct usb_serial *serial);
+static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios);
static void visor_write_bulk_callback (struct urb *urb);
@@ -94,6 +100,7 @@ struct usb_serial_device_type handspring_device = {
throttle: visor_throttle,
unthrottle: visor_unthrottle,
startup: visor_startup,
+ shutdown: visor_shutdown,
ioctl: visor_ioctl,
set_termios: visor_set_termios,
write: visor_write,
@@ -117,13 +124,18 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
return -EINVAL;
}
- port->active = 1;
-
- /*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
- dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ if (!port->active) {
+ port->active = 1;
- return (0);
+ /*Start reading from the device*/
+ if (usb_submit_urb(port->read_urb))
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+ }
+
+ return 0;
}
@@ -134,19 +146,24 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
dbg(__FUNCTION__ " - port %d", port->number);
- if (!transfer_buffer) {
- err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
- } else {
- /* send a shutdown message to the device */
- usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
- 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
- kfree (transfer_buffer);
- }
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+
+ if (port->open_count <= 0) {
+ if (!transfer_buffer) {
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+ } else {
+ /* send a shutdown message to the device */
+ usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
+ 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+ kfree (transfer_buffer);
+ }
- /* shutdown our bulk reads and writes */
- usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
- port->active = 0;
+ /* shutdown our bulk read */
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+ port->open_count = 0;
+ }
}
@@ -282,6 +299,8 @@ static int visor_startup (struct usb_serial *serial)
} else {
struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
char *string;
+
+ le16_to_cpus(&connection_info->num_ports);
info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
for (i = 0; i < connection_info->num_ports; ++i) {
switch (connection_info->connections[i].port_function_id) {
@@ -322,6 +341,21 @@ static int visor_startup (struct usb_serial *serial)
}
+static void visor_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ visor_close (&serial->port[i], NULL);
+ }
+ }
+}
+
+
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 7da59f78e..e7761863e 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -5,6 +5,7 @@
O_TARGET := usb-storage.o
M_OBJS := usb-storage.o
O_OBJS := scsiglue.o protocol.o transport.o usb.o
+MOD_LIST_NAME := USB_STORAGE_MODULES
CFLAGS_scsiglue.o:= -I../../scsi/
CFLAGS_protocol.o:= -I../../scsi/
@@ -13,6 +14,7 @@ CFLAGS_debug.o:= -I../../scsi/
CFLAGS_usb.o:= -I../../scsi/
CFLAGS_shuttle_usbat.o:= -I../../scsi/
CFLAGS_sddr09.o:= -I../../scsi/
+CFLAGS_dpcm.o:= -I../../scsi/
ifeq ($(CONFIG_USB_STORAGE_DEBUG),y)
O_OBJS += debug.o
@@ -37,5 +39,9 @@ endif
ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y)
O_OBJS += shuttle_cf.o
endif
+
+ifeq ($(CONFIG_USB_STORAGE_DPCM),y)
+ O_OBJS += dpcm.o
+endif
include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
new file mode 100644
index 000000000..8b7195bfc
--- /dev/null
+++ b/drivers/usb/storage/dpcm.c
@@ -0,0 +1,83 @@
+/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
+ *
+ * $Id: dpcm.c,v 1.1 2000/08/08 01:26:12 webbb Exp $
+ *
+ * DPCM driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintainance by:
+ * (c) 2000 Brian Webb (webbb@earthlink.net)
+ *
+ * This device contains both a CompactFlash card reader, which
+ * usest the Control/Bulk w/o Interrupt protocol and
+ * a SmartMedia card reader that uses the same protocol
+ * as the SDDR09.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "dpcm.h"
+#include "sddr09.h"
+
+
+/*
+ * Transport for the Microtech DPCM-USB
+ *
+ */
+int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int ret;
+
+ if(srb == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ US_DEBUGP("dpcm_transport: LUN=%d\n", srb->lun);
+
+ switch(srb->lun) {
+ case 0:
+
+ /*
+ * LUN 0 corresponds to the CompactFlash card reader.
+ */
+ return usb_stor_CB_transport(srb, us);
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+ case 1:
+
+ /*
+ * LUN 1 corresponds to the SmartMedia card reader.
+ */
+
+ /*
+ * Set the LUN to 0 (just in case).
+ */
+ srb->lun = 0; us->srb->lun = 0;
+ ret = sddr09_transport(srb, us);
+ srb->lun = 1; us->srb->lun = 1;
+
+ return ret;
+#endif
+
+ default:
+ US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->lun);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+}
diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h
new file mode 100644
index 000000000..d6e5f86ad
--- /dev/null
+++ b/drivers/usb/storage/dpcm.h
@@ -0,0 +1,34 @@
+/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
+ *
+ * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $
+ *
+ * DPCM driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintainance by:
+ * (c) 2000 Brian Webb (webbb@earthlink.net)
+ *
+ * See dpcm.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MICROTECH_DPCM_USB_H
+#define _MICROTECH_DPCM_USB_H
+
+extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 7517d63bc..c823aaed1 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
- * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $
+ * $Id: scsiglue.c,v 1.8 2000/08/11 23:15:05 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -189,6 +189,12 @@ static int command_abort( Scsi_Cmnd *srb )
return SUCCESS;
}
+ /* This is a sanity check that we should never hit */
+ if (in_interrupt()) {
+ printk(KERN_ERR "usb-storage: command_abort() called from an interrupt!!! BAD!!! BAD!! BAD!!\n");
+ return FAILED;
+ }
+
/* if we have an urb pending, let's wake the control thread up */
if (us->current_urb->status == -EINPROGRESS) {
/* cancel the URB */
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index f68595c47..492bc7259 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1,5 +1,7 @@
/* Driver for SCM Microsystems USB-ATAPI cable
*
+ * $Id: shuttle_usbat.c,v 1.2 2000/08/03 00:03:39 groovyjava Exp $
+ *
* SCM driver v0.2:
*
* Removed any reference to maxlen for bulk transfers.
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h
index eede2651f..ff5c07541 100644
--- a/drivers/usb/storage/shuttle_usbat.h
+++ b/drivers/usb/storage/shuttle_usbat.h
@@ -1,6 +1,8 @@
/* Driver for SCM Microsystems USB-ATAPI cable
* Header File
*
+ * $Id: shuttle_usbat.h,v 1.2 2000/08/03 00:03:39 groovyjava Exp $
+ *
* Current development and maintainance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
*
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index a0fb2407c..dd3c489f1 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1,12 +1,13 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.5 2000/07/28 22:40:20 mdharm Exp $
+ * $Id: transport.c,v 1.12 2000/08/08 15:22:38 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)
@@ -52,6 +53,353 @@
#include <linux/malloc.h>
/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+/* Calculate the length of the data transfer (not the command) for any
+ * given SCSI command
+ */
+static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int i;
+ unsigned int total = 0;
+ struct scatterlist *sg;
+
+ /* support those devices which need the length calculated
+ * differently
+ */
+ if (srb->cmnd[0] == INQUIRY) {
+ srb->cmnd[4] = 36;
+ }
+
+ if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
+ return srb->cmnd[4];
+
+ if (srb->cmnd[0] == TEST_UNIT_READY)
+ return 0;
+
+ /* Are we going to scatter gather? */
+ if (srb->use_sg) {
+ /* Add up the sizes of all the scatter-gather segments */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ total += sg[i].length;
+
+ return total;
+ }
+ else
+ /* Just return the length of the buffer */
+ return srb->request_bufflen;
+}
+
+/* Calculate the length of the data transfer (not the command) for any
+ * given SCSI command
+ */
+static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int i;
+ int doDefault = 0;
+ unsigned int len = 0;
+ unsigned int total = 0;
+ struct scatterlist *sg;
+
+ /* This table tells us:
+ X = command not supported
+ L = return length in cmnd[4] (8 bits).
+ M = return length in cmnd[8] (8 bits).
+ G = return length in cmnd[3] and cmnd[4] (16 bits)
+ H = return length in cmnd[7] and cmnd[8] (16 bits)
+ I = return length in cmnd[8] and cmnd[9] (16 bits)
+ C = return length in cmnd[2] to cmnd[5] (32 bits)
+ D = return length in cmnd[6] to cmnd[9] (32 bits)
+ B = return length in blocksize so we use buff_len
+ R = return length in cmnd[2] to cmnd[4] (24 bits)
+ S = return length in cmnd[3] to cmnd[5] (24 bits)
+ T = return length in cmnd[6] to cmnd[8] (24 bits)
+ U = return length in cmnd[7] to cmnd[9] (24 bits)
+ 0-9 = fixed return length
+ V = 20 bytes
+ W = 24 bytes
+ Z = return length is mode dependant or not in command, use buff_len
+ */
+
+ static char *lengths =
+
+ /* 0123456789ABCDEF 0123456789ABCDEF */
+
+ "00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X" /* 00-1F */
+ "XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH" /* 20-3F */
+ "M0HHB0X000H0HH0X" "XHH00HXX0TH0H0XX" /* 40-5F */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */
+ "X0XXX00XB0BXBXBB" "ZZZ0XUIDU000XHBX" /* A0-BF */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */
+ "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
+
+ /* Commands checked in table:
+
+ CHANGE_DEFINITION 40
+ COMPARE 39
+ COPY 18
+ COPY_AND_VERIFY 3a
+ ERASE 19
+ ERASE_10 2c
+ ERASE_12 ac
+ EXCHANGE_MEDIUM a6
+ FORMAT_UNIT 04
+ GET_DATA_BUFFER_STATUS 34
+ GET_MESSAGE_10 28
+ GET_MESSAGE_12 a8
+ GET_WINDOW 25 !!! Has more data than READ_CAPACITY, need to fix table
+ INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len
+ INQUIRY 12
+ LOAD_UNLOAD 1b
+ LOCATE 2b
+ LOCK_UNLOCK_CACHE 36
+ LOG_SELECT 4c
+ LOG_SENSE 4d
+ MEDIUM_SCAN 38 !!! This was M
+ MODE_SELECT6 15
+ MODE_SELECT_10 55
+ MODE_SENSE_6 1a
+ MODE_SENSE_10 5a
+ MOVE_MEDIUM a5
+ OBJECT_POSITION 31 !!! Same as SEARCH_DATA_EQUAL
+ PAUSE_RESUME 4b
+ PLAY_AUDIO_10 45
+ PLAY_AUDIO_12 a5
+ PLAY_AUDIO_MSF 47
+ PLAY_AUDIO_TRACK_INDEX 48
+ PLAY_AUDIO_TRACK_RELATIVE_10 49
+ PLAY_AUDIO_TRACK_RELATIVE_12 a9
+ POSITION_TO_ELEMENT 2b
+ PRE-FETCH 34
+ PREVENT_ALLOW_MEDIUM_REMOVAL 1e
+ PRINT 0a !!! Same as WRITE_6 but is always in bytes
+ READ_6 08
+ READ_10 28
+ READ_12 a8
+ READ_BLOCK_LIMITS 05
+ READ_BUFFER 3c
+ READ_CAPACITY 25
+ READ_CDROM_CAPACITY 25
+ READ_DEFECT_DATA 37
+ READ_DEFECT_DATA_12 b7
+ READ_ELEMENT_STATUS b8 !!! Think this is in bytes
+ READ_GENERATION 29 !!! Could also be M?
+ READ_HEADER 44 !!! This was L
+ READ_LONG 3e
+ READ_POSITION 34 !!! This should be V but conflicts with PRE-FETCH
+ READ_REVERSE 0f
+ READ_SUB-CHANNEL 42 !!! Is this in bytes?
+ READ_TOC 43 !!! Is this in bytes?
+ READ_UPDATED_BLOCK 2d
+ REASSIGN_BLOCKS 07
+ RECEIVE 08 !!! Same as READ_6 probably in bytes though
+ RECEIVE_DIAGNOSTIC_RESULTS 1c
+ RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes
+ RELEASE_UNIT 17
+ REQUEST_SENSE 03
+ REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes
+ RESERVE_UNIT 16
+ REWIND 01
+ REZERO_UNIT 01
+ SCAN 1b !!! Conflicts with various commands, should be L
+ SEARCH_DATA_EQUAL 31
+ SEARCH_DATA_EQUAL_12 b1
+ SEARCH_DATA_LOW 30
+ SEARCH_DATA_LOW_12 b0
+ SEARCH_DATA_HIGH 32
+ SEARCH_DATA_HIGH_12 b2
+ SEEK_6 0b !!! Conflicts with SLEW_AND_PRINT
+ SEEK_10 2b
+ SEND 0a !!! Same as WRITE_6, probably in bytes though
+ SEND 2a !!! Similar to WRITE_10 but for scanners
+ SEND_DIAGNOSTIC 1d
+ SEND_MESSAGE_6 0a !!! Same as WRITE_6 - is in bytes
+ SEND_MESSAGE_10 2a !!! Same as WRITE_10 - is in bytes
+ SEND_MESSAGE_12 aa !!! Same as WRITE_12 - is in bytes
+ SEND_VOLUME_TAG b6 !!! Think this is in bytes
+ SET_LIMITS 33
+ SET_LIMITS_12 b3
+ SET_WINDOW 24
+ SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6
+ SPACE 11
+ START_STOP_UNIT 1b
+ STOP_PRINT 1b
+ SYNCHRONIZE_BUFFER 10
+ SYNCHRONIZE_CACHE 35
+ TEST_UNIT_READY 00
+ UPDATE_BLOCK 3d
+ VERIFY 13
+ VERIFY 2f
+ VERIFY_12 af
+ WRITE_6 0a
+ WRITE_10 2a
+ WRITE_12 aa
+ WRITE_AND_VERIFY 2e
+ WRITE_AND_VERIFY_12 ae
+ WRITE_BUFFER 3b
+ WRITE_FILEMARKS 10
+ WRITE_LONG 3f
+ WRITE_SAME 41
+ */
+
+ /* Not sure this is right as an INQUIRY can contain nonstandard info */
+ if (srb->cmnd[0] == INQUIRY)
+ srb->cmnd[4] = 36;
+
+ if (srb->sc_data_direction == SCSI_DATA_WRITE) {
+ doDefault = 1;
+ }
+ else
+ switch (lengths[srb->cmnd[0]]) {
+ case 'L':
+ len = srb->cmnd[4];
+ break;
+
+ case 'M':
+ len = srb->cmnd[8];
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ len = lengths[srb->cmnd[0]]-'0';
+ break;
+
+ case 'G':
+ len = (((unsigned int)srb->cmnd[3])<<8) |
+ srb->cmnd[4];
+ break;
+
+ case 'H':
+ len = (((unsigned int)srb->cmnd[7])<<8) |
+ srb->cmnd[8];
+ break;
+
+ case 'I':
+ len = (((unsigned int)srb->cmnd[8])<<8) |
+ srb->cmnd[9];
+ break;
+
+ case 'R':
+ len = (((unsigned int)srb->cmnd[2])<<16) |
+ (((unsigned int)srb->cmnd[3])<<8) |
+ srb->cmnd[4];
+ break;
+
+ case 'S':
+ len = (((unsigned int)srb->cmnd[3])<<16) |
+ (((unsigned int)srb->cmnd[4])<<8) |
+ srb->cmnd[5];
+ break;
+
+ case 'T':
+ len = (((unsigned int)srb->cmnd[6])<<16) |
+ (((unsigned int)srb->cmnd[7])<<8) |
+ srb->cmnd[8];
+ break;
+
+ case 'U':
+ len = (((unsigned int)srb->cmnd[7])<<16) |
+ (((unsigned int)srb->cmnd[8])<<8) |
+ srb->cmnd[9];
+ break;
+
+ case 'C':
+ len = (((unsigned int)srb->cmnd[2])<<24) |
+ (((unsigned int)srb->cmnd[3])<<16) |
+ (((unsigned int)srb->cmnd[4])<<8) |
+ srb->cmnd[5];
+ break;
+
+ case 'D':
+ len = (((unsigned int)srb->cmnd[6])<<24) |
+ (((unsigned int)srb->cmnd[7])<<16) |
+ (((unsigned int)srb->cmnd[8])<<8) |
+ srb->cmnd[9];
+ break;
+
+ case 'V':
+ len = 20;
+ break;
+
+ case 'W':
+ len = 24;
+ break;
+
+ case 'B':
+ /* Use buffer size due to different block sizes */
+ doDefault = 1;
+ break;
+
+ case 'X':
+ US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
+ srb->cmnd[0]);
+ doDefault = 1;
+ break;
+
+ case 'Z':
+ /* Use buffer size due to mode dependence */
+ doDefault = 1;
+ break;
+
+ default:
+ US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n",
+ srb->cmnd[0], lengths[srb->cmnd[0]] );
+ doDefault = 1;
+ }
+
+ if ( doDefault == 1 ) {
+ /* Are we going to scatter gather? */
+ if (srb->use_sg) {
+ /* Add up the sizes of all the sg segments */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ total += sg[i].length;
+ len = total;
+ }
+ else
+ /* Just return the length of the buffer */
+ len = srb->request_bufflen;
+ }
+
+ return len;
+}
+
+/* This is a version of usb_clear_halt() that doesn't read the status from
+ * the device -- this is because some devices crash their internal firmware
+ * when the status is requested after a halt
+ */
+static int clear_halt(struct usb_device *dev, int pipe)
+{
+ int result;
+ int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);
+
+ result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
+ endp, NULL, 0, HZ * 3);
+
+ /* this is a failure case */
+ if (result < 0)
+ return result;
+
+ /* reset the toggles and endpoint flags */
+ usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
+
+ return 0;
+}
+
+/***********************************************************************
* Data transfer routines
***********************************************************************/
@@ -217,7 +565,7 @@ static int us_transfer_partial(struct us_data *us, char *buf, int length)
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
+ clear_halt(us->pusb_dev, pipe);
}
/* did we send all the data? */
@@ -287,44 +635,6 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
srb->result = result;
}
-/* Calculate the length of the data transfer (not the command) for any
- * given SCSI command
- */
-static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
-{
- int i;
- unsigned int total = 0;
- struct scatterlist *sg;
-
- /* support those devices which need the length calculated
- * differently
- */
- if (us->flags & US_FL_ALT_LENGTH) {
- if (srb->cmnd[0] == INQUIRY) {
- srb->cmnd[4] = 36;
- }
-
- if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
- return srb->cmnd[4];
-
- if (srb->cmnd[0] == TEST_UNIT_READY)
- return 0;
- }
-
- /* Are we going to scatter gather? */
- if (srb->use_sg) {
- /* Add up the sizes of all the scatter-gather segments */
- sg = (struct scatterlist *) srb->request_buffer;
- for (i = 0; i < srb->use_sg; i++)
- total += sg[i].length;
-
- return total;
- }
- else
- /* Just return the length of the buffer */
- return srb->request_bufflen;
-}
-
/***********************************************************************
* Transport routines
***********************************************************************/
@@ -363,7 +673,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
* of determining status on it's own, we need to auto-sense almost
* every time.
*/
- if (us->protocol == US_PR_CB) {
+ if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) {
US_DEBUGP("-- CB transport device requiring auto-sense\n");
need_auto_sense = 1;
@@ -490,7 +800,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
* This is necessary because the auto-sense for some devices always
* sets byte 0 == 0x70, even if there is no error
*/
- if ((us->protocol == US_PR_CB) &&
+ if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
(result == USB_STOR_TRANSPORT_GOOD) &&
((srb->sense_buffer[2] & 0xf) == 0x0))
srb->sense_buffer[0] = 0x0;
@@ -548,10 +858,10 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
/* STALL must be cleared when they are detected */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
- result = usb_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0));
- US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ result = clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- clear_halt() returns %d\n", result);
return USB_STOR_TRANSPORT_FAILED;
}
@@ -652,10 +962,10 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
/* a stall is a fatal condition from the device */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe. Clearing\n");
- result = usb_clear_halt(us->pusb_dev,
- usb_sndctrlpipe(us->pusb_dev,
- 0));
- US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ result = clear_halt(us->pusb_dev,
+ usb_sndctrlpipe(us->pusb_dev,
+ 0));
+ US_DEBUGP("-- clear_halt() returns %d\n", result);
return USB_STOR_TRANSPORT_FAILED;
}
@@ -710,7 +1020,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
/* if we get a STALL, clear the stall */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
+ clear_halt(us->pusb_dev, pipe);
}
/* return the default -- no LUNs */
@@ -757,7 +1067,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* if we stall, we need to clear it before we go on */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
+ clear_halt(us->pusb_dev, pipe);
} else if (result) {
/* unknown error -- we've got a problem */
return USB_STOR_TRANSPORT_ERROR;
@@ -796,7 +1106,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* did the attempt to read the CSW fail? */
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
+ clear_halt(us->pusb_dev, pipe);
/* get the status again */
US_DEBUGP("Attempting to get CSW (2nd try)...\n");
@@ -810,7 +1120,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* if it fails again, we need a reset and return an error*/
if (result == -EPIPE) {
US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
- usb_clear_halt(us->pusb_dev, pipe);
+ clear_halt(us->pusb_dev, pipe);
return USB_STOR_TRANSPORT_ERROR;
}
}
@@ -877,10 +1187,10 @@ int usb_stor_CB_reset(struct us_data *us)
schedule_timeout(HZ*6);
US_DEBUGP("CB_reset: clearing endpoint halt\n");
- usb_clear_halt(us->pusb_dev,
- usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
- usb_clear_halt(us->pusb_dev,
- usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+ clear_halt(us->pusb_dev,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ clear_halt(us->pusb_dev,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
US_DEBUGP("CB_reset done\n");
return 0;
@@ -904,14 +1214,13 @@ int usb_stor_Bulk_reset(struct us_data *us)
if (result < 0)
US_DEBUGP("Bulk hard reset failed %d\n", result);
- usb_clear_halt(us->pusb_dev,
- usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
- usb_clear_halt(us->pusb_dev,
- usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+ clear_halt(us->pusb_dev,
+ usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+ clear_halt(us->pusb_dev,
+ usb_sndbulkpipe(us->pusb_dev, us->ep_out));
/* long wait for reset */
schedule_timeout(HZ*6);
return result;
}
-
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 9d0993c1e..4615569f3 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -1,7 +1,7 @@
/* Driver for USB Mass Storage compliant devices
* Transport Functions Header File
*
- * $Id: transport.h,v 1.6 2000/07/27 14:42:43 groovyjava Exp $
+ * $Id: transport.h,v 1.8 2000/08/08 01:23:55 webbb Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -58,6 +58,7 @@
#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for
SDDR-09 */
#endif
+#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */
/*
* Bulk only data structures
@@ -133,4 +134,6 @@ extern int usb_stor_Bulk_reset(struct us_data*);
void usb_stor_invoke_transport(Scsi_Cmnd *, struct us_data *);
+extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us);
+
#endif
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index fc70bc72a..50ebddd6f 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.16 2000/08/01 22:01:19 mdharm Exp $
+ * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -44,7 +44,6 @@
*/
#include <linux/config.h>
-
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
@@ -56,6 +55,9 @@
#ifdef CONFIG_USB_STORAGE_SDDR09
#include "sddr09.h"
#endif
+#ifdef CONFIG_USB_STORAGE_DPCM
+#include "dpcm.h"
+#endif
#include <linux/module.h>
#include <linux/sched.h>
@@ -63,6 +65,10 @@
#include <linux/init.h>
#include <linux/malloc.h>
+/* Some informational data */
+MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
+MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
+
/*
* Per device data
*/
@@ -91,6 +97,58 @@ static struct usb_driver storage_driver = {
disconnect: storage_disconnect,
};
+/*
+ * fill_inquiry_response takes an unsigned char array (which must
+ * be at least 36 characters) and populates the vendor name,
+ * product name, and revision fields. Then the array is copied
+ * into the SCSI command's response buffer (oddly enough
+ * called request_buffer). data_len contains the length of the
+ * data array, which again must be at least 36.
+ */
+
+void fill_inquiry_response(struct us_data *us, unsigned char *data,
+ unsigned int data_len) {
+
+ int i;
+ struct scatterlist *sg;
+ int len =
+ us->srb->request_bufflen > data_len ? data_len :
+ us->srb->request_bufflen;
+ int transferred;
+ int amt;
+
+ if (data_len<36) // You lose.
+ return;
+
+ memcpy(data+8, us->unusual_dev->vendorName,
+ strlen(us->unusual_dev->vendorName) > 8 ? 8 :
+ strlen(us->unusual_dev->vendorName));
+ memcpy(data+16, us->unusual_dev->productName,
+ strlen(us->unusual_dev->productName) > 16 ? 16 :
+ strlen(us->unusual_dev->productName));
+ data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F);
+ data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F);
+ data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F);
+ data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F);
+
+ if (us->srb->use_sg) {
+ sg = (struct scatterlist *)us->srb->request_buffer;
+ for (i=0; i<us->srb->use_sg; i++)
+ memset(sg[i].address, 0, sg[i].length);
+ for (i=0, transferred=0;
+ i<us->srb->use_sg && transferred < len;
+ i++) {
+ amt = sg[i].length > len-transferred ?
+ len-transferred : sg[i].length;
+ memcpy(sg[i].address, data+transferred, amt);
+ transferred -= amt;
+ }
+ } else {
+ memset(us->srb->request_buffer, 0, us->srb->request_bufflen);
+ memcpy(us->srb->request_buffer, data, len);
+ }
+}
+
static int usb_stor_control_thread(void * __us)
{
wait_queue_t wait;
@@ -176,7 +234,7 @@ static int usb_stor_control_thread(void * __us)
us->srb = NULL;
break;
}
-
+
/* lock the device pointers */
down(&(us->dev_semaphore));
@@ -246,50 +304,140 @@ static int usb_stor_control_thread(void * __us)
}
/* This is the list of devices we recognize, along with their flag data */
+
+/* The vendor name should be kept at eight characters or less, and
+ * the product name should be kept at 16 characters or less. If a device
+ * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
+ * normally generated by a device thorugh the INQUIRY response will be
+ * taken from this list, and this is the reason for the above size
+ * restriction. However, if the flag is not present, then you
+ * are free to use as many characters as you like.
+ */
+
static struct us_unusual_dev us_unusual_dev_list[] = {
- { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus",
- US_SC_8070, US_PR_CB, 0},
+
+ { 0x03f0, 0x0107, 0x0200, 0x0200,
+ "HP",
+ "CD-Writer+",
+ US_SC_8070, US_PR_CB, NULL,
+ 0},
+
#ifdef CONFIG_USB_STORAGE_HP8200e
- { 0x03f0, 0x0207, 0x0001, 0x0001, "HP USB CD-Writer Plus 8200e",
- US_SC_8070, US_PR_SCM_ATAPI,
- US_FL_ALT_LENGTH | US_FL_NEED_INIT | US_FL_SINGLE_LUN},
+ { 0x03f0, 0x0207, 0x0001, 0x0001,
+ "HP",
+ "CD-Writer+ 8200e",
+ US_SC_8070, US_PR_SCM_ATAPI, init_8200e,
+ US_FL_SINGLE_LUN},
#endif
- { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120",
- US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30/S70",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
- US_FL_MODE_XLATE | US_FL_ALT_LENGTH | US_FL_ALT_LENGTH},
- { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
- US_FL_MODE_XLATE | US_FL_ALT_LENGTH},
- { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U",
- US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U",
- US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN},
- { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-05a)",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP},
-#ifdef CONFIG_USB_STORAGE_SDDR09
- { 0x0781, 0x0200, 0x0100, 0x0100, "Sandisk ImageMate (SDDR-09)",
- US_SC_SCSI, US_PR_EUSB_SDDR09,
+
+ { 0x04e6, 0x0001, 0x0200, 0x0200,
+ "Matshita",
+ "LS-120",
+ US_SC_8020, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x04e6, 0x0002, 0x0100, 0x0100,
+ "Shuttle",
+ "eUSCSI Bridge",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x04e6, 0x0006, 0x0100, 0x0100,
+ "Shuttle",
+ "eUSB MMC Adapter",
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x054c, 0x0010, 0x0210, 0x0210,
+ "Sony",
+ "DSC-S30/S70",
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE },
+
+ { 0x054c, 0x002d, 0x0100, 0x0100,
+ "Sony",
+ "Memorystick MSAC-US1",
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE },
+
+ { 0x057b, 0x0000, 0x0000, 0x0299,
+ "Y-E Data",
+ "Flashbuster-U",
+ US_SC_UFI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x057b, 0x0000, 0x0300, 0x9999,
+ "Y-E Data",
+ "Flashbuster-U",
+ US_SC_UFI, US_PR_CBI, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x0693, 0x0002, 0x0100, 0x0100,
+ "Hagiwara",
+ "FlashGate SmartMedia",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x0781, 0x0001, 0x0200, 0x0200,
+ "Sandisk",
+ "ImageMate SDDR05a",
+ US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP},
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+ { 0x0781, 0x0200, 0x0100, 0x0100,
+ "Sandisk",
+ "ImageMate SDDR09",
+ US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP },
+#endif
+
+ { 0x0781, 0x0002, 0x0009, 0x0009,
+ "Sandisk",
+ "ImageMate SDDR31",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ US_FL_IGNORE_SER},
+
+ { 0x07af, 0x0004, 0x0100, 0x0100,
+ "Microtech",
+ "USB-SCSI-DB25",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x059f, 0xa601, 0x0200, 0x0200,
+ "LaCie",
+ "USB Hard Disk",
+ US_SC_RBC, US_PR_CB, NULL,
+ 0 },
+
+#ifdef CONFIG_USB_STORAGE_DPCM
+ { 0x07af, 0x0006, 0x0100, 0x0100,
+ "Microtech",
+ "CameraMate (DPCM_USB)",
+ US_SC_SCSI, US_PR_DPCM_USB, NULL,
+ US_FL_START_STOP },
#endif
- { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)",
- US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER},
- { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech USB-SCSI-DB25",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge",
- US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0 }};
+
+ { 0x07af, 0x0005, 0x0100, 0x0100,
+ "Microtech",
+ "USB-SCSI-HD50",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x05ab, 0x0031, 0x0100, 0x0100,
+ "In-System",
+ "USB/IDE Bridge",
+ US_SC_8070, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x0693, 0x0005, 0x0100, 0x0100,
+ "Hagiwara",
+ "Flashgate",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0 }
+};
/* Search our ususual device list, based on vendor/product combinations
* to see if we can support this device. Returns a pointer to a structure
@@ -319,7 +467,8 @@ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
}
/* otherwise, we found one! */
- US_DEBUGP("-- found matching device: %s\n", ptr->name);
+ US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName,
+ ptr->productName);
return ptr;
}
@@ -546,15 +695,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
USB_ENDPOINT_NUMBER_MASK;
ss->ep_int = ep_int;
- /* Reset the device's NEED_INIT flag if it needs to be
- initialized with a magic sequence */
-
- if (flags & US_FL_NEED_INIT)
- ss->flags |= US_FL_NEED_INIT;
-
/* allocate an IRQ callback if one is needed */
if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
return NULL;
+
+ /* Re-Initialize the device if it needs it */
+
+ if (unusual_dev && unusual_dev->initFunction)
+ (*unusual_dev->initFunction)(ss);
+
} else {
/* New device -- allocate memory and initialize */
US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
@@ -586,6 +735,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->subclass = subclass;
ss->protocol = protocol;
ss->flags = flags;
+ ss->unusual_dev = unusual_dev;
/* copy over the endpoint data */
if (ep_in)
@@ -604,10 +754,22 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
strncpy(ss->vendor, mf, USB_STOR_STRING_LEN);
strncpy(ss->product, prod, USB_STOR_STRING_LEN);
strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
- if (strlen(ss->vendor) == 0)
- strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN);
- if (strlen(ss->product) == 0)
- strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN);
+ if (strlen(ss->vendor) == 0) {
+ if (unusual_dev)
+ strncpy(ss->vendor, unusual_dev->vendorName,
+ USB_STOR_STRING_LEN);
+ else
+ strncpy(ss->vendor, "Unknown",
+ USB_STOR_STRING_LEN);
+ }
+ if (strlen(ss->product) == 0) {
+ if (unusual_dev)
+ strncpy(ss->product, unusual_dev->productName,
+ USB_STOR_STRING_LEN);
+ else
+ strncpy(ss->product, "Unknown",
+ USB_STOR_STRING_LEN);
+ }
if (strlen(ss->serial) == 0)
strncpy(ss->serial, "None", USB_STOR_STRING_LEN);
@@ -657,6 +819,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->max_lun = 1;
break;
#endif
+
+#ifdef CONFIG_USB_STORAGE_DPCM
+ case US_PR_DPCM_USB:
+ ss->transport_name = "Control/Bulk-EUSB/SDDR09";
+ ss->transport = dpcm_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ ss->max_lun = 1;
+ break;
+#endif
default:
ss->transport_name = "Unknown";
@@ -734,6 +905,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
* we to do it?
*/
(struct us_data *)ss->htmplt.proc_dir = ss;
+
+ /* Just before we start our control thread, initialize
+ * the device if it needs initialization */
+ if (unusual_dev && unusual_dev->initFunction)
+ (*unusual_dev->initFunction)(ss);
/* start up our control thread */
ss->pid = kernel_thread(usb_stor_control_thread, ss,
@@ -878,6 +1054,3 @@ void __exit usb_stor_exit(void)
module_init(usb_stor_init) ;
module_exit(usb_stor_exit) ;
-
-MODULE_AUTHOR("Michael Gee <michael@linuxspecific.com>, David L. Brown, Jr. <usb-storage@davidb.org>, Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
-MODULE_DESCRIPTION("USB Mass Storage driver");
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index b376d39ee..435ad9777 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.4 2000/07/28 20:14:49 groovyjava Exp $
+ * $Id: usb.h,v 1.7 2000/08/15 00:06:38 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -77,6 +77,8 @@ static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *seri
}
}
+struct us_data;
+
/*
* Unusual device list definitions
*/
@@ -89,9 +91,11 @@ struct us_unusual_dev {
__u16 bcdDeviceMax;
/* the list specifies these parameters */
- const char* name;
+ const char* vendorName;
+ const char* productName;
__u8 useProtocol;
__u8 useTransport;
+ int (*initFunction)(struct us_data *);
unsigned int flags;
};
@@ -100,15 +104,11 @@ struct us_unusual_dev {
#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for
Win/MacOS compatibility */
#define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */
-#define US_FL_ALT_LENGTH 0x00000008 /* use the alternate algorithm for
- us_transfer_length() */
#define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */
-#define US_FL_NEED_INIT 0x00000020 /* Device needs initialization */
+#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */
#define USB_STOR_STRING_LEN 32
-struct us_data;
-
typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
typedef int (*trans_reset)(struct us_data*);
typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
@@ -176,6 +176,7 @@ struct us_data {
/* mutual exclusion structures */
struct semaphore notify; /* thread begin/end */
struct semaphore queue_exclusion; /* to protect data structs */
+ struct us_unusual_dev *unusual_dev; /* If unusual device */
void *extra; /* Any extra data */
void (*extra_destructor)(void *); /* extra data destructor */
};
@@ -184,4 +185,9 @@ struct us_data {
extern struct us_data *us_list;
extern struct semaphore us_list_semaphore;
+/* Function to fill an inquiry response. See usb.c for details */
+
+extern void fill_inquiry_response(struct us_data *us,
+ unsigned char *data, unsigned int data_len);
+
#endif
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
index 25d1d24cf..017a99dce 100644
--- a/drivers/usb/usb-core.c
+++ b/drivers/usb/usb-core.c
@@ -13,6 +13,7 @@
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/config.h>
+#include <linux/init.h>
#include <linux/usb.h>
/*
@@ -42,13 +43,11 @@ int dsbr100_init(void);
int uhci_init(void);
int ohci_hcd_init(void);
-#ifdef MODULE
-
/*
* Cleanup
*/
-void cleanup_module(void)
+static void __exit usb_exit(void)
{
usb_major_cleanup();
usbdevfs_cleanup();
@@ -59,10 +58,7 @@ void cleanup_module(void)
* Init
*/
-int init_module(void)
-#else
-int usb_init(void)
-#endif
+static int __init usb_init(void)
{
usb_major_init();
usbdevfs_init();
@@ -99,3 +95,6 @@ int usb_init(void)
#endif
return 0;
}
+
+module_init(usb_init);
+module_exit(usb_exit);
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 367f0d3f6..316394a84 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -76,7 +76,6 @@
(OHCI_CTRL_CBSR & 0x3) \
| OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
-static DECLARE_WAIT_QUEUE_HEAD (op_wakeup);
static LIST_HEAD (ohci_hcd_list);
static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
@@ -534,7 +533,6 @@ static int sohci_unlink_urb (urb_t * urb)
{
unsigned long flags;
ohci_t * ohci;
- DECLARE_WAITQUEUE (wait, current);
if (!urb) /* just to be sure */
return -EINVAL;
@@ -580,14 +578,18 @@ static int sohci_unlink_urb (urb_t * urb)
spin_unlock_irqrestore (&usb_ed_lock, flags);
if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+ DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
+ DECLARE_WAITQUEUE (wait, current);
+
usb_dec_dev_use (urb->dev);
- add_wait_queue (&op_wakeup, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
/* wait until all TDs are deleted */
- if (!schedule_timeout (HZ / 10))
- err("unlink URB timeout!");
- remove_wait_queue (&op_wakeup, &wait);
+ add_wait_queue (&unlink_wakeup, &wait);
+ urb_priv->wait = &unlink_wakeup;
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule ();
+ remove_wait_queue (&unlink_wakeup, &wait);
urb->status = -ENOENT;
+ urb_priv->wait = 0;
} else {
/* usb_dec_dev_use done in dl_del_list() */
urb->status = -EINPROGRESS;
@@ -634,7 +636,6 @@ static int sohci_free_dev (struct usb_device * usb_dev)
unsigned long flags;
int i, cnt = 0;
ed_t * ed;
- DECLARE_WAITQUEUE (wait, current);
struct ohci_device * dev = usb_to_ohci (usb_dev);
ohci_t * ohci = usb_dev->bus->hcpriv;
@@ -643,13 +644,20 @@ static int sohci_free_dev (struct usb_device * usb_dev)
if (usb_dev->devnum >= 0) {
- /* delete all TDs of all EDs */
+ /* driver disconnects should have unlinked all urbs
+ * (freeing all the TDs, unlinking EDs) but we need
+ * to defend against bugs that prevent that.
+ */
spin_lock_irqsave (&usb_ed_lock, flags);
for(i = 0; i < NUM_EDS; i++) {
ed = &(dev->ed[i]);
if (ed->state != ED_NEW) {
- if (ed->state == ED_OPER)
+ if (ed->state == ED_OPER) {
+ /* driver on that interface didn't unlink an urb */
+ dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",
+ ohci->ohci_dev->slot_name, usb_dev->devnum, i);
ep_unlink (ohci, ed);
+ }
ep_rm_ed (usb_dev, ed);
ed->state = ED_DEL;
cnt++;
@@ -657,6 +665,9 @@ static int sohci_free_dev (struct usb_device * usb_dev)
}
spin_unlock_irqrestore (&usb_ed_lock, flags);
+ /* if the controller is running, tds for those unlinked
+ * urbs get freed by dl_del_list at the next SF interrupt
+ */
if (cnt > 0) {
if (ohci->disabled) {
@@ -670,15 +681,21 @@ static int sohci_free_dev (struct usb_device * usb_dev)
warn ("TD leak, %d", cnt);
} else if (!in_interrupt ()) {
+ DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup);
+ DECLARE_WAITQUEUE (wait, current);
+
/* SF interrupt handler calls dl_del_list */
- add_wait_queue (&op_wakeup, &wait);
+ add_wait_queue (&freedev_wakeup, &wait);
+ dev->wait = &freedev_wakeup;
current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout (HZ / 10);
- remove_wait_queue (&op_wakeup, &wait);
+ schedule ();
+ remove_wait_queue (&freedev_wakeup, &wait);
} else {
- /* drivers mustn't expect this to work */
- err ("can't free tds, interrupt context");
+ /* likely some interface's driver has a refcount bug */
+ err ("bus %s devnum %d deletion in interrupt",
+ ohci->ohci_dev->slot_name, usb_dev->devnum);
+ BUG ();
}
}
}
@@ -907,35 +924,34 @@ static int ep_unlink (ohci_t * ohci, ed_t * ed)
#endif
break;
- case ISO:
- if (ohci->ed_isotail == ed)
- ohci->ed_isotail = ed->ed_prev;
+ case ISO:
+ if (ohci->ed_isotail == ed)
+ ohci->ed_isotail = ed->ed_prev;
if (ed->hwNextED != 0)
- ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-
+ ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+
if (ed->ed_prev != NULL) {
ed->ed_prev->hwNextED = ed->hwNextED;
} else {
- for (i = 0; i < 32; i += inter) {
- inter = 1;
+ for (i = 0; i < 32; i++) {
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]);
- *ed_p != 0;
- ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
- inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
- if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
+ *ed_p != 0;
+ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
+ // inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+ if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ }
}
}
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_ISO");
#endif
break;
- }
- ed->state = ED_UNLINK;
- return 0;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
}
@@ -1276,28 +1292,33 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame)
tdINFO = le32_to_cpup (&td->hwINFO);
if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td);
*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
- if(++ (urb_priv->td_cnt) == urb_priv->length)
+ /* URB is done; clean up */
+ if (++(urb_priv->td_cnt) == urb_priv->length) {
+ void *condition = urb_priv->wait;
+
urb_rm_priv (urb);
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
usb_dec_dev_use (urb->dev);
urb->status = -ECONNRESET;
urb->complete (urb);
- } else {
- wake_up (&op_wakeup);
+ } else if (condition) {
+ /* unblock sohci_unlink_urb */
+ wake_up (condition);
}
+ }
} else {
td_p = &td->hwNextTD;
}
-
}
+
if (ed->state & ED_DEL) { /* set by sohci_free_dev */
struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
- OHCI_FREE (tdTailP); /* free dummy td */
+ OHCI_FREE (tdTailP); /* free dummy td */
ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP);
ed->state = ED_NEW;
/* if all eds are removed wake up sohci_free_dev */
- if (!--dev->ed_cnt)
- wake_up (&op_wakeup);
+ if (!--dev->ed_cnt && dev->wait)
+ wake_up (dev->wait);
}
else {
ed->state &= ~ED_URB_DEL;
@@ -1839,6 +1860,7 @@ static int hc_start (ohci_t * ohci)
/* start controller operations */
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
writel (ohci->hc_control, &ohci->regs->control);
/* Choose the interrupts we care about now, others later on demand */
@@ -1850,25 +1872,28 @@ static int hc_start (ohci_t * ohci)
writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
&ohci->regs->roothub.a);
writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
-#endif /* OHCI_USE_NPS */
/* connect the virtual root hub */
ohci->rh.devnum = 0;
usb_dev = usb_alloc_dev (NULL, ohci->bus);
- if (!usb_dev)
+ if (!usb_dev) {
+ ohci->disabled = 1;
return -ENOMEM;
+ }
dev = usb_to_ohci (usb_dev);
ohci->bus->root_hub = usb_dev;
usb_connect (usb_dev);
if (usb_new_device (usb_dev) != 0) {
usb_free_dev (usb_dev);
+ ohci->disabled = 1;
return -ENODEV;
}
- ohci->disabled = 0;
return 0;
}
@@ -1936,7 +1961,7 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
/* allocate OHCI */
-static ohci_t * __devinit hc_alloc_ohci (void * mem_base)
+static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
{
ohci_t * ohci;
struct usb_bus * bus;
@@ -1947,9 +1972,16 @@ static ohci_t * __devinit hc_alloc_ohci (void * mem_base)
memset (ohci, 0, sizeof (ohci_t));
+ ohci->disabled = 1;
ohci->irq = -1;
ohci->regs = mem_base;
+ ohci->ohci_dev = dev;
+ dev->driver_data = ohci;
+
+ INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+ list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+
bus = usb_alloc_bus (&sohci_device_operations);
if (!bus) {
kfree (ohci);
@@ -1958,8 +1990,7 @@ static ohci_t * __devinit hc_alloc_ohci (void * mem_base)
ohci->bus = bus;
bus->hcpriv = (void *) ohci;
- ohci->disabled = 1;
-
+
return ohci;
}
@@ -2008,6 +2039,7 @@ static int __devinit
hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
{
ohci_t * ohci;
+ u8 latency, limit;
char buf[8], *bufp = buf;
#ifndef __sparc__
@@ -2019,15 +2051,24 @@ hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
(unsigned long) mem_base, bufp);
printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
- ohci = hc_alloc_ohci (mem_base);
+ ohci = hc_alloc_ohci (dev, mem_base);
if (!ohci) {
return -ENOMEM;
}
- ohci->ohci_dev = dev;
- dev->driver_data = ohci;
- INIT_LIST_HEAD (&ohci->ohci_hcd_list);
- list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+ /* bad pci latencies can contribute to overruns */
+ pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+ if (latency) {
+ pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
+ if (limit && limit < latency) {
+ dbg ("PCI latency reduced to max %d", limit);
+ pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
+ ohci->pci_latency = limit;
+ } else {
+ /* it might already have been reduced */
+ ohci->pci_latency = latency;
+ }
+ }
if (hc_reset (ohci) < 0) {
hc_release_ohci (ohci);
@@ -2042,7 +2083,7 @@ hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
if (request_irq (irq, hc_interrupt, SA_SHIRQ,
ohci_pci_driver.name, ohci) != 0) {
- err ("request interrupt %d failed", irq);
+ err ("request interrupt %s failed", bufp);
hc_release_ohci (ohci);
return -EBUSY;
}
@@ -2072,6 +2113,9 @@ static void hc_restart (ohci_t *ohci)
int temp;
int i;
+ if (ohci->pci_latency)
+ pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
+
ohci->disabled = 1;
if (ohci->bus->root_hub)
usb_disconnect (&ohci->bus->root_hub);
@@ -2106,7 +2150,6 @@ static int __devinit
ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned long mem_resource, mem_len;
- u8 latency, limit;
void *mem_base;
if (pci_enable_device(dev) < 0)
@@ -2128,14 +2171,6 @@ ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
/* controller writes into our memory */
pci_set_master (dev);
- pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
- if (latency) {
- pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
- if (limit && limit < latency) {
- dbg ("PCI latency reduced to max %d", limit);
- pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
- }
- }
return hc_found_ohci (dev, dev->irq, mem_base);
}
@@ -2157,6 +2192,9 @@ ohci_pci_remove (struct pci_dev *dev)
ohci->disabled ? " (disabled)" : "",
in_interrupt () ? " in interrupt" : ""
);
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#endif
/* don't wake up sleeping controllers, or block in interrupt context */
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {
@@ -2209,6 +2247,14 @@ ohci_pci_resume (struct pci_dev *dev)
ohci_t *ohci = (ohci_t *) dev->driver_data;
int temp;
+ /* guard against multiple resumes */
+ atomic_inc (&ohci->resume_count);
+ if (atomic_read (&ohci->resume_count) != 1) {
+ err ("concurrent PCI resumes for usb-%s", dev->slot_name);
+ atomic_dec (&ohci->resume_count);
+ return;
+ }
+
/* did we suspend, or were we powered off? */
ohci->hc_control = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS;
@@ -2253,6 +2299,9 @@ ohci_pci_resume (struct pci_dev *dev)
default:
warn ("odd PCI resume for usb-%s", dev->slot_name);
}
+
+ /* controller is operational, extra resumes are harmless */
+ atomic_dec (&ohci->resume_count);
}
#endif /* CONFIG_PM */
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
index e326f5ee6..d286265e3 100644
--- a/drivers/usb/usb-ohci.h
+++ b/drivers/usb/usb-ohci.h
@@ -366,6 +366,7 @@ typedef struct ohci {
int irq;
int disabled; /* e.g. got a UE, we're hung */
+ atomic_t resume_count; /* defending against multiple resumes */
struct ohci_regs * regs; /* OHCI controller's memory */
struct list_head ohci_hcd_list; /* list of all ohci_hcd */
@@ -384,7 +385,10 @@ typedef struct ohci {
struct usb_bus * bus;
struct usb_device * dev[128];
struct virt_root_hub rh;
- struct pci_dev *ohci_dev;
+
+ /* PCI device handle and settings */
+ struct pci_dev *ohci_dev;
+ u8 pci_latency;
} ohci_t;
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
index bd721cba2..14c6e649e 100644
--- a/drivers/usb/usb-uhci.c
+++ b/drivers/usb/usb-uhci.c
@@ -12,7 +12,7 @@
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: usb-uhci.c,v 1.236 2000/08/02 20:28:28 acher Exp $
+ * $Id: usb-uhci.c,v 1.237 2000/08/08 14:58:17 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.236 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.237 $ time " __TIME__ " " __DATE__
#include <linux/usb.h>
#include "usb-uhci.h"
@@ -888,7 +888,7 @@ _static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
data += pktsze;
len -= pktsze;
- last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || (urb->transfer_flags & USB_DISABLE_SPD)));
+ 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
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 777e2d650..93fe7826c 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -1222,9 +1222,7 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface *int
int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer)
{
- int i;
- int retval;
- int size;
+ int i, retval, size;
struct usb_descriptor_header *header;
memcpy(config, buffer, USB_DT_CONFIG_SIZE);
@@ -1252,19 +1250,54 @@ int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor
size -= config->bLength;
for (i = 0; i < config->bNumInterfaces; i++) {
- header = (struct usb_descriptor_header *)buffer;
- if ((header->bLength > size) || (header->bLength <= 2)) {
- err("ran out of descriptors parsing");
- return -1;
- }
-
- if (header->bDescriptorType != USB_DT_INTERFACE) {
- warn("unexpected descriptor 0x%X",
- header->bDescriptorType);
+ int numskipped, len;
+ char *begin;
+
+ /* Skip over the rest of the Class Specific or Vendor */
+ /* Specific descriptors */
+ begin = buffer;
+ numskipped = 0;
+ while (size >= sizeof(struct usb_descriptor_header)) {
+ header = (struct usb_descriptor_header *)buffer;
+
+ if ((header->bLength > size) || (header->bLength < 2)) {
+ err("invalid descriptor length of %d", header->bLength);
+ return -1;
+ }
+
+ /* If we find another descriptor which is at or below */
+ /* us in the descriptor heirarchy then we're done */
+ if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
+ (header->bDescriptorType == USB_DT_INTERFACE) ||
+ (header->bDescriptorType == USB_DT_CONFIG) ||
+ (header->bDescriptorType == USB_DT_DEVICE))
+ break;
+
+ dbg("skipping descriptor 0x%X", header->bDescriptorType);
+ numskipped++;
buffer += header->bLength;
size -= header->bLength;
- continue;
+ }
+ if (numskipped)
+ dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
+
+ /* Copy any unknown descriptors into a storage area for */
+ /* drivers to later parse */
+ len = (int)(buffer - begin);
+ if (!len) {
+ config->extra = NULL;
+ config->extralen = 0;
+ } else {
+ config->extra = kmalloc(len, GFP_KERNEL);
+ if (!config->extra) {
+ err("couldn't allocate memory for config extra descriptors");
+ config->extralen = 0;
+ return -1;
+ }
+
+ memcpy(config->extra, begin, len);
+ config->extralen = len;
}
retval = usb_parse_interface(dev, config->interface + i, buffer, size);
diff --git a/drivers/usb/usbkbd.c b/drivers/usb/usbkbd.c
index 89cc76537..bbf4b59ac 100644
--- a/drivers/usb/usbkbd.c
+++ b/drivers/usb/usbkbd.c
@@ -1,5 +1,5 @@
/*
- * $Id: usbkbd.c,v 1.11 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: usbkbd.c,v 1.16 2000/08/14 21:05:26 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
@@ -47,8 +47,8 @@ static unsigned char usb_kbd_keycode[256] = {
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
- 115,114, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189,
+ 190,191,192,193,194,195,196,197,198, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -63,7 +63,7 @@ struct usb_kbd {
unsigned char old[8];
struct urb irq, led;
devrequest dr;
- unsigned char leds;
+ unsigned char leds, newleds;
char name[128];
int open;
};
@@ -104,28 +104,37 @@ int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, i
if (type != EV_LED) return -1;
- if (kbd->led.status == -EINPROGRESS) {
- warn("had to kill led urb");
- usb_unlink_urb(&kbd->led);
- }
- kbd->leds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
- (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
- (!!test_bit(LED_NUML, dev->led));
+ kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+ (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
+ (!!test_bit(LED_NUML, dev->led));
+
+ if (kbd->led.status == -EINPROGRESS)
+ return 0;
+ if (kbd->leds == kbd->newleds)
+ return 0;
- if (usb_submit_urb(&kbd->led)) {
+ kbd->leds = kbd->newleds;
+ if (usb_submit_urb(&kbd->led))
err("usb_submit_urb(leds) failed");
- return -1;
- }
return 0;
}
static void usb_kbd_led(struct urb *urb)
{
+ struct usb_kbd *kbd = urb->context;
+
if (urb->status)
warn("led urb status %d received", urb->status);
+
+ if (kbd->leds == kbd->newleds)
+ return;
+
+ kbd->leds = kbd->newleds;
+ if (usb_submit_urb(&kbd->led))
+ err("usb_submit_urb(leds) failed");
}
static int usb_kbd_open(struct input_dev *dev)