Commit 1a11f106 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

merge

parents 3f69168f 9616878a
......@@ -2669,6 +2669,13 @@ S: Kasarmikatu 11 A4
S: 70110 Kuopio
S: Finland
N: Luca Risolia
E: luca_ing@libero.it
D: V4L driver for W996[87]CF JPEG USB Dual Mode Camera Chip
S: Via Libertà 41/a
S: Osio Sotto, 24046, Bergamo
S: Italy
N: William E. Roadcap
E: roadcapw@cfw.com
W: http://www.cfw.com/~roadcapw
......@@ -3569,4 +3576,4 @@ S: France
# alphabetically. Leonard used to be very proud of being the
# last entry, and he'll get positively pissed if he can't even
# be second-to-last. (and this file really _is_ supposed to be
# in alphabetic order)
# in alphabetic order)
W996[87]CF JPEG USB Dual Mode Camera Chip driver for Linux 2.6
==============================================================
- Documentation -
Index
=====
1. Copyright
2. License
3. Overview
4. Supported devices
5. Kernel configuration and third-part module compilation
6. Module loading
7. Module paramaters
8. Credits
1. Copyright
============
Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>
2. License
==========
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3. Overview
===========
This driver supports the video streaming capabilities of the devices mounting
Winbond W9967CF and Winbond W9968CF JPEG USB Dual Mode Camera Chips, when they
are being commanded by USB.
The driver relies on the Video4Linux, USB and I2C core modules of the Linux
kernel, version 2.6.0 or greater, and is not compatible in any way with
previous versions. It has been designed to run properly on SMP systems
as well. At the moment, an additional module, "ovcamchip", is mandatory; it
provides support for some OmniVision CMOS sensors connected to the W996[87]CF
chips.
The driver is split into two modules: the basic one, "w9968cf", is needed for
the supported devices to work; the second one, "w9968cf-vpp", is an optional
module, which provides some useful video post-processing functions like video
decoding, up-scaling and colour conversions. These routines can't be included
into official kernels for performance purposes. Once the driver is installed,
every time an application tries to open a recognized device, "w9968cf" checks
the presence of the "w9968cf-vpp" module and loads it automatically by default.
Up to 32 cameras can be handled at the same time. They can be connected and
disconnected from the host many times without turning off the computer, if
your system supports the hotplug facility.
To change the default settings for each camera, many paramaters can be passed
through command line when the module is loaded into memory.
The latest and full featured version of the W996[87]CF driver can be found at:
http://go.lamarinapunto.com/
The "ovcamchip" module is part of the OV511 driver, version 2.25, which can be
downloaded from internet:
http://alpha.dyndns.org/ov511/
To know how to patch, compile and load it, read the paragraphs below.
4. Supported devices
====================
At the moment, known W996[87]CF based devices are:
- Aroma Digi Pen ADG-5000 Refurbished
- AVerTV USB
- Creative Labs Video Blaster WebCam Go
- Creative Labs Video Blaster WebCam Go Plus
- Die Lebon LDC-D35A Digital Kamera
- Ezonics EZ-802 EZMega Cam
- OPCOM Digi Pen VGA Dual Mode Pen Camera
If you know any other W996[87]CF based cameras, please contact me.
The list above does NOT imply that all those devices work with this driver: up
until now only webcams that have a CMOS sensor supported by the "ovcamchip"
module work.
For a list of supported CMOS sensors, please visit the module author homepage:
http://alpha.dyndns.org/ov511/
Possible external microcontrollers of those webcams are not supported: this
means that still images can't be downloaded from the device memory.
Furthermore, it's worth to note that I was only able to run tests on my
"Creative Labs Video Blaster WebCam Go". Donations of other models, for
additional testing and full support, would be much appreciated.
5. Kernel configuration and third-part module compilation
=========================================================
As noted above, kernel 2.6.0 is the minimum for this driver; for it to work
properly, the driver needs kernel support for Video4Linux, USB and I2C, and a
third-part module for the CMOS sensor.
The following options of the kernel configuration file must be enabled and
corresponding modules must be compiled:
# Multimedia devices
#
CONFIG_VIDEO_DEV=m
# I2C support
#
CONFIG_I2C=m
The I2C core module can be compiled statically in the kernel as well.
# USB support
#
CONFIG_USB=m
In addition, depending on the hardware being used, just one of the modules
below is necessary:
# USB Host Controller Drivers
#
CONFIG_USB_EHCI_HCD=m
CONFIG_USB_UHCI_HCD=m
CONFIG_USB_OHCI_HCD=m
Also, make sure "Enforce bandwidth allocation" is NOT enabled.
# USB Multimedia devices
#
CONFIG_USB_W9968CF=m
The last module we need is "ovcamchip.o". To obtain it, you have to download
the OV511 driver, version 2.25 - don't use other versions - which is available
at http://alpha.dyndns.org/ov511/ . Then you have to download the latest
version of the full featured W996[87]CF driver, which contains a patch for the
"ovcamchip" module; it is available at http://go.lamarinapunto.com .
Once you have obtained the packages, decompress, patch and compile the
"ovcamchip" module. In other words:
[user@localhost home]$ tar xvzf w9968cf-x.x.tar.gz
[user@localhost home]$ tar xvjf ov511-2.25.tar.bz2
[user@localhost home]$ cd ov511-2.25
[user@localhost ov511-2.25]$ patch -p1 < \
/path/to/w9968cf-x.x/ov511-2.25.patch
[user@localhost ov511-2.25]$ make
It's worth to note that the full featured version of the W996[87]CF driver
can also be installed overwriting the one in the kernel; in this case, read the
documentation included in the package.
If everything went well, the W996[87]CF driver can be immediatly used (see next
paragraph).
6. Module loading
=================
To use the driver, it is necessary to load the "w9968cf" module into memory
after every other module required.
For example, loading can be done this way, as root:
[root@localhost home]# modprobe usbcore
[root@localhost home]# modprobe i2c-core
[root@localhost ov511-x.xx]# insmod ./ovcamchip.ko
[root@localhost home]# modprobe w9968cf
At this point the devices should be recognized: "dmesg" can be used to analyze
kernel messages:
[user@localhost home]$ dmesg
There are a lot of parameters the module can use to change the default
settings for each device. To list every possible parameter with a brief
explanation about them and which syntax to use, it is recommended to run the
"modinfo" command:
[root@locahost home]# modinfo w9968cf
7. Module paramaters
====================
Module paramaters are listed below:
-------------------------------------------------------------------------------
Name: vppmod_load
Type: int
Syntax: <0|1>
Description: Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled.
If enabled, every time an application attempts to open a
camera, 'insmod' searches for the video post-processing module
in the system and loads it automatically (if present).
The 'w9968cf-vpp' module adds extra image manipulation
capabilities to the 'w9968cf' module,like software up-scaling,
colour conversions and video decoding.
Default: 1
-------------------------------------------------------------------------------
Name: simcams
Type: int
Syntax: <n>
Description: Number of cameras allowed to stream simultaneously.
n may vary from 0 to 32.
Default: 32
-------------------------------------------------------------------------------
Name: video_nr
Type: int array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Specify V4L minor mode number.
-1 = use next available
n = use minor number n
You can specify 32 cameras this way.
For example:
video_nr=-1,2,-1 would assign minor number 2 to the second
recognized camera and use auto for the first one and for every
other camera.
Default: -1
-------------------------------------------------------------------------------
Name: packet_size
Type: int array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Specify the maximum data payload size in bytes for alternate
settings, for each device. n is scaled between 63 and 1023.
Default: 1023
-------------------------------------------------------------------------------
Name: max_buffers
Type: int array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Only for advanced users.
Specify the maximum number of video frame buffers to allocate
for each device, from 2 to 32.
Default: 2
-------------------------------------------------------------------------------
Name: double_buffer
Type: int array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Hardware double buffering: 0 disabled, 1 enabled.
It should be enabled if you want smooth video output: if you
obtain out of sync. video, disable it at all, or try to
decrease the 'clockdiv' module paramater value.
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: clamping
Type: int array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Video data clamping: 0 disabled, 1 enabled.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: filter_type
Type: int array (min = 0, max = 32)
Syntax: <0|1|2[,...]>
Description: Video filter type.
0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
The filter is used to reduce noise and aliasing artifacts
produced by the CCD or CMOS sensor.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: largeview
Type: int array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Large view: 0 disabled, 1 enabled.
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: upscaling
Type: int array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Software scaling (for non-compressed video only):
0 disabled, 1 enabled.
Disable it if you have a slow CPU or you don't have enough
memory.
Default: 0 for every device.
Note: If 'w9968cf-vpp' is not loaded, this paramater is set to 0.
-------------------------------------------------------------------------------
Name: decompression
Type: int array (min = 0, max = 32)
Syntax: <0|1|2[,...]>
Description: Software video decompression:
0 = disables decompression
(doesn't allow formats needing decompression).
1 = forces decompression
(allows formats needing decompression only).
2 = allows any permitted formats.
Formats supporting (de)compressed video are YUV422P and
YUV420P/YUV420 in any resolutions where width and height are
multiples of 16.
Default: 2 for every device.
Note: If 'w9968cf-vpp' is not loaded, forcing decompression is not
allowed; in this case this paramater is set to 2.
-------------------------------------------------------------------------------
Name: force_palette
Type: int array (min = 0, max = 32)
Syntax: <0|9|10|13|15|8|7|1|6|3|4|5[,...]>
Description: Force picture palette.
In order:
0 = Off - allows any of the following formats:
9 = UYVY 16 bpp - Original video, compression disabled
10 = YUV420 12 bpp - Original video, compression enabled
13 = YUV422P 16 bpp - Original video, compression enabled
15 = YUV420P 12 bpp - Original video, compression enabled
8 = YUVY 16 bpp - Software conversion from UYVY
7 = YUV422 16 bpp - Software conversion from UYVY
1 = GREY 8 bpp - Software conversion from UYVY
6 = RGB555 16 bpp - Software conversion from UYVY
3 = RGB565 16 bpp - Software conversion from UYVY
4 = RGB24 24 bpp - Software conversion from UYVY
5 = RGB32 32 bpp - Software conversion from UYVY
When not 0, this paramater will override 'decompression'.
Default: 0 for every device. Initial palette is 9 (UYVY).
Note: If 'w9968cf-vpp' is not loaded, this paramater is set to 9.
-------------------------------------------------------------------------------
Name: force_rgb
Type: int array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Read RGB video data instead of BGR:
1 = use RGB component ordering.
0 = use BGR component ordering.
This parameter has effect when using RGBX palettes only.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autobright
Type: long array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: CMOS sensor automatically changes brightness:
0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autoexp
Type: long array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: CMOS sensor automatically changes exposure:
0 = no, 1 = yes
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: lightfreq
Type: long array (min = 0, max = 32)
Syntax: <50|60[,...]>
Description: Light frequency in Hz:
50 for European and Asian lighting, 60 for American lighting.
Default: 50 for every device.
-------------------------------------------------------------------------------
Name: bandingfilter
Type: long array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Banding filter to reduce effects of fluorescent
lighting:
0 disabled, 1 enabled.
This filter tries to reduce the pattern of horizontal
light/dark bands caused by some (usually fluorescent) lighting.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: clockdiv
Type: long array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Force pixel clock divisor to a specific value (for experts):
n may vary from 0 to 127.
-1 for automatic value.
See also the 'double_buffer' module paramater.
Default: -1 for every device.
-------------------------------------------------------------------------------
Name: backlight
Type: long array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Objects are lit from behind:
0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: mirror
Type: long array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Reverse image horizontally:
0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: sensor_mono
Type: long array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: The CMOS sensor is monochrome:
0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: brightness
Type: long array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Set picture brightness (0-65535).
This parameter has no effect if 'autobright' is enabled.
Default: 31000 for every device.
-------------------------------------------------------------------------------
Name: hue
Type: long array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Set picture hue (0-65535).
Default: 32768 for every device.
-------------------------------------------------------------------------------
Name: colour
Type: long array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Set picture saturation (0-65535).
Default: 32768 for every device.
-------------------------------------------------------------------------------
Name: contrast
Type: long array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Set picture contrast (0-65535).
Default: 50000 for every device.
-------------------------------------------------------------------------------
Name: whiteness
Type: long array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Set picture whiteness (0-65535).
Default: 32768 for every device.
-------------------------------------------------------------------------------
Name: debug
Type: int
Syntax: <n>
Description: Debugging information level, from 0 to 6:
0 = none (be cautious)
1 = critical errors
2 = significant informations
3 = configuration or general messages
4 = warnings
5 = called functions
6 = function internals
Level 5 and 6 are useful for testing only, when just one
device is used.
Default: 2
-------------------------------------------------------------------------------
Name: specific_debug
Type: int
Syntax: <0|1>
Description: Enable or disable specific debugging messages:
0 = print messages concerning every level <= 'debug' level.
1 = print messages concerning the level indicated by 'debug'.
Default: 0
-------------------------------------------------------------------------------
8. Credits
==========
The development would not have proceed much further without having looked at
the source code of other drivers and without the help of several persons; in
particular:
- the I2C interface to kernel and high-level CMOS sensor control routines have
been taken from the OV511 driver by Mark McClelland;
- memory management code has been copied from the bttv driver by Ralph Metzler,
Marcus Metzler and Gerd Knorr;
- the low-level I2C read function has been written by Frédéric Jouault, who
also gave me commented logs about sniffed USB traffic taken from another
driver for another system;
- the low-level I2C fast write function has been written by Piotr Czerczak;
......@@ -2218,6 +2218,13 @@ M: dbrownell@users.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
USB W996[87]CF DRIVER
P: Luca Risolia
M: luca_ing@libero.it
L: linux-usb-devel@lists.sourceforge.net
W: http://go.lamarinapunto.com
S: Maintained
USER-MODE LINUX
P: Jeff Dike
M: jdike@karaya.com
......
......@@ -34,6 +34,7 @@ obj-$(CONFIG_USB_PWC) += media/
obj-$(CONFIG_USB_SE401) += media/
obj-$(CONFIG_USB_STV680) += media/
obj-$(CONFIG_USB_VICAM) += media/
obj-$(CONFIG_USB_W9968CF) += media/
obj-$(CONFIG_USB_CATC) += net/
obj-$(CONFIG_USB_KAWETH) += net/
......@@ -58,4 +59,3 @@ obj-$(CONFIG_USB_SPEEDTOUCH) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TIGL) += misc/
obj-$(CONFIG_USB_USS720) += misc/
#define USB_DT_CS_DEVICE 0x21
#define USB_DT_CS_CONFIG 0x22
#define USB_DT_CS_STRING 0x23
#define USB_DT_CS_INTERFACE 0x24
#define USB_DT_CS_ENDPOINT 0x25
#define CS_AUDIO_UNDEFINED 0x20
#define CS_AUDIO_DEVICE 0x21
#define CS_AUDIO_CONFIGURATION 0x22
......
/*
* acm.c Version 0.22
* cdc-acm.c
*
* Copyright (c) 1999 Armin Fuerst <fuerst@in.tum.de>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
......@@ -26,6 +26,7 @@
* v0.21 - revert to probing on device for devices with multiple configs
* v0.22 - probe only the control interface. if usbcore doesn't choose the
* config we want, sysadmin changes bConfigurationValue in sysfs.
* v0.23 - use softirq for rx processing, as needed by tty layer
*/
/*
......@@ -44,6 +45,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
......@@ -54,14 +57,13 @@
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#undef DEBUG
#include <linux/usb.h>
#include <asm/byteorder.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v0.21"
#define DRIVER_VERSION "v0.23"
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
......@@ -146,7 +148,8 @@ struct acm {
struct tty_struct *tty; /* the corresponding tty */
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
struct acm_line line; /* line coding (bits, stop, parity) */
struct work_struct work; /* work queue entry for line discipline waking up */
struct work_struct work; /* work queue entry for line discipline waking up */
struct tasklet_struct bh; /* rx processing */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
unsigned int ctrlout; /* output control lines (DTR, RTS) */
unsigned int writesize; /* max packet size for the output bulk endpoint */
......@@ -184,9 +187,10 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
#define acm_send_break(acm, ms) acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
/*
* Interrupt handler for various ACM control events
* Interrupt handlers for various ACM device responses
*/
/* control interface reports status changes with "interrupt" transfers */
static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = urb->context;
......@@ -251,20 +255,30 @@ static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
__FUNCTION__, status);
}
/* data interface returns incoming bytes, or we got unthrottled */
static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = urb->context;
struct tty_struct *tty = acm->tty;
unsigned char *data = urb->transfer_buffer;
int i = 0;
if (!ACM_READY(acm))
return;
if (urb->status)
dbg("nonzero read bulk status received: %d", urb->status);
dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status);
/* calling tty_flip_buffer_push() in_irq() isn't allowed */
tasklet_schedule(&acm->bh);
}
static void acm_rx_tasklet(unsigned long _acm)
{
struct acm *acm = (void *)_acm;
struct urb *urb = acm->readurb;
struct tty_struct *tty = acm->tty;
unsigned char *data = urb->transfer_buffer;
int i = 0;
if (!urb->status && !acm->throttle) {
if (urb->actual_length > 0 && !acm->throttle) {
for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
/* if we insert more than TTY_FLIPBUF_SIZE characters,
* we drop them. */
......@@ -285,10 +299,12 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
urb->actual_length = 0;
urb->dev = acm->dev;
if (usb_submit_urb(urb, GFP_ATOMIC))
dbg("failed resubmitting read urb");
i = usb_submit_urb(urb, GFP_ATOMIC);
if (i)
dev_dbg(&acm->data->dev, "bulk rx resubmit %d\n", i);
}
/* data interface wrote those outgoing bytes */
static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = (struct acm *)urb->context;
......@@ -621,6 +637,8 @@ static int acm_probe (struct usb_interface *intf,
acm->minor = minor;
acm->dev = dev;
acm->bh.func = acm_rx_tasklet;
acm->bh.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint, acm);
if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
......
......@@ -28,12 +28,6 @@
#define USB_SUBCLASS_MIDISTREAMING 3
#endif
#define USB_DT_CS_DEVICE 0x21
#define USB_DT_CS_CONFIG 0x22
#define USB_DT_CS_STRING 0x23
#define USB_DT_CS_INTERFACE 0x24
#define USB_DT_CS_ENDPOINT 0x25
/* ------------------------------------------------------------------------- */
/* Roland MIDI Devices */
......
......@@ -610,7 +610,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if (!usblp->wcomplete) {
barrier();
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
return writecount ? writecount : -EAGAIN;
timeout = USBLP_WRITE_TIMEOUT;
add_wait_queue(&usblp->wait, &wait);
......@@ -673,8 +673,12 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
usblp->writeurb->dev = usblp->dev;
usblp->wcomplete = 0;
if (usb_submit_urb(usblp->writeurb, GFP_KERNEL)) {
count = -EIO;
err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
if (err) {
if (err != -ENOMEM)
count = -EIO;
else
count = writecount ? writecount : -ENOMEM;
up (&usblp->sem);
break;
}
......@@ -706,8 +710,6 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
goto done;
}
// FIXME: only use urb->status inside completion
// callbacks; this way is racey...
add_wait_queue(&usblp->wait, &wait);
while (1==1) {
if (signal_pending(current)) {
......@@ -1093,7 +1095,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
/* First two bytes are length in big-endian.
* They count themselves, and we copy them into
* the user's buffer. */
length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1];
length = be16_to_cpu(*((u16 *)usblp->device_id_string));
if (length < 2)
length = 2;
else if (length >= USBLP_DEVICE_ID_SIZE)
......
......@@ -1165,6 +1165,7 @@ static int hcd_unlink_urb (struct urb *urb)
struct device *sys = 0;
unsigned long flags;
struct completion_splice splice;
struct list_head *tmp;
int retval;
if (!urb)
......@@ -1203,7 +1204,12 @@ static int hcd_unlink_urb (struct urb *urb)
*/
WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT);
if (!urb->hcpriv) {
/* insist the urb is still queued */
list_for_each(tmp, &dev->urb_list) {
if (tmp == &urb->urb_list)
break;
}
if (tmp != &urb->urb_list) {
retval = -EINVAL;
goto done;
}
......
......@@ -126,14 +126,20 @@ static int get_port_status(struct usb_device *dev, int port,
static void hub_irq(struct urb *urb, struct pt_regs *regs)
{
struct usb_hub *hub = (struct usb_hub *)urb->context;
unsigned long flags;
int status;
spin_lock(&hub_event_lock);
hub->urb_active = 0;
if (hub->urb_complete) { /* disconnect or rmmod */
complete(hub->urb_complete);
goto done;
}
switch (urb->status) {
case -ENOENT: /* synchronous unlink */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware going away */
return;
goto done;
default: /* presumably an error */
/* Cause a hub reset after 10 consecutive errors */
......@@ -151,18 +157,20 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs)
hub->nerrors = 0;
/* Something happened, let khubd figure it out */
spin_lock_irqsave(&hub_event_lock, flags);
if (list_empty(&hub->event_list)) {
list_add(&hub->event_list, &hub_event_list);
wake_up(&khubd_wait);
}
spin_unlock_irqrestore(&hub_event_lock, flags);
resubmit:
if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
/* ENODEV means we raced disconnect() */
&& status != -ENODEV)
dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status);
if (status == 0)
hub->urb_active = 1;
done:
spin_unlock(&hub_event_lock);
}
/* USB 2.0 spec Section 11.24.2.3 */
......@@ -467,7 +475,8 @@ static int hub_configure(struct usb_hub *hub,
message = "couldn't submit status urb";
goto fail;
}
hub->urb_active = 1;
/* Wake up khubd */
wake_up(&khubd_wait);
......@@ -485,6 +494,7 @@ static int hub_configure(struct usb_hub *hub,
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
DECLARE_COMPLETION(urb_complete);
unsigned long flags;
if (!hub)
......@@ -492,12 +502,11 @@ static void hub_disconnect(struct usb_interface *intf)
usb_set_intfdata (intf, NULL);
spin_lock_irqsave(&hub_event_lock, flags);
hub->urb_complete = &urb_complete;
/* Delete it and then reset it */
list_del(&hub->event_list);
INIT_LIST_HEAD(&hub->event_list);
list_del(&hub->hub_list);
INIT_LIST_HEAD(&hub->hub_list);
list_del_init(&hub->event_list);
list_del_init(&hub->hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
......@@ -510,6 +519,8 @@ static void hub_disconnect(struct usb_interface *intf)
if (hub->urb) {
usb_unlink_urb(hub->urb);
if (hub->urb_active)
wait_for_completion(&urb_complete);
usb_free_urb(hub->urb);
hub->urb = NULL;
}
......
......@@ -172,6 +172,8 @@ extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe);
struct usb_hub {
struct usb_interface *intf; /* the "real" device */
struct urb *urb; /* for interrupt polling pipe */
struct completion *urb_complete; /* wait for urb to end */
unsigned int urb_active:1;
/* buffer for urb ... 1 bit each for hub and children, rounded up */
char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
......
......@@ -1086,6 +1086,11 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
ret = -EINVAL;
goto out;
}
/* The USB spec says configuration 0 means unconfigured.
* But if a device includes a configuration numbered 0,
* we will accept it as a correctly configured state.
*/
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
......@@ -1101,7 +1106,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
goto out;
dev->actconfig = cp;
if (!configuration)
if (!cp)
dev->state = USB_STATE_ADDRESS;
else {
dev->state = USB_STATE_CONFIGURED;
......
......@@ -80,7 +80,7 @@ static struct device_driver usb_generic_driver = {
static int usb_generic_driver_data;
/* needs to be called with BKL held */
/* called from driver core with usb_bus_type.subsys writelock */
int usb_probe_interface(struct device *dev)
{
struct usb_interface * intf = to_usb_interface(dev);
......@@ -93,12 +93,14 @@ int usb_probe_interface(struct device *dev)
if (!driver->probe)
return error;
/* driver claim() doesn't yet affect dev->driver... */
if (intf->driver)
return error;
id = usb_match_id (intf, driver->id_table);
if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
down (&driver->serialize);
error = driver->probe (intf, id);
up (&driver->serialize);
}
if (!error)
intf->driver = driver;
......@@ -106,23 +108,24 @@ int usb_probe_interface(struct device *dev)
return error;
}
/* called from driver core with usb_bus_type.subsys writelock */
int usb_unbind_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_driver *driver = to_usb_driver(dev->driver);
down(&driver->serialize);
struct usb_driver *driver = intf->driver;
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
if (intf->driver && intf->driver->disconnect)
intf->driver->disconnect(intf);
/* force a release and re-initialize the interface */
usb_driver_release_interface(driver, intf);
if (driver && driver->disconnect)
driver->disconnect(intf);
up(&driver->serialize);
/* reset other interface state */
usb_set_interface(interface_to_usbdev(intf),
intf->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(intf, NULL);
intf->driver = NULL;
return 0;
}
......@@ -152,8 +155,6 @@ int usb_register(struct usb_driver *new_driver)
new_driver->driver.probe = usb_probe_interface;
new_driver->driver.remove = usb_unbind_interface;
init_MUTEX(&new_driver->serialize);
retval = driver_register(&new_driver->driver);
if (!retval) {
......@@ -170,7 +171,7 @@ int usb_register(struct usb_driver *new_driver)
/**
* usb_deregister - unregister a USB driver
* @driver: USB operations of the driver to unregister
* Context: !in_interrupt (), must be called with BKL held
* Context: must be able to sleep
*
* Unlinks the specified driver from the internal USB driver list.
*
......@@ -264,26 +265,22 @@ usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
* Few drivers should need to use this routine, since the most natural
* way to bind to an interface is to return the private data from
* the driver's probe() method.
*
* Callers must own the driver model's usb bus writelock. So driver
* probe() entries don't need extra locking, but other call contexts
* may need to explicitly claim that lock.
*/
int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
{
if (!iface || !driver)
return -EINVAL;
/* this is mainly to lock against usbfs */
lock_kernel();
if (iface->driver) {
unlock_kernel();
err ("%s driver booted %s off interface %p",
driver->name, iface->driver->name, iface);
if (iface->driver)
return -EBUSY;
} else {
dbg("%s driver claimed interface %p", driver->name, iface);
}
/* FIXME should device_bind_driver() */
iface->driver = driver;
usb_set_intfdata(iface, priv);
unlock_kernel();
return 0;
}
......@@ -323,13 +320,22 @@ int usb_interface_claimed(struct usb_interface *iface)
* usually won't need to call this.
*
* This call is synchronous, and may not be used in an interrupt context.
* Callers must own the driver model's usb bus writelock. So driver
* disconnect() entries don't need extra locking, but other call contexts
* may need to explicitly claim that lock.
*/
void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
{
/* this should never happen, don't release something that's not ours */
if (iface->driver && iface->driver != driver)
if (!iface || !iface->driver || iface->driver != driver)
return;
if (iface->dev.driver) {
/* FIXME should be the ONLY case here */
device_release_driver(&iface->dev);
return;
}
usb_set_interface(interface_to_usbdev(iface),
iface->altsetting[0].desc.bInterfaceNumber,
0);
......@@ -991,6 +997,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
int err = -EINVAL;
int i;
int j;
int config;
/*
* Set the driver for the usb device to point to the "generic" driver.
......@@ -1108,18 +1115,30 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
/* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them.
* NOTE: should interact with hub power budgeting.
*/
config = dev->config[0].desc.bConfigurationValue;
if (dev->descriptor.bNumConfigurations != 1) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
if (dev->config[i].interface[0]->altsetting
->desc.bInterfaceClass
== USB_CLASS_VENDOR_SPEC)
continue;
config = dev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
dev->config[0].desc.bConfigurationValue,
config,
dev->descriptor.bNumConfigurations);
}
err = usb_set_configuration(dev,
dev->config[0].desc.bConfigurationValue);
err = usb_set_configuration(dev, config);
if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n",
dev->config[0].desc.bConfigurationValue, err);
config, err);
device_del(&dev->dev);
goto fail;
}
......
......@@ -269,18 +269,19 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
ohci_dump_status (controller, NULL, 0);
if (controller->hcca)
ohci_dbg (controller,
"hcca frame #%04x\n", controller->hcca->frame_no);
"hcca frame #%04x\n", OHCI_FRAME_NO(controller->hcca));
ohci_dump_roothub (controller, 1, NULL, 0);
}
static const char data0 [] = "DATA0";
static const char data1 [] = "DATA1";
static void ohci_dump_td (struct ohci_hcd *ohci, char *label, struct td *td)
static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
const struct td *td)
{
u32 tmp = le32_to_cpup (&td->hwINFO);
ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x",
ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x\n",
label, td,
(tmp & TD_DONE) ? " (DONE)" : "",
td->urb, td->index,
......@@ -301,28 +302,28 @@ static void ohci_dump_td (struct ohci_hcd *ohci, char *label, struct td *td)
case TD_DP_OUT: pid = "OUT"; break;
default: pid = "(bad pid)"; break;
}
ohci_dbg (ohci, " info %08x CC=%x %s DI=%d %s %s", tmp,
ohci_dbg (ohci, " info %08x CC=%x %s DI=%d %s %s\n", tmp,
TD_CC_GET(tmp), /* EC, */ toggle,
(tmp & TD_DI) >> 21, pid,
(tmp & TD_R) ? "R" : "");
cbp = le32_to_cpup (&td->hwCBP);
be = le32_to_cpup (&td->hwBE);
ohci_dbg (ohci, " cbp %08x be %08x (len %d)", cbp, be,
ohci_dbg (ohci, " cbp %08x be %08x (len %d)\n", cbp, be,
cbp ? (be + 1 - cbp) : 0);
} else {
unsigned i;
ohci_dbg (ohci, " info %08x CC=%x FC=%d DI=%d SF=%04x", tmp,
ohci_dbg (ohci, " info %08x CC=%x FC=%d DI=%d SF=%04x\n", tmp,
TD_CC_GET(tmp),
(tmp >> 24) & 0x07,
(tmp & TD_DI) >> 21,
tmp & 0x0000ffff);
ohci_dbg (ohci, " bp0 %08x be %08x",
ohci_dbg (ohci, " bp0 %08x be %08x\n",
le32_to_cpup (&td->hwCBP) & ~0x0fff,
le32_to_cpup (&td->hwBE));
for (i = 0; i < MAXPSW; i++) {
u16 psw = le16_to_cpup (&td->hwPSW [i]);
int cc = (psw >> 12) & 0x0f;
ohci_dbg (ohci, " psw [%d] = %2x, CC=%x %s=%d", i,
ohci_dbg (ohci, " psw [%d] = %2x, CC=%x %s=%d\n", i,
psw, cc,
(cc >= 0x0e) ? "OFFSET" : "SIZE",
psw & 0x0fff);
......@@ -332,12 +333,13 @@ static void ohci_dump_td (struct ohci_hcd *ohci, char *label, struct td *td)
/* caller MUST own hcd spinlock if verbose is set! */
static void __attribute__((unused))
ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
const struct ed *ed, int verbose)
{
u32 tmp = ed->hwINFO;
char *type = "";
ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x",
ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n",
label,
ed, ed->state, edstring (ed->type),
le32_to_cpup (&ed->hwNextED));
......@@ -347,7 +349,7 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
/* else from TDs ... control */
}
ohci_dbg (ohci,
" info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
" info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", le32_to_cpu (tmp),
0x03ff & (le32_to_cpu (tmp) >> 16),
(tmp & ED_DEQUEUE) ? " DQ" : "",
(tmp & ED_ISO) ? " ISO" : "",
......@@ -356,7 +358,7 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
0x000f & (le32_to_cpu (tmp) >> 7),
type,
0x007f & le32_to_cpu (tmp));
ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s",
ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s\n",
tmp = le32_to_cpup (&ed->hwHeadP),
(ed->hwHeadP & ED_C) ? data1 : data0,
(ed->hwHeadP & ED_H) ? " HALT" : "",
......@@ -541,24 +543,29 @@ show_periodic (struct class_device *class_dev, char *buf)
if (temp == seen_count) {
u32 info = ed->hwINFO;
u32 scratch = cpu_to_le32p (&ed->hwINFO);
struct list_head *entry;
unsigned qlen = 0;
/* qlen measured here in TDs, not urbs */
list_for_each (entry, &ed->td_list)
qlen++;
temp = snprintf (next, size,
" (%cs dev%d%s ep%d%s"
" (%cs dev%d ep%d%s-%s qlen %u"
" max %d %08x%s%s)",
(info & ED_LOWSPEED) ? 'l' : 'f',
scratch & 0x7f,
(info & ED_ISO) ? " iso" : "",
(scratch >> 7) & 0xf,
(info & ED_IN) ? "in" : "out",
(info & ED_ISO) ? "iso" : "int",
qlen,
0x03ff & (scratch >> 16),
scratch,
(info & ED_SKIP) ? " s" : "",
(info & ED_SKIP) ? " K" : "",
(ed->hwHeadP & ED_H) ? " H" : "");
size -= temp;
next += temp;
// FIXME some TD info too
if (seen_count < DBG_SCHED_LIMIT)
seen [seen_count++] = ed;
......@@ -617,7 +624,7 @@ show_registers (struct class_device *class_dev, char *buf)
/* hcca */
if (ohci->hcca)
ohci_dbg_sw (ohci, &next, &size,
"hcca frame 0x%04x\n", ohci->hcca->frame_no);
"hcca frame 0x%04x\n", OHCI_FRAME_NO(ohci->hcca));
/* other registers mostly affect frame timings */
rdata = readl (&regs->fminterval);
......
......@@ -226,7 +226,7 @@ static int ohci_urb_enqueue (
if (retval < 0)
goto fail;
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = le16_to_cpu (ohci->hcca->frame_no);
u16 frame = OHCI_FRAME_NO(ohci->hcca);
/* delay a few frames before the first TD */
frame += max_t (u16, 8, ed->interval);
......@@ -281,7 +281,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
urb_priv = urb->hcpriv;
if (urb_priv) {
if (urb_priv->ed->state == ED_OPER)
start_urb_unlink (ohci, urb_priv->ed);
start_ed_unlink (ohci, urb_priv->ed);
}
} else {
/*
......@@ -363,7 +363,7 @@ static int ohci_get_frame (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
return le16_to_cpu (ohci->hcca->frame_no);
return OHCI_FRAME_NO(ohci->hcca);
}
/*-------------------------------------------------------------------------*
......@@ -591,7 +591,7 @@ static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
*/
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca),
ptregs);
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
&& HCD_IS_RUNNING(ohci->hcd.state))
......
......@@ -430,7 +430,7 @@ static struct ed *ed_get (
* put the ep on the rm_list
* real work is done at the next start frame (SF) hardware interrupt
*/
static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
{
ed->hwINFO |= ED_DEQUEUE;
ed->state = ED_UNLINK;
......@@ -441,7 +441,7 @@ static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
* behave. frame_no wraps every 2^16 msec, and changes right before
* SF is triggered.
*/
ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1;
ed->tick = OHCI_FRAME_NO(ohci->hcca) + 1;
/* rm_list is just singly linked, for simplicity */
ed->ed_next = ohci->ed_rm_list;
......@@ -479,7 +479,8 @@ td_fill (struct ohci_hcd *ohci, u32 info,
* and iso; other urbs rarely need more than one TD per urb.
* this way, only final tds (or ones with an error) cause IRQs.
* at least immediately; use DI=6 in case any control request is
* tempted to die part way through.
* tempted to die part way through. (and to force the hc to flush
* its donelist soonish, even on unlink paths.)
*
* NOTE: could delay interrupts even for the last TD, and get fewer
* interrupts ... increasing per-urb latency by sharing interrupts.
......@@ -879,12 +880,27 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
u32 *prev;
/* only take off EDs that the HC isn't using, accounting for
* frame counter wraps.
* frame counter wraps and EDs with partially retired TDs
*/
if (tick_before (tick, ed->tick)
&& HCD_IS_RUNNING(ohci->hcd.state)) {
last = &ed->ed_next;
continue;
if (likely (HCD_IS_RUNNING(ohci->hcd.state))) {
if (tick_before (tick, ed->tick)) {
skip_ed:
last = &ed->ed_next;
continue;
}
if (!list_empty (&ed->td_list)) {
struct td *td;
u32 head;
td = list_entry (ed->td_list.next, struct td,
td_list);
head = cpu_to_le32 (ed->hwHeadP) & TD_MASK;
/* INTR_WDH may need to clean up first */
if (td->td_dma != head)
goto skip_ed;
}
}
/* reentrancy: if we drop the schedule lock, someone might
......
......@@ -172,8 +172,14 @@ static const int cc_to_error [16] = {
struct ohci_hcca {
#define NUM_INTS 32
__u32 int_table [NUM_INTS]; /* periodic schedule */
__u16 frame_no; /* current frame number */
__u16 pad1; /* set to 0 on each frame_no change */
/*
* OHCI defines u16 frame_no, followed by u16 zero pad.
* Since some processors can't do 16 bit bus accesses,
* portable access must be a 32 bit byteswapped access.
*/
u32 frame_no; /* current frame number */
#define OHCI_FRAME_NO(hccap) ((u16)le32_to_cpup(&(hccap)->frame_no))
__u32 done_head; /* info returned for an interrupt */
u8 reserved_for_hc [116];
u8 what [4]; /* spec only identifies 252 bytes :) */
......
......@@ -380,6 +380,10 @@
* Visioneer scanners.
* - Added test for USB_CLASS_CDC_DATA which is used by some fingerprint scanners.
*
* 0.4.16 2003-11-04
* - Added vendor/product ids for Epson, Genius, Microtek, Plustek, Reflecta, and
* Visioneer scanners. Removed ids for HP PSC devices as these are supported by
* the hpoj userspace driver.
*
* TODO
* - Performance
......
......@@ -43,7 +43,7 @@
// #define DEBUG
#define DRIVER_VERSION "0.4.15"
#define DRIVER_VERSION "0.4.16"
#define DRIVER_DESC "USB Scanner Driver"
#include <linux/usb.h>
......@@ -146,7 +146,12 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x0458, 0x2015) }, /* ColorPage HR7LE */
{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage HR6X */
{ USB_DEVICE(0x0458, 0x2018) }, /* ColorPage HR7X */
{ USB_DEVICE(0x0458, 0x201b) }, /* Colorpage Vivid 4x */
/* Hewlett Packard */
/* IMPORTANT: Hewlett-Packard multi-function peripherals (OfficeJet,
Printer/Scanner/Copier (PSC), LaserJet, or PhotoSmart printer)
should not be added to this table because they are accessed by a
userspace driver (hpoj) */
{ USB_DEVICE(0x03f0, 0x0101) }, /* ScanJet 4100C */
{ USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
{ USB_DEVICE(0x03f0, 0x0105) }, /* ScanJet 4200C */
......@@ -168,10 +173,10 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x03F0, 0x1105) }, /* ScanJet 5470C */
{ USB_DEVICE(0x03f0, 0x1205) }, /* ScanJet 5550C */
{ USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */
{ USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 */
// { USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 - NOT SUPPORTED - use hpoj userspace driver */
{ USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */
{ USB_DEVICE(0x03f0, 0x2205) }, /* ScanJet 3500c */
{ USB_DEVICE(0x03f0, 0x2f11) }, /* PSC 1210 */
// { USB_DEVICE(0x03f0, 0x2f11) }, /* PSC 1210 - NOT SUPPORTED - use hpoj userspace driver */
/* Lexmark */
{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
{ USB_DEVICE(0x043d, 0x003d) }, /* X83 */
......@@ -187,6 +192,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */
{ USB_DEVICE(0x05da, 0x30cf) }, /* ScanMaker 4800 */
{ USB_DEVICE(0x05da, 0x30d4) }, /* ScanMaker 3830 + 3840 */
{ USB_DEVICE(0x05da, 0x30d8) }, /* ScanMaker 5900 */
{ USB_DEVICE(0x04a7, 0x0224) }, /* Scanport 3000 (actually Visioneer?)*/
/* The following SCSI-over-USB Microtek devices are supported by the
microtek driver: Enable SCSI and USB Microtek in kernel config */
......@@ -245,6 +251,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x07b3, 0x0400) }, /* OpticPro 1248U */
{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U (another one) */
{ USB_DEVICE(0x07b3, 0x0403) }, /* U16B */
{ USB_DEVICE(0x07b3, 0x0413) }, /* OpticSlim 1200 */
/* Primax/Colorado */
{ USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */
{ USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */
......@@ -261,6 +268,8 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
/* Prolink */
{ USB_DEVICE(0x06dc, 0x0014) }, /* Winscan Pro 2448U */
/* Reflecta */
{ USB_DEVICE(0x05e3, 0x0120) }, /* iScan 1800 */
/* Relisis */
// { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */
{ USB_DEVICE(0x0475, 0x0210) }, /* Scorpio Ultra 3 */
......@@ -285,6 +294,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04b8, 0x011c) }, /* Perfection 3200 */
{ USB_DEVICE(0x04b8, 0x011d) }, /* Perfection 1260 */
{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
{ USB_DEVICE(0x04b8, 0x011f) }, /* Perfection 1670 */
{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
/* Siemens */
......@@ -309,6 +319,7 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
{ USB_DEVICE(0x04a7, 0x0224) }, /* OneTouch 4800 USB */
{ USB_DEVICE(0x04a7, 0x0226) }, /* OneTouch 5800 USB */
{ USB_DEVICE(0x04a7, 0x0229) }, /* OneTouch 7100 USB */
{ USB_DEVICE(0x04a7, 0x022c) }, /* OneTouch 9020 USB */
{ USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */
{ USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */
......
......@@ -113,16 +113,17 @@ config USB_PWC
webcams:
* Philips PCA645, PCA646
* Philips PCVC675, PCVC680, PCVC690
* Philips PCVC730, PCVC740, PCVC750
* Philips PCVC720/40, PCVC730, PCVC740, PCVC750
* Askey VC010
* Logitech QuickCam Pro 3000, 4000, 'Zoom' and 'Notebook'
* Samsung MPC-C10, MPC-C30
* Creative Webcam 5
* SOTECT Afina Eye
* Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
and 'Orbit'/'Sphere'
* Samsung MPC-C10, MPC-C30
* Creative Webcam 5, Pro Ex
* SOTEC Afina Eye
* Visionite VCS-UC300, VCS-UM100
The PCA635, PCVC665 and PCVC720 are not supported by this driver
and never will be, but the 665 and 720 are supported by other
The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
and never will be, but the 665 and 720/20 are supported by other
drivers.
This driver has an optional plugin (called PWCX), which is
......@@ -177,3 +178,30 @@ config USB_STV680
To compile this driver as a module, choose M here: the
module will be called stv680.
config USB_W9968CF
tristate "USB W996[87]CF JPEG Dual Mode Camera support"
depends on USB && VIDEO_DEV && I2C
---help---
Say Y here if you want support for cameras based on
Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
This driver has an optional plugin, which is distributed as a
separate module only (released under GPL). It contains code that
allows you to use higher resolutions and framerates, and can't
be included into the official Linux kernel for performance
purposes.
At the moment the driver needs a third-part module for the CMOS
sensors, which is available on internet: it is recommended to read
<file:Documentation/usb/w9968cf.txt> for more informations and for
a list of supported cameras.
This driver uses the Video For Linux and the I2C APIs.
You must say Y or M to both "Video For Linux" and
"I2C Support" to use this driver.
Information on this API and pointers to "v4l" programs may be found
on the WWW at <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
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 w9968cf.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
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