diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2002-10-13 02:00:40 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2002-10-13 02:00:40 -0700 |
| commit | 31c96625109bb9deb166cfd3fbe08d0a92ad98fa (patch) | |
| tree | e92290f60c8e083ec83b9968b54f2a4762c66c47 | |
| parent | e0970dce2a44f75f560b1a9a48a33c7828e191cc (diff) | |
| parent | 321d6a826727fac90daa8cf21c4c9d973400750d (diff) | |
Merge kroah.com:/home/linux/linux/BK/bleeding-2.5
into kroah.com:/home/linux/linux/BK/gregkh-2.5
42 files changed, 2363 insertions, 1847 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 23c9f7b02d97..a9b191413d74 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1592,6 +1592,11 @@ P: Julien Blache M: jb@technologeek.org S: Maintained +TI PARALLEL LINK CABLE DRIVER +P: Romain Lievin +M: roms@lpg.ticalc.org +S: Maintained + TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER P: Stephane Dalton M: sdalton@videotron.ca diff --git a/drivers/char/Config.help b/drivers/char/Config.help index acc31b2a2416..b03cd9da93b0 100644 --- a/drivers/char/Config.help +++ b/drivers/char/Config.help @@ -1033,3 +1033,24 @@ CONFIG_SCx200_GPIO If compiled as a module, it will be called scx200_gpio.o. +Texas Instruments parallel link cable support +CONFIG_TIPAR + If you own a Texas Instruments graphing calculator and use a + parallel link cable, then you might be interested in this driver. + + If you enable this driver, you will be able to communicate with + your calculator through a set of device nodes under /dev. The + main advantage of this driver is that you don't have to be root + to use this precise link cable (depending on the permissions on + the device nodes, though). + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tipar.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know what a parallel link cable is or what a Texas + Instruments graphing calculator is, then you probably don't need this + driver. + + If unsure, say N.
\ No newline at end of file diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 680bafe4ca4a..84eec6579e76 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -80,6 +80,7 @@ if [ "$CONFIG_PARPORT" != "n" ]; then bool ' Support for console on line printer' CONFIG_LP_CONSOLE fi dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT + dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT fi if [ "$CONFIG_PPC_PSERIES" = "y" ]; then bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 80a28ced908c..d0be4dd0e8cb 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_PRINTER) += lp.o +obj-$(CONFIG_TIPAR) += tipar.o obj-$(CONFIG_BUSMOUSE) += busmouse.o obj-$(CONFIG_DTLK) += dtlk.o diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c new file mode 100644 index 000000000000..16adba7c4148 --- /dev/null +++ b/drivers/char/tipar.c @@ -0,0 +1,541 @@ +/* Hey EMACS -*- linux-c -*- + * + * tipar - low level driver for handling a parallel link cable designed + * for Texas Instruments graphing calculators (http://lpg.ticalc.org). + * A part of the TiLP project. + * + * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org> + * under the terms of the GNU General Public License. + * + * Various fixes & clean-up from the Linux Kernel Mailing List + * (Alan Cox, Richard B. Johnson, Christoph Hellwig). + */ + +/* This driver should, in theory, work with any parallel port that has an + * appropriate low-level driver; all I/O is done through the parport + * abstraction layer. + * + * If this driver is built into the kernel, you can configure it using the + * kernel command-line. For example: + * + * tipar=timeout,delay (set timeout and delay) + * + * If the driver is loaded as a module, similar functionality is available + * using module parameters. The equivalent of the above commands would be: + * + * # insmod tipar timeout=15 delay=10 + */ + +/* COMPATIBILITY WITH OLD KERNELS + * + * Usually, parallel cables were bound to ports at + * particular I/O addresses, as follows: + * + * tipar0 0x378 + * tipar1 0x278 + * tipar2 0x3bc + * + * + * This driver, by default, binds tipar devices according to parport and + * the minor number. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/fcntl.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/bitops.h> +#include <linux/devfs_fs_kernel.h> /* DevFs support */ +#include <linux/parport.h> /* Our code depend on parport */ + +/* + * TI definitions + */ +#include <linux/ticable.h> + +/* + * Version Information + */ +#define DRIVER_VERSION "1.17" +#define DRIVER_AUTHOR "Romain Lievin <roms@lpg.ticalc.org>" +#define DRIVER_DESC "Device driver for TI/PC parallel link cables" +#define DRIVER_LICENSE "GPL" + +#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) +#if LINUX_VERSION_CODE < VERSION(2,5,0) +# define minor(x) MINOR(x) +# define need_resched() (current->need_resched) +#endif + +/* ----- global variables --------------------------------------------- */ + +struct tipar_struct { + struct pardevice *dev; /* Parport device entry */ +}; + +#define PP_NO 3 +static struct tipar_struct table[PP_NO]; + +static int delay = IO_DELAY; /* inter-bit delay in microseconds */ +static int timeout = TIMAXTIME; /* timeout in tenth of seconds */ + +static devfs_handle_t devfs_handle; +static unsigned int tp_count; /* tipar count */ +static unsigned long opened; /* opened devices */ + +/* --- macros for parport access -------------------------------------- */ + +#define r_dtr(x) (parport_read_data(table[(x)].dev->port)) +#define r_str(x) (parport_read_status(table[(x)].dev->port)) +#define w_ctr(x,y) (parport_write_control(table[(x)].dev->port, (y))) +#define w_dtr(x,y) (parport_write_data(table[(x)].dev->port, (y))) + +/* --- setting states on the D-bus with the right timing: ------------- */ + +static inline void +outbyte(int value, int minor) +{ + w_dtr(minor, value); +} + +static inline int +inbyte(int minor) +{ + return (r_str(minor)); +} + +static inline void +init_ti_parallel(int minor) +{ + outbyte(3, minor); +} + +/* ----- global defines ----------------------------------------------- */ + +#define START(x) { x=jiffies+HZ/(timeout/10); } +#define WAIT(x) { \ + if (time_before((x), jiffies)) return -1; \ + if (need_resched()) schedule(); } + +/* ----- D-bus bit-banging functions ---------------------------------- */ + +/* D-bus protocol (45kbit/s max): + 1 0 0 + _______ ______|______ __________|________ __________ +Red : ________ | ____ | ____ + _ ____________|________ ______|__________ _____ +White: ________ | ______ | _______ +*/ + +/* Try to transmit a byte on the specified port (-1 if error). */ +static int +put_ti_parallel(int minor, unsigned char data) +{ + int bit; + unsigned long max; + + for (bit = 0; bit < 8; bit++) { + if (data & 1) { + outbyte(2, minor); + START(max); + do { + WAIT(max); + } while (inbyte(minor) & 0x10); + + outbyte(3, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x10)); + } else { + outbyte(1, minor); + START(max); + do { + WAIT(max); + } while (inbyte(minor) & 0x20); + + outbyte(3, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x20)); + } + + data >>= 1; + udelay(delay); + + if (need_resched()) + schedule(); + } + + return 0; +} + +/* Receive a byte on the specified port or -1 if error. */ +static int +get_ti_parallel(int minor) +{ + int bit; + unsigned char v, data = 0; + unsigned long max; + + for (bit = 0; bit < 8; bit++) { + START(max); + do { + WAIT(max); + } while ((v = inbyte(minor) & 0x30) == 0x30); + + if (v == 0x10) { + data = (data >> 1) | 0x80; + outbyte(1, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x20)); + outbyte(3, minor); + } else { + data = data >> 1; + outbyte(2, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x10)); + outbyte(3, minor); + } + + udelay(delay); + if (need_resched()) + schedule(); + } + + return (int) data; +} + +/* Try to detect a parallel link cable on the specified port */ +static int +probe_ti_parallel(int minor) +{ + int i; + int seq[] = { 0x00, 0x20, 0x10, 0x30 }; + + for (i = 3; i >= 0; i--) { + outbyte(3, minor); + outbyte(i, minor); + udelay(delay); + /*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */ + if ((inbyte(minor) & 0x30) != seq[i]) { + outbyte(3, minor); + return -1; + } + } + + outbyte(3, minor); + return 0; +} + +/* ----- kernel module functions--------------------------------------- */ + +static int +tipar_open(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR; + + if (minor > tp_count - 1) + return -ENXIO; + + if (test_and_set_bit(minor, &opened)) + return -EBUSY; + + parport_claim_or_block(table[minor].dev); + init_ti_parallel(minor); + parport_release(table[minor].dev); + + return 0; +} + +static int +tipar_close(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR; + + if (minor > tp_count - 1) + return -ENXIO; + + clear_bit(minor, &opened); + + return 0; +} + +static ssize_t +tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + unsigned int minor = + minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR; + ssize_t n; + + printk("_write\n"); + parport_claim_or_block(table[minor].dev); + + for (n = 0; n < count; n++) { + unsigned char b; + + if (get_user(b, buf + n)) { + n = -EFAULT; + goto out; + } + + if (put_ti_parallel(minor, b) == -1) { + init_ti_parallel(minor); + n = -ETIMEDOUT; + goto out; + } + } + out: + parport_release(table[minor].dev); + return n; +} + +static ssize_t +tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + int b = 0; + unsigned int minor = + minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR; + ssize_t retval = 0; + ssize_t n = 0; + + if (count == 0) + return 0; + + if (ppos != &file->f_pos) + return -ESPIPE; + + printk("_read\n"); + parport_claim_or_block(table[minor].dev); + + while (n < count) { + b = get_ti_parallel(minor); + if (b == -1) { + init_ti_parallel(minor); + retval = -ETIMEDOUT; + goto out; + } else { + if (put_user(b, ((unsigned char *) buf) + n)) { + retval = -EFAULT; + break; + } else + retval = ++n; + } + + /* Non-blocking mode : try again ! */ + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + /* Signal pending, try again ! */ + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + if (need_resched()) + schedule(); + } + + out: + parport_release(table[minor].dev); + return retval; +} + +static int +tipar_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + switch (cmd) { + case IOCTL_TIPAR_DELAY: + delay = (int)arg; //get_user(delay, &arg); + break; + case IOCTL_TIPAR_TIMEOUT: + timeout = (int)arg; //get_user(timeout, &arg); + break; + default: + retval = -ENOTTY; + break; + } + + return retval; +} + +/* ----- kernel module registering ------------------------------------ */ + +static struct file_operations tipar_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + read:tipar_read, + write:tipar_write, + ioctl:tipar_ioctl, + open:tipar_open, + release:tipar_close, +}; + +/* --- initialisation code ------------------------------------- */ + +#ifndef MODULE +/* You must set these - there is no sane way to probe for this cable. + * You can use 'tipar=timeout,delay' to set these now. */ +static int __init +tipar_setup(char *str) +{ + int ints[2]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) { + timeout = ints[1]; + if (ints[0] > 1) { + delay = ints[2]; + } + } + + return 1; +} +#endif + +/* + * Register our module into parport. + * Pass also 2 callbacks functions to parport: a pre-emptive function and an + * interrupt handler function (unused). + * Display a message such "tipar0: using parport0 (polling)". + */ +static int +tipar_register(int nr, struct parport *port) +{ + char name[8]; + + /* Register our module into parport */ + table[nr].dev = parport_register_device(port, "tipar", + NULL, NULL, NULL, 0, + (void *) &table[nr]); + + if (table[nr].dev == NULL) + return 1; + + /* Use devfs, tree: /dev/ticables/par/[0..2] */ + sprintf(name, "%d", nr); + printk + ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n", + TISER_MAJOR, (TIPAR_MINOR + nr), name); + devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR, + TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO, + &tipar_fops, NULL); + + /* Display informations */ + printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name, + (port->irq == + PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven"); + + if (probe_ti_parallel(nr) != -1) + printk("tipar%d: link cable found !\n", nr); + else + printk("tipar%d: link cable not found.\n", nr); + + return 0; +} + +static void +tipar_attach(struct parport *port) +{ + if (tp_count == PP_NO) { + printk("tipar: ignoring parallel port (max. %d)\n", PP_NO); + return; + } + + if (!tipar_register(tp_count, port)) + tp_count++; +} + +static void +tipar_detach(struct parport *port) +{ + /* Nothing to do */ +} + +static struct parport_driver tipar_driver = { + "tipar", + tipar_attach, + tipar_detach, + NULL +}; + +int __init +tipar_init_module(void) +{ + printk("tipar: parallel link cable driver, version %s\n", + DRIVER_VERSION); + + if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) { + printk("tipar: unable to get major %d\n", TIPAR_MAJOR); + return -EIO; + } + + /* Use devfs with tree: /dev/ticables/par/[0..2] */ + devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL); + + if (parport_register_driver(&tipar_driver)) { + printk("tipar: unable to register with parport\n"); + return -EIO; + } + + return 0; +} + +void __exit +tipar_cleanup_module(void) +{ + unsigned int i; + + /* Unregistering module */ + parport_unregister_driver(&tipar_driver); + + devfs_unregister(devfs_handle); + unregister_chrdev(TIPAR_MAJOR, "tipar"); + + for (i = 0; i < PP_NO; i++) { + if (table[i].dev == NULL) + continue; + parport_unregister_device(table[i].dev); + } + + printk("tipar: module unloaded !\n"); +} + +/* --------------------------------------------------------------------- */ + +__setup("tipar=", tipar_setup); +module_init(tipar_init_module); +module_exit(tipar_cleanup_module); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + +EXPORT_NO_SYMBOLS; + +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)"); +MODULE_PARM(delay, "i"); +MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)"); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 5ef04cef469e..142115d509b1 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -62,6 +62,9 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) int retval, region; char buf [8], *bufp = buf; + if (usb_disabled()) + return -ENODEV; + if (!id || !(driver = (struct hc_driver *) id->driver_data)) return -EINVAL; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 204cf874c8e6..e12b720f0145 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -943,7 +943,9 @@ static void usb_hub_events(void) list_del_init(tmp); - down(&hub->khubd_sem); /* never blocks, we were on list */ + if (unlikely(down_trylock(&hub->khubd_sem))) + BUG(); /* never blocks, we were on list */ + spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { @@ -1067,10 +1069,10 @@ static int usb_hub_thread(void *__hub) } static struct usb_device_id hub_id_table [] = { - { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS, - bDeviceClass: USB_CLASS_HUB}, - { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, - bInterfaceClass: USB_CLASS_HUB}, + { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, + .bDeviceClass = USB_CLASS_HUB}, + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, + .bInterfaceClass = USB_CLASS_HUB}, { } /* Terminating entry */ }; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 96575bb2b465..9c35f4a3698f 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -45,7 +45,8 @@ static struct inode_operations usbfs_dir_inode_operations; static struct vfsmount *usbdevfs_mount; static struct vfsmount *usbfs_mount; static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; -static int mount_count; /* = 0 */ +static int usbdevfs_mount_count; /* = 0 */ +static int usbfs_mount_count; /* = 0 */ static struct dentry *devices_usbdevfs_dentry; static struct dentry *devices_usbfs_dentry; @@ -507,14 +508,14 @@ static struct file_system_type usb_fs_type = { }; /* --------------------------------------------------------------------- */ -static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount) +static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount, int *mount_count) { struct vfsmount *mnt; spin_lock (&mount_lock); if (*mount) { mntget(*mount); - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); goto go_ahead; } @@ -528,33 +529,33 @@ static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount) spin_lock (&mount_lock); if (!*mount) { *mount = mnt; - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); goto go_ahead; } mntget(*mount); - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); mntput(mnt); go_ahead: - dbg("mount_count = %d", mount_count); + dbg("mount_count = %d", *mount_count); return 0; } -static void put_mount (struct vfsmount **mount) +static void put_mount (struct vfsmount **mount, int *mount_count) { struct vfsmount *mnt; spin_lock (&mount_lock); mnt = *mount; - --mount_count; - if (!mount_count) + --(*mount_count); + if (!(*mount_count)) *mount = NULL; spin_unlock (&mount_lock); mntput(mnt); - dbg("mount_count = %d", mount_count); + dbg("mount_count = %d", *mount_count); } static int create_special_files (void) @@ -563,13 +564,13 @@ static int create_special_files (void) int retval = 0; /* create the devices special file */ - retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount); + retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount, &usbdevfs_mount_count); if (retval) { err ("Unable to get usbdevfs mount"); goto exit; } - retval = get_mount (&usb_fs_type, &usbfs_mount); + retval = get_mount (&usb_fs_type, &usbfs_mount, &usbfs_mount_count); if (retval) { err ("Unable to get usbfs mount"); goto error_clean_usbdevfs_mount; @@ -604,10 +605,10 @@ error_remove_file: devices_usbfs_dentry = NULL; error_clean_mounts: - put_mount (&usbfs_mount); + put_mount (&usbfs_mount, &usbfs_mount_count); error_clean_usbdevfs_mount: - put_mount (&usbdevfs_mount); + put_mount (&usbdevfs_mount, &usbdevfs_mount_count); exit: return retval; @@ -621,8 +622,8 @@ static void remove_special_files (void) fs_remove_file (devices_usbfs_dentry); devices_usbdevfs_dentry = NULL; devices_usbfs_dentry = NULL; - put_mount (&usbdevfs_mount); - put_mount (&usbfs_mount); + put_mount (&usbdevfs_mount, &usbdevfs_mount_count); + put_mount (&usbfs_mount, &usbfs_mount_count); } void usbfs_update_special (void) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 17ab912a3f4b..0d1dad8253fc 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -756,6 +756,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * * This is used to enable data transfers on interfaces that may not * be enabled by default. Not all devices support such configurability. + * Only the driver bound to an interface may change its setting. * * Within any given configuration, each interface may have several * alternative settings. These are often used to control levels of @@ -808,6 +809,22 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) interface, NULL, 0, HZ * 5)) < 0) return ret; + /* FIXME drivers shouldn't need to replicate/bugfix the logic here + * when they implement async or easily-killable versions of this or + * other "should-be-internal" functions (like clear_halt). + * should hcd+usbcore postprocess control requests? + */ + + /* prevent submissions using previous endpoint settings */ + iface_as = iface->altsetting + iface->act_altsetting; + for (i = 0; i < iface_as->bNumEndpoints; i++) { + u8 ep = iface_as->endpoint [i].bEndpointAddress; + int out = !(ep & USB_DIR_IN); + + ep &= USB_ENDPOINT_NUMBER_MASK; + (out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0; + // FIXME want hcd hook here, "no such endpoint" + } iface->act_altsetting = alternate; /* 9.1.1.5: reset toggles for all endpoints affected by this iface-as @@ -819,21 +836,20 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * any SetInterface request and hence assume toggles need to be reset. * However, EP0 toggles are re-synced for every individual transfer * during the SETUP stage - hence EP0 toggles are "don't care" here. + * (Likewise, EP0 never "halts" on well designed devices.) */ iface_as = &iface->altsetting[alternate]; for (i = 0; i < iface_as->bNumEndpoints; i++) { u8 ep = iface_as->endpoint[i].bEndpointAddress; + int out = !(ep & USB_DIR_IN); - usb_settoggle(dev, ep&USB_ENDPOINT_NUMBER_MASK, usb_endpoint_out(ep), 0); + ep &= USB_ENDPOINT_NUMBER_MASK; + usb_settoggle (dev, ep, out, 0); + (out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep] + = iface_as->endpoint [ep].wMaxPacketSize; } - /* usb_set_maxpacket() sets the maxpacket size for all EP in all - * interfaces but it shouldn't do any harm here: we have changed - * the AS for the requested interface only, hence for unaffected - * interfaces it's just re-application of still-valid values. - */ - usb_set_maxpacket(dev); return 0; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 30a2ba8585b1..aaf31af0a45b 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -272,9 +272,9 @@ int usb_submit_urb(struct urb *urb, int mem_flags) /* enforce simple/standard policy */ allowed = USB_ASYNC_UNLINK; // affects later unlinks allowed |= URB_NO_DMA_MAP; + allowed |= URB_NO_INTERRUPT; switch (temp) { case PIPE_BULK: - allowed |= URB_NO_INTERRUPT; if (is_out) allowed |= USB_ZERO_PACKET; /* FALLTHROUGH */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 5b3ec48092ad..556dbacb7c23 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -50,6 +50,9 @@ extern int usb_major_init(void); extern void usb_major_cleanup(void); +int nousb; /* Disable USB when built into kernel image */ + /* Not honored on modular build */ + static int generic_probe (struct device *dev) { @@ -167,6 +170,9 @@ int usb_register(struct usb_driver *new_driver) { int retval = 0; + if (nousb) + return -ENODEV; + new_driver->driver.name = (char *)new_driver->name; new_driver->driver.bus = &usb_bus_type; new_driver->driver.probe = usb_device_probe; @@ -1338,11 +1344,37 @@ struct bus_type usb_bus_type = { .hotplug = usb_hotplug, }; +#ifndef MODULE + +static int __init usb_setup_disable(char *str) +{ + nousb = 1; + return 1; +} + +/* format to disable USB on kernel command line is: nousb */ +__setup("nousb", usb_setup_disable); + +#endif + +/* + * for external read access to <nousb> + */ +int usb_disabled(void) +{ + return nousb; +} + /* * Init */ static int __init usb_init(void) { + if (nousb) { + info("USB support disabled\n"); + return 0; + } + bus_register(&usb_bus_type); usb_major_init(); usbfs_init(); @@ -1358,6 +1390,10 @@ static int __init usb_init(void) */ static void __exit usb_exit(void) { + /* This will matter if shutdown/reboot does exitcalls. */ + if (nousb) + return; + remove_driver(&usb_generic_driver); usb_major_cleanup(); usbfs_cleanup(); @@ -1377,6 +1413,7 @@ EXPORT_SYMBOL(usb_epnum_to_ep_desc); EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); +EXPORT_SYMBOL(usb_disabled); EXPORT_SYMBOL(usb_device_probe); EXPORT_SYMBOL(usb_device_remove); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ed92a80f66d0..0398d58d7f3a 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -985,6 +985,9 @@ MODULE_LICENSE ("GPL"); static int __init init (void) { dbg (DRIVER_INFO); + if (usb_disabled()) + return -ENODEV; + dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd", sizeof (struct ehci_qh), sizeof (struct ehci_qtd), sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); diff --git a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c index 334d30ba13a4..a83f7e83ac33 100644 --- a/drivers/usb/host/hc_sl811.c +++ b/drivers/usb/host/hc_sl811.c @@ -1321,6 +1321,9 @@ static int __init hci_hcd_init (void) int ret; DBGFUNC ("Enter hci_hcd_init\n"); + if (usb_disabled()) + return -ENODEV; + ret = hc_found_hci (base_addr, data_reg_addr, irq); return ret; diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a1979e532787..29b767ec52b7 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -365,6 +365,9 @@ static struct pci_driver ohci_pci_driver = { static int __init ohci_hcd_pci_init (void) { dbg (DRIVER_INFO " (PCI)"); + if (usb_disabled()) + return -ENODEV; + dbg ("block sizes: ed %d td %d", sizeof (struct ed), sizeof (struct td)); return pci_module_init (&ohci_pci_driver); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index a6a34619d4fd..98996cd62d6e 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -23,6 +23,8 @@ #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." #endif +extern int usb_disabled(void); + /*-------------------------------------------------------------------------*/ static void sa1111_start_hc(struct sa1111_dev *dev) @@ -355,6 +357,9 @@ static int ohci_hcd_sa1111_drv_probe(struct device *_dev) struct usb_hcd *hcd = NULL; int ret; + if (usb_disabled()) + return -ENODEV; + ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev); if (ret == 0) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 8d8a5cd42fa5..1e4038ac97ca 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -2484,6 +2484,9 @@ static int __init uhci_hcd_init(void) info(DRIVER_DESC " " DRIVER_VERSION); + if (usb_disabled()) + return -ENODEV; + if (debug) { errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); if (!errbuf) diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index ac7bdcace180..d5016e83ba62 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -402,7 +402,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; - char rep_data[2] = {0x02, 0x02}; char path[64]; if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index b3aa1f558bbe..d30da815bf8f 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -14,6 +14,6 @@ obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o -obj-$(CONFIG_USB_VICAM) += vicam.o +obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o include $(TOPDIR)/Rules.make diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c index 5b673019b7e1..709cdf93afa3 100644 --- a/drivers/usb/media/vicam.c +++ b/drivers/usb/media/vicam.c @@ -1,102 +1,356 @@ -/* -*- linux-c -*- - * USB ViCAM driver - * - * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx) - * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE +/* + * USB ViCam WebCam driver + * Copyright (c) 2002 Joe Burks (jburks@wavicle.org) * - * 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. + * Supports 3COM HomeConnect PC Digital WebCam * - * This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB + * 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. * - * Thanks to Greg Kroah-Hartman for the USB Skeleton driver + * 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. * - * TODO: - * - find out the ids for the Vista Imaging ViCAM + * 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. * - * History: + * This source code is based heavily on the CPiA webcam driver which was + * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt * - * 2001_07_07 - 0.1 - christopher: first version - * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try - while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done - yep, moving pictures. - * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun, - get gqcam-0.9, compile it and run. Better than dd ;-). - * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional) - kill update_params if it does not seem to work for you. - * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk - + * Portions of this code were also copied from usbvideo.c * - * FIXME: It crashes on rmmod with camera plugged. - */ -#define DEBUG 1 + * Special thanks to the the whole team at Sourceforge for help making + * this driver become a reality. Notably: + * Andy Armstrong who reverse engineered the color encoding and + * Pavel Machek and Chris Cheney who worked on reverse engineering the + * camera controls and wrote the first generation driver. + * */ -#include <linux/config.h> #include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/pagemap.h> -#include <linux/slab.h> -#include <linux/fcntl.h> +#include <linux/wrapper.h> #include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/list.h> -#include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> +#include <linux/init.h> +#include <linux/videodev.h> #include <linux/usb.h> - -#include <asm/io.h> -#include <linux/wrapper.h> #include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include "usbvideo.h" -#include <linux/videodev.h> +// #define VICAM_DEBUG -#include "vicam.h" -#include "vicamurbs.h" +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(a) +#endif + +#ifndef bool +#define bool int +#endif + +#ifdef VICAM_DEBUG +#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) +#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) +#else +#define DBG(fmn,args...) do {} while(0) +#endif /* Version Information */ -#define DRIVER_VERSION "v0" -#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>" -#define DRIVER_DESC "USB ViCAM Driver" +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" +#define DRIVER_DESC "ViCam WebCam Driver" /* Define these values to match your device */ -#define USB_VICAM_VENDOR_ID 0x04C1 -#define USB_VICAM_PRODUCT_ID 0x009D +#define USB_VICAM_VENDOR_ID 0x04c1 +#define USB_VICAM_PRODUCT_ID 0x009d -/* table of devices that work with this driver */ -static struct usb_device_id vicam_table [] = { - { USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) }, - { } /* Terminating entry */ -}; +#define VICAM_BYTES_PER_PIXEL 3 +#define VICAM_MAX_READ_SIZE (512*242+128) +#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) +#define VICAM_FRAMES 2 -MODULE_DEVICE_TABLE (usb, vicam_table); +/* Not sure what all the bytes in these char + * arrays do, but they're necessary to make + * the camera work. + */ -static int video_nr = -1; /* next avail video device */ -static struct usb_driver vicam_driver; +static unsigned char setup1[] = { + 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67, + 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00, + 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17, + 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00, + 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 +}; -static char *buf, *buf2; -static volatile int change_pending = 0; +static unsigned char setup2[] = { + 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00, + 0x00, 0x00 +}; -static int vicam_parameters(struct usb_vicam *vicam); +static unsigned char setup3[] = { + 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 +}; -/****************************************************************************** - * - * Memory management functions - * - * Taken from bttv-drivers.c 2.4.7-pre3 - * - ******************************************************************************/ +static unsigned char setup4[] = { + 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07, + 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00, + 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00, + 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07, + 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00, + 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00, + 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07, + 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, + 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0, + 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07, + 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00, + 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0, + 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1, + 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09, + 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, + 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF, + 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02, + 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, + 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF, + 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00, + 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00, + 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05, + 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA, + 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06, + 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF, + 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05, + 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01, + 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09, + 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06, + 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05, + 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA, + 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05, + 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, + 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00, + 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF, + 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00, + 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0, + 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06, + 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00, + 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07, + 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF, + 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00, + 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, + 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57, + 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57, + 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00, + 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0, + 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B, + 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06, + 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, + 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E, + 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, + 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, + 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00, + 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, + 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF, + 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0, + 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, + 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05, + 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF, + 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0, + 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07, + 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07, + 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF, + 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF, + 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, + 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1, + 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67, + 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00, + 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07, + 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07, + 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07, + 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00, + 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06, + 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67, + 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8, + 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, + 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF, + 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02, + 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, + 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06, + 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05, + 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, + 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00, + 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06, + 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, + 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05, + 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05, + 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, + 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04, + 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF, + 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06, + 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00, + 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05, + 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07, + 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07, + 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07, + 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF, + 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07, + 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06, + 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05, + 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07, + 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00, + 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00, + 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77, + 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04, + 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0, + 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1, + 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07, + 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, + 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, + 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, + 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77, + 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1, + 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07, + 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06, + 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, + 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, + 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07, + 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00, + 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00, + 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F, + 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00, + 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00, + 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA, + 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, + 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06, + 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B, + 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09, + 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05, + 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07, + 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00, + 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF, + 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05, + 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00, + 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00, + 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00, + 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09, + 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00, + 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00, + 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0, + 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67, + 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87, + 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9, + 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1, + 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF, + 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00, + 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0, + 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87, + 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, + 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67, + 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, + 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67, + 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, + 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00, + 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF, + 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67, + 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09, + 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA, + 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87, + 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07, + 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, + 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07, + 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, + 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02, + 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, + 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) +static unsigned char setup5[] = { + 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00, + 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, + 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00, + 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00, + 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, + 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00, + 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00, + 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01, + 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01, + 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01, + 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01, + 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01, + 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01, + 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01, + 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01, + 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02, + 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02, + 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, + 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02, + 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, + 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02, + 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02, + 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02, + 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03, + 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03, + 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03, + 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03, + 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03, + 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03, + 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03, + 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04, + 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04, + 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04, + 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04, + 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04, + 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04, + 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04, + 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05, + 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 +}; + +static unsigned long kvirt_to_pa(unsigned long adr) { unsigned long kva, ret; @@ -106,526 +360,734 @@ static inline unsigned long kvirt_to_pa(unsigned long adr) return ret; } -static void * rvmalloc(unsigned long size) +/* rvmalloc / rvfree copied from usbvideo.c + * + * Not sure why these are not yet non-statics which I can reference through + * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime + * in the future. + * +*/ +static void *rvmalloc(unsigned long size) { - void * mem; + void *mem; unsigned long adr; - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - mem_map_reserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + mem_map_reserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; } + return mem; } -static void rvfree(void * mem, unsigned long size) +static void rvfree(void *mem, unsigned long size) { unsigned long adr; - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - mem_map_unreserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; } + vfree(mem); } + +struct vicam_camera { + u16 shutter_speed; // capture shutter speed + u16 gain; // capture gain -/****************************************************************************** - * - * Foo Bar - * - ******************************************************************************/ + u8 *raw_image; // raw data captured from the camera + u8 *framebuf; // processed data in RGB24 format -/** - * usb_vicam_debug_data - */ -static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data) -{ - int i; + struct video_device vdev; // v4l video device + struct usb_device *udev; // usb device - if (!debug) - return; + struct semaphore busy_lock; // guard against SMP multithreading - printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", - function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -} + bool is_initialized; + u8 open_count; + u8 bulkEndpoint; + bool needsDummyRead; -/***************************************************************************** - * - * Send command to vicam - * - *****************************************************************************/ + u32 framebuf_size; // # of valid bytes in framebuf + u32 framebuf_read_start; // position in frame buf that a read is happening at. + +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_entry; +#endif -static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req, - unsigned short value, unsigned char *cp, int size) +}; + +static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); +static void vicam_disconnect(struct usb_interface *intf); +static void read_frame(struct vicam_camera *cam, int framenum); + +static int +send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index, + unsigned char *cp, u16 size) { - int ret; - unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL); + int status; - /* Needs to return data I think, works for sending though */ + // for reasons not yet known to me, you can't send USB control messages + // with data in the module (if you are compiled as a module). Whatever + // the reason, copying it to memory allocated as kernel memory then + // doing the usb control message fixes the problem. + + unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); memcpy(transfer_buffer, cp, size); - - ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ); + + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, + transfer_buffer, size, HZ); kfree(transfer_buffer); - if (ret) - printk("vicam: error: %d\n", ret); - mdelay(100); - return ret; -} + if (status < 0) { + printk(KERN_INFO "Failed sending control message, error %d.\n", + status); + } -/***************************************************************************** - * - * Video4Linux Helpers - * - *****************************************************************************/ + return status; +} -static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b) +static int +initialize_camera(struct vicam_camera *cam) { - dbg("vicam_get_capability"); - - strcpy(b->name, vicam->camera_name); - b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME; - b->channels = 1; - b->audios = 0; - - b->maxwidth = vicam->width[vicam->sizes-1]; - b->maxheight = vicam->height[vicam->sizes-1]; - b->minwidth = vicam->width[0]; - b->minheight = vicam->height[0]; + struct usb_device *udev = cam->udev; + int status; + + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0) + return status; return 0; } - -static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v) + +static int +set_camera_power(struct vicam_camera *cam, int state) { - dbg("vicam_get_channel"); + int status; - if (v->channel != 0) - return -EINVAL; - - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); + if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0) + return status; - return 0; -} - -static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v) -{ - dbg("vicam_set_channel"); + if (state) { + send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0); + } - if (v->channel != 0) - return -EINVAL; - return 0; } - -static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm) + +static int +vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long ul_arg) { - int i; + void *arg = (void *)ul_arg; + struct vicam_camera *cam = file->private_data; + int retval = 0; - dbg("vicam_get_mmapbuffer"); + if (!cam) + return -ENODEV; - memset(vm, 0, sizeof(vm)); - vm->size = VICAM_NUMFRAMES * vicam->maxframesize; - vm->frames = VICAM_NUMFRAMES; + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; - for (i=0; i<VICAM_NUMFRAMES; i++) - vm->offsets[i] = vicam->maxframesize * i; + switch (ioctlnr) { + /* query capabilites */ + case VIDIOCGCAP: + { + struct video_capability b; + + DBG("VIDIOCGCAP\n"); + strcpy(b.name, "ViCam-based Camera"); + b.type = VID_TYPE_CAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = 320; /* VIDEOSIZE_CIF */ + b.maxheight = 240; + b.minwidth = 320; /* VIDEOSIZE_48_48 */ + b.minheight = 240; + + if (copy_to_user(arg, &b, sizeof (b))) + retval = -EFAULT; + + break; + } + /* get/set video source - we are a camera and nothing else */ + case VIDIOCGCHAN: + { + struct video_channel v; + + DBG("VIDIOCGCHAN\n"); + if (copy_from_user(&v, arg, sizeof (v))) { + retval = -EFAULT; + break; + } + if (v.channel != 0) { + retval = -EINVAL; + break; + } + + v.channel = 0; + strcpy(v.name, "Camera"); + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = 0; + + if (copy_to_user(arg, &v, sizeof (v))) + retval = -EFAULT; + break; + } - return 0; -} + case VIDIOCSCHAN: + { + int v; -static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p) -{ - dbg("vicam_get_picture"); + if (copy_from_user(&v, arg, sizeof (v))) + retval = -EFAULT; + DBG("VIDIOCSCHAN %d\n", v); - /* This is probably where that weird 0x56 call goes */ - p->brightness = vicam->win.brightness; - p->hue = vicam->win.hue; - p->colour = vicam->win.colour; - p->contrast = vicam->win.contrast; - p->whiteness = vicam->win.whiteness; - p->depth = vicam->win.depth; - p->palette = vicam->win.palette; + if (retval == 0 && v != 0) + retval = -EINVAL; - return 0; -} + break; + } -static void synchronize(struct usb_vicam *vicam) -{ - DECLARE_WAITQUEUE(wait, current); - change_pending = 1; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&vicam->wait, &wait); - if (change_pending) - schedule(); - remove_wait_queue(&vicam->wait, &wait); - set_current_state(TASK_RUNNING); - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); - mdelay(10); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); - mdelay(10); -} + /* image properties */ + case VIDIOCGPICT: + { + struct video_picture vp; + DBG("VIDIOCGPICT\n"); + memset(&vp, 0, sizeof (struct video_picture)); + vp.brightness = cam->gain << 8; + vp.depth = 24; + vp.palette = VIDEO_PALETTE_RGB24; + if (copy_to_user + (arg, &vp, sizeof (struct video_picture))) + retval = -EFAULT; + break; + } -static void params_changed(struct usb_vicam *vicam) -{ -#if 1 - synchronize(vicam); - mdelay(10); - vicam_parameters(vicam); - printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL)); -#endif + case VIDIOCSPICT: + { + struct video_picture *vp = (struct video_picture *) arg; + + DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth, + vp->palette); + + cam->gain = vp->brightness >> 8; + + if (vp->depth != 24 + || vp->palette != VIDEO_PALETTE_RGB24) + retval = -EINVAL; + + break; + } + + /* get/set capture window */ + case VIDIOCGWIN: + { + struct video_window vw; + vw.x = 0; + vw.y = 0; + vw.width = 320; + vw.height = 240; + vw.chromakey = 0; + vw.flags = 0; + vw.clips = NULL; + vw.clipcount = 0; + + DBG("VIDIOCGWIN\n"); + + if (copy_to_user + ((void *) arg, (void *) &vw, sizeof (vw))) + retval = -EFAULT; + + // I'm not sure what the deal with a capture window is, it is very poorly described + // in the doc. So I won't support it now. + break; + } + + case VIDIOCSWIN: + { + + struct video_window *vw = (struct video_window *) arg; + DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height); + + if ( vw->width != 320 || vw->height != 240 ) + retval = -EFAULT; + + break; + } + + /* mmap interface */ + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + DBG("VIDIOCGMBUF\n"); + memset(&vm, 0, sizeof (vm)); + vm.size = + VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; + vm.frames = VICAM_FRAMES; + for (i = 0; i < VICAM_FRAMES; i++) + vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; + + if (copy_to_user + ((void *) arg, (void *) &vm, sizeof (vm))) + retval = -EFAULT; + + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + // int video_size; + + if (copy_from_user + ((void *) &vm, (void *) arg, sizeof (vm))) { + retval = -EFAULT; + break; + } + + DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); + + if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) + retval = -EINVAL; + + // in theory right here we'd start the image capturing + // (fill in a bulk urb and submit it asynchronously) + // + // Instead we're going to do a total hack job for now and + // retrieve the frame in VIDIOCSYNC + + break; + } + + case VIDIOCSYNC: + { + int frame; + + if (copy_from_user((void *) &frame, arg, sizeof (int))) { + retval = -EFAULT; + break; + } + DBG("VIDIOCSYNC: %d\n", frame); + + read_frame(cam, frame); + + break; + } + + /* pointless to implement overlay with this camera */ + case VIDIOCCAPTURE: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case VIDIOCKEY: + retval = -EINVAL; + break; + + /* tuner interface - we have none */ + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + retval = -EINVAL; + break; + + /* audio interface - we have none */ + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + retval = -EINVAL; + break; + default: + retval = -ENOIOCTLCMD; + break; + } + + up(&cam->busy_lock); + return retval; } -static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p) +static int +vicam_open(struct inode *inode, struct file *file) { - int changed = 0; - info("vicam_set_picture (%d)", p->brightness); - - -#define SET(x) \ - if (vicam->win.x != p->x) \ - vicam->win.x = p->x, changed = 1; - SET(brightness); - SET(hue); - SET(colour); - SET(contrast); - SET(whiteness); - SET(depth); - SET(palette); - if (changed) - params_changed(vicam); + struct video_device *dev = video_devdata(file); + struct vicam_camera *cam = + (struct vicam_camera *) dev->priv; + DBG("open\n"); + + if (!cam) { + printk(KERN_ERR + "vicam video_device improperly initialized"); + } - return 0; - /* Investigate what should be done maybe 0x56 type call */ - if (p->depth != 8) return 1; - if (p->palette != VIDEO_PALETTE_GREY) return 1; + down_interruptible(&cam->busy_lock); + + if (cam->open_count > 0) { + printk(KERN_INFO + "vicam_open called on already opened camera"); + up(&cam->busy_lock); + return -EBUSY; + } + + if (!cam->raw_image) { + cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); + if (!cam->raw_image) { + up(&cam->busy_lock); + return -ENOMEM; + } + } + + if (!cam->framebuf) { + cam->framebuf = + rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); + if (!cam->framebuf) { + kfree(cam->raw_image); + up(&cam->busy_lock); + return -ENOMEM; + } + } + // First upload firmware, then turn the camera on + + if (!cam->is_initialized) { + initialize_camera(cam); + + cam->is_initialized = 1; + } + + set_camera_power(cam, 1); + + cam->needsDummyRead = 1; + cam->open_count++; + up(&cam->busy_lock); + + file->private_data = cam; + return 0; } -/* FIXME - vicam_sync_frame - important */ -static int vicam_sync_frame(struct usb_vicam *vicam, int frame) +static int +vicam_close(struct inode *inode, struct file *file) { - dbg("vicam_sync_frame"); + struct vicam_camera *cam = file->private_data; + DBG("close\n"); + set_camera_power(cam, 0); - if(frame <0 || frame >= VICAM_NUMFRAMES) - return -EINVAL; + cam->open_count--; - /* Probably need to handle various cases */ -/* ret=vicam_newframe(vicam, frame); - vicam->frame[frame].grabstate=FRAME_UNUSED; -*/ return 0; } - -static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw) -{ - dbg("vicam_get_window"); - vw->x = 0; - vw->y = 0; - vw->chromakey = 0; - vw->flags = 0; - vw->clipcount = 0; - vw->width = vicam->win.width; - vw->height = vicam->win.height; +inline int pin(int x) +{ + return((x > 255) ? 255 : ((x < 0) ? 0 : x)); +} - return 0; +inline void writepixel(char *rgb, int Y, int Cr, int Cb) +{ + Y = 1160 * (Y - 16); + + rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 ); + rgb[1] = pin( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 ); + rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 ); } -static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw) +#define DATA_HEADER_SIZE 64 + +// -------------------------------------------------------------------------------- +// vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB +// +// Copyright (C) 2002 Monroe Williams (monroe@pobox.com) +// -------------------------------------------------------------------------------- + +void vicam_decode_color( char *data, char *rgb) { - info("vicam_set_window"); - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; + int x,y; + int Cr, Cb; + int sign; + int prevX, nextX, prevY, nextY; + int skip; + unsigned char *src; + unsigned char *dst; - if (vicam->win.width == vw->width && vicam->win.height == vw->height) - return 0; + prevY = 512; + nextY = 512; - /* Pick largest mode that is smaller than specified res */ - /* If specified res is too small reject */ + src = data + DATA_HEADER_SIZE; + dst = rgb; - /* Add urb send to device... */ + for(y = 1; y < 241; y += 2) + { + // even line + sign = 1; + prevX = 1; + nextX = 1; - vicam->win.width = vw->width; - vicam->win.height = vw->height; - params_changed(vicam); + skip = 0; - return 0; -} + dst = rgb + (y-1)*320*3; + + for(x = 0; x < 512; x++) + { + if(x == 512-1) + nextX = -1; -/* FIXME - vicam_mmap_capture - important */ -static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm) -{ - dbg("vicam_mmap_capture"); + Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1; + Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2; - /* usbvideo.c looks good for using here */ + writepixel( + dst + ((x*5)>>3)*3, + src[0] + (sign * (Cr >> 1)), + Cr, + Cb); - /* - if (vm->frame >= VICAM_NUMFRAMES) - return -EINVAL; - if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED) - return -EBUSY; - vicam->frame[vm->frame].grabstate=FRAME_READY; - */ + src++; + sign *= -1; + prevX = -1; + } - /* No need to vicam_set_window here according to Alan */ + prevY = -512; - /* - if (!vicam->streaming) - vicam_start_stream(vicam); - */ + if(y == (242 - 2)) + nextY = -512; - /* set frame as ready */ + // odd line + sign = 1; + prevX = 1; + nextX = 1; - return 0; -} + skip = 0; -/***************************************************************************** - * - * Video4Linux - * - *****************************************************************************/ + dst = rgb + (y)*320*3; + + for(x = 0; x < 512; x++) + { + if(x == 512-1) + nextX = -1; + + Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2; + Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1; + + writepixel( + dst + ((x * 5)>>3)*3, + src[0] - (sign * (Cb >> 1)), + Cr, + Cb); + + src++; + sign *= -1; + prevX = -1; + } + } +} -static int vicam_v4l_open(struct inode *inode, struct file *file) +static void +read_frame(struct vicam_camera *cam, int framenum) { - struct video_device *vdev = video_devdata(file); - struct usb_vicam *vicam = (struct usb_vicam *)vdev; - int err = 0; - - dbg("vicam_v4l_open"); - down(&vicam->sem); - - vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES); - if (vicam->open_count) { - err = -EBUSY; - } else if (!vicam->fbuf) { - err =- ENOMEM; + unsigned char request[16]; + int realShutter; + int n; + int actual_length; + + memset(request, 0, 16); + request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain + + request[1] = 0; // 512x242 capture + + request[2] = 0x90; // the function of these two bytes + request[3] = 0x07; // is not yet understood + + if (cam->shutter_speed > 60) { + // Short exposure + realShutter = + ((-15631900 / cam->shutter_speed) + 260533) / 1000; + request[4] = realShutter & 0xFF; + request[5] = (realShutter >> 8) & 0xFF; + request[6] = 0x03; + request[7] = 0x01; } else { -#ifdef BLINKING - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); - info ("led on"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); -#endif - vicam->open_count++; - file->private_data = vdev; + // Long exposure + realShutter = 15600 / cam->shutter_speed - 1; + request[4] = 0; + request[5] = 0; + request[6] = realShutter & 0xFF; + request[7] = realShutter >> 8; } - up(&vicam->sem); - return err; -} - -static int vicam_v4l_close(struct inode *inode, struct file *file) -{ - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; + // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 + request[8] = 0; + // bytes 9-15 do not seem to affect exposure or image quality - dbg("vicam_v4l_close"); - - down(&vicam->sem); + n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16); -#ifdef BLINKING - info ("led off"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); -// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on -#endif + if (n < 0) { + printk(KERN_ERR + " Problem sending frame capture control message"); + return; + } - rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES); - vicam->fbuf = 0; - vicam->open_count=0; - file->private_data = NULL; + n = usb_bulk_msg(cam->udev, + usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), + cam->raw_image, + 512 * 242 + 128, &actual_length, HZ*10); - up(&vicam->sem); - /* Why does se401.c have a usbdevice check here? */ - /* If device is unplugged while open, I guess we only may unregister now */ - return 0; -} + if (n < 0) { + printk(KERN_ERR "Problem during bulk read of frame data: %d\n", + n); + } -static int vicam_v4l_read(struct file *file, char *user_buf, - size_t buflen, loff_t *ppos) -{ - struct video_device *vdev = file->private_data; - //struct usb_vicam *vicam = (struct usb_vicam *)vdev; + vicam_decode_color(cam->raw_image, + cam->framebuf + + framenum * VICAM_MAX_FRAME_SIZE ); - dbg("vicam_v4l_read(%d)", buflen); + cam->framebuf_size = + 320 * 240 * VICAM_BYTES_PER_PIXEL; + cam->framebuf_read_start = 0; - if (!vdev || !buf) - return -EFAULT; + return; - if (copy_to_user(user_buf, buf2, buflen)) - return -EFAULT; - return buflen; } -static int vicam_v4l_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int +vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos ) { - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; - int ret = -EL3RST; + struct vicam_camera *cam = file->private_data; + DBG("read %d bytes.\n", (int) count); - if (!vicam->udev) - return -EIO; + if (!buf) + return -EINVAL; - down(&vicam->sem); + if (!count) + return -EINVAL; - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - ret = vicam_get_capability(vicam,b); - dbg("name %s",b->name); - break; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param"); - /* frame buffer not supported, not used */ - memset(vb, 0, sizeof(*vb)); - ret = 0; - break; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - ret = vicam_get_window(vicam, vw); - break; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - ret = vicam_set_window(vicam, vw); - break; + // This is some code that will hopefully allow us to do shell copies from + // the /dev/videoX to a file and have it actually work. + if (cam->framebuf_size != 0) { + if (cam->framebuf_read_start == cam->framebuf_size) { + cam->framebuf_size = cam->framebuf_read_start = 0; + return 0; + } else { + if (cam->framebuf_read_start + count <= + cam->framebuf_size) { + // count does not exceed available bytes + copy_to_user(buf, + (cam->framebuf) + + cam->framebuf_read_start, count); + cam->framebuf_read_start += count; + return count; + } else { + count = + cam->framebuf_size - + cam->framebuf_read_start; + copy_to_user(buf, + (cam->framebuf) + + cam->framebuf_read_start, count); + cam->framebuf_read_start = cam->framebuf_size; + return count; + } + } } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - ret = vicam_get_channel(vicam,v); - break; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - ret = vicam_set_channel(vicam,v); - break; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - ret = vicam_get_picture(vicam,p); - break; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - ret = vicam_set_picture(vicam,p); - break; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - ret = vicam_get_mmapbuffer(vicam,vm); - break; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - ret = vicam_mmap_capture(vicam,vm); - break; - } - case VIDIOCSYNC: - { - int *frame = arg; - ret = vicam_sync_frame(vicam,*frame); - break; + down_interruptible(&cam->busy_lock); + + if (cam->needsDummyRead) { + read_frame(cam, 0); + cam->needsDummyRead = 0; } + // read_frame twice because the camera doesn't seem to take the shutter speed for the first one. - case VIDIOCKEY: - ret = 0; - - case VIDIOCCAPTURE: - case VIDIOCSFBUF: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOCGUNIT: - ret = -EINVAL; + read_frame(cam, 0); - default: - { - info("vicam_v4l_ioctl - %ui",cmd); - ret = -ENOIOCTLCMD; - } - } /* end switch */ + if (count > cam->framebuf_size) + count = cam->framebuf_size; - up(&vicam->sem); - return ret; -} + copy_to_user(buf, cam->framebuf, count); -static int vicam_v4l_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, vicam_v4l_do_ioctl); + if (count != cam->framebuf_size) + cam->framebuf_read_start = count; + else + cam->framebuf_size = 0; + + up(&cam->busy_lock); + + return count; } -static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma) + +static int +vicam_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; + // TODO: allocate the raw frame buffer if necessary + unsigned long page, pos; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; + struct vicam_camera *cam = file->private_data; - down(&vicam->sem); - - if (vicam->udev == NULL) { - up(&vicam->sem); - return -EIO; - } -#if 0 - if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { - up(&vicam->sem); - return -EINVAL; + if (!cam) + return -ENODEV; + + DBG("vicam_mmap: %ld\n", size); + + /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes + * to the size the application requested for mmap and it was screwing apps up. + if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) + return -EINVAL; + */ + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + if (!cam->framebuf) { /* we do lazy allocation */ + cam->framebuf = + rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); + if (!cam->framebuf) { + up(&cam->busy_lock); + return -ENOMEM; + } } -#endif - pos = (unsigned long)vicam->fbuf; + + pos = (unsigned long)cam->framebuf; while (size > 0) { page = kvirt_to_pa(pos); - if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&vicam->sem); + if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; - } + start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) @@ -633,299 +1095,315 @@ static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma) else size = 0; } - up(&vicam->sem); - return 0; + up(&cam->busy_lock); + + return 0; } -/* FIXME - vicam_template - important */ -static struct file_operations vicam_fops = { - .owner = THIS_MODULE, - .open = vicam_v4l_open, - .release = vicam_v4l_close, - .read = vicam_v4l_read, - .mmap = vicam_v4l_mmap, - .ioctl = vicam_v4l_ioctl, - .llseek = no_llseek, -}; -static struct video_device vicam_template = { - .owner = THIS_MODULE, - .name = "vicam USB camera", - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_SE401, /* need to ask for own id */ - .fops = &vicam_fops, -}; +#ifdef CONFIG_PROC_FS -/****************************************************************************** - * - * Some Routines - * - ******************************************************************************/ +static struct proc_dir_entry *vicam_proc_root = NULL; -/* -Flash the led -vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); -info ("led on"); -vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); -info ("led off"); -vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); -vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); -*/ +static int +vicam_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *out = page; + int len; + struct vicam_camera *cam = (struct vicam_camera *) data; + + out += + sprintf(out, "Vicam-based WebCam Linux Driver.\n"); + out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n"); + out += sprintf(out, "vicam stats:\n"); + out += sprintf(out, " Shutter Speed: 1/%d\n", cam->shutter_speed); + out += sprintf(out, " Gain: %d\n", cam->gain); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + return len; +} -static void vicam_bulk(struct urb *urb) +static int +vicam_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) { - struct usb_vicam *vicam = urb->context; + char *in; + char *start; + struct vicam_camera *cam = (struct vicam_camera *) data; - /* if (!vicam || !vicam->dev || !vicam->used) - return; - */ + in = kmalloc(count + 1, GFP_KERNEL); + if (!in) + return -ENOMEM; - if (urb->status) - printk("vicam%d: nonzero read/write bulk status received: %d", - 0, urb->status); + in[count] = 0; // I'm not sure buffer is gauranteed to be null terminated + // so I do this to make sure I have a null in there. - urb->actual_length = 0; - urb->dev = vicam->udev; + strncpy(in, buffer, count); - memcpy(buf2, buf+64, 0x1e480); - if (vicam->fbuf) - memcpy(vicam->fbuf, buf+64, 0x1e480); + start = strstr(in, "gain="); + if (start + && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) + cam->gain = simple_strtoul(start + 5, NULL, 10); - if (!change_pending) { - if (usb_submit_urb(urb, GFP_ATOMIC)) - dbg("failed resubmitting read urb"); - } else { - change_pending = 0; - wake_up_interruptible(&vicam->wait); - } + start = strstr(in, "shutter="); + if (start + && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) + cam->shutter_speed = simple_strtoul(start + 8, NULL, 10); + + kfree(in); + return count; } -static int vicam_parameters(struct usb_vicam *vicam) +void +vicam_create_proc_root(void) { - unsigned char req[0x10]; - unsigned int shutter; - shutter = 10; + vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0); - switch (vicam->win.width) { - case 512: - default: - memcpy(req, s512x242bw, 0x10); - break; - case 256: - memcpy(req, s256x242bw, 0x10); - break; - case 128: - memcpy(req, s128x122bw, 0x10); - break; - } + if (vicam_proc_root) + vicam_proc_root->owner = THIS_MODULE; + else + printk(KERN_ERR + "could not create /proc entry for vicam!"); +} +void +vicam_destroy_proc_root(void) +{ + if (vicam_proc_root) + remove_proc_entry("video/vicam", 0); +} - mdelay(10); - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); - info ("led on"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); +void +vicam_create_proc_entry(void *ptr) +{ + struct vicam_camera *cam = (struct vicam_camera *) ptr; - mdelay(10); + char name[7]; + struct proc_dir_entry *ent; - shutter = vicam->win.contrast / 256; - if (shutter == 0) - shutter = 1; - printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter ); - req[0] = vicam->win.brightness /256; - shutter = 15600/shutter - 1; - req[6] = shutter & 0xff; - req[7] = (shutter >> 8) & 0xff; - vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10); - mdelay(10); - vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10); - mdelay(10); + DBG(KERN_INFO "vicam: creating proc entry\n"); - return 0; + if (!vicam_proc_root || !cam) { + printk(KERN_INFO + "vicam: could not create proc entry, %s pointer is null.\n", + (!cam ? "camera" : "root")); + return; + } + + sprintf(name, "video%d", cam->vdev.minor); + + ent = + create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, + vicam_proc_root); + if (!ent) + return; + + ent->data = cam; + ent->read_proc = vicam_read_proc; + ent->write_proc = vicam_write_proc; + ent->size = 512; + cam->proc_entry = ent; } -static int vicam_init(struct usb_vicam *vicam) +void +vicam_destroy_proc_entry(void *ptr) { - int width[] = {128, 256, 512}; - int height[] = {122, 242, 242}; - - dbg("vicam_init"); - buf = kmalloc(0x1e480, GFP_KERNEL); - buf2 = kmalloc(0x1e480, GFP_KERNEL); - if ((!buf) || (!buf2)) { - printk("Not enough memory for vicam!\n"); - goto error; - } + struct vicam_camera *cam = (struct vicam_camera *) ptr; + char name[7]; - /* do we do aspect correction in kernel or not? */ - vicam->sizes = 3; - vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); - vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); - memcpy(vicam->width, &width, sizeof(width)); - memcpy(vicam->height, &height, sizeof(height)); - vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1]; + if (!cam || !cam->proc_entry) + return; - /* Download firmware to camera */ - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); + sprintf(name, "video%d", cam->vdev.minor); + remove_proc_entry(name, vicam_proc_root); + cam->proc_entry = NULL; - vicam_parameters(vicam); +} - FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81), - buf, 0x1e480, vicam_bulk, vicam); - printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL)); +#endif +int +vicam_video_init(struct video_device *vdev) +{ + // This would normally create the proc entry for this camera +#ifdef CONFIG_PROC_FS + vicam_create_proc_entry(vdev->priv); +#endif return 0; -error: - if (buf) - kfree(buf); - if (buf2) - kfree(buf2); - return 1; } -static int vicam_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_vicam *vicam; - char *camera_name=NULL; +static struct file_operations vicam_fops = { + .owner = THIS_MODULE, + .open = vicam_open, + .release =vicam_close, + .read = vicam_read, + .mmap = vicam_mmap, + .ioctl = vicam_ioctl, + .llseek = no_llseek, +}; + +static struct video_device vicam_template = { + .owner = THIS_MODULE, + .name = "ViCam-based USB Camera", + .type = VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_VICAM, + .fops = &vicam_fops, +// .initialize = vicam_video_init, + .minor = -1, +}; + +/* table of devices that work with this driver */ +static struct usb_device_id vicam_table[] = { + {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, vicam_table); - dbg("vicam_probe"); +static struct usb_driver vicam_driver = { + name:"vicam", + probe:vicam_probe, + disconnect:vicam_disconnect, + id_table:vicam_table +}; +/** + * vicam_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int +vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + int bulkEndpoint = 0; + const struct usb_interface_descriptor *interface; + const struct usb_endpoint_descriptor *endpoint; + struct vicam_camera *cam; + /* See if the device offered us matches what we can accept */ - if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || - (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { + if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || + (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { return -ENODEV; } - - camera_name="3Com HomeConnect USB"; - info("ViCAM camera found: %s", camera_name); - - vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL); - if (vicam == NULL) { - err ("couldn't kmalloc vicam struct"); - return -ENOMEM; + + printk(KERN_INFO "ViCam based webcam connected\n"); + + interface = &intf->altsetting[0]; + + DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", + ifnum, (unsigned) (interface->bNumEndpoints)); + endpoint = &interface->endpoint[0]; + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + bulkEndpoint = endpoint->bEndpointAddress; + } else { + printk(KERN_ERR + "No bulk in endpoint was found ?! (this is bad)\n"); } - memset(vicam, 0, sizeof(*vicam)); - vicam->readurb = usb_alloc_urb(0, GFP_KERNEL); - if (!vicam->readurb) { - kfree(vicam); + if ((cam = + kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING + "could not allocate kernel memory for vicam_camera struct\n"); return -ENOMEM; } - vicam->udev = udev; - vicam->camera_name = camera_name; - vicam->win.brightness = 128; - vicam->win.contrast = 10; + memset(cam, 0, sizeof (struct vicam_camera)); - /* FIXME */ - if (vicam_init(vicam)) { - usb_free_urb(vicam->readurb); - kfree(vicam); - return -ENOMEM; - } - memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template)); - memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name)); - - if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { - err("video_register_device"); - usb_free_urb(vicam->readurb); - kfree(vicam); + cam->shutter_speed = 15; + + init_MUTEX(&cam->busy_lock); + + memcpy(&cam->vdev, &vicam_template, + sizeof (vicam_template)); + cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only + + cam->udev = dev; + cam->bulkEndpoint = bulkEndpoint; + + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { + kfree(cam); + printk(KERN_WARNING "video_register_device failed\n"); return -EIO; } - info("registered new video device: video%d", vicam->vdev.minor); - - init_MUTEX (&vicam->sem); - init_waitqueue_head(&vicam->wait); + printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); + + dev_set_drvdata(&intf->dev, cam); - dev_set_drvdata (&intf->dev, vicam); return 0; } - -/* FIXME - vicam_disconnect - important */ -static void vicam_disconnect(struct usb_interface *intf) +static void +vicam_disconnect(struct usb_interface *intf) { - struct usb_vicam *vicam; + struct vicam_camera *cam = dev_get_drvdata(&intf->dev); - vicam = dev_get_drvdata (&intf->dev); + dev_set_drvdata ( &intf->dev, NULL ); + usb_put_dev(cam->udev); + + cam->udev = NULL; + + video_unregister_device(&cam->vdev); - dev_set_drvdata (&intf->dev, NULL); +#ifdef CONFIG_PROC_FS + vicam_destroy_proc_entry(cam); +#endif - if (vicam) { - video_unregister_device(&vicam->vdev); - vicam->udev = NULL; -/* - vicam->frame[0].grabstate = FRAME_ERROR; - vicam->frame[1].grabstate = FRAME_ERROR; -*/ + if (cam->raw_image) + kfree(cam->raw_image); + if (cam->framebuf) + rvfree(cam->framebuf, + VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - /* Free buffers and shit */ - info("%s disconnected", vicam->camera_name); - synchronize(vicam); + kfree(cam); - if (!vicam->open_count) { - /* Other random junk */ - usb_free_urb(vicam->readurb); - kfree(vicam); - vicam = NULL; - } - } + printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); } -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vicam_driver = { - .owner = THIS_MODULE, - .name = "vicam", - .probe = vicam_probe, - .disconnect = vicam_disconnect, - .id_table = vicam_table, -}; - -/****************************************************************************** - * - * Module Routines - * - ******************************************************************************/ - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -/* Module paramaters */ -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -static int __init usb_vicam_init(void) +/* + */ +static int __init +usb_vicam_init(void) { - int result; - - printk("VICAM: initializing\n"); - /* register this driver with the USB subsystem */ - result = usb_register(&vicam_driver); - if (result < 0) { - err("usb_register failed for the "__FILE__" driver. Error number %d", - result); - return -1; - } - - info(DRIVER_VERSION " " DRIVER_AUTHOR); - info(DRIVER_DESC); + DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); +#ifdef CONFIG_PROC_FS + vicam_create_proc_root(); +#endif + if (usb_register(&vicam_driver) != 0) + printk(KERN_WARNING "usb_register failed!\n"); return 0; } -static void __exit usb_vicam_exit(void) +static void __exit +usb_vicam_exit(void) { - /* deregister this driver with the USB subsystem */ + DBG(KERN_INFO + "ViCam-based WebCam driver shutdown\n"); + usb_deregister(&vicam_driver); +#ifdef CONFIG_PROC_FS + vicam_destroy_proc_root(); +#endif } module_init(usb_vicam_init); module_exit(usb_vicam_exit); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/media/vicam.h b/drivers/usb/media/vicam.h deleted file mode 100644 index 4527d8e644f7..000000000000 --- a/drivers/usb/media/vicam.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver - * Christopher L Cheney (C) 2001 - * - */ - -#ifndef __LINUX_VICAM_H -#define __LINUX_VICAM_H - - -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) - -#define VICAM_NUMFRAMES 30 -#define VICAM_NUMSBUF 1 - -/* USB REQUEST NUMBERS */ -#define VICAM_REQ_VENDOR 0xff -#define VICAM_REQ_CAMERA_POWER 0x50 -#define VICAM_REQ_CAPTURE 0x51 -#define VICAM_REQ_LED_CONTROL 0x55 -#define VICAM_REQ_GET_SOMETHIN 0x56 - -/* not required but lets you know camera is on */ -/* camera must be on to turn on led */ -/* 0x01 always on 0x03 on when picture taken (flashes) */ - -struct picture_parm -{ - int width; - int height; - int brightness; - int hue; - int colour; - int contrast; - int whiteness; - int depth; - int palette; -}; - -struct vicam_scratch { - unsigned char *data; - volatile int state; - int offset; - int length; -}; - -/* Structure to hold all of our device specific stuff */ -struct usb_vicam -{ - struct video_device vdev; - struct usb_device *udev; - - int open_count; /* number of times this port has been opened */ - struct semaphore sem; /* locks this structure */ - wait_queue_head_t wait; /* Processes waiting */ - - int streaming; - - /* v4l stuff */ - char *camera_name; - char *fbuf; - struct urb *urb[VICAM_NUMSBUF]; - int sizes; - int *width; - int *height; - int maxframesize; - struct picture_parm win; - struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */ - struct urb *readurb; -}; - -#endif diff --git a/drivers/usb/media/vicamurbs.h b/drivers/usb/media/vicamurbs.h deleted file mode 100644 index 5068d01330c3..000000000000 --- a/drivers/usb/media/vicamurbs.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * - * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver - * Christopher L Cheney (C) 2001 - * - */ - - -#ifndef __LINUX_VICAMURBS_H -#define __LINUX_VICAMURBS_H - -/* -------------------------------------------------------------------------- */ - -/* FIXME - Figure out transfers so that this doesn't need to be here - * - * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */ - -/* Request 0x51 Image Setup */ - -#if 0 -/* 128x98 ? 0x3180 size */ -static unsigned char s128x98bw[] = { - 0, 0x34, 0xC4, 0x00, 0x00, 0x00, 0, 0, - 0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; -#endif - -/* 128x122 3D80 size */ -static unsigned char s128x122bw[] = { - 0, 0x34, 0xF4, 0x00, 0x00, 0x00, 0, 0, - 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* 256x242 ? 0xF280 size */ -static unsigned char s256x242bw[] = { - 0, 0x03, 0xC8, 0x03, 0x00, 0x00, 0, 0, - 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* 512x242 0x1E480 size */ -static unsigned char s512x242bw[] = { - 0, 0x05, 0x90, 0x07, 0x00, 0x00, 0, 0, - 0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* In s512x242: - byte 0: gain -- higher number means brighter image - byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000). -*/ - -/* -------------------------------------------------------------------------- */ - -static unsigned char fsetup[] = { - 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, - - 0x00, 0x00 -}; - -static unsigned char firmware1[] = { - 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, - - 0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, - 0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, - 0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, - 0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 -}; - -static unsigned char findex1[] = { - 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, - - 0x18, 0x00, 0x00, 0x00 -}; - -static unsigned char firmware2[] = { - 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, - - 0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, - 0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, - 0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, - 0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, - 0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, - 0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, - 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, - 0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, - 0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, - 0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, - 0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, - 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, - 0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, - 0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, - 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, - 0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, - 0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, - 0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, - 0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, - 0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, - 0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, - 0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, - 0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, - 0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, - 0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, - 0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, - 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, - 0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, - 0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, - 0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, - 0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, - 0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, - 0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, - 0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, - 0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, - 0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, - 0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, - 0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, - 0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, - 0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, - 0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, - 0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, - 0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, - 0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, - 0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, - 0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, - 0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, - 0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, - 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, - 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, - 0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, - 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, - 0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, - 0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, - 0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, - 0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, - 0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, - 0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, - 0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, - 0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, - 0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, - 0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, - 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, - 0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, - 0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, - 0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, - 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, - 0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, - 0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, - 0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, - 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, - 0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, - 0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, - 0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, - 0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, - 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, - 0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, - 0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, - 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, - 0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, - 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, - 0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, - 0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, - 0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, - 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, - 0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, - 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, - 0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, - 0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, - 0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, - 0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, - 0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, - 0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, - 0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, - 0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, - 0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, - 0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, - 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, - 0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, - 0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, - 0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, - 0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, - 0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, - 0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, - 0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, - 0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, - 0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, - 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, - 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, - 0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, - 0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, - 0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, - 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, - 0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, - 0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, - 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, - 0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, - 0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, - 0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, - 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, - 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, - 0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, - 0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, - 0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, - 0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, - 0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, - 0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, - 0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, - 0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, - 0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, - 0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, - 0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, - 0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, - 0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, - 0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, - 0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, - 0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, - 0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, - 0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, - 0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, - 0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, - 0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, - 0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, - 0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, - 0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, - 0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, - 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, - 0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, - 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, - 0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, - 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, - 0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, - 0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, - 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, - 0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, - 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, - 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, - 0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, - 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, - 0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, - 0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, - 0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, - 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, - 0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, - 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, - 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, - 0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char findex2[] = { - 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, - - 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, - 0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, - 0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, - 0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, - 0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, - 0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, - 0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, - 0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, - 0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, - 0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, - 0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, - 0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, - 0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, - 0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, - 0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, - 0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, - 0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, - 0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, - 0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, - 0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, - 0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, - 0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, - 0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, - 0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, - 0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, - 0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, - 0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, - 0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, - 0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, - 0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, - 0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, - 0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, - 0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, - 0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, - 0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, - 0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, - 0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, - 0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 -}; - -#endif diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 45c76c1b8b97..15b5030ebee8 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -2092,7 +2092,7 @@ static const struct usb_device_id products [] = { #ifdef CONFIG_USB_EPSON2888 { USB_DEVICE (0x0525, 0x2888), // EPSON USB client - driver_info: (unsigned long) &epson2888_info, + .driver_info = (unsigned long) &epson2888_info, }, #endif diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 81fa9f2479eb..11ec19125bcd 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2617,47 +2617,47 @@ static void edge_shutdown (struct usb_serial *serial) static struct usb_serial_device_type edgeport_1port_device = { - owner: THIS_MODULE, - name: "Edgeport TI 1 port adapter", - id_table: edgeport_1port_id_table, - num_interrupt_in: 1, - num_bulk_in: 1, - num_bulk_out: 1, - num_ports: 1, - open: edge_open, - close: edge_close, - throttle: edge_throttle, - unthrottle: edge_unthrottle, - attach: edge_startup, - shutdown: edge_shutdown, - ioctl: edge_ioctl, - set_termios: edge_set_termios, - write: edge_write, - write_room: edge_write_room, - chars_in_buffer: edge_chars_in_buffer, - break_ctl: edge_break, + .owner = THIS_MODULE, + .name = "Edgeport TI 1 port adapter", + .id_table = edgeport_1port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, }; static struct usb_serial_device_type edgeport_2port_device = { - owner: THIS_MODULE, - name: "Edgeport TI 2 port adapter", - id_table: edgeport_2port_id_table, - num_interrupt_in: 1, - num_bulk_in: 2, - num_bulk_out: 2, - num_ports: 2, - open: edge_open, - close: edge_close, - throttle: edge_throttle, - unthrottle: edge_unthrottle, - attach: edge_startup, - shutdown: edge_shutdown, - ioctl: edge_ioctl, - set_termios: edge_set_termios, - write: edge_write, - write_room: edge_write_room, - chars_in_buffer: edge_chars_in_buffer, - break_ctl: edge_break, + .owner = THIS_MODULE, + .name = "Edgeport TI 2 port adapter", + .id_table = edgeport_2port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 2, + .num_bulk_out = 2, + .num_ports = 2, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, }; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 4b133ec1ad66..4cb3cb879e1b 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1237,16 +1237,17 @@ int usb_serial_probe(struct usb_interface *interface, } #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE) -#if 0 /* BEGIN HORRIBLE HACK FOR PL2303 */ /* this is needed due to the looney way its endpoints are set up */ - if (ifnum == 1) { - if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) && - (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || - ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && - (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { + if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) && + (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || + ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && + (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { + //if (ifnum == 1) { + if (interface != &dev->actconfig->interface[0]) { /* check out the endpoints of the other interface*/ - interface = &dev->actconfig->interface[ifnum ^ 1]; + //interface = &dev->actconfig->interface[ifnum ^ 1]; + interface = &dev->actconfig->interface[0]; iface_desc = &interface->altsetting[0]; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i]; @@ -1259,10 +1260,19 @@ int usb_serial_probe(struct usb_interface *interface, } } } + + /* Now make sure the PL-2303 is configured correctly. + * If not, give up now and hope this hack will work + * properly during a later invocation of usb_serial_probe + */ + if (num_bulk_in == 0 || num_bulk_out == 0) { + info("PL-2303 hack: descriptors matched but endpoints did not"); + kfree (serial); + return -ENODEV; + } } /* END HORRIBLE HACK FOR PL2303 */ #endif -#endif /* found all that we need */ info("%s converter detected", type->name); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 69ede41337e6..65164618696c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -669,7 +669,7 @@ static int clie_3_5_startup (struct usb_serial *serial) /* get the interface number */ result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQ_GET_INTERFACE, - USB_DIR_IN | USB_DT_DEVICE, + USB_DIR_IN | USB_RECIP_INTERFACE, 0, 0, &data, 1, HZ * 3); if (result < 0) { err("%s: get interface number failed: %d", __FUNCTION__, result); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 57ad099241fd..5ba0d8471674 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -334,6 +334,12 @@ static int whiteheat_attach (struct usb_serial *serial) command_port = &serial->port[COMMAND_PORT]; pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress); + /* + * When the module is reloaded the firmware is still there and + * the endpoints are still in the usb core unchanged. This is the + * unlinking bug in disguise. Same for the call below. + */ + usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't send command [%d]", serial->type->name, ret); @@ -344,6 +350,8 @@ static int whiteheat_attach (struct usb_serial *serial) } pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress); + /* See the comment on the usb_clear_halt() above */ + usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't get results [%d]", serial->type->name, ret); @@ -438,6 +446,10 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp) if (retval) goto exit; + /* Work around HCD bugs */ + usb_clear_halt(port->serial->dev, port->read_urb->pipe); + usb_clear_halt(port->serial->dev, port->write_urb->pipe); + /* Start reading from the device */ port->read_urb->dev = port->serial->dev; retval = usb_submit_urb(port->read_urb, GFP_KERNEL); @@ -489,7 +501,8 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) { dbg("%s - port %d", __FUNCTION__, port->number); - if (tty_hung_up_p(filp)) { + /* filp is NULL when called from usb_serial_disconnect */ + if (filp && (tty_hung_up_p(filp))) { return; } @@ -1145,6 +1158,9 @@ static int start_command_port(struct usb_serial *serial) command_info = (struct whiteheat_command_private *)command_port->private; spin_lock_irqsave(&command_info->lock, flags); if (!command_info->port_running) { + /* Work around HCD bugs */ + usb_clear_halt(serial->dev, command_port->read_urb->pipe); + command_port->read_urb->dev = serial->dev; retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); if (retval) { diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 8e1514ac51e2..980253839108 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -67,25 +67,23 @@ static int datafab_determine_lun(struct us_data *us, static inline int datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("datafab_bulk_read: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, len, NULL); } static inline int datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("datafab_bulk_write: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + data, len, NULL); } @@ -522,6 +520,7 @@ int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO); if (!us->extra) { diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 13c758c8a0e6..72112d97487a 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -108,72 +108,9 @@ struct freecom_status { /* All packets (except for status) are 64 bytes long. */ #define FCM_PACKET_LENGTH 64 -/* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this - * function simply determines if we're going to use scatter-gather or not, - * and acts appropriately. For now, it also re-interprets the error codes. - */ -static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount) -{ - int i; - int result = -1; - struct scatterlist *sg; - unsigned int total_transferred = 0; - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; - - /* are we scatter-gathering? */ - if (srb->use_sg) { - - /* loop over all the scatter gather structures and - * make the appropriate requests for each, until done - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { - - US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred); - - /* End this if we're done */ - if (transfer_amount == total_transferred) - break; - - /* transfer the lesser of the next buffer or the - * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); - total_transferred += transfer_amount - total_transferred; - } - - /* if we get an error, end the loop here */ - if (result) - break; - } - } - else - /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); - - /* return the result in the data structure itself */ - srb->result = result; -} - static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) + unsigned int ipipe, unsigned int opipe, int count) { freecom_udata_t extra = (freecom_udata_t) us->extra; struct freecom_xfer_wrap *fxfr = @@ -206,15 +143,15 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, /* Now transfer all of our blocks. */ US_DEBUGP("Start of read\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, ipipe, srb, count); US_DEBUGP("freecom_readdata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } static int freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) + int unsigned ipipe, unsigned int opipe, int count) { freecom_udata_t extra = (freecom_udata_t) us->extra; struct freecom_xfer_wrap *fxfr = @@ -248,10 +185,10 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, /* Now transfer all of our blocks. */ US_DEBUGP("Start of write\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, opipe, srb, count); US_DEBUGP("freecom_writedata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } /* @@ -262,7 +199,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) { struct freecom_cb_wrap *fcb; struct freecom_status *fst; - int ipipe, opipe; /* We need both pipes. */ + unsigned int ipipe, opipe; /* We need both pipes. */ int result; int partial; int length; @@ -276,8 +213,8 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP("Freecom TRANSPORT STARTED\n"); /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); + opipe = us->send_bulk_pipe; + ipipe = us->recv_bulk_pipe; /* The ATAPI Command always goes out first. */ fcb->Type = FCM_PACKET_ATAPI | 0x00; @@ -515,8 +452,7 @@ freecom_init (struct us_data *us) } } - result = usb_control_msg(us->pusb_dev, - usb_rcvctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->recv_ctrl_pipe, 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); buffer[32] = '\0'; US_DEBUGP("String returned from FC init is: %s\n", buffer); @@ -528,8 +464,7 @@ freecom_init (struct us_data *us) */ /* send reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from activate reset is %d\n", result); @@ -537,8 +472,7 @@ freecom_init (struct us_data *us) mdelay(250); /* clear reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from clear reset is %d\n", result); diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index f89bd597bbfe..76b1782a24c2 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -50,7 +50,7 @@ int usb_stor_euscsi_init(struct us_data *us) int result; US_DEBUGP("Attempting to init eUSCSI bridge...\n"); - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, 0x01, 0x0, &data, 0x1, 5*HZ); US_DEBUGP("-- result is %d\n", result); diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index f80db3ba115b..5fb82bfaa294 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -408,13 +408,13 @@ static int isd200_transfer_partial( struct us_data *us, { int result; int partial; - int pipe; + unsigned int pipe; /* calculate the appropriate pipe information */ if (dataDirection == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + pipe = us->recv_bulk_pipe; else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + pipe = us->send_bulk_pipe; /* transfer the data */ US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length); @@ -546,7 +546,6 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; int result; - int pipe; int partial; unsigned int transfer_amount; @@ -566,9 +565,6 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, bcb.Length = AtaCdbLength; - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, AtaCdb, bcb.Length); @@ -578,8 +574,8 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0xFF), le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, + US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ @@ -589,8 +585,9 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, else if (result == -EPIPE) { /* if we stall, we need to clear it before we go on */ - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - if (usb_stor_clear_halt(us, pipe) < 0) + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->send_bulk_pipe); + if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0) return ISD200_TRANSPORT_ERROR; } else if (result) return ISD200_TRANSPORT_ERROR; @@ -608,13 +605,10 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, * an explanation of how this code works. */ - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, + US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { return ISD200_TRANSPORT_ABORTED; @@ -622,13 +616,14 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - if (usb_stor_clear_halt(us, pipe) < 0) + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->recv_bulk_pipe); + if (usb_stor_clear_halt(us, us->recv_bulk_pipe) < 0) return ISD200_TRANSPORT_ERROR; /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, US_BULK_CS_WRAP_LEN, &partial); /* if the command was aborted, indicate that */ @@ -638,8 +633,9 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing halt for pipe 0x%x\n", + us->recv_bulk_pipe); + usb_stor_clear_halt(us, us->recv_bulk_pipe); return ISD200_TRANSPORT_ERROR; } } @@ -937,7 +933,7 @@ int isd200_write_config( struct us_data *us ) /* let's send the command via the control pipe */ result = usb_stor_control_msg( us, - usb_sndctrlpipe(us->pusb_dev,0), + us->send_ctrl_pipe, 0x01, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x0000, @@ -978,7 +974,7 @@ int isd200_read_config( struct us_data *us ) result = usb_stor_control_msg( us, - usb_rcvctrlpipe(us->pusb_dev,0), + us->recv_ctrl_pipe, 0x02, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x0000, diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index 34e639762b69..e599c83fbc31 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -62,13 +62,12 @@ static inline int jumpshot_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("jumpshot_bulk_read: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, len, NULL); } @@ -76,13 +75,12 @@ static inline int jumpshot_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("jumpshot_bulk_write: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + data, len, NULL); } @@ -95,12 +93,11 @@ static int jumpshot_get_status(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; // send the setup - rc = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev, 0), + rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, 0, 0xA0, 0, 7, &reply, 1); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; + if (rc != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (reply != 0x50) { US_DEBUGP("jumpshot_get_status: 0x%2x\n", @@ -160,10 +157,9 @@ static int jumpshot_read_data(struct us_data *us, command[5] |= (sector >> 24) & 0x0F; // send the setup + command - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 1, command, 7); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result != USB_STOR_XFER_GOOD) goto leave; // read the result @@ -247,9 +243,10 @@ static int jumpshot_write_data(struct us_data *us, command[5] |= (sector >> 24) & 0x0F; // send the setup + command - result = usb_storage_send_control( - us, usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 1, command, 7); + if (result != USB_STOR_XFER_GOOD) + goto leave; // send the data result = jumpshot_bulk_write(us, ptr, len); @@ -302,11 +299,10 @@ static int jumpshot_id_device(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; // send the setup - rc = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), + rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 6, command, 2); - if (rc != USB_STOR_TRANSPORT_GOOD) { + if (rc != USB_STOR_XFER_GOOD) { US_DEBUGP("jumpshot_id_device: Gah! " "send_control for read_capacity failed\n"); return rc; @@ -468,7 +464,7 @@ int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; - + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO); if (!us->extra) { diff --git a/drivers/usb/storage/raw_bulk.c b/drivers/usb/storage/raw_bulk.c index 4e3b755d5cdc..eef495ea97b5 100644 --- a/drivers/usb/storage/raw_bulk.c +++ b/drivers/usb/storage/raw_bulk.c @@ -13,219 +13,6 @@ #include "transport.h" #include "raw_bulk.h" -#ifdef CONFIG_USB_STORAGE_DEBUG -#define DEBUG_PRCT 12 -#else -#define DEBUG_PRCT 0 -#endif - -/* - * Send a control message and wait for the response. - * - * us - the pointer to the us_data structure for the device to use - * - * request - the URB Setup Packet's first 6 bytes. The first byte always - * corresponds to the request type, and the second byte always corresponds - * to the request. The other 4 bytes do not correspond to value and index, - * since they are used in a custom way by the SCM protocol. - * - * xfer_data - a buffer from which to get, or to which to store, any data - * that gets send or received, respectively, with the URB. Even though - * it looks like we allocate a buffer in this code for the data, xfer_data - * must contain enough allocated space. - * - * xfer_len - the number of bytes to send or receive with the URB. - * - */ - -int -usb_storage_send_control(struct us_data *us, - int pipe, - unsigned char request, - unsigned char requesttype, - unsigned int value, - unsigned int index, - unsigned char *xfer_data, - unsigned int xfer_len) { - - int result; - - // Send the URB to the device and wait for a response. - - /* Why are request and request type reversed in this call? */ - - result = usb_stor_control_msg(us, pipe, - request, requesttype, value, index, - xfer_data, xfer_len); - - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_send_control(): transfer aborted\n"); - return USB_STOR_TRANSPORT_ABORTED; - } - - // Check the return code for the command. - if (result < 0) { - - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -int -usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data, - unsigned int len, unsigned int *act_len) { - - int result; - int pipe; - - if (direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - result = usb_stor_bulk_msg(us, data, pipe, len, act_len); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("EPIPE: clearing endpoint halt for" - " pipe 0x%x, stalled at %d bytes\n", - pipe, *act_len); - if (usb_stor_clear_halt(us, pipe) < 0) - return USB_STOR_XFER_ERROR; - return USB_STOR_XFER_STALLED; - } - - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_storage_raw_bulk(): transfer aborted\n"); - return USB_STOR_XFER_ABORTED; - } - - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) - US_DEBUGP("raw_bulk(): device NAKed\n"); - else if (result == -EOVERFLOW) - US_DEBUGP("raw_bulk(): babble/overflow\n"); - else if (result == -ECONNRESET) - US_DEBUGP("raw_bulk(): asynchronous reset\n"); - else if (result != -EPIPE) - US_DEBUGP("raw_bulk(): unknown error %d\n", - result); - - return USB_STOR_XFER_ERROR; - } - - if (*act_len != len) { - US_DEBUGP("Warning: Transferred only %d of %d bytes\n", - *act_len, len); - return USB_STOR_XFER_SHORT; - } - -#if 0 - US_DEBUGP("raw_bulk(): Transferred %s %d of %d bytes\n", - (direction == SCSI_DATA_READ) ? "in" : "out", - *act_len, len); -#endif - - return USB_STOR_XFER_GOOD; -} - -int -usb_storage_bulk_transport(struct us_data *us, int direction, - unsigned char *data, unsigned int len, - int use_sg) { - - int result = USB_STOR_XFER_ERROR; - int transferred = 0; - int i; - struct scatterlist *sg; - unsigned int act_len; - - if (len == 0) - return USB_STOR_XFER_GOOD; - -#if DEBUG_PRCT - - if (direction == SCSI_DATA_WRITE && !use_sg) { - char string[64]; - - /* Debug-print the first N bytes of the write transfer */ - - strcpy(string, "wr: "); - for (i=0; i<len && i<DEBUG_PRCT; i++) { - sprintf(string+strlen(string), "%02X ", data[i]); - if ((i%16) == 15) { - US_DEBUGP("%s\n", string); - strcpy(string, "wr: "); - } - } - if ((i%16)!=0) - US_DEBUGP("%s\n", string); - } - - US_DEBUGP("SCM data %s transfer %d sg buffers %d\n", - (direction == SCSI_DATA_READ) ? "in" : "out", - len, use_sg); - -#endif /* DEBUG_PRCT */ - - if (!use_sg) - result = usb_storage_raw_bulk(us, direction, - data, len, &act_len); - else { - sg = (struct scatterlist *)data; - - for (i=0; i<use_sg && transferred<len; i++) { - unsigned char *buf; - unsigned int length; - - buf = sg_address(sg[i]); - length = len-transferred; - if (length > sg[i].length) - length = sg[i].length; - - result = usb_storage_raw_bulk(us, direction, - buf, length, &act_len); - if (result != USB_STOR_XFER_GOOD) - break; - transferred += length; - } - } - -#if DEBUG_PRCT - - if (direction == SCSI_DATA_READ && !use_sg) { - char string[64]; - - /* Debug-print the first N bytes of the read transfer */ - - strcpy(string, "rd: "); - for (i=0; i<len && i<act_len && i<DEBUG_PRCT; i++) { - sprintf(string+strlen(string), "%02X ", data[i]); - if ((i%16) == 15) { - US_DEBUGP("%s\n", string); - strcpy(string, "rd: "); - } - } - if ((i%16)!=0) - US_DEBUGP("%s\n", string); - } - -#endif /* DEBUG_PRCT */ - - return result; -} - /* * The routines below convert scatter-gather to single buffer. * Some drivers claim this is necessary. diff --git a/drivers/usb/storage/raw_bulk.h b/drivers/usb/storage/raw_bulk.h index 0361b39ec1f9..9a0e479eaf2e 100644 --- a/drivers/usb/storage/raw_bulk.h +++ b/drivers/usb/storage/raw_bulk.h @@ -1,21 +1,6 @@ #ifndef _USB_STORAGE_RAW_BULK_H_ #define _USB_STORAGE_RAW_BULK_H_ -/* usb bulk */ -extern int usb_storage_send_control( - struct us_data *us, int pipe, - unsigned char request, unsigned char requesttype, - unsigned int value, unsigned int index, - unsigned char *xfer_data, unsigned int xfer_len); - -extern int usb_storage_raw_bulk( - struct us_data *us, int direction, - unsigned char *data, unsigned int len, unsigned int *act_len); - -extern int usb_storage_bulk_transport( - struct us_data *us, int direction, - unsigned char *data, unsigned int len, int use_sg); - /* scatter-gather */ extern unsigned char *us_copy_from_sgbuf( unsigned char *content, int buflen, diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 718759ecd8d4..79ca7238af77 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -224,18 +224,21 @@ sddr09_send_command(struct us_data *us, unsigned char direction, unsigned char *xfer_data, unsigned int xfer_len) { - int pipe; + unsigned int pipe; unsigned char requesttype = (0x41 | direction); + int rc; // Get the receive or send control pipe number if (direction == USB_DIR_IN) - pipe = usb_rcvctrlpipe(us->pusb_dev,0); + pipe = us->recv_ctrl_pipe; else - pipe = usb_sndctrlpipe(us->pusb_dev,0); + pipe = us->send_ctrl_pipe; - return usb_storage_send_control(us, pipe, request, requesttype, + rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype, 0, 0, xfer_data, xfer_len); + return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : + USB_STOR_TRANSPORT_ERROR); } static int @@ -276,7 +279,6 @@ sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { 0x03, LUNBITS, 0, 0, buflen, 0, 0, 0, 0, 0, 0, 0 }; int result; - unsigned int act_len; result = sddr09_send_scsi_command(us, command, sizeof(command)); if (result != USB_STOR_TRANSPORT_GOOD) { @@ -284,7 +286,8 @@ sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { return result; } - result = usb_storage_raw_bulk(us, SCSI_DATA_READ, sensebuf, buflen, &act_len); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + sensebuf, buflen, NULL); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("request sense bulk in failed\n"); return USB_STOR_TRANSPORT_ERROR; @@ -343,11 +346,11 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress, return result; } - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - buf, bulklen, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, + buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_read2%d %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n", x, result); return USB_STOR_TRANSPORT_ERROR; } @@ -510,11 +513,11 @@ sddr09_writeX(struct us_data *us, return result; } - result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, - buf, bulklen, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, + buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_writeX %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -592,11 +595,11 @@ sddr09_read_sg_test_only(struct us_data *us) { if (!buf) return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - buf, bulklen, 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + buf, bulklen, NULL); kfree(buf); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -631,8 +634,8 @@ sddr09_read_status(struct us_data *us, unsigned char *status) { if (result != USB_STOR_TRANSPORT_GOOD) return result; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - data, sizeof(data), 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, sizeof(data), NULL); *status = data[0]; return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -954,7 +957,8 @@ sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { if (result != USB_STOR_TRANSPORT_GOOD) return result; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, 64, 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + content, 64, NULL); for (i = 0; i < 4; i++) deviceID[i] = content[i]; @@ -1368,6 +1372,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + srb->resid = 0; info = (struct sddr09_card_info *)us->extra; if (!info) { nand_init_ecc(); @@ -1544,17 +1549,16 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) if (srb->sc_data_direction == SCSI_DATA_WRITE || srb->sc_data_direction == SCSI_DATA_READ) { + unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE) + ? us->send_bulk_pipe : us->recv_bulk_pipe; US_DEBUGP("SDDR09: %s %d bytes\n", (srb->sc_data_direction == SCSI_DATA_WRITE) ? "sending" : "receiving", srb->request_bufflen); - result = usb_storage_bulk_transport(us, - srb->sc_data_direction, - srb->request_buffer, - srb->request_bufflen, - srb->use_sg); + result = usb_stor_bulk_transfer_srb(us, pipe, srb, + srb->request_bufflen); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index 20c9692c1027..484576cc3c90 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -75,10 +75,13 @@ static int sddr55_bulk_transport(struct us_data *us, int direction, unsigned char *data, unsigned int len) { struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; + unsigned int pipe = (direction == SCSI_DATA_READ) ? + us->recv_bulk_pipe : us->send_bulk_pipe; - if (len) - info->last_access = jiffies; - return usb_storage_bulk_transport(us, direction, data, len, 0); + if (!len) + return USB_STOR_XFER_GOOD; + info->last_access = jiffies; + return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL); } /* check if card inserted, if there is, update read_only status @@ -743,6 +746,7 @@ int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) unsigned short pages; struct sddr55_card_info *info; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc( sizeof(struct sddr55_card_info), GFP_NOIO); diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 21a74c17df38..8bec05bdd5b5 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -50,12 +50,6 @@ #include <linux/errno.h> #include <linux/slab.h> -extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); - #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) @@ -69,8 +63,8 @@ int usbat_read(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->recv_ctrl_pipe, access, 0xC0, (u16)reg, @@ -88,8 +82,8 @@ int usbat_write(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, access|0x01, 0x40, short_pack(reg, content), @@ -114,8 +108,8 @@ int usbat_set_shuttle_features(struct us_data *us, test_pattern, mask_byte, subcountL, subcountH }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -139,8 +133,11 @@ int usbat_read_block(struct us_data *us, LSB_of(len), MSB_of(len) }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + if (!len) + return USB_STOR_TRANSPORT_GOOD; + + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -148,10 +145,11 @@ int usbat_read_block(struct us_data *us, command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, + content, len, use_sg, NULL); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -178,8 +176,8 @@ int usbat_wait_not_busy(struct us_data *us, int minutes) { result = usbat_read(us, USBAT_ATA, 0x17, &status); - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; + if (result!=USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (status&0x01) { // check condition result = usbat_read(us, USBAT_ATA, 0x10, &status); return USB_STOR_TRANSPORT_FAILED; @@ -221,8 +219,11 @@ int usbat_write_block(struct us_data *us, LSB_of(len), MSB_of(len) }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + if (!len) + return USB_STOR_TRANSPORT_GOOD; + + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -230,10 +231,11 @@ int usbat_write_block(struct us_data *us, command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, + content, len, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -257,6 +259,8 @@ int usbat_rw_block_test(struct us_data *us, int minutes) { int result; + unsigned int pipe = (direction == SCSI_DATA_READ) ? + us->recv_bulk_pipe : us->send_bulk_pipe; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, // but that's what came out of the trace every single time. @@ -292,8 +296,8 @@ int usbat_rw_block_test(struct us_data *us, * that, we just return a failure. */ - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -301,16 +305,16 @@ int usbat_rw_block_test(struct us_data *us, (i==0 ? command : command+8), (i==0 ? 16 : 8)); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (i==0) { - result = usb_storage_bulk_transport(us, - SCSI_DATA_WRITE, - data, num_registers*2, 0); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, + data, num_registers*2, NULL); - if (result!=USB_STOR_XFER_GOOD) + if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } @@ -320,8 +324,8 @@ int usbat_rw_block_test(struct us_data *us, // direction == SCSI_DATA_WRITE ? "out" : "in", // len, use_sg); - result = usb_storage_bulk_transport(us, - direction, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, + pipe, content, len, use_sg, NULL); /* * If we get a stall on the bulk download, we'll retry @@ -352,8 +356,7 @@ int usbat_rw_block_test(struct us_data *us, if (direction==SCSI_DATA_READ && i==0) { if (usb_stor_clear_halt(us, - usb_sndbulkpipe(us->pusb_dev, - us->ep_out)) < 0) + us->send_bulk_pipe) < 0) return USB_STOR_TRANSPORT_ERROR; } @@ -365,8 +368,8 @@ int usbat_rw_block_test(struct us_data *us, direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, &status); - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; + if (result!=USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (status&0x01) // check condition return USB_STOR_TRANSPORT_FAILED; if (status&0x20) // device fault @@ -412,8 +415,8 @@ int usbat_multiple_write(struct us_data *us, data[1+(i<<1)] = data_out[i]; } - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -421,11 +424,11 @@ int usbat_multiple_write(struct us_data *us, command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, - SCSI_DATA_WRITE, data, num_registers*2, 0); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, data, num_registers*2, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -438,8 +441,8 @@ int usbat_read_user_io(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->recv_ctrl_pipe, 0x82, 0xC0, 0, @@ -456,8 +459,8 @@ int usbat_write_user_io(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x82, 0x40, short_pack(enable_flags, data_flags), @@ -589,7 +592,6 @@ int usbat_handle_read10(struct us_data *us, static int hp_8200e_select_and_test_registers(struct us_data *us) { - int result; int selector; unsigned char status; @@ -597,44 +599,44 @@ static int hp_8200e_select_and_test_registers(struct us_data *us) { for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { - if ( (result = usbat_write(us, USBAT_ATA, 0x16, selector)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ATA, 0x16, selector) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x17, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x17, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x16, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x16, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_write(us, USBAT_ATA, 0x14, 0x55)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ATA, 0x14, 0x55) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_write(us, USBAT_ATA, 0x15, 0xAA)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ATA, 0x15, 0xAA) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; } - return result; + return USB_STOR_TRANSPORT_GOOD; } int init_8200e(struct us_data *us) { @@ -644,44 +646,44 @@ int init_8200e(struct us_data *us) { // Enable peripheral control signals - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 1\n"); wait_ms(2000); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 2\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 3\n"); // Reset peripheral, enable periph control signals // (bring reset signal up) - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 4\n"); // Enable periph control signals // (bring reset signal down) - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 5\n"); @@ -689,23 +691,23 @@ int init_8200e(struct us_data *us) { // Write 0x80 to ISA port 0x3F - if ( (result = usbat_write(us, USBAT_ISA, 0x3F, 0x80)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ISA, 0x3F, 0x80) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 6\n"); // Read ISA port 0x27 - if ( (result = usbat_read(us, USBAT_ISA, 0x27, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ISA, 0x27, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 7\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 8\n"); @@ -715,32 +717,32 @@ int init_8200e(struct us_data *us) { US_DEBUGP("INIT 9\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 10\n"); // Enable periph control signals and card detect - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 11\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 12\n"); wait_ms(1400); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 13\n"); @@ -750,14 +752,14 @@ int init_8200e(struct us_data *us) { US_DEBUGP("INIT 14\n"); - if ( (result = usbat_set_shuttle_features(us, - 0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_set_shuttle_features(us, + 0x83, 0x00, 0x88, 0x08, 0x15, 0x14) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 15\n"); - return result; + return USB_STOR_TRANSPORT_ERROR; } /* @@ -773,6 +775,7 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) int i; char string[64]; + srb->resid = 0; len = srb->request_bufflen; /* Send A0 (ATA PACKET COMMAND). @@ -863,17 +866,16 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) // How many bytes to read in? Check cylL register - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) { + return USB_STOR_TRANSPORT_ERROR; } - if (len>0xFF) { // need to read cylH also + if (len > 0xFF) { // need to read cylH also len = status; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, - &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) { + return USB_STOR_TRANSPORT_ERROR; } len += ((unsigned int)status)<<8; } diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 9303b8b502a7..6281a3e5e81a 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -488,7 +488,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, /* This is our function to emulate usb_bulk_msg() with enough control * to make aborts/resets/timeouts work */ -int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, +int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe, unsigned int len, unsigned int *act_len) { int status; @@ -515,13 +515,12 @@ int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, * Since many vendors in this space limit their testing to interoperability * with these two OSes, specification violations like this one are common. */ -int usb_stor_clear_halt(struct us_data *us, int pipe) +int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) { int result; int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); - result = usb_stor_control_msg(us, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_control_msg(us, us->send_ctrl_pipe, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0); /* note: no 3*HZ timeout */ US_DEBUGP("usb_stor_clear_halt: result=%d\n", result); @@ -542,37 +541,81 @@ int usb_stor_clear_halt(struct us_data *us, int pipe) } /* - * Transfer one SCSI scatter-gather buffer via bulk transfer + * Transfer one control message * - * Note that this function is necessary because we want the ability to - * use scatter-gather memory. Good performance is achieved by a combination - * of scatter-gather and clustering (which makes each chunk bigger). + * This function does basically the same thing as usb_stor_control_msg() + * above, except that return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. + */ +int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size) { + int result; + + US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x " + "value=%04x index=%02x len=%d\n", + request, requesttype, value, index, size); + result = usb_stor_control_msg(us, pipe, request, requesttype, + value, index, data, size); + US_DEBUGP("usb_stor_control_msg returned %d\n", result); + + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("-- transfer aborted\n"); + return USB_STOR_XFER_ABORTED; + } + + /* a stall indicates a protocol error */ + if (result == -EPIPE) { + US_DEBUGP("-- stall on control pipe\n"); + return USB_STOR_XFER_ERROR; + } + + /* some other serious problem here */ + if (result < 0) { + US_DEBUGP("-- unknown error\n"); + return USB_STOR_XFER_ERROR; + } + + /* was the entire command transferred? */ + if (result < size) { + US_DEBUGP("-- transferred only %d bytes\n", result); + return USB_STOR_XFER_SHORT; + } + + US_DEBUGP("-- transfer completed successfully\n"); + return USB_STOR_XFER_GOOD; +} + +/* + * Transfer one buffer via bulk transfer + * + * This function does basically the same thing as usb_stor_bulk_msg() + * above, except that: * - * Note that the lower layer will always retry when a NAK occurs, up to the - * timeout limit. Thus we don't have to worry about it for individual - * packets. + * 1. If the bulk pipe stalls during the transfer, the halt is + * automatically cleared; + * 2. Return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. */ -int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) +int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len) { int result; int partial; - int pipe; - - /* calculate the appropriate pipe information */ - if (us->srb->sc_data_direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* transfer the data */ - US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length); + US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %d bytes\n", length); result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length); + if (act_len) + *act_len = partial; /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x," + " stalled at %d bytes\n", pipe, partial); if (usb_stor_clear_halt(us, pipe) < 0) return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; @@ -580,25 +623,25 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + US_DEBUGP("-- transfer aborted\n"); return USB_STOR_XFER_ABORTED; } /* NAK - that means we've retried a few times already */ if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); + US_DEBUGP("-- device NAKed\n"); return USB_STOR_XFER_ERROR; } /* the catch-all error case */ if (result) { - US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); + US_DEBUGP("-- unknown error\n"); return USB_STOR_XFER_ERROR; } /* did we send all the data? */ if (partial == length) { - US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n"); + US_DEBUGP("-- transfer complete\n"); return USB_STOR_XFER_GOOD; } @@ -611,59 +654,51 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses usb_stor_transfer_partial to achieve its goals -- this + * Note that this uses usb_stor_transfer_buf to achieve its goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ -void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us) +int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, + char *buf, unsigned int length_left, int use_sg, int *residual) { int i; int result = -1; struct scatterlist *sg; - unsigned int total_transferred = 0; - unsigned int transfer_amount; - - /* calculate how much we want to transfer */ - transfer_amount = usb_stor_transfer_length(srb); - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; + unsigned int amount; + unsigned int partial; /* are we scatter-gathering? */ - if (srb->use_sg) { + if (use_sg) { /* loop over all the scatter gather structures and * make the appropriate requests for each, until done */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { + sg = (struct scatterlist *) buf; + for (i = 0; (i < use_sg) && (length_left > 0); (i++, ++sg)) { /* transfer the lesser of the next buffer or the * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); + amount = sg->length < length_left ? + sg->length : length_left; + result = usb_stor_bulk_transfer_buf(us, pipe, + sg_address(*sg), amount, &partial); + length_left -= partial; /* if we get an error, end the loop here */ - if (result) + if (result != USB_STOR_XFER_GOOD) break; } - } - else + } else { /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); + result = usb_stor_bulk_transfer_buf(us, pipe, buf, + length_left, &partial); + length_left -= partial; + } - /* return the result in the data structure itself */ - srb->result = result; + /* store the residual and return the error code */ + if (residual) + *residual = length_left; + return result; } /*********************************************************************** @@ -742,7 +777,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * Also, if we have a short transfer on a command that can't have * a short transfer, we're going to do this. */ - if ((srb->result == USB_STOR_XFER_SHORT) && + if ((srb->resid > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -974,6 +1009,7 @@ void usb_stor_CBI_irq(struct urb *urb) int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* re-initialize the mutex so that we avoid any races with @@ -985,14 +1021,14 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); + if (result != USB_STOR_XFER_GOOD) { /* Reset flag for status notification */ clear_bit(US_FLIDX_IP_WANTED, &us->flags); } @@ -1003,22 +1039,16 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_ABORTED; } - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (result < 0) { + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length > 0) { + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CBI data stage result is 0x%x\n", result); /* report any errors */ @@ -1093,39 +1123,34 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) */ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); - return USB_STOR_TRANSPORT_ABORTED; - } + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); + return USB_STOR_TRANSPORT_ABORTED; + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length) + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CB data stage result is 0x%x\n", result); /* report any errors */ @@ -1153,12 +1178,12 @@ int usb_stor_Bulk_max_lun(struct us_data *us) { unsigned char data; int result; - int pipe; - /* issue the command -- use usb_control_msg() because - * this is not a scsi queued-command */ - pipe = usb_rcvctrlpipe(us->pusb_dev, 0); - result = usb_control_msg(us->pusb_dev, pipe, + /* Issue the command -- use usb_control_msg() because this is + * not a scsi queued-command. Also note that at this point the + * cached pipe values have not yet been stored. */ + result = usb_control_msg(us->pusb_dev, + usb_rcvctrlpipe(us->pusb_dev, 0), US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, @@ -1179,13 +1204,13 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) { struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; - int pipe; int partial; /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); + bcb.DataTransferLength = cpu_to_le32(transfer_length); bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; @@ -1193,9 +1218,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) bcb.Lun |= srb->target << 4; bcb.Length = srb->cmd_len; - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, srb->cmnd, bcb.Length); @@ -1205,8 +1227,8 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0x0F), bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, + US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ @@ -1217,47 +1239,45 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->send_bulk_pipe); + result = usb_stor_clear_halt(us, us->send_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); return USB_STOR_TRANSPORT_ABORTED; } - if (result < 0) - return USB_STOR_TRANSPORT_ERROR; - result = -EPIPE; + return USB_STOR_TRANSPORT_ERROR; } 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 */ - if (result == 0) { - /* send/receive data payload, if there is any */ - if (bcb.DataTransferLength) { - usb_stor_transfer(srb, us); - result = srb->result; - US_DEBUGP("Bulk data transfer result 0x%x\n", result); - - /* if it was aborted, we need to indicate that */ - if (result == USB_STOR_XFER_ABORTED) - return USB_STOR_TRANSPORT_ABORTED; - } + /* DATA STAGE */ + /* send/receive data payload, if there is any */ + if (transfer_length) { + unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + us->recv_bulk_pipe : us->send_bulk_pipe; + result = usb_stor_bulk_transfer_srb(us, pipe, srb, + transfer_length); + US_DEBUGP("Bulk data transfer result 0x%x\n", result); + + /* if it was aborted, we need to indicate that */ + if (result == USB_STOR_XFER_ABORTED) + return USB_STOR_TRANSPORT_ABORTED; + if (result == USB_STOR_XFER_ERROR) + return USB_STOR_TRANSPORT_ERROR; } /* See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, + US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1267,8 +1287,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->recv_bulk_pipe); + result = usb_stor_clear_halt(us, us->recv_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1280,7 +1301,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ @@ -1291,8 +1312,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing halt for pipe 0x%x\n", + us->recv_bulk_pipe); + result = usb_stor_clear_halt(us, us->recv_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1364,7 +1386,7 @@ static int usb_stor_reset_common(struct us_data *us, * following a powerup or USB attach event. */ /* Use usb_control_msg() because this is not a queued-command */ - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, request, requesttype, value, index, data, size, 20*HZ); if (result < 0) @@ -1377,14 +1399,12 @@ static int usb_stor_reset_common(struct us_data *us, /* Use usb_clear_halt() because this is not a queued-command */ US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + result = usb_clear_halt(us->pusb_dev, us->recv_bulk_pipe); if (result < 0) goto Done; US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + result = usb_clear_halt(us->pusb_dev, us->send_bulk_pipe); Done: diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 914ecb8be155..7b40bc350ae0 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -115,7 +115,7 @@ struct bulk_cs_wrap { #define US_BULK_GET_MAX_LUN 0xfe /* - * usb_stor_transfer() return codes, in order of severity + * usb_stor_bulk_transfer_xxx() return codes, in order of severity */ #define USB_STOR_XFER_GOOD 0 /* good transfer */ #define USB_STOR_XFER_SHORT 1 /* transfered less than expected */ @@ -151,14 +151,26 @@ extern int usb_stor_Bulk_reset(struct us_data*); extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*); extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); extern void usb_stor_abort_transport(struct us_data*); -extern int usb_stor_transfer_partial(struct us_data*, char*, int); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); +extern int usb_stor_bulk_msg(struct us_data *us, void *data, + unsigned int pipe, unsigned int len, unsigned int *act_len); extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size); -extern int usb_stor_clear_halt(struct us_data*, int ); -extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe); +extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size); +extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len); +extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, int use_sg, int *residual); + +static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us, + unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) { + return usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, + length, srb->use_sg, &srb->resid); +} + #endif diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index f423b7e69ab5..6eebb126156d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -525,6 +525,12 @@ static int usb_stor_allocate_urbs(struct us_data *ss) int maxp; int result; + /* calculate and store the pipe values */ + ss->send_bulk_pipe = usb_sndbulkpipe(ss->pusb_dev, ss->ep_out); + ss->recv_bulk_pipe = usb_rcvbulkpipe(ss->pusb_dev, ss->ep_in); + ss->send_ctrl_pipe = usb_sndctrlpipe(ss->pusb_dev, 0); + ss->recv_ctrl_pipe = usb_rcvctrlpipe(ss->pusb_dev, 0); + /* allocate the usb_ctrlrequest for control packets */ US_DEBUGP("Allocating usb_ctrlrequest\n"); ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 2a9e9a1f6c2e..9b078b5c4c2a 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -134,6 +134,10 @@ struct us_data { struct semaphore dev_semaphore; /* protect pusb_dev */ struct usb_device *pusb_dev; /* this usb_device */ unsigned long flags; /* from filter initially */ + unsigned int send_bulk_pipe; /* cached pipe values */ + unsigned int recv_bulk_pipe; + unsigned int send_ctrl_pipe; + unsigned int recv_ctrl_pipe; /* information about the device -- always good */ char vendor[USB_STOR_STRING_LEN]; diff --git a/include/linux/usb.h b/include/linux/usb.h index 5dbc3cb115f7..fe144bda56f0 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -222,12 +222,42 @@ struct usb_interface_descriptor { int extralen; }; +/** + * struct usb_interface - what usb device drivers talk to + * @altsetting: array of interface descriptors, one for each alternate + * setting that may be selected. each one includes a set of + * endpoint configurations. + * @num_altsetting: number of altsettings defined. + * @act_altsetting: index of current altsetting. this number is always + * less than num_altsetting. after the device is configured, each + * interface uses its default setting of zero. + * @dev: driver model's view of this device + * + * USB device drivers attach to interfaces on a physical device. Each + * interface encapsulates a single high level function, such as feeding + * an audio stream to a speaker or reporting a change in a volume control. + * Many USB devices only have one interface. The protocol used to talk to + * an interface's endpoints can be defined in a usb "class" specification, + * or by a product's vendor. The (default) control endpoint is part of + * every interface, but is never listed among the interface's descriptors. + * + * The driver that is bound to the interface can use standard driver model + * calls such as dev_get_drvdata() on the dev member of this structure. + * + * Each interface may have alternate settings. The initial configuration + * of a device sets the first of these, but the device driver can change + * that setting using usb_set_interface(). Alternate settings are often + * used to control the the use of periodic endpoints, such as by having + * different endpoints use different amounts of reserved USB bandwidth. + * All standards-conformant USB devices that use isochronous endpoints + * will use them in non-default settings. + */ struct usb_interface { struct usb_interface_descriptor *altsetting; - int act_altsetting; /* active alternate setting */ - int num_altsetting; /* number of alternate settings */ - int max_altsetting; /* total memory allocated */ + unsigned act_altsetting; /* active alternate setting */ + unsigned num_altsetting; /* number of alternate settings */ + unsigned max_altsetting; /* total memory allocated */ struct usb_driver *driver; /* driver */ struct device dev; /* interface specific device info */ @@ -670,6 +700,7 @@ extern void usb_deregister_dev(int num_minors, int start_minor); extern int usb_device_probe(struct device *dev); extern int usb_device_remove(struct device *dev); +extern int usb_disabled(void); /* -------------------------------------------------------------------------- */ diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 80966ed8e288..a90d968374eb 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -397,6 +397,7 @@ struct video_code #define VID_HARDWARE_PWC 31 /* Philips webcams */ #define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ #define VID_HARDWARE_CPIA2 33 +#define VID_HARDWARE_VICAM 34 #endif /* __LINUX_VIDEODEV_H */ |
