summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-25 01:20:01 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-25 01:20:01 +0000
commit3797ba0b62debb71af4606910acacc9896a9ae3b (patch)
tree414eea76253c7871bfdf3bd9d1817771eb40917c /drivers/usb
parent2b6c0c580795a4404f72d2a794214dd9e080709d (diff)
Merge with Linux 2.4.0-test2.
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Config.in5
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/devio.c2
-rw-r--r--drivers/usb/evdev.c36
-rw-r--r--drivers/usb/iforce.c335
-rw-r--r--drivers/usb/input.c4
-rw-r--r--drivers/usb/joydev.c54
-rw-r--r--drivers/usb/mousedev.c55
-rw-r--r--drivers/usb/pegasus.c269
-rw-r--r--drivers/usb/serial/usbserial.c128
-rw-r--r--drivers/usb/serial/visor.c29
-rw-r--r--drivers/usb/usb-storage.c730
-rw-r--r--drivers/usb/usb-storage.h3
-rw-r--r--drivers/usb/wmforce.c190
14 files changed, 1389 insertions, 453 deletions
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
index 042f742da..5032a9b75 100644
--- a/drivers/usb/Config.in
+++ b/drivers/usb/Config.in
@@ -70,7 +70,10 @@ comment 'USB HID'
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 ' Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $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
+ 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
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ec8687ae6..7d95c0c98 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -61,7 +61,7 @@ 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_USB_WMFORCE) += wmforce.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
diff --git a/drivers/usb/devio.c b/drivers/usb/devio.c
index 235385515..d6cedee9b 100644
--- a/drivers/usb/devio.c
+++ b/drivers/usb/devio.c
@@ -1044,7 +1044,7 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
kfree (buf);
return -EFAULT;
} else
- memset (arg, size, 0);
+ memset (arg, 0, size);
}
/* ioctl to device */
diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c
index 3e21f6cb5..7eca5e304 100644
--- a/drivers/usb/evdev.c
+++ b/drivers/usb/evdev.c
@@ -1,5 +1,5 @@
/*
- * $Id: evdev.c,v 1.8 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
@@ -39,7 +39,7 @@
#include <linux/input.h>
struct evdev {
- int used;
+ int exist;
int open;
int minor;
struct input_handle handle;
@@ -99,13 +99,14 @@ static int evdev_release(struct inode * inode, struct file * file)
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
- if (!--list->evdev->open)
- input_close_device(&list->evdev->handle);
-
- if (!--list->evdev->used) {
- input_unregister_minor(list->evdev->devfs);
- evdev_table[list->evdev->minor] = NULL;
- kfree(list->evdev);
+ 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);
@@ -121,9 +122,8 @@ static int evdev_open(struct inode * inode, struct file * file)
if (i > EVDEV_MINORS || !evdev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) {
+ if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
return -ENOMEM;
- }
memset(list, 0, sizeof(struct evdev_list));
list->evdev = evdev_table[i];
@@ -132,10 +132,9 @@ static int evdev_open(struct inode * inode, struct file * file)
file->private_data = list;
- list->evdev->used++;
-
if (!list->evdev->open++)
- input_open_device(&list->evdev->handle);
+ if (list->evdev->exist)
+ input_open_device(&list->evdev->handle);
return 0;
}
@@ -303,7 +302,7 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
evdev->handle.handler = handler;
evdev->handle.private = evdev;
- evdev->used = 1;
+ evdev->exist = 1;
evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
@@ -316,10 +315,11 @@ static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
- if (evdev->open)
- input_close_device(handle);
+ evdev->exist = 0;
- if (!--evdev->used) {
+ if (evdev->open) {
+ input_close_device(handle);
+ } else {
input_unregister_minor(evdev->devfs);
evdev_table[evdev->minor] = NULL;
kfree(evdev);
diff --git a/drivers/usb/iforce.c b/drivers/usb/iforce.c
new file mode 100644
index 000000000..a61b7801f
--- /dev/null
+++ b/drivers/usb/iforce.c
@@ -0,0 +1,335 @@
+/*
+ * $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>");
+
+#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/input.c b/drivers/usb/input.c
index 66a3d2911..4fb2985af 100644
--- a/drivers/usb/input.c
+++ b/drivers/usb/input.c
@@ -386,8 +386,8 @@ 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, 0, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
- S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, &input_fops, NULL);
+ 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)
diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c
index 0f0bb2773..5349d515c 100644
--- a/drivers/usb/joydev.c
+++ b/drivers/usb/joydev.c
@@ -1,7 +1,7 @@
/*
- * $Id: joydev.c,v 1.7 2000/05/29 09:01:52 vojtech Exp $
+ * $Id: joydev.c,v 1.11 2000/06/23 09:23:00 vojtech Exp $
*
- * Copyright (c) 1999-2000 Vojtech Pavlik
+ * Copyright (c) 1999-2000 Vojtech Pavlik
* Copyright (c) 1999 Colin Van Dyke
*
* Joystick device driver for the input driver suite.
@@ -50,7 +50,7 @@
#define JOYDEV_BUFFER_SIZE 64
struct joydev {
- int used;
+ int exist;
int open;
int minor;
struct input_handle handle;
@@ -66,6 +66,7 @@ struct joydev {
__u16 keypam[KEY_MAX - BTN_MISC];
__u8 absmap[ABS_MAX];
__u8 abspam[ABS_MAX];
+ __s16 abs[ABS_MAX];
};
struct joydev_list {
@@ -121,7 +122,9 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
case EV_ABS:
event.type = JS_EVENT_AXIS;
event.number = joydev->absmap[code];
- event.value = joydev_correct(value, &joydev->corr[event.number]);
+ 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:
@@ -165,13 +168,14 @@ static int joydev_release(struct inode * inode, struct file * file)
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
- if (!--list->joydev->open)
- input_close_device(&list->joydev->handle);
-
- if (!--list->joydev->used) {
- input_unregister_minor(list->joydev->devfs);
- joydev_table[list->joydev->minor] = NULL;
- kfree(list->joydev);
+ 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);
@@ -187,9 +191,8 @@ static int joydev_open(struct inode *inode, struct file *file)
if (i > JOYDEV_MINORS || !joydev_table[i])
return -ENODEV;
- if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) {
+ if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
return -ENOMEM;
- }
memset(list, 0, sizeof(struct joydev_list));
list->joydev = joydev_table[i];
@@ -198,10 +201,9 @@ static int joydev_open(struct inode *inode, struct file *file)
file->private_data = list;
- list->joydev->used++;
-
if (!list->joydev->open++)
- input_open_device(&list->joydev->handle);
+ if (list->joydev->exist)
+ input_open_device(&list->joydev->handle);
return 0;
}
@@ -228,8 +230,8 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
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_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x;
- data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y;
+ 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;
@@ -274,13 +276,12 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
if (list->startup < joydev->nkey) {
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- event.value = !!test_bit(joydev->keypam[list->startup], input->key);
event.number = list->startup;
+ event.value = !!test_bit(joydev->keypam[event.number], input->key);
} else {
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- event.value = joydev_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]],
- &joydev->corr[list->startup - joydev->nkey]);
event.number = list->startup - joydev->nkey;
+ event.value = joydev->abs[event.number];
}
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
@@ -407,7 +408,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev->handle.handler = handler;
joydev->handle.private = joydev;
- joydev->used = 1;
+ joydev->exist = 1;
for (i = 0; i < ABS_MAX; i++)
if (test_bit(i, dev->absbit)) {
@@ -442,6 +443,8 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
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);
@@ -455,10 +458,11 @@ static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
- if (joydev->open)
- input_close_device(handle);
+ joydev->exist = 0;
- if (!--joydev->used) {
+ if (joydev->open) {
+ input_close_device(handle);
+ } else {
input_unregister_minor(joydev->devfs);
joydev_table[joydev->minor] = NULL;
kfree(joydev);
diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c
index 399d2a0c0..5c871a88d 100644
--- a/drivers/usb/mousedev.c
+++ b/drivers/usb/mousedev.c
@@ -1,5 +1,5 @@
/*
- * $Id: mousedev.c,v 1.8 2000/05/28 17:31:36 vojtech Exp $
+ * $Id: mousedev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
*
* Copyright (c) 1999-2000 Vojtech Pavlik
*
@@ -47,7 +47,7 @@
#endif
struct mousedev {
- int used;
+ int exist;
int open;
int minor;
wait_queue_head_t wait;
@@ -172,22 +172,30 @@ static int mousedev_release(struct inode * inode, struct file * file)
struct input_handle *handle = mousedev_handler.handle;
while (handle) {
struct mousedev *mousedev = handle->private;
- if (!mousedev->open)
- input_close_device(handle);
+ 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)
- input_close_device(&list->mousedev->handle);
+ 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);
+ }
+ }
}
}
- if (!--list->mousedev->used) {
- input_unregister_minor(list->mousedev->devfs);
- mousedev_table[list->mousedev->minor] = NULL;
- kfree(list->mousedev);
- }
-
kfree(list);
return 0;
@@ -210,20 +218,20 @@ static int mousedev_open(struct inode * inode, struct file * file)
mousedev_table[i]->list = list;
file->private_data = list;
- list->mousedev->used++;
-
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)
- input_open_device(handle);
+ if (mousedev->exist)
+ input_open_device(handle);
handle = handle->hnext;
}
} else {
- if (!mousedev_mix.open)
- input_open_device(&list->mousedev->handle);
+ if (!mousedev_mix.open)
+ if (list->mousedev->exist)
+ input_open_device(&list->mousedev->handle);
}
}
@@ -402,7 +410,7 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
memset(mousedev, 0, sizeof(struct mousedev));
init_waitqueue_head(&mousedev->wait);
- mousedev->used = 1;
+ mousedev->exist = 1;
mousedev->minor = minor;
mousedev_table[minor] = mousedev;
@@ -424,10 +432,13 @@ static void mousedev_disconnect(struct input_handle *handle)
{
struct mousedev *mousedev = handle->private;
- if (mousedev->open || mousedev_mix.open)
- input_close_device(handle);
+ mousedev->exist = 0;
- if (!--mousedev->used) {
+ 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);
@@ -449,7 +460,7 @@ static int __init mousedev_init(void)
memset(&mousedev_mix, 0, sizeof(struct mousedev));
init_waitqueue_head(&mousedev_mix.wait);
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
- mousedev_mix.used = 1;
+ mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
diff --git a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
index 80b82bba2..8c588f79e 100644
--- a/drivers/usb/pegasus.c
+++ b/drivers/usb/pegasus.c
@@ -1,11 +1,37 @@
/*
** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
**
-** Copyright (R) 1999,2000 Petko Manolov - Petkan (petkan@spct.net)
+** Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@spct.net)
+**
**
-** Distribute under GPL version 2 or later.
+** ChangeLog:
+** .... Most of the time spend reading sources & docs.
+** v0.2.x First official release for the Linux kernel.
+** v0.3.0 Beutified and structured, some bugs fixed.
+** v0.3.x URBifying bulk requests and bugfixing. First relatively
+** stable release. Still can touch device's registers only
+** from top-halves.
+** v0.4.0 Control messages remained unurbified are now URBs.
+** Now we can touch the HW at any time.
*/
+/*
+ * 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
+ */
+
+
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/malloc.h>
@@ -16,7 +42,7 @@
#include <linux/usb.h>
-static const char *version = __FILE__ ": v0.3.14 2000/06/09 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
+static const char *version = __FILE__ ": v0.4.0 2000/06/15 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
#define PEGASUS_MTU 1500
@@ -24,17 +50,39 @@ static const char *version = __FILE__ ": v0.3.14 2000/06/09 (C) 1999-2000 Petko
#define SROM_WRITE 0x01
#define SROM_READ 0x02
#define PEGASUS_TX_TIMEOUT (HZ*5)
+#define PEGASUS_CTRL_TIMEOUT 1000
#define PEGASUS_RESET 1
#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
+enum pegasus_registers {
+ EthCtrl0 = 0,
+ EthCtrl1 = 1,
+ EthCtrl2 = 2,
+ EthID = 0x10,
+ EpromOffset = 0x20,
+ EpromData = 0x21, /* 0x21 low, 0x22 high byte */
+ EpromCtrl = 0x23,
+ PhyAddr = 0x25,
+ PhyData = 0x26, /* 0x26 low, 0x27 high byte */
+ PhyCtrl = 0x28,
+ UsbStst = 0x2a,
+ EthTxStat0 = 0x2b,
+ EthTxStat1 = 0x2c,
+ EthRxStat = 0x2d,
+ Gpio0 = 0x7e,
+ Gpio1 = 0x7f,
+};
+
+
struct pegasus {
struct usb_device *usb;
struct net_device *net;
struct net_device_stats stats;
int flags;
- spinlock_t pegasus_lock;
- struct urb rx_urb, tx_urb, intr_urb;
+ 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]);
unsigned char ALIGN(intr_buff[8]);
@@ -64,7 +112,7 @@ 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 DU-10", 0x07b8, 0xabc1, NULL},
+ {"D-Link DU-E10", 0x07b8, 0xabc1, NULL},
{"D-Link DU-E100", 0x07b8, 0x4002, NULL},
{"Linksys USB100TX", 0x066b, 0x2203, NULL},
{"Linksys USB100TX", 0x066b, 0x2204, NULL},
@@ -78,23 +126,120 @@ static struct usb_eth_dev usb_dev_id[] = {
};
-#define pegasus_get_registers(dev, indx, size, data)\
- usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ);
-#define pegasus_set_registers(dev, indx, size, data)\
- usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, 0, indx, data, size, HZ);
-#define pegasus_set_register(dev, indx, value) \
- { __u8 __data = value; \
- usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, __data, indx, &__data, 1, HZ);}
+
+static void pegasus_ctrl_end( urb_t *urb )
+{
+ if ( urb->status )
+ warn("ctrl_urb end status %d", urb->status);
+}
-static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regdata)
+static int pegasus_ctrl_timeout( urb_t *ctrl_urb )
+{
+ 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;
+}
+
+
+static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data )
+{
+ int ret;
+
+
+ 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;
+
+ FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+ usb_rcvctrlpipe(pegasus->usb,0), (char *)&pegasus->dr,
+ data, size, pegasus_ctrl_end, pegasus );
+
+ 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 );
+
+ 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 );
+
+ 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 );
+
+ return ret;
+}
+
+
+static int pegasus_read_phy_word(struct pegasus *pegasus, __u8 index, __u16 *regdata)
{
int i;
__u8 data[4] = { 1, 0, 0, 0x40 + index };
- pegasus_set_registers(dev, 0x25, 4, data);
+ pegasus_set_registers(pegasus, PhyAddr, 4, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 0x26, 3, data);
+ pegasus_get_registers(pegasus, PhyData, 3, data);
if (data[2] & 0x80) {
*regdata = *(__u16 *)(data);
return 0;
@@ -107,14 +252,14 @@ static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regd
}
-static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata)
+static int pegasus_write_phy_word(struct pegasus *pegasus, __u8 index, __u16 regdata)
{
int i;
__u8 data[4] = { 1, regdata, regdata >> 8, 0x20 + index };
- pegasus_set_registers(dev, 0x25, 4, data);
+ pegasus_set_registers(pegasus, PhyAddr, 4, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 0x28, 1, data);
+ pegasus_get_registers(pegasus, PhyCtrl, 1, data);
if (data[0] & 0x80)
return 0;
udelay(100);
@@ -125,51 +270,51 @@ static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regd
}
-static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
+static int pegasus_rw_eprom_word(struct pegasus *pegasus, __u8 index, __u16 *retdata, __u8 direction)
{
int i;
__u8 data[4] = { index, 0, 0, direction };
- pegasus_set_registers(dev, 0x20, 4, data);
+ pegasus_set_registers(pegasus, EpromOffset, 4, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 0x23, 1, data);
+ pegasus_get_registers(pegasus, EpromCtrl, 1, data);
if (data[0] & 4) {
- pegasus_get_registers(dev, 0x21, 2, data);
+ pegasus_get_registers(pegasus, EpromData, 2, data);
*retdata = *(__u16 *)data;
return 0;
}
}
- warn("pegasus_rw_srom_word() failed");
+ warn("pegasus_rw_eprom_word() failed");
return 1;
}
-static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
+static int pegasus_get_node_id(struct pegasus *pegasus, __u8 *id)
{
int i;
for (i = 0; i < 3; i++)
- if (pegasus_rw_srom_word(dev,i,(__u16 *)&id[i * 2],SROM_READ))
+ if (pegasus_rw_eprom_word(pegasus,i,(__u16 *)&id[i*2],SROM_READ))
return 1;
return 0;
}
-static int pegasus_reset_mac(struct usb_device *dev)
+static int pegasus_reset_mac(struct pegasus *pegasus)
{
__u8 data = 0x8;
int i;
- pegasus_set_register(dev, 1, data);
+ pegasus_set_register(pegasus, EthCtrl1, data);
for (i = 0; i < 100; i++) {
- pegasus_get_registers(dev, 1, 1, &data);
+ pegasus_get_registers(pegasus, EthCtrl1, 1, &data);
if (~data & 0x08) {
if (loopback & 1)
return 0;
if (loopback & 2)
- pegasus_write_phy_word(dev, 0, 0x4000);
- pegasus_set_register(dev, 0x7e, 0x24);
- pegasus_set_register(dev, 0x7e, 0x27);
+ pegasus_write_phy_word(pegasus, 0, 0x4000);
+ pegasus_set_register(pegasus, Gpio0, 0x24);
+ pegasus_set_register(pegasus, Gpio0, 0x27);
return 0;
}
}
@@ -183,22 +328,22 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
__u16 partmedia, temp;
__u8 node_id[6];
__u8 data[4];
+ struct pegasus *pegasus = dev->priv;
- if (pegasus_get_node_id(usb, node_id))
+ if (pegasus_get_node_id(pegasus, node_id))
return 1;
- pegasus_set_registers(usb, 0x10, 6, node_id);
+ pegasus_set_registers(pegasus, EthID, 6, node_id);
memcpy(dev->dev_addr, node_id, 6);
- if (pegasus_read_phy_word(usb, 1, &temp))
+ if (pegasus_read_phy_word(pegasus, 1, &temp))
return 2;
if ((~temp & 4) && !loopback) {
- warn("%s: link NOT established (0x%x), check the cable.",
+ warn("%s: link NOT established (0x%x) - check the cable.",
dev->name, temp);
- /* return 3; FIXME */
}
- if (pegasus_read_phy_word(usb, 5, &partmedia))
+ if (pegasus_read_phy_word(pegasus, 5, &partmedia))
return 4;
if ((partmedia & 0x1f) != 1) {
@@ -210,7 +355,7 @@ static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0);
data[2] = (loopback & 1) ? 0x09 : 0x01;
- pegasus_set_registers(usb, 0, 3, data);
+ pegasus_set_registers(pegasus, EthCtrl0, 3, data);
return 0;
}
@@ -281,24 +426,26 @@ static void pegasus_write_bulk(struct urb *urb)
{
struct pegasus *pegasus = urb->context;
- spin_lock(&pegasus->pegasus_lock);
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);
-
- spin_unlock(&pegasus->pegasus_lock);
}
static void pegasus_tx_timeout(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
- warn("%s: Tx timed out. Reseting...", net->name);
+
usb_unlink_urb(&pegasus->tx_urb);
+ warn("%s: Tx timed out. Reseting...", net->name);
+ pegasus_reset_mac( pegasus );
pegasus->stats.tx_errors++;
net->trans_start = jiffies;
- pegasus->flags |= PEGASUS_RESET;
netif_wake_queue(net);
}
@@ -372,6 +519,8 @@ static int pegasus_close(struct net_device *net)
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 )
@@ -394,12 +543,12 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE:
data[0] = 1;
case SIOCDEVPRIVATE+1:
- pegasus_read_phy_word(pegasus->usb, data[1] & 0x1f, &data[3]);
+ pegasus_read_phy_word(pegasus, data[1] & 0x1f, &data[3]);
return 0;
case SIOCDEVPRIVATE+2:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- pegasus_write_phy_word(pegasus->usb, data[1] & 0x1f, data[2]);
+ pegasus_write_phy_word(pegasus, data[1] & 0x1f, data[2]);
return 0;
default:
return -EOPNOTSUPP;
@@ -410,19 +559,23 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
static void pegasus_set_rx_mode(struct net_device *net)
{
struct pegasus *pegasus = net->priv;
+ __u8 tmp;
netif_stop_queue(net);
if (net->flags & IFF_PROMISC) {
info("%s: Promiscuous mode enabled", net->name);
-/* pegasus_set_register(pegasus->usb, 2, 0x04); FIXME */
+ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp);
+ pegasus_set_register(pegasus, EthCtrl2, tmp | 4);
} else if ((net->mc_count > multicast_filter_limit) ||
(net->flags & IFF_ALLMULTI)) {
- pegasus_set_register(pegasus->usb, 0, 0xfa);
- pegasus_set_register(pegasus->usb, 2, 0);
+ pegasus_set_register(pegasus, EthCtrl0, 0xfa);
+ pegasus_set_register(pegasus, EthCtrl2, 0);
info("%s set allmulti", net->name);
} else {
info("%s: set Rx mode", net->name);
+ pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp);
+ pegasus_set_register(pegasus, EthCtrl2, tmp & ~4);
}
netif_wake_queue(net);
@@ -464,12 +617,6 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
}
memset(pegasus, 0, sizeof(struct pegasus));
- if (pegasus_reset_mac(dev)) {
- err("can't reset MAC");
- kfree(pegasus);
- return NULL;
- }
-
net = init_etherdev(0, 0);
net->priv = pegasus;
net->open = pegasus_open;
@@ -485,6 +632,7 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
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,
@@ -495,7 +643,12 @@ static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
pegasus->intr_buff, 8, pegasus_irq, pegasus, 500);
-
+ if (pegasus_reset_mac(pegasus)) {
+ err("can't reset MAC");
+ kfree(pegasus);
+ return NULL;
+ }
+
printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
return pegasus;
@@ -515,7 +668,9 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
dev_close(pegasus->net);
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 )
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index b2e18bd8e..d60fd8e33 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -14,6 +14,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/23/2000) gkh
+ * Cleaned up debugging statements in a quest to find UHCI timeout bug.
+ *
* (05/22/2000) gkh
* Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
* removed from the individual device source files.
@@ -358,7 +361,7 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
int i, j;
int good_spot;
- dbg("get_free_serial %d", num_ports);
+ dbg(__FUNCTION__ " %d", num_ports);
*minor = 0;
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
@@ -373,14 +376,14 @@ static struct usb_serial *get_free_serial (int num_ports, int *minor)
continue;
if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
- err("Out of memory");
+ err(__FUNCTION__ " - Out of memory");
return NULL;
}
memset(serial, 0, sizeof(struct usb_serial));
serial->magic = USB_SERIAL_MAGIC;
serial_table[i] = serial;
*minor = i;
- dbg("minor base = %d", *minor);
+ dbg(__FUNCTION__ " - minor base = %d", *minor);
for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
return serial;
@@ -393,7 +396,7 @@ static void return_serial (struct usb_serial *serial)
{
int i;
- dbg("return_serial");
+ dbg(__FUNCTION__);
if (serial == NULL)
return;
@@ -418,7 +421,7 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
// dbg("ezusb_writememory %x, %d", address, length);
if (!transfer_buffer) {
- err("ezusb_writememory: kmalloc(%d) failed.", length);
+ err(__FUNCTION__ " - kmalloc(%d) failed.", length);
return -ENOMEM;
}
memcpy (transfer_buffer, data, length);
@@ -431,10 +434,10 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da
int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
{
int response;
- dbg("ezusb_set_reset: %d", reset_bit);
+ dbg(__FUNCTION__ " - %d", reset_bit);
response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0) {
- err("ezusb_set_reset %d failed", reset_bit);
+ err(__FUNCTION__ "- %d failed", reset_bit);
}
return response;
}
@@ -451,7 +454,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
struct usb_serial_port *port;
int portNumber;
- dbg("serial_open");
+ dbg(__FUNCTION__);
/* initialize the pointer incase something fails */
tty->driver_data = NULL;
@@ -459,7 +462,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
/* get the serial object associated with this tty pointer */
serial = get_serial_by_minor (MINOR(tty->device));
- if (serial_paranoia_check (serial, "serial_open")) {
+ if (serial_paranoia_check (serial, __FUNCTION__)) {
return -ENODEV;
}
@@ -481,16 +484,16 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_close");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_close port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not opened");
+ dbg (__FUNCTION__ " - port not opened");
return;
}
@@ -506,16 +509,16 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_write");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
- dbg("serial_write port %d, %d byte(s)", port->number, count);
+ dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count);
if (!port->active) {
- dbg ("port not opened");
+ dbg (__FUNCTION__ " - port not opened");
return -EINVAL;
}
@@ -531,16 +534,16 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_write_room");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
- dbg("serial_write_room port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return -EINVAL;
}
@@ -556,14 +559,14 @@ static int serial_write_room (struct tty_struct *tty)
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_chars_in_buffer");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return -EINVAL;
}
@@ -579,16 +582,16 @@ static int serial_chars_in_buffer (struct tty_struct *tty)
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_throttle");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_throttle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -604,16 +607,16 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_unthrottle");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_unthrottle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -629,16 +632,16 @@ static void serial_unthrottle (struct tty_struct * tty)
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_ioctl");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return -ENODEV;
}
- dbg("serial_ioctl port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return -ENODEV;
}
@@ -654,16 +657,16 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_set_termios");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_set_termios port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -679,16 +682,16 @@ static void serial_set_termios (struct tty_struct *tty, struct termios * old)
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
- struct usb_serial *serial = get_usb_serial (port, "serial_break");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
if (!serial) {
return;
}
- dbg("serial_break port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!port->active) {
- dbg ("port not open");
+ dbg (__FUNCTION__ " - port not open");
return;
}
@@ -708,10 +711,10 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
- dbg("generic_open port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (port->active) {
- dbg ("device already open");
+ dbg (__FUNCTION__ " - device already open");
return -EINVAL;
}
port->active = 1;
@@ -720,7 +723,7 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
if (serial->num_bulk_in) {
/*Start reading from the device*/
if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
}
return (0);
@@ -731,7 +734,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp)
{
struct usb_serial *serial = port->serial;
- dbg("generic_close port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
/* shutdown any bulk reads that might be going on */
if (serial->num_bulk_out) {
@@ -749,22 +752,33 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns
{
struct usb_serial *serial = port->serial;
- dbg("generic_serial_write port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (count == 0) {
- dbg("write request of 0 bytes");
+ dbg(__FUNCTION__ " - write request of 0 bytes");
return (0);
}
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS) {
- dbg ("already writing");
+ dbg (__FUNCTION__ " - already writing");
return (0);
}
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+#ifdef DEBUG
+ {
+ int i;
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+ for (i = 0; i < count; ++i) {
+ printk ("%.2x ", buf[i]);
+ }
+ printk ("\n");
+ }
+#endif
+
if (from_user) {
copy_from_user(port->write_urb->transfer_buffer, buf, count);
}
@@ -776,7 +790,7 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns
port->write_urb->transfer_buffer_length = count;
if (usb_submit_urb(port->write_urb))
- dbg("usb_submit_urb(write bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed");
return (count);
}
@@ -791,14 +805,14 @@ static int generic_write_room (struct usb_serial_port *port)
struct usb_serial *serial = port->serial;
int room;
- dbg("generic_write_room port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS)
room = 0;
else
room = port->bulk_out_size;
- dbg("generic_write_room returns %d", room);
+ dbg(__FUNCTION__ " returns %d", room);
return (room);
}
@@ -810,7 +824,7 @@ static int generic_chars_in_buffer (struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- dbg("generic_chars_in_buffer port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS) {
@@ -825,23 +839,25 @@ static int generic_chars_in_buffer (struct usb_serial_port *port)
static void generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = get_usb_serial (port, "generic_read_bulk_callback");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
+ dbg (__FUNCTION__ " - enter");
+
if (!serial) {
return;
}
if (urb->status) {
- dbg("nonzero read bulk status received: %d", urb->status);
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
return;
}
#ifdef DEBUG
if (urb->actual_length) {
- printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+ printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
for (i = 0; i < urb->actual_length; ++i) {
printk ("%.2x ", data[i]);
}
@@ -859,8 +875,10 @@ static void generic_read_bulk_callback (struct urb *urb)
/* Continue trying to always read */
if (usb_submit_urb(urb))
- dbg("failed resubmitting read urb");
+ dbg(__FUNCTION__ " - failed resubmitting read urb");
+ dbg (__FUNCTION__ " - exit");
+
return;
}
@@ -868,15 +886,17 @@ static void generic_read_bulk_callback (struct urb *urb)
static void generic_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = get_usb_serial (port, "generic_write_bulk_callback");
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct tty_struct *tty;
+ dbg (__FUNCTION__ " - enter");
+
if (!serial) {
return;
}
if (urb->status) {
- dbg("nonzero write bulk status received: %d", urb->status);
+ dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
return;
}
@@ -886,6 +906,8 @@ static void generic_write_bulk_callback (struct urb *urb)
wake_up_interruptible(&tty->write_wait);
+ dbg (__FUNCTION__ " - exit");
+
return;
}
@@ -1255,7 +1277,7 @@ int usb_serial_init(void)
serial_tty_driver.init_termios = tty_std_termios;
serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
if (tty_register_driver (&serial_tty_driver)) {
- err("failed to register tty driver");
+ err(__FUNCTION__ " - failed to register tty driver");
return -1;
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 5cfb4c42a..8be2dd351 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -11,6 +11,9 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (06/23/2000) gkh
+ * Cleaned up debugging statements in a quest to find UHCI timeout bug.
+ *
* (04/27/2000) Ryan VanderBijl
* Fixed memory leak in visor_close
*
@@ -80,10 +83,10 @@ struct usb_serial_device_type handspring_device = {
******************************************************************************/
static int visor_open (struct usb_serial_port *port, struct file *filp)
{
- dbg("visor_open port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (port->active) {
- dbg ("device already open");
+ dbg (__FUNCTION__ " - device already open");
return -EINVAL;
}
@@ -91,7 +94,7 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
/*Start reading from the device*/
if (usb_submit_urb(port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
return (0);
}
@@ -102,10 +105,10 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
struct usb_serial *serial = port->serial;
unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL);
- dbg("visor_close port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (!transfer_buffer) {
- err("visor_close: kmalloc(%d) failed.", 0x12);
+ 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,
@@ -122,7 +125,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
static void visor_throttle (struct usb_serial_port *port)
{
- dbg("visor_throttle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
usb_unlink_urb (port->read_urb);
@@ -132,10 +135,10 @@ static void visor_throttle (struct usb_serial_port *port)
static void visor_unthrottle (struct usb_serial_port *port)
{
- dbg("visor_unthrottle port %d", port->number);
+ dbg(__FUNCTION__ " - port %d", port->number);
if (usb_unlink_urb (port->read_urb))
- dbg("usb_submit_urb(read bulk) failed");
+ dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
return;
}
@@ -148,20 +151,20 @@ static int visor_startup (struct usb_serial *serial)
unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL);
if (!transfer_buffer) {
- err("visor_startup: kmalloc(%d) failed.", 256);
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 256);
return -ENOMEM;
}
- dbg("visor_startup");
+ dbg(__FUNCTION__);
- dbg("visor_setup: Set config to 1");
+ dbg(__FUNCTION__ " - Set config to 1");
usb_set_configuration (serial->dev, 1);
/* send a get connection info request */
response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
if (response < 0) {
- err("visor_startup: error getting connection information");
+ err(__FUNCTION__ " - error getting connection information");
} else {
struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
char *string;
@@ -195,7 +198,7 @@ static int visor_startup (struct usb_serial *serial)
response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
if (response < 0) {
- err("visor_startup: error getting bytes available request");
+ err(__FUNCTION__ " - error getting bytes available request");
}
kfree (transfer_buffer);
diff --git a/drivers/usb/usb-storage.c b/drivers/usb/usb-storage.c
index b9cead4fe..6d88d360b 100644
--- a/drivers/usb/usb-storage.c
+++ b/drivers/usb/usb-storage.c
@@ -1,11 +1,16 @@
/* Driver for USB Mass Storage compliant devices
*
- * Initial work by:
- * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ * $Id: usb-storage.c,v 1.11 2000/06/20 03:19:31 mdharm 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)
+ *
+ * Initial work by:
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
* devices. Clearly, the designers had SCSI and ATAPI commands in
@@ -22,6 +27,20 @@
*
* Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
* information about this driver.
+ *
+ * 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/module.h>
@@ -88,6 +107,7 @@ struct us_data {
char *protocol_name;
u8 subclass;
u8 protocol;
+ u8 max_lun;
/* information about the device -- only good if device is attached */
u8 ifnum; /* interface number */
@@ -536,8 +556,9 @@ static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
/* save the old command */
memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
+ /* set the command and the LUN */
srb->cmnd[0] = REQUEST_SENSE;
- srb->cmnd[1] = 0;
+ srb->cmnd[1] = old_cmnd[1] & 0xE0;
srb->cmnd[2] = 0;
srb->cmnd[3] = 0;
srb->cmnd[4] = 18;
@@ -791,7 +812,7 @@ static int Bulk_max_lun(struct us_data *us)
result, data);
/* if we have a successful request, return the result */
- if (!result)
+ if (result == 1)
return data;
/* if we get a STALL, clear the stall */
@@ -839,6 +860,9 @@ static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
usb_clear_halt(us->pusb_dev, pipe);
+ } else if (result) {
+ /* unknown error -- we've got a problem */
+ return USB_STOR_TRANSPORT_ERROR;
}
/* if the command transfered well, then we go to the data stage */
@@ -976,25 +1000,17 @@ static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
srb->cmnd[0] = srb->cmnd[0] | 0x20;
break;
} /* end switch on cmnd[0] */
+
+ /* convert MODE_SELECT data here */
+ if (old_cmnd == MODE_SELECT)
+ usb_stor_scsiSense6to10(srb);
/* send the command to the transport layer */
invoke_transport(srb, us);
- /* Fix the MODE_SENSE data if we translated the command
- */
- if (old_cmnd == MODE_SENSE) {
- unsigned char *dta = (unsigned char *)us->srb->request_buffer;
-
- /* FIXME: we need to compress the entire data structure here
- */
- dta[0] = dta[1]; /* data len */
- dta[1] = dta[2]; /* med type */
- dta[2] = dta[3]; /* dev-spec prm */
- dta[3] = dta[7]; /* block desc len */
- printk (KERN_DEBUG USB_STORAGE
- "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
- dta[0], dta[1], dta[2], dta[3]);
- }
+ /* Fix the MODE_SENSE data if we translated the command */
+ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
+ usb_stor_scsiSense10to6(srb);
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
@@ -1084,24 +1100,16 @@ static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
break;
} /* end switch on cmnd[0] */
+ /* convert MODE_SELECT data here */
+ if (old_cmnd == MODE_SELECT)
+ usb_stor_scsiSense6to10(srb);
+
/* send the command to the transport layer */
invoke_transport(srb, us);
- /* Fix the MODE_SENSE data here if we had to translate the command
- */
- if (old_cmnd == MODE_SENSE) {
- unsigned char *dta = (unsigned char *)us->srb->request_buffer;
-
- /* FIXME: we need to compress the entire data structure here
- */
- dta[0] = dta[1]; /* data len */
- dta[1] = dta[2]; /* med type */
- dta[2] = dta[3]; /* dev-spec prm */
- dta[3] = dta[7]; /* block desc len */
- printk (KERN_DEBUG USB_STORAGE
- "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
- dta[0], dta[1], dta[2], dta[3]);
- }
+ /* Fix the MODE_SENSE data if we translated the command */
+ if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD))
+ usb_stor_scsiSense10to6(srb);
/* Fix-up the return data from an INQUIRY command to show
* ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
@@ -1310,9 +1318,8 @@ static int us_release(struct Scsi_Host *psh)
down(&(us->notify));
/* free the data structure we were using */
- US_DEBUGP("-- freeing private host data structure\n");
+ US_DEBUGP("-- freeing URB\n");
kfree(us->current_urb);
- kfree(us);
(struct us_data*)psh->hostdata[0] = NULL;
/* we always have a successful release */
@@ -1536,11 +1543,10 @@ static int usb_stor_control_thread(void * __us)
switch (action) {
case US_ACT_COMMAND:
- /* reject if target != 0 or if single-lun device
- * and LUN != 0
+ /* reject if target != 0 or if LUN is higher than
+ * the maximum known LUN
*/
- if (us->srb->target ||
- ((us->flags & US_FL_SINGLE_LUN) && us->srb->lun)) {
+ if (us->srb->target || (us->srb->lun > us->max_lun)) {
US_DEBUGP("Bad device number (%d/%d)\n",
us->srb->target, us->srb->lun);
@@ -1623,32 +1629,37 @@ static int usb_stor_control_thread(void * __us)
/* This is the list of devices we recognize, along with their flag data */
static struct us_unusual_dev us_unusual_dev_list[] = {
- { 0x03f0, 0x0107, 0x0200,
- "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0},
- { 0x04e6, 0x0001, 0x0200,
- "Matshita LS-120", US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x04e6, 0x0002, 0x0100,
- "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x04e6, 0x0006, 0x0100,
- "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x057b, 0x0000, 0x0114,
- "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x059b, 0x0030, 0x0100,
- "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN},
- { 0x0693, 0x0002, 0x0100,
- "Hagiwara FlashGate SmartMedia", US_SC_SCSI, US_PR_BULK,
- US_FL_ALT_LENGTH},
- { 0x0781, 0x0001, 0x0200,
- "Sandisk ImageMate (SDDR-01)", US_SC_SCSI, US_PR_CB,
- US_FL_SINGLE_LUN | US_FL_START_STOP},
- { 0x0781, 0x0002, 0x0009,
- "Sandisk Imagemate (SDDR-31)", US_SC_SCSI, US_PR_BULK,
- US_FL_SINGLE_LUN | US_FL_IGNORE_SER},
- { 0x07af, 0x0005, 0x0100,
- "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x0000, 0x0000, 0x0,
- "", 0, 0, 0}
-};
+ { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus",
+ US_SC_8070, US_PR_CB, 0},
+ { 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",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
+ US_FL_MODE_XLATE | 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-01)",
+ US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP},
+ { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)",
+ US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER},
+ { 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 }};
/* Search our ususual device list, based on vendor/product combinations
* to see if we can support this device. Returns a pointer to a structure
@@ -1667,7 +1678,8 @@ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
while ((ptr->idVendor != 0x0000) &&
!((ptr->idVendor == idVendor) &&
(ptr->idProduct == idProduct) &&
- (ptr->bcdDevice == bcdDevice)))
+ (ptr->bcdDeviceMin <= bcdDevice) &&
+ (ptr->bcdDeviceMax >= bcdDevice)))
ptr++;
/* if the search ended because we hit the end record, we failed */
@@ -1968,20 +1980,21 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->transport_name = "Control/Bulk";
ss->transport = CB_transport;
ss->transport_reset = CB_reset;
+ ss->max_lun = 7;
break;
case US_PR_CBI:
ss->transport_name = "Control/Bulk/Interrupt";
ss->transport = CBI_transport;
ss->transport_reset = CB_reset;
+ ss->max_lun = 7;
break;
case US_PR_BULK:
ss->transport_name = "Bulk";
ss->transport = Bulk_transport;
ss->transport_reset = Bulk_reset;
- /* FIXME: for testing purposes only */
- Bulk_max_lun(ss);
+ ss->max_lun = Bulk_max_lun(ss);
break;
default:
@@ -1994,6 +2007,10 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
}
US_DEBUGP("Transport: %s\n", ss->transport_name);
+ /* fix for single-lun devices */
+ if (ss->flags & US_FL_SINGLE_LUN)
+ ss->max_lun = 0;
+
switch (ss->subclass) {
case US_SC_RBC:
ss->protocol_name = "Reduced Block Commands (RBC)";
@@ -2134,6 +2151,576 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
up(&(ss->dev_semaphore));
}
+/**************************************************************
+ **************************************************************/
+
+#define USB_STOR_SCSI_SENSE_HDRSZ 4
+#define USB_STOR_SCSI_SENSE_10_HDRSZ 8
+
+struct usb_stor_scsi_sense_hdr
+{
+ __u8* dataLength;
+ __u8* mediumType;
+ __u8* devSpecParms;
+ __u8* blkDescLength;
+};
+
+typedef struct usb_stor_scsi_sense_hdr Usb_Stor_Scsi_Sense_Hdr;
+
+union usb_stor_scsi_sense_hdr_u
+{
+ Usb_Stor_Scsi_Sense_Hdr hdr;
+ __u8* array[USB_STOR_SCSI_SENSE_HDRSZ];
+};
+
+typedef union usb_stor_scsi_sense_hdr_u Usb_Stor_Scsi_Sense_Hdr_u;
+
+struct usb_stor_scsi_sense_hdr_10
+{
+ __u8* dataLengthMSB;
+ __u8* dataLengthLSB;
+ __u8* mediumType;
+ __u8* devSpecParms;
+ __u8* reserved1;
+ __u8* reserved2;
+ __u8* blkDescLengthMSB;
+ __u8* blkDescLengthLSB;
+};
+
+typedef struct usb_stor_scsi_sense_hdr_10 Usb_Stor_Scsi_Sense_Hdr_10;
+
+union usb_stor_scsi_sense_hdr_10_u
+{
+ Usb_Stor_Scsi_Sense_Hdr_10 hdr;
+ __u8* array[USB_STOR_SCSI_SENSE_10_HDRSZ];
+};
+
+typedef union usb_stor_scsi_sense_hdr_10_u Usb_Stor_Scsi_Sense_Hdr_10_u;
+
+void usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* , Usb_Stor_Scsi_Sense_Hdr_u*,
+ Usb_Stor_Scsi_Sense_Hdr_10_u*, int* );
+void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd );
+
+int
+usb_stor_scsiSense10to6( Scsi_Cmnd* the10 )
+{
+ __u8 *buffer=0;
+ int outputBufferSize = 0;
+ int length=0;
+ struct scatterlist *sg = 0;
+ int i=0, j=0, element=0;
+ Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
+ Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
+ int sb=0,si=0,db=0,di=0;
+ int sgLength=0;
+
+#if 0
+ /* Make sure we get a MODE_SENSE_10 command */
+ if ( the10->cmnd[0] != MODE_SENSE_10 )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Scsi_Cmnd was not a MODE_SENSE_10.\n" );
+ return -1;
+ }
+
+ /* Now start to format the output */
+ the10->cmnd[0] = MODE_SENSE;
+#endif
+ US_DEBUGP("-- converting 10 byte sense data to 6 byte\n");
+ the10->cmnd[0] = the10->cmnd[0] & 0xBF;
+
+ /* Determine buffer locations */
+ usb_stor_scsiSenseParseBuffer( the10, &the6Locations, &the10Locations,
+ &length );
+
+ /* Work out minimum buffer to output */
+ outputBufferSize = *the10Locations.hdr.dataLengthLSB;
+ outputBufferSize += USB_STOR_SCSI_SENSE_HDRSZ;
+
+ /* Check to see if we need to truncate the output */
+ if ( outputBufferSize > length )
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Had to truncate MODE_SENSE_10 buffer into MODE_SENSE.\n" );
+ printk( KERN_WARNING USB_STORAGE
+ "outputBufferSize is %d and length is %d.\n",
+ outputBufferSize, length );
+ }
+ outputBufferSize = length;
+
+ /* Data length */
+ if ( *the10Locations.hdr.dataLengthMSB != 0 ) /* MSB must be zero */
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Command will be truncated to fit in SENSE6 buffer.\n" );
+ *the6Locations.hdr.dataLength = 0xff;
+ }
+ else
+ {
+ *the6Locations.hdr.dataLength = *the10Locations.hdr.dataLengthLSB;
+ }
+
+ /* Medium type and DevSpecific parms */
+ *the6Locations.hdr.mediumType = *the10Locations.hdr.mediumType;
+ *the6Locations.hdr.devSpecParms = *the10Locations.hdr.devSpecParms;
+
+ /* Block descriptor length */
+ if ( *the10Locations.hdr.blkDescLengthMSB != 0 ) /* MSB must be zero */
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Command will be truncated to fit in SENSE6 buffer.\n" );
+ *the6Locations.hdr.blkDescLength = 0xff;
+ }
+ else
+ {
+ *the6Locations.hdr.blkDescLength = *the10Locations.hdr.blkDescLengthLSB;
+ }
+
+ if ( the10->use_sg == 0 )
+ {
+ buffer = the10->request_buffer;
+ /* Copy the rest of the data */
+ memmove( &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
+ &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ outputBufferSize - USB_STOR_SCSI_SENSE_HDRSZ );
+ /* initialise last bytes left in buffer due to smaller header */
+ memset( &(buffer[outputBufferSize
+ -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ)]),
+ 0,
+ USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
+ }
+ else
+ {
+ sg = (struct scatterlist *) the10->request_buffer;
+ /* scan through this scatterlist and figure out starting positions */
+ for ( i=0; i < the10->use_sg; i++)
+ {
+ sgLength = sg[i].length;
+ for ( j=0; j<sgLength; j++ )
+ {
+ /* get to end of header */
+ if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ db=i;
+ di=j;
+ }
+ if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ sb=i;
+ si=j;
+ /* we've found both sets now, exit loops */
+ j=sgLength;
+ i=the10->use_sg;
+ }
+ element++;
+ }
+ }
+
+ /* Now we know where to start the copy from */
+ element = USB_STOR_SCSI_SENSE_HDRSZ;
+ while ( element < outputBufferSize
+ -(USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
+ {
+ /* check limits */
+ if ( sb >= the10->use_sg ||
+ si >= sg[sb].length ||
+ db >= the10->use_sg ||
+ di >= sg[db].length )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ /* copy one byte */
+ sg[db].address[di] = sg[sb].address[si];
+
+ /* get next destination */
+ if ( sg[db].length-1 == di )
+ {
+ db++;
+ di=0;
+ }
+ else
+ {
+ di++;
+ }
+
+ /* get next source */
+ if ( sg[sb].length-1 == si )
+ {
+ sb++;
+ si=0;
+ }
+ else
+ {
+ si++;
+ }
+
+ element++;
+ }
+ /* zero the remaining bytes */
+ while ( element < outputBufferSize )
+ {
+ /* check limits */
+ if ( db >= the10->use_sg ||
+ di >= sg[db].length )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ sg[db].address[di] = 0;
+
+ /* get next destination */
+ if ( sg[db].length-1 == di )
+ {
+ db++;
+ di=0;
+ }
+ else
+ {
+ di++;
+ }
+ element++;
+ }
+ }
+
+ /* All done any everything was fine */
+ return 0;
+}
+
+int
+usb_stor_scsiSense6to10( Scsi_Cmnd* the6 )
+{
+ /* will be used to store part of buffer */
+ __u8 tempBuffer[USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ],
+ *buffer=0;
+ int outputBufferSize = 0;
+ int length=0;
+ struct scatterlist *sg = 0;
+ int i=0, j=0, element=0;
+ Usb_Stor_Scsi_Sense_Hdr_u the6Locations;
+ Usb_Stor_Scsi_Sense_Hdr_10_u the10Locations;
+ int sb=0,si=0,db=0,di=0;
+ int lsb=0,lsi=0,ldb=0,ldi=0;
+
+#if 0
+ /* Make sure we get a MODE_SENSE command */
+ if ( the6->cmnd[0] != MODE_SENSE )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Scsi_Cmnd was not MODE_SENSE.\n" );
+ return -1;
+ }
+
+ /* Now start to format the output */
+ the6->cmnd[0] = MODE_SENSE_10;
+#endif
+ US_DEBUGP("-- converting 6 byte sense data to 10 byte\n");
+ the6->cmnd[0] = the6->cmnd[0] | 0x40;
+
+ /* Determine buffer locations */
+ usb_stor_scsiSenseParseBuffer( the6, &the6Locations, &the10Locations,
+ &length );
+
+ /* Work out minimum buffer to output */
+ outputBufferSize = *the6Locations.hdr.dataLength;
+ outputBufferSize += USB_STOR_SCSI_SENSE_10_HDRSZ;
+
+ /* Check to see if we need to trucate the output */
+ if ( outputBufferSize > length )
+ {
+ printk( KERN_WARNING USB_STORAGE
+ "Had to truncate MODE_SENSE into MODE_SENSE_10 buffer.\n" );
+ printk( KERN_WARNING USB_STORAGE
+ "outputBufferSize is %d and length is %d.\n",
+ outputBufferSize, length );
+ }
+ outputBufferSize = length;
+
+ /* Block descriptor length - save these before overwriting */
+ tempBuffer[2] = *the10Locations.hdr.blkDescLengthMSB;
+ tempBuffer[3] = *the10Locations.hdr.blkDescLengthLSB;
+ *the10Locations.hdr.blkDescLengthLSB = *the6Locations.hdr.blkDescLength;
+ *the10Locations.hdr.blkDescLengthMSB = 0;
+
+ /* reserved - save these before overwriting */
+ tempBuffer[0] = *the10Locations.hdr.reserved1;
+ tempBuffer[1] = *the10Locations.hdr.reserved2;
+ *the10Locations.hdr.reserved1 = *the10Locations.hdr.reserved2 = 0;
+
+ /* Medium type and DevSpecific parms */
+ *the10Locations.hdr.devSpecParms = *the6Locations.hdr.devSpecParms;
+ *the10Locations.hdr.mediumType = *the6Locations.hdr.mediumType;
+
+ /* Data length */
+ *the10Locations.hdr.dataLengthLSB = *the6Locations.hdr.dataLength;
+ *the10Locations.hdr.dataLengthMSB = 0;
+
+ if ( !the6->use_sg )
+ {
+ buffer = the6->request_buffer;
+ /* Copy the rest of the data */
+ memmove( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ &(buffer[USB_STOR_SCSI_SENSE_HDRSZ]),
+ outputBufferSize-USB_STOR_SCSI_SENSE_10_HDRSZ );
+ /* Put the first four bytes (after header) in place */
+ memcpy( &(buffer[USB_STOR_SCSI_SENSE_10_HDRSZ]),
+ tempBuffer,
+ USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ );
+ }
+ else
+ {
+ sg = (struct scatterlist *) the6->request_buffer;
+ /* scan through this scatterlist and figure out ending positions */
+ for ( i=0; i < the6->use_sg; i++)
+ {
+ for ( j=0; j<sg[i].length; j++ )
+ {
+ /* get to end of header */
+ if ( element == USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ ldb=i;
+ ldi=j;
+ }
+ if ( element == USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ lsb=i;
+ lsi=j;
+ /* we've found both sets now, exit loops */
+ j=sg[i].length;
+ i=the6->use_sg;
+ break;
+ }
+ element++;
+ }
+ }
+ /* scan through this scatterlist and figure out starting positions */
+ element = length-1;
+ /* destination is the last element */
+ db=the6->use_sg-1;
+ di=sg[db].length-1;
+ for ( i=the6->use_sg-1; i >= 0; i--)
+ {
+ for ( j=sg[i].length-1; j>=0; j-- )
+ {
+ /* get to end of header and find source for copy */
+ if ( element == length - 1
+ - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ) )
+ {
+ sb=i;
+ si=j;
+ /* we've found both sets now, exit loops */
+ j=-1;
+ i=-1;
+ }
+ element--;
+ }
+ }
+ /* Now we know where to start the copy from */
+ element = length-1
+ - (USB_STOR_SCSI_SENSE_10_HDRSZ-USB_STOR_SCSI_SENSE_HDRSZ);
+ while ( element >= USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* check limits */
+ if ( ( sb <= lsb && si < lsi ) ||
+ ( db <= ldb && di < ldi ) )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ /* copy one byte */
+ sg[db].address[di] = sg[sb].address[si];
+
+ /* get next destination */
+ if ( di == 0 )
+ {
+ db--;
+ di=sg[db].length-1;
+ }
+ else
+ {
+ di--;
+ }
+
+ /* get next source */
+ if ( si == 0 )
+ {
+ sb--;
+ si=sg[sb].length-1;
+ }
+ else
+ {
+ si--;
+ }
+
+ element--;
+ }
+ /* copy the remaining four bytes */
+ while ( element >= USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ /* check limits */
+ if ( db <= ldb && di < ldi )
+ {
+ printk( KERN_ERR USB_STORAGE
+ "Buffer overrun averted, this shouldn't happen!\n" );
+ break;
+ }
+
+ sg[db].address[di] = tempBuffer[element-USB_STOR_SCSI_SENSE_HDRSZ];
+
+ /* get next destination */
+ if ( di == 0 )
+ {
+ db--;
+ di=sg[db].length-1;
+ }
+ else
+ {
+ di--;
+ }
+ element--;
+ }
+ }
+
+ /* All done and everything was fine */
+ return 0;
+}
+
+void
+usb_stor_scsiSenseParseBuffer( Scsi_Cmnd* srb, Usb_Stor_Scsi_Sense_Hdr_u* the6,
+ Usb_Stor_Scsi_Sense_Hdr_10_u* the10,
+ int* length_p )
+
+{
+ int i = 0, j=0, element=0;
+ struct scatterlist *sg = 0;
+ int length = 0;
+ __u8* buffer=0;
+
+ /* are we scatter-gathering? */
+ if ( srb->use_sg != 0 )
+ {
+ /* loop over all the scatter gather structures and
+ * get pointer to the data members in the headers
+ * (also work out the length while we're here)
+ */
+ sg = (struct scatterlist *) srb->request_buffer;
+ for (i = 0; i < srb->use_sg; i++)
+ {
+ length += sg[i].length;
+ /* We only do the inner loop for the headers */
+ if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* scan through this scatterlist */
+ for ( j=0; j<sg[i].length; j++ )
+ {
+ if ( element < USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ /* fill in the pointers for both header types */
+ the6->array[element] = &(sg[i].address[j]);
+ the10->array[element] = &(sg[i].address[j]);
+ }
+ else if ( element < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ {
+ /* only the longer headers still cares now */
+ the10->array[element] = &(sg[i].address[j]);
+ }
+ /* increase element counter */
+ element++;
+ }
+ }
+ }
+ }
+ else
+ {
+ length = srb->request_bufflen;
+ buffer = srb->request_buffer;
+ if ( length < USB_STOR_SCSI_SENSE_10_HDRSZ )
+ printk( KERN_ERR USB_STORAGE
+ "Buffer length smaller than header!!" );
+ for( i=0; i<USB_STOR_SCSI_SENSE_10_HDRSZ; i++ )
+ {
+ if ( i < USB_STOR_SCSI_SENSE_HDRSZ )
+ {
+ the6->array[i] = &(buffer[i]);
+ the10->array[i] = &(buffer[i]);
+ }
+ else
+ {
+ the10->array[i] = &(buffer[i]);
+ }
+ }
+ }
+
+ /* Set value of length passed in */
+ *length_p = length;
+}
+
+void
+usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd )
+{
+ int i=0, bufferSize = cmd->request_bufflen;
+ __u8* buffer = cmd->request_buffer;
+ struct scatterlist* sg = (struct scatterlist*)cmd->request_buffer;
+
+ printk( KERN_ERR "Dumping information about %p.\n", cmd );
+ printk( KERN_ERR "cmd->cmnd[0] value is %d.\n", cmd->cmnd[0] );
+ printk( KERN_ERR "(MODE_SENSE is %d and MODE_SENSE_10 is %d)\n",
+ MODE_SENSE, MODE_SENSE_10 );
+
+ printk( KERN_ERR "buffer is %p with length %d.\n", buffer, bufferSize );
+ for ( i=0; i<bufferSize; i+=16 )
+ {
+ printk( KERN_ERR "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+ buffer[i],
+ buffer[i+1],
+ buffer[i+2],
+ buffer[i+3],
+ buffer[i+4],
+ buffer[i+5],
+ buffer[i+6],
+ buffer[i+7],
+ buffer[i+8],
+ buffer[i+9],
+ buffer[i+10],
+ buffer[i+11],
+ buffer[i+12],
+ buffer[i+13],
+ buffer[i+14],
+ buffer[i+15] );
+ }
+
+ printk( KERN_ERR "Buffer has %d scatterlists.\n", cmd->use_sg );
+ for ( i=0; i<cmd->use_sg; i++ )
+ {
+ printk( KERN_ERR "Length of scatterlist %d is %d.\n", i, sg[i].length );
+ printk( KERN_ERR "%2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+ sg[i].address[0],
+ sg[i].address[1],
+ sg[i].address[2],
+ sg[i].address[3],
+ sg[i].address[4],
+ sg[i].address[5],
+ sg[i].address[6],
+ sg[i].address[7],
+ sg[i].address[8],
+ sg[i].address[9],
+ sg[i].address[10],
+ sg[i].address[11],
+ sg[i].address[12],
+ sg[i].address[13],
+ sg[i].address[14],
+ sg[i].address[15] );
+ }
+}
+
+/**************************************************************
+ **************************************************************/
/***********************************************************************
* Initialization and registration
@@ -2183,6 +2770,11 @@ void __exit usb_stor_exit(void)
US_DEBUGP("-- calling scsi_unregister_module()\n");
scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+ /* Now that scsi_unregister_module is done with the host
+ * template, we can free the us_data structure (the host
+ * template is inline in this structure). */
+ kfree (us_list);
+
/* advance the list pointer */
us_list = next;
}
diff --git a/drivers/usb/usb-storage.h b/drivers/usb/usb-storage.h
index 6e54b059b..82475f094 100644
--- a/drivers/usb/usb-storage.h
+++ b/drivers/usb/usb-storage.h
@@ -139,7 +139,8 @@ struct us_unusual_dev {
/* we search the list based on these parameters */
__u16 idVendor;
__u16 idProduct;
- __u16 bcdDevice;
+ __u16 bcdDeviceMin;
+ __u16 bcdDeviceMax;
/* the list specifies these parameters */
const char* name;
diff --git a/drivers/usb/wmforce.c b/drivers/usb/wmforce.c
deleted file mode 100644
index dff963b74..000000000
--- a/drivers/usb/wmforce.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * $Id: wmforce.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $
- *
- * Copyright (c) 2000 Vojtech Pavlik
- *
- * USB Logitech WingMan Force joystick support
- *
- * 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>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-
-#define USB_VENDOR_ID_LOGITECH 0x046d
-#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281
-
-struct wmforce {
- signed char data[8];
- struct input_dev dev;
- struct urb irq;
- int open;
-};
-
-static struct {
- __s32 x;
- __s32 y;
-} wmforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-static char *wmforce_name = "Logitech WingMan Force";
-
-static void wmforce_irq(struct urb *urb)
-{
- struct wmforce *wmforce = urb->context;
- unsigned char *data = wmforce->data;
- struct input_dev *dev = &wmforce->dev;
-
- if (urb->status) return;
-
- if (data[0] != 1) {
- if (data[0] != 2)
- warn("received unknown report #%d", data[0]);
- return;
- }
-
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[2] << 8) | data[1]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[4] << 8) | data[3]));
- input_report_abs(dev, ABS_THROTTLE, data[5]);
- input_report_abs(dev, ABS_HAT0X, wmforce_hat_to_axis[data[7] >> 4].x);
- input_report_abs(dev, ABS_HAT0Y, wmforce_hat_to_axis[data[7] >> 4].y);
-
- input_report_key(dev, BTN_TRIGGER, data[6] & 0x01);
- input_report_key(dev, BTN_TOP, data[6] & 0x02);
- input_report_key(dev, BTN_THUMB, data[6] & 0x04);
- input_report_key(dev, BTN_TOP2, data[6] & 0x08);
- input_report_key(dev, BTN_BASE, data[6] & 0x10);
- input_report_key(dev, BTN_BASE2, data[6] & 0x20);
- input_report_key(dev, BTN_BASE3, data[6] & 0x40);
- input_report_key(dev, BTN_BASE4, data[6] & 0x80);
- input_report_key(dev, BTN_BASE5, data[7] & 0x01);
-}
-
-static int wmforce_open(struct input_dev *dev)
-{
- struct wmforce *wmforce = dev->private;
-
- if (wmforce->open++)
- return 0;
-
- if (usb_submit_urb(&wmforce->irq))
- return -EIO;
-
- return 0;
-}
-
-static void wmforce_close(struct input_dev *dev)
-{
- struct wmforce *wmforce = dev->private;
-
- if (!--wmforce->open)
- usb_unlink_urb(&wmforce->irq);
-}
-
-static void *wmforce_probe(struct usb_device *dev, unsigned int ifnum)
-{
- struct usb_endpoint_descriptor *endpoint;
- struct wmforce *wmforce;
- int i;
-
- 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 (!(wmforce = kmalloc(sizeof(struct wmforce), GFP_KERNEL))) return NULL;
- memset(wmforce, 0, sizeof(struct wmforce));
-
- wmforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- wmforce->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);
- wmforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
-
- for (i = ABS_X; i <= ABS_Y; i++) {
- wmforce->dev.absmax[i] = 1920;
- wmforce->dev.absmin[i] = -1920;
- wmforce->dev.absflat[i] = 128;
- }
-
- wmforce->dev.absmax[ABS_THROTTLE] = 255;
- wmforce->dev.absmin[ABS_THROTTLE] = 0;
-
- for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) {
- wmforce->dev.absmax[i] = 1;
- wmforce->dev.absmin[i] = -1;
- }
-
- wmforce->dev.private = wmforce;
- wmforce->dev.open = wmforce_open;
- wmforce->dev.close = wmforce_close;
-
- wmforce->dev.name = wmforce_name;
- wmforce->dev.idbus = BUS_USB;
- wmforce->dev.idvendor = dev->descriptor.idVendor;
- wmforce->dev.idproduct = dev->descriptor.idProduct;
- wmforce->dev.idversion = dev->descriptor.bcdDevice;
-
- FILL_INT_URB(&wmforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wmforce->data, 8, wmforce_irq, wmforce, endpoint->bInterval);
-
- input_register_device(&wmforce->dev);
-
- printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
- wmforce->dev.number, wmforce_name, dev->bus->busnum, dev->devnum, ifnum);
-
- return wmforce;
-}
-
-static void wmforce_disconnect(struct usb_device *dev, void *ptr)
-{
- struct wmforce *wmforce = ptr;
- usb_unlink_urb(&wmforce->irq);
- input_unregister_device(&wmforce->dev);
- kfree(wmforce);
-}
-
-static struct usb_driver wmforce_driver = {
- name: "wmforce",
- probe: wmforce_probe,
- disconnect: wmforce_disconnect,
-};
-
-static int __init wmforce_init(void)
-{
- usb_register(&wmforce_driver);
- return 0;
-}
-
-static void __exit wmforce_exit(void)
-{
- usb_deregister(&wmforce_driver);
-}
-
-module_init(wmforce_init);
-module_exit(wmforce_exit);