Commit 31c96625 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/linux/linux/BK/bleeding-2.5

into kroah.com:/home/linux/linux/BK/gregkh-2.5
parents e0970dce 321d6a82
......@@ -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
......
......@@ -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
......@@ -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
......
......@@ -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
......
/* 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)");
......@@ -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;
......
......@@ -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 */
};
......
......@@ -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 @@ static int create_special_files (void)
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)
......
......@@ -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;
}
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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));
......
......@@ -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;
......
......@@ -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);
......
......@@ -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)
......
......@@ -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)
......
......@@ -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)))
......
......@@ -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
/* -*- 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)
{
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)
{
adr = (unsigned long) mem;
while (size > 0) {
mem_map_reserve(vmalloc_to_page((void *)adr));
adr+=PAGE_SIZE;
size-=PAGE_SIZE;
}
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)
{
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;
adr += PAGE_SIZE;
size -= PAGE_SIZE;
}
vfree(mem);
}
}
/******************************************************************************
*
* Foo Bar
*
******************************************************************************/
struct vicam_camera {
u16 shutter_speed; // capture shutter speed
u16 gain; // capture gain
/**
* usb_vicam_debug_data
*/
static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data)
{
int i;
u8 *raw_image; // raw data captured from the camera
u8 *framebuf; // processed data in RGB24 format
if (!debug)
return;
struct video_device vdev; // v4l video device
struct usb_device *udev; // usb device
printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
function, size);
for (i = 0; i < size; ++i) {
printk ("%.2x ", data[i]);
}
printk ("\n");
}
struct semaphore busy_lock; // guard against SMP multithreading
/*****************************************************************************
*
* Send command to vicam
*
*****************************************************************************/
bool is_initialized;
u8 open_count;
u8 bulkEndpoint;
bool needsDummyRead;
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;
// 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.
/* Needs to return data I think, works for sending though */
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;
if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0)
return status;
v->flags = 0;
v->tuners = 0;
v->type = VIDEO_TYPE_CAMERA;
strcpy(v->name, "Camera");
if (state) {
send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
}
return 0;
}
static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v)
static int
vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long ul_arg)
{
dbg("vicam_set_channel");
void *arg = (void *)ul_arg;
struct vicam_camera *cam = file->private_data;
int retval = 0;
if (v->channel != 0)
return -EINVAL;
if (!cam)
return -ENODEV;
return 0;
}
/* make this _really_ smp-safe */
if (down_interruptible(&cam->busy_lock))
return -EINTR;
static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm)
{
int i;
switch (ioctlnr) {
/* query capabilites */
case VIDIOCGCAP:
{
struct video_capability b;
dbg("vicam_get_mmapbuffer");
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;
memset(vm, 0, sizeof(vm));
vm->size = VICAM_NUMFRAMES * vicam->maxframesize;
vm->frames = VICAM_NUMFRAMES;
if (copy_to_user(arg, &b, sizeof (b)))
retval = -EFAULT;
for (i=0; i<VICAM_NUMFRAMES; i++)
vm->offsets[i] = vicam->maxframesize * i;
break;
}
/* get/set video source - we are a camera and nothing else */
case VIDIOCGCHAN:
{
struct video_channel v;
return 0;
}
DBG("VIDIOCGCHAN\n");
if (copy_from_user(&v, arg, sizeof (v))) {
retval = -EFAULT;
break;
}
if (v.channel != 0) {
retval = -EINVAL;
break;
}
static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p)
{
dbg("vicam_get_picture");
v.channel = 0;
strcpy(v.name, "Camera");
v.tuners = 0;
v.flags = 0;
v.type = VIDEO_TYPE_CAMERA;
v.norm = 0;
/* 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 (copy_to_user(arg, &v, sizeof (v)))
retval = -EFAULT;
break;
}
return 0;
}
case VIDIOCSCHAN:
{
int v;
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);
}
if (copy_from_user(&v, arg, sizeof (v)))
retval = -EFAULT;
DBG("VIDIOCSCHAN %d\n", v);
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
}
if (retval == 0 && v != 0)
retval = -EINVAL;
static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p)
{
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);
break;
}
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;
/* 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;
}
return 0;
}
case VIDIOCSPICT:
{
struct video_picture *vp = (struct video_picture *) arg;
/* FIXME - vicam_sync_frame - important */
static int vicam_sync_frame(struct usb_vicam *vicam, int frame)
{
dbg("vicam_sync_frame");
DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth,
vp->palette);
if(frame <0 || frame >= VICAM_NUMFRAMES)
return -EINVAL;
cam->gain = vp->brightness >> 8;
/* Probably need to handle various cases */
/* ret=vicam_newframe(vicam, frame);
vicam->frame[frame].grabstate=FRAME_UNUSED;
*/
return 0;
}
if (vp->depth != 24
|| vp->palette != VIDEO_PALETTE_RGB24)
retval = -EINVAL;
static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw)
{
dbg("vicam_get_window");
break;
}
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;
/* 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;
}
return 0;
}
case VIDIOCSWIN:
{
static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw)
{
info("vicam_set_window");
struct video_window *vw = (struct video_window *) arg;
DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
if (vw->flags)
return -EINVAL;
if (vw->clipcount)
return -EINVAL;
if ( vw->width != 320 || vw->height != 240 )
retval = -EFAULT;
if (vicam->win.width == vw->width && vicam->win.height == vw->height)
return 0;
break;
}
/* Pick largest mode that is smaller than specified res */
/* If specified res is too small reject */
/* mmap interface */
case VIDIOCGMBUF:
{
struct video_mbuf vm;
int i;
/* Add urb send to device... */
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;
vicam->win.width = vw->width;
vicam->win.height = vw->height;
params_changed(vicam);
if (copy_to_user
((void *) arg, (void *) &vm, sizeof (vm)))
retval = -EFAULT;
return 0;
}
break;
}
/* FIXME - vicam_mmap_capture - important */
static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm)
{
dbg("vicam_mmap_capture");
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
// int video_size;
/* usbvideo.c looks good for using here */
if (copy_from_user
((void *) &vm, (void *) arg, sizeof (vm))) {
retval = -EFAULT;
break;
}
/*
if (vm->frame >= VICAM_NUMFRAMES)
return -EINVAL;
if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED)
return -EBUSY;
vicam->frame[vm->frame].grabstate=FRAME_READY;
*/
DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
/* No need to vicam_set_window here according to Alan */
if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
retval = -EINVAL;
/*
if (!vicam->streaming)
vicam_start_stream(vicam);
*/
// 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
/* set frame as ready */
break;
}
return 0;
}
case VIDIOCSYNC:
{
int frame;
/*****************************************************************************
*
* Video4Linux
*
*****************************************************************************/
if (copy_from_user((void *) &frame, arg, sizeof (int))) {
retval = -EFAULT;
break;
}
DBG("VIDIOCSYNC: %d\n", frame);
static int vicam_v4l_open(struct inode *inode, struct file *file)
{
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;
} 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;
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(&vicam->sem);
return err;
up(&cam->busy_lock);
return retval;
}
static int vicam_v4l_close(struct inode *inode, struct file *file)
static int
vicam_open(struct inode *inode, struct file *file)
{
struct video_device *vdev = file->private_data;
struct usb_vicam *vicam = (struct usb_vicam *)vdev;
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");
}
dbg("vicam_v4l_close");
down_interruptible(&cam->busy_lock);
down(&vicam->sem);
if (cam->open_count > 0) {
printk(KERN_INFO
"vicam_open called on already opened camera");
up(&cam->busy_lock);
return -EBUSY;
}
#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 (!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;
}
rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES);
vicam->fbuf = 0;
vicam->open_count=0;
file->private_data = NULL;
set_camera_power(cam, 1);
cam->needsDummyRead = 1;
cam->open_count++;
up(&cam->busy_lock);
file->private_data = cam;
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;
}
static int vicam_v4l_read(struct file *file, char *user_buf,
size_t buflen, loff_t *ppos)
static int
vicam_close(struct inode *inode, struct file *file)
{
struct video_device *vdev = file->private_data;
//struct usb_vicam *vicam = (struct usb_vicam *)vdev;
struct vicam_camera *cam = file->private_data;
DBG("close\n");
set_camera_power(cam, 0);
dbg("vicam_v4l_read(%d)", buflen);
cam->open_count--;
if (!vdev || !buf)
return -EFAULT;
return 0;
}
if (copy_to_user(user_buf, buf2, buflen))
return -EFAULT;
return buflen;
inline int pin(int x)
{
return((x > 255) ? 255 : ((x < 0) ? 0 : x));
}
static int vicam_v4l_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
inline void writepixel(char *rgb, int Y, int Cr, int Cb)
{
struct video_device *vdev = file->private_data;
struct usb_vicam *vicam = (struct usb_vicam *)vdev;
int ret = -EL3RST;
Y = 1160 * (Y - 16);
if (!vicam->udev)
return -EIO;
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 );
}
down(&vicam->sem);
#define DATA_HEADER_SIZE 64
switch (cmd) {
case VIDIOCGCAP:
// --------------------------------------------------------------------------------
// 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)
{
int x,y;
int Cr, Cb;
int sign;
int prevX, nextX, prevY, nextY;
int skip;
unsigned char *src;
unsigned char *dst;
prevY = 512;
nextY = 512;
src = data + DATA_HEADER_SIZE;
dst = rgb;
for(y = 1; y < 241; y += 2)
{
struct video_capability *b = arg;
ret = vicam_get_capability(vicam,b);
dbg("name %s",b->name);
break;
}
case VIDIOCGFBUF:
// even line
sign = 1;
prevX = 1;
nextX = 1;
skip = 0;
dst = rgb + (y-1)*320*3;
for(x = 0; x < 512; x++)
{
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;
if(x == 512-1)
nextX = -1;
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;
writepixel(
dst + ((x*5)>>3)*3,
src[0] + (sign * (Cr >> 1)),
Cr,
Cb);
src++;
sign *= -1;
prevX = -1;
}
case VIDIOCGWIN:
prevY = -512;
if(y == (242 - 2))
nextY = -512;
// odd line
sign = 1;
prevX = 1;
nextX = 1;
skip = 0;
dst = rgb + (y)*320*3;
for(x = 0; x < 512; x++)
{
struct video_window *vw = arg;
ret = vicam_get_window(vicam, vw);
break;
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;
}
case VIDIOCSWIN:
{
struct video_window *vw = arg;
ret = vicam_set_window(vicam, vw);
break;
}
case VIDIOCGCHAN:
{
struct video_channel *v = arg;
}
ret = vicam_get_channel(vicam,v);
break;
static void
read_frame(struct vicam_camera *cam, int framenum)
{
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 {
// Long exposure
realShutter = 15600 / cam->shutter_speed - 1;
request[4] = 0;
request[5] = 0;
request[6] = realShutter & 0xFF;
request[7] = realShutter >> 8;
}
case VIDIOCSCHAN:
{
struct video_channel *v = arg;
ret = vicam_set_channel(vicam,v);
break;
// Per John Markus Bjrndalen, 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
n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
if (n < 0) {
printk(KERN_ERR
" Problem sending frame capture control message");
return;
}
case VIDIOCGPICT:
{
struct video_picture *p = arg;
ret = vicam_get_picture(vicam,p);
break;
n = usb_bulk_msg(cam->udev,
usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
cam->raw_image,
512 * 242 + 128, &actual_length, HZ*10);
if (n < 0) {
printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
n);
}
case VIDIOCSPICT:
{
struct video_picture *p = arg;
ret = vicam_set_picture(vicam,p);
break;
vicam_decode_color(cam->raw_image,
cam->framebuf +
framenum * VICAM_MAX_FRAME_SIZE );
cam->framebuf_size =
320 * 240 * VICAM_BYTES_PER_PIXEL;
cam->framebuf_read_start = 0;
return;
}
static int
vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos )
{
struct vicam_camera *cam = file->private_data;
DBG("read %d bytes.\n", (int) count);
if (!buf)
return -EINVAL;
if (!count)
return -EINVAL;
// 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 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;
read_frame(cam, 0);
case VIDIOCCAPTURE:
case VIDIOCSFBUF:
case VIDIOCGTUNER:
case VIDIOCSTUNER:
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOCGUNIT:
ret = -EINVAL;
if (count > cam->framebuf_size)
count = cam->framebuf_size;
default:
{
info("vicam_v4l_ioctl - %ui",cmd);
ret = -ENOIOCTLCMD;
}
} /* end switch */
copy_to_user(buf, cam->framebuf, count);
up(&vicam->sem);
return ret;
}
if (count != cam->framebuf_size)
cam->framebuf_read_start = count;
else
cam->framebuf_size = 0;
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);
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 (!cam)
return -ENODEV;
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);
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);
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;
static void vicam_bulk(struct urb *urb)
*start = page + off;
return len;
}
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;
}
/* 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];
/* 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));
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));
struct vicam_camera *cam = (struct vicam_camera *) ptr;
char name[7];
if (!cam || !cam->proc_entry)
return;
sprintf(name, "video%d", cam->vdev.minor);
remove_proc_entry(name, vicam_proc_root);
cam->proc_entry = NULL;
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)
#endif
int
vicam_video_init(struct video_device *vdev)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_vicam *vicam;
char *camera_name=NULL;
// This would normally create the proc entry for this camera
#ifdef CONFIG_PROC_FS
vicam_create_proc_entry(vdev->priv);
#endif
return 0;
}
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);
printk(KERN_INFO "ViCam based webcam connected\n");
vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL);
if (vicam == NULL) {
err ("couldn't kmalloc vicam struct");
return -ENOMEM;
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));
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
if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
err("video_register_device");
usb_free_urb(vicam->readurb);
kfree(vicam);
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);
printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
init_MUTEX (&vicam->sem);
init_waitqueue_head(&vicam->wait);
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;
vicam = dev_get_drvdata (&intf->dev);
struct vicam_camera *cam = dev_get_drvdata(&intf->dev);
dev_set_drvdata (&intf->dev, NULL);
dev_set_drvdata ( &intf->dev, NULL );
usb_put_dev(cam->udev);
if (vicam) {
video_unregister_device(&vicam->vdev);
vicam->udev = NULL;
/*
vicam->frame[0].grabstate = FRAME_ERROR;
vicam->frame[1].grabstate = FRAME_ERROR;
*/
cam->udev = NULL;
/* Free buffers and shit */
info("%s disconnected", vicam->camera_name);
synchronize(vicam);
video_unregister_device(&cam->vdev);
if (!vicam->open_count) {
/* Other random junk */
usb_free_urb(vicam->readurb);
kfree(vicam);
vicam = NULL;
}
}
}
#ifdef CONFIG_PROC_FS
vicam_destroy_proc_entry(cam);
#endif
/* 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,
};
if (cam->raw_image)
kfree(cam->raw_image);
if (cam->framebuf)
rvfree(cam->framebuf,
VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
/******************************************************************************
*
* Module Routines
*
******************************************************************************/
kfree(cam);
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");
printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
}
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");
/*
*
* 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
/*
*
* 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
......@@ -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
......
......@@ -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,
};
......
......@@ -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 (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,9 +1260,18 @@ 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 */
......
......@@ -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);
......
......@@ -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) {
......
......@@ -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) {
......
......@@ -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);
......
......@@ -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);
......
......@@ -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,
......
......@@ -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) {
......
......@@ -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.
......
#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,
......
......@@ -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);
......
......@@ -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)
if (!len)
return USB_STOR_XFER_GOOD;
info->last_access = jiffies;
return usb_storage_bulk_transport(us, direction, data, len, 0);
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);
......
......@@ -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;
}
......
......@@ -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) {
US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
/* 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;
}
/* a stall indicates a protocol error */
if (result == -EPIPE) {
US_DEBUGP("-- Stall on control pipe\n");
return USB_STOR_TRANSPORT_ERROR;
}
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;
} 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) {
/* DATA STAGE */
/* send/receive data payload, if there is any */
if (bcb.DataTransferLength) {
usb_stor_transfer(srb, us);
result = srb->result;
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:
......
......@@ -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
......@@ -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);
......
......@@ -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];
......
......@@ -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);
/* -------------------------------------------------------------------------- */
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment