diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-25 01:20:01 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-25 01:20:01 +0000 |
commit | 3797ba0b62debb71af4606910acacc9896a9ae3b (patch) | |
tree | 414eea76253c7871bfdf3bd9d1817771eb40917c /drivers/usb | |
parent | 2b6c0c580795a4404f72d2a794214dd9e080709d (diff) |
Merge with Linux 2.4.0-test2.
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/Config.in | 5 | ||||
-rw-r--r-- | drivers/usb/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/devio.c | 2 | ||||
-rw-r--r-- | drivers/usb/evdev.c | 36 | ||||
-rw-r--r-- | drivers/usb/iforce.c | 335 | ||||
-rw-r--r-- | drivers/usb/input.c | 4 | ||||
-rw-r--r-- | drivers/usb/joydev.c | 54 | ||||
-rw-r--r-- | drivers/usb/mousedev.c | 55 | ||||
-rw-r--r-- | drivers/usb/pegasus.c | 269 | ||||
-rw-r--r-- | drivers/usb/serial/usbserial.c | 128 | ||||
-rw-r--r-- | drivers/usb/serial/visor.c | 29 | ||||
-rw-r--r-- | drivers/usb/usb-storage.c | 730 | ||||
-rw-r--r-- | drivers/usb/usb-storage.h | 3 | ||||
-rw-r--r-- | drivers/usb/wmforce.c | 190 |
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); |