## Automatically generated incremental diff
## From:   linux-2.4.22-bk41
## To:     linux-2.4.22-bk42
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.22-bk41/CREDITS linux-2.4.22-bk42/CREDITS
--- linux-2.4.22-bk41/CREDITS	2003-10-26 02:49:49.000000000 -0800
+++ linux-2.4.22-bk42/CREDITS	2003-10-26 02:49:52.000000000 -0800
@@ -2590,6 +2590,13 @@
 S: Tucson, Arizona
 S: USA
 
+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
@@ -3439,4 +3446,4 @@
 # 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)
diff -urN linux-2.4.22-bk41/Documentation/Configure.help linux-2.4.22-bk42/Documentation/Configure.help
--- linux-2.4.22-bk41/Documentation/Configure.help	2003-10-26 02:49:49.000000000 -0800
+++ linux-2.4.22-bk42/Documentation/Configure.help	2003-10-26 02:49:52.000000000 -0800
@@ -14663,6 +14663,25 @@
   The module will be called usb-ohci.o. If you want to compile it
   as a module, say M here and read <file:Documentation/modules.txt>.
 
+SL811HS (x86, StrongARM) support
+CONFIG_USB_SL811HS
+  Embedded Open Host Controller SL811HS from CYPRESS SEMICONDUCTOR INC.
+  <pbl@cypress.com>
+    
+  Board USB1104 in i386 architecture with PC/104-bus.
+  <http://www.ssv-embedded.de>
+  <file:Documentation/usb/hc_sl811.txt>
+	  
+  StrongARM is currently not testet and not for PC/104-bus!
+  StrongARM need a special hardware with Chip Select directly from CPU.
+  See also SL811HS_ALT.
+	      
+SL811HS_ALT (x86, StrongARM) support
+CONFIG_USB_SL811HS_ALT
+  Embedded Open Host Controller SL811HS from CYPRESS SEMICONDUCTOR INC.
+  Alternate with isochornous mode and better interrupt handling.
+  See also SL811HS.
+
 USB Human Interface Device (full HID) support
 CONFIG_USB_HID
   Say Y here if you want full HID support to connect keyboards,
@@ -15276,6 +15295,32 @@
   The module will be called ov511.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+USB W996[87]CF Camera support
+CONFIG_USB_W9968CF
+  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>.
+
 USB Communication Class Ethernet device support
 CONFIG_USB_CDCETHER
   This driver supports devices conforming to the Communication Device
@@ -15776,6 +15821,88 @@
   The module will be called speedtch.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_USB_GADGET
+  USB is a master/slave protocol, organized with one master
+  host (such as a PC) controlling up to 127 peripheral devices.
+  The USB hardware is asymmetric, which makes it easier to set up:
+  you can't connect two "to-the-host" connectors to each other.
+
+  Linux can run in the host, or in the peripheral.  In both cases
+  you need a low level bus controller driver, and some software
+  talking to it.  Peripheral controllers are often discrete silicon,
+  or are integrated with the CPU in a microcontroller.  The more
+  familiar host side controllers have names like like "EHCI", "OHCI",
+  or "UHCI", and are usually integrated into southbridges on PC
+  motherboards.
+
+  Enable this configuration option if you want to run Linux inside
+  a USB peripheral device.  Configure one hardware driver for your
+  peripheral/device side bus controller, and a "gadget driver" for
+  your peripheral protocol.  (If you use modular gadget drivers,
+  you may configure more than one.)
+
+  If in doubt, say "N" and don't enable these drivers; most people
+  don't have this kind of hardware (except maybe inside Linux PDAs).
+
+CONFIG_USB_NET2280
+  NetChip 2280 is a PCI based USB peripheral controller which
+  supports both full and high speed USB 2.0 data transfers.  
+           
+  It has six configurable endpoints, as well as endpoint zero
+  (for control transfers) and several endpoints with dedicated
+  functions.
+
+  Say "y" to link the driver statically, or "m" to build a
+  dynamically linked module called "net2280" and force all
+  gadget drivers to also be dynamically linked.
+
+CONFIG_USB_ZERO
+  Gadget Zero is a two-configuration device.  It either sinks and
+  sources bulk data; or it loops back a configurable number of
+  transfers.  It also implements control requests, for "chapter 9"
+  conformance.  The driver needs only two bulk-capable endpoints, so
+  it can work on top of most device-side usb controllers.  It's
+  useful for testing, and is also a working example showing how
+  USB "gadget drivers" can be written.
+
+  Make this be the first driver you try using on top of any new
+  USB peripheral controller driver.  Then you can use host-side
+  test software, like the "usbtest" driver, to put your hardware
+  and its driver through a basic set of functional tests.
+
+  Gadget Zero also works with the host-side "usb-skeleton" driver,
+  and with many kinds of host-side test software.  You may need
+  to tweak product and vendor IDs before host software knows about
+  this device, and arrange to select an appropriate configuration.
+
+  Say "y" to link the driver statically, or "m" to build a
+  dynamically linked module called "g_zero".
+
+CONFIG_USB_ETH
+  This driver implements Ethernet style communication, in either
+  of two ways:
+          
+   - The "Communication Device Class" (CDC) Ethernet Control Model.
+     That protocol is often avoided with pure Ethernet adapters, in
+     favor of simpler vendor-specific hardware, but is widely
+     supported by firmware for smart network devices.
+
+   - On hardware can't implement that protocol, a simpler approach
+     is used, placing fewer demands on USB.
+
+   Within the USB device, this gadget driver exposes a network device
+   "usbX", where X depends on what other networking devices you have.
+   Treat it like a two-node Ethernet link:  host, and gadget.
+
+   The Linux-USB host-side "usbnet" driver interoperates with this
+   driver, so that deep I/O queues can be supported.  On 2.4 kernels,
+   use "CDCEther" instead, if you're using the CDC option. That CDC
+   mode should also interoperate with standard CDC Ethernet class
+   drivers on other host operating systems.
+
+   Say "y" to link the driver statically, or "m" to build a
+   dynamically linked module called "g_ether".
+
 Always do synchronous disk IO for UBD
 CONFIG_BLK_DEV_UBD_SYNC
   The User-Mode Linux port includes a driver called UBD which will let
diff -urN linux-2.4.22-bk41/Documentation/usb/sl811hc.txt linux-2.4.22-bk42/Documentation/usb/sl811hc.txt
--- linux-2.4.22-bk41/Documentation/usb/sl811hc.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/Documentation/usb/sl811hc.txt	2003-10-26 02:49:52.000000000 -0800
@@ -0,0 +1,331 @@
+README for embedded host controller SL811 (i386)
+================================================
+
+Original drivers from Pei Liu <pbl@cypress.com> for ARM architecture only.
+Documentaion and readme for Architecture x86 (ADNP/1486) premealy.
+
+
+Kernel configuration:
+---------------------
+o Patch USB drivers into your kerneltree
+	cd Your_kernel_root
+
+	gunzip linux-2.4.20-usb-1.patch.gz
+	patch -p1 -T < linux-2.4.20-usb*.patch
+   OR
+	gunzip -dc linux-2.4.20-usb*.patch.gz | patch -p1 -T
+
+o Load default configuration for CP486SX/2 with ADNP/1486 and USB
+	arch/i386/adnp1486-usb104-SSV20030516
+
+o Run "make configure" and set / verify this entries
+    Code maturity level options  --->
+	[*] Prompt for development and/or incomplete code/drivers
+    General setup  --->
+	[*] PCI support
+	(BIOS)   PCI access mode
+	[ ] PCI device name database
+    SCSI support  --->
+	<M> SCSI support
+	<M>   SCSI disk support
+	(8) Maximum number of SCSI disks that can be loaded as modules
+	... Disable all other options ...
+	SCSI low-level drivers  ---> 
+	    ... Disable all low level drivers ...
+    Input core support  --->
+	<M> Input core support			(Need only for Keyboard or Mouse)
+	<M>   Keyboard support
+	<M>   Mouse support
+    Character devices  --->
+	[*] Virtual terminal			(Need only for Keyboard)
+    Console drivers  --->
+	[*] VGA text console			(Need only for Key/Mouse)
+	Frame-buffer support  --->		(... or use FB)
+    USB support  --->
+	<M> Support for USB
+	[ ]   USB verbose debug messages	(Optional)
+	[*]   Preliminary USB device filesystem	(Optional for debugging)
+    --- USB Host Controller Drivers
+	<M>   SL811HS Alternate (support isochronous mode)
+	...
+	<M>   SL811HS (x86, StrongARM)  support (old driver)
+	Disable all others "USB Host Controller Drivers"
+    --- USB Device Class drivers
+	<M>   USB Mass Storage support
+	... and some aditional devices ...
+	<M>   USB Printer support
+	<M>   USB HIDBP Keyboard (basic) support
+	<M>   USB HIDBP Mouse (basic) support
+	USB Serial Converter support  --->
+	    <M> USB Serial Converter support
+	    <M>   USB FTDI Single Port Serial Driver
+o We have no PCI- and no SCSI-System, but all USB-drivers need CONFIG_PCI=y.
+  USB-Floppy driver need the SCSI-Subsystem, so we must enable this global
+  and disable all low level drivers in this menu.
+--- OR ---
+  Download origanal kerneltree, and patch comlplete ADNP
+  with USB support and load configuration for this:
+	bunzip2 -c linux-2.4.20.tar.bz2 | tar xvf -
+	gunzip -c linux-2.4.20-SSV20030516.diff.gz | patch -p1 -T
+	Configuration: arch/i386/adnp1486-usb104-SSV20030516
+  
+o Compile the kernel
+  make dep
+  make ROOT_DEV=/dev/ram0 zImage
+  make modules
+  export INSTALL_MOD_PATH="`pwd`/_install" ; make modules_install
+
+
+Default device configuration hc_sl811.o for USB1/104:
+-----------------------------------------------------
+io	= 0x220
+irq	= 12
+Remember: Second Controller was handled internal with IO offset +2.
+
+
+Installation hc_sl811.o for CF1/USB:
+------------------------------------
+Compact Flash to USB adapter in io address of ide driver. It is for embedded
+deviced only.
+Please disable IDE driver in kernel configuration or do not load IDE drivers!
+Change MAX_CONTROLERS = 1 into source asm/sl811-hw.h, recompile driver!
+  First Controller only
+    insmod hc_sl811.o io=0x1F0 irq=14
+  Second Controller only
+    insmod hc_sl811.o io=0x3F6 irq=14
+
+Driver hc_sl811.o can not handle both controllers at same time.
+This driver need a address-offset of 2 between controllers.
+Please use alternate driver sl811.o instand.
+
+
+Installation Alternate driver sl811.o:
+--------------------------------------
+This driver have a better interrupt handler, but don't tested with all devices.
+
+Install both controllers on USB1-104 (default):
+    insmod sl811.o io=0x220,0x222 irq=12,12
+
+Install both controllers on CF/USB1:
+    insmod sl811.o io=0x1f0,0x3f6 irq=14,14
+
+Second controller can disable with specific IOBASE=0 for this controller.
+
+
+General about USB:
+------------------
+Please install first the driver for hardware,
+and than plugin the hardware into first USB port.
+
+If your hardware find no driver the usbcore give ub a massage for missing
+driver on conole or in file /proc/kmsg such as:
+    new USB device <NULL>-1.9, assigned address 7
+    USB device 7 (vend/prod 0x403/0x8372) is not claimed by any active drive
+In this case remove the hardware from USB port, install the driver and
+than plugin hardware again.
+A list of driver for this missing hardware can found in file
+/_install/lib/modules/2.4.20/modules.usbmap
+Search the number 8372 in this file an verify the vendor ID. So you will
+find the driver name "ftdi_sio" in this file.
+If your hardware not listen in this file. Look into source and search your
+numbers in source.
+More read file:/Documentation/usb/proc_usb_info.txt
+
+Drivers are all under contructions. So some drivers make a kernel panic. In
+this case read all about the drivers dokumentaiona and the drivers source.
+Some drivers need a other kernel driver, but not strictly checked in kenel
+configuration. Here can help the ksymsoops.
+
+
+
+Install a Floppy (NEC UF0001) or USB Stick Fujitsu/Siemens/iomega:
+------------------------------
+Copy files to target (FTP) and load all drivers.
+Load Generic USB-Handler
+	insmod usbcore.o
+Load USB-Host controller, parameters are optional (default urb_debug=0 io=220 irq=12)
+	insmod hc_sl811.o
+Run the USB-Filesystem
+	mount -t usbdevfs usbdevfs /proc/bus/usb
+Load drivers for disk storage and file systems
+	insmod scsi_mod.o
+	insmod usb-storage.o
+	insmod fat.o
+	insmod vfat.o
+	insmod sd_mod.o
+Create node for floppy
+	mknod /dev/sda b 8 0
+
+Put a disk into your floppy anth than plugin a USB-Floppy (such NEC Model UF0001)
+into first USB-Port. Some Messages will be list on console or in file /proc/kmsg.
+The disk is power on and the SCSI driver will search some partions on disk. Floppy
+have no partions, so must use the first SCSI device without a partion number for mount.
+Than mount the floppy:
+	mount /dev/sda /mnt -t vfat
+
+If you see a partions check with valid partion 1, you should mount this partion.
+Mostly Memory Sticks are formated with one partion. But if Windows format it again,
+no partions is use.
+
+You see that:
+	Partition check:
+	 sda: sda1
+Than mount with follow steps:
+	mknod /dev/sda1 b 8 1
+	mount /dev/sda1 /mnt -t vfat
+
+Create complete list of nodes for SCSI-devices:
+    # First inserted device
+    echo -n "Create /dev/sda... "
+    mknod /dev/sda b 8 0
+    for i in  1 2 3 4 5 6 7
+    do
+      echo -n "$i "
+      mknod sda$i c 8 $i
+    done
+    # Second inserted device
+    echo -n "Create /dev/sdb... "
+    mknod /dev/sdb b 8 16
+    mknod /dev/sdb1 b 8 17
+    echo " done"
+    # Set some rights
+    chown root.disk sd*
+    chmod 660 sd*
+
+
+Install a Keyboard:
+-------------------
+Copy files to target (FTP) and load all drivers.
+Load Generic USB-Handler
+	insmod usbcore.o
+Load USB-Host controller, parameters are optional (default urb_debug=0 io=220 irq=12)
+	insmod hc_sl811.o
+Run the USB-Filesystem
+	mount -t usbdevfs usbdevfs /proc/bus/usb
+Load drivers for USB-Keyboard
+	insmod input.o
+	insmod keybdev.o
+	insmod usbkbd.o
+Now you can plugin Keyboard into first USB-Port and login on first console.
+
+Something stuff:
+"Undefined Symbols handle_scancode, keyboard_tasklet, kbd_ledfunc" at install ???
+USB keyboard need PC-style keyboard driver, because the USB driver
+simulate standard AT-Keycodes. A normaly AT- or PS/2-Keyboard must not
+exist for this. The driver says normaly error (Timeout) on boot.
+You must enable CONFIG_VT in kernel konfiguration!
+Character devices  --->
+    [*] Virtual terminal
+    [ ]   Support for console on virtual terminal
+
+Read <file:Documentation/input/input.txt>
+
+
+Install a Mouse:
+----------------
+Load Generic USB-Handle
+	insmod usbcore.o
+Load USB-Host controller
+	insmod hc_sl811.o
+Run the USB-Filesystem
+	mount -t usbdevfs usbdevfs /proc/bus/usb
+Load Generic Input device
+	insmod input.o
+Load USB-Mouse driver
+	insmod input.o
+	insmod mousedev.o
+	insmod usbmouse.o
+
+Read <file:Documentation/input/input.txt>
+
+
+Install a serial adapter (Sample FTDI):
+---------------------------------------
+Load Generic USB-Handle
+	insmod usbcore.o
+Load USB-Host controller
+	insmod hc_sl811.o
+Run the USB-Filesystem
+	mount -t usbdevfs usbdevfs /proc/bus/usb
+Load Generic derial device and hardware specific device
+	insmod usbserial.o
+	insmod ftdi_sio.o
+Create node entry for this device
+	mknod /dev/ttyUSB0 c 188 0
+Than plugin the hardware into first USB port and
+use serial device on /dev/ttyUSB0, such call a login:
+	/sbin/getty 115200 ttyUSB0 vt100 &
+
+
+USB-Utils:
+----------
+- usb-0.6-7.rpm, usb-0.6-7.src.rpm
+  /usr/sbin/lsusb, /usr/share/usb.ids
+  Good tool to list devices parameters.
+  You must load usbcore.o, hc_sl811.o and proc-usb before
+  program works right (use script usb.sh).
+  More details: Install usb-0.6-7.rpm on Your desktop and use "man lsusb".
+
+
+Known Bugs:
+-----------
+
+PL2302 Profilic USB to serial converter will not work with hc_sl811.c (Bulk/Timeout).
+USB Floppy will not work with alternate driver sl811.o (Sector not found)
+
+
+CHANGELOG:
+----------
+* Fri 03 Okt 2003 hne
+- Patch for 2.4.23-pre6
+- Only low level port io in hardware include as inline functions.
+- Move hc_sl811 and sl811 into host directory.
+- sl811 for two controllers (alternate x86 only).
+
+* Mit 24 Sep 2003 hne
+- Misplaced "host/uhci.o" in Makefile.
+- Move all x86/arm arch depens from main sl811.c to sl811-hw.h.
+
+* Die 23 Sep 2003 hne
+- Put arm and x86 architectur into separate file in include directory.
+- Modifications for both controllers on CF/USB1, alternate sl811 only.
+  Parameter for CF/USB1: "io=0x1f0,0x3f6 irq=14".
+
+* Fri 19 Sep 2003 hne
+- First version for both controllers on USB1-104.
+- Alternative driver sl811.c from kernel 2.4.22 (thanks Yinah),
+  also for 2.4.20. USB Sticks works, Floppy not.
+
+* Die 02 Sep 2003 hne
+- IO range only 2 address. For CF1USB we need io addres 3F6 and 3F7,
+  but do not use 3f8 (ttyS0).
+
+* Mon 11 Aug 2003 hne
+- Comments for using iomega Memory Stick
+
+* Don 12 Jun 2003 hne
+- Added Bus-Name for Kernel 2.4.20, no pattern_test at unload driver.
+- more doc
+
+* Fri May 16 2003 hne
+- More comments, new patchfile, include usb-konfiguration as file
+
+* Wed May 14 2003 hne
+- Patch error: Old Sources was in Kerneltree!
+
+* Mon Mar 17 2003 hne
+- Copy usb SL811 from 2.4.19-rc into 2.4.20 kerneltree
+- Add SL811 in Config and Make
+
+* 18.11.2002 hne
+- hc_sl811_rh.c:
+  rh_unlink_urb: Use usb_dec_dev_use instand of usb_put_dev. Function
+  usb_put_dev isn't known in this module. Some others have a macro for
+  this. What is right usb_put_dev or usb_dec_dev_use?
+- hc_sl811.c:
+  Split into 3 files. Arcitectures store in hc_sl811-arm.c and hc_sl811-x86.c
+  Correct release_region() for both io address, so we can unload modul and
+  load again without reboot.
+  All IO access use 8 bit Data and register number (type __u8).
+  All functions static.
+  Only x86: base_addr renamed to io. data_reg_addr not used.
diff -urN linux-2.4.22-bk41/Documentation/usb/w9968cf.txt linux-2.4.22-bk42/Documentation/usb/w9968cf.txt
--- linux-2.4.22-bk41/Documentation/usb/w9968cf.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/Documentation/usb/w9968cf.txt	2003-10-26 02:49:52.000000000 -0800
@@ -0,0 +1,486 @@
+
+         W996[87]CF JPEG USB Dual Mode Camera Chip driver for Linux 2.4
+         ==============================================================
+
+                               - 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.4.19 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). 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.
+
+It is recommended to install the latest and full featured version of the 
+W996[87]CF driver, which 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 "Kernel configuration"
+paragraph.
+
+
+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.4.19 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=m
+	CONFIG_USB_UHCI_ALT=m
+	CONFIG_USB_OHCI=m
+
+Also, make sure "Enforce bandwidth allocation" is NOT enabled.
+
+The /proc filesystem can be optionally built into the kernel:
+
+	# File systems
+	#
+	CONFIG_PROC_FS=y
+
+	# Video For Linux
+	#
+	CONFIG_VIDEO_PROC_FS=y
+
+	# 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; they are named, in order: "videodev",
+"usbcore", then "ehci-hcd", "usb-uhci", "uhci", "usb-ohci" (just one), and also
+"i2c-core" and "ovcamchip".
+
+Loading can be done this way, from root:
+
+	[root@localhost home]# modprobe i2c-core
+	[root@localhost ov511-x.xx]# insmod ./ovcamchip.o
+	[root@localhost home]# modprobe w9968cf
+
+At this point the devices should be recognized. There are two ways of verifying
+that the loading process has gone well: the first is to analyze kernel 
+messages:
+
+	[user@localhost home]$ dmesg
+
+A second way is to retrieve informations from the entries that have just been
+created in the /proc/video/w9968cf/ directory; this feature works if and only
+if the kernel has been built with the /proc filesystem support.
+As an example, the following command will print the list of registered cameras:
+
+	[user@localhost home]$ cat /proc/video/w9968cf/global
+
+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, this paramater is set to,
+                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;
diff -urN linux-2.4.22-bk41/MAINTAINERS linux-2.4.22-bk42/MAINTAINERS
--- linux-2.4.22-bk41/MAINTAINERS	2003-10-26 02:49:49.000000000 -0800
+++ linux-2.4.22-bk42/MAINTAINERS	2003-10-26 02:49:52.000000000 -0800
@@ -2068,6 +2068,13 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
+USB W9968CF DRIVER
+P:      Luca Risolia
+M:      luca_ing@libero.it
+L:      linux-usb-devel@lists.sourceforge.net
+W:      http://go.lamarinapunto.com
+S:      Maintained
+
 VFAT FILESYSTEM:
 P:	Gordon Chaffee
 M:	chaffee@cs.berkeley.edu
diff -urN linux-2.4.22-bk41/Makefile linux-2.4.22-bk42/Makefile
--- linux-2.4.22-bk41/Makefile	2003-10-26 02:49:49.000000000 -0800
+++ linux-2.4.22-bk42/Makefile	2003-10-26 02:49:52.000000000 -0800
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 22
-EXTRAVERSION = -bk41
+EXTRAVERSION = -bk42
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.22-bk41/drivers/usb/Config.in linux-2.4.22-bk42/drivers/usb/Config.in
--- linux-2.4.22-bk41/drivers/usb/Config.in	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/Config.in	2003-10-26 02:49:55.000000000 -0800
@@ -78,6 +78,7 @@
       dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB W996[87]CF Camera support' CONFIG_USB_W9968CF $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_I2C
       dep_tristate '  USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
       dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
       dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
diff -urN linux-2.4.22-bk41/drivers/usb/Makefile linux-2.4.22-bk42/drivers/usb/Makefile
--- linux-2.4.22-bk41/drivers/usb/Makefile	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk42/drivers/usb/Makefile	2003-10-26 02:49:55.000000000 -0800
@@ -77,6 +77,9 @@
 	obj-y += host/usb-ohci.o
 endif
 
+subdir-$(CONFIG_USB_SL811HS_ALT)	+= host
+subdir-$(CONFIG_USB_SL811HS)	+= host
+
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
 obj-$(CONFIG_USB_HID)		+= hid.o
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
@@ -100,6 +103,7 @@
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
 obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_OV511)		+= ov511.o
+obj-$(CONFIG_USB_W9968CF)	+= w9968cf.o
 obj-$(CONFIG_USB_SE401)		+= se401.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
diff -urN linux-2.4.22-bk41/drivers/usb/brlvger.c linux-2.4.22-bk42/drivers/usb/brlvger.c
--- linux-2.4.22-bk41/drivers/usb/brlvger.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/brlvger.c	2003-10-26 02:49:55.000000000 -0800
@@ -623,14 +623,14 @@
 			int firstpart = 6 - off;
 			
 #ifdef WRITE_DEBUG
-			dbg3("off: %d, rs: %d, count: %d, firstpart: %d",
+			dbg3("off: %lld, rs: %d, count: %d, firstpart: %d",
 			     off, rs, count, firstpart);
 #endif
 
 			firstpart = (firstpart < count) ? firstpart : count;
 
 #ifdef WRITE_DEBUG
-			dbg3("off: %d", off);
+			dbg3("off: %lld", off);
 			dbg3("firstpart: %d", firstpart);
 #endif
 
@@ -650,7 +650,7 @@
 			off +=2;
 
 #ifdef WRITE_DEBUG
-			dbg3("off: %d, rs: %d, count: %d, firstpart: %d, "
+			dbg3("off: %lld, rs: %d, count: %d, firstpart: %d, "
 				"written: %d", 	off, rs, count, firstpart, written);
 #endif
 		}
diff -urN linux-2.4.22-bk41/drivers/usb/gadget/Config.in linux-2.4.22-bk42/drivers/usb/gadget/Config.in
--- linux-2.4.22-bk41/drivers/usb/gadget/Config.in	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/gadget/Config.in	2003-10-26 02:49:55.000000000 -0800
@@ -5,6 +5,8 @@
 # Long term, this likely doesn't all belong in one directory
 # Plan to split it up eventually.
 #
+# CAREFUL!  Some versions of "xconfig" don't execute this correctly.
+#
 mainmenu_option next_comment
 comment 'Support for USB gadgets'
 
@@ -18,11 +20,14 @@
   comment 'USB Peripheral Controller Drivers'
   
   # assume all the dependencies may be undefined ("== true", yeech)
+  define_tristate CONFIG_USB_GADGET_CONTROLLER n
   if [ "$CONFIG_PCI" = "y" ] ; then
     tristate '  NetChip 2280 support' CONFIG_USB_NET2280
     define_tristate CONFIG_USB_GADGET_CONTROLLER $CONFIG_USB_NET2280
   fi
 
+  # pxa2xx_udc, goku_udc, and others also work on 2.4 ...
+
   if [ "$CONFIG_USB_GADGET_CONTROLLER" = "y" -o "$CONFIG_USB_GADGET_CONTROLLER" = "m" ] ; then
 
   #
@@ -44,25 +49,28 @@
   if [ "$CONFIG_USB_ZERO" = "y" -o "$CONFIG_USB_ZERO" = "m" ]; then
       if [ "$CONFIG_USB_NET2280" = "y" -o "$CONFIG_USB_NET2280" = "m" ]; then
   	define_bool CONFIG_USB_ZERO_NET2280 y
-      fi
-      if [ "$CONFIG_USB_PXA2XX" = "y" -o "$CONFIG_USB_PXA2XX" = "m" ]; then
+      else if [ "$CONFIG_USB_PXA2XX" = "y" -o "$CONFIG_USB_PXA2XX" = "m" ]; then
   	define_bool CONFIG_USB_ZERO_PXA2XX y
-      fi
+      else if [ "$CONFIG_USB_GOKU" = "y" -o "$CONFIG_USB_GOKU" = "m" ]; then
+  	define_bool CONFIG_USB_ZERO_GOKU y
+      fi fi fi
       # ...
   fi
   
-  dep_tristate '  Ethernet Gadget (EXPERIMENTAL)' CONFIG_USB_ETH $CONFIG_USB_GADGET_CONTROLLER
+  dep_tristate '  Ethernet Gadget (EXPERIMENTAL)' CONFIG_USB_ETH $CONFIG_USB_GADGET_CONTROLLER $CONFIG_NET
   if [ "$CONFIG_USB_ETH" = "y" -o "$CONFIG_USB_ETH" = "m" ]; then
       if [ "$CONFIG_USB_NET2280" = "y" -o "$CONFIG_USB_NET2280" = "m" ]; then
   	define_bool CONFIG_USB_ETH_NET2280 y
-      fi
-      if [ "$CONFIG_USB_PXA2XX" = "y" -o "$CONFIG_USB_PXA2XX" = "m" ]; then
+      else if [ "$CONFIG_USB_PXA2XX" = "y" -o "$CONFIG_USB_PXA2XX" = "m" ]; then
   	define_bool CONFIG_USB_ETH_PXA2XX y
-      fi
+      else if [ "$CONFIG_USB_GOKU" = "y" -o "$CONFIG_USB_GOKU" = "m" ]; then
+  	define_bool CONFIG_USB_ETH_GOKU y
+      fi fi fi
       # ...
   fi
   
-  # ... or other gadget drivers:  printer class, storage, hid, etc ...
+  
+  # ... or other gadget drivers:  printer class, hid, etc ...
 
   fi
 fi
diff -urN linux-2.4.22-bk41/drivers/usb/gadget/ether.c linux-2.4.22-bk42/drivers/usb/gadget/ether.c
--- linux-2.4.22-bk41/drivers/usb/gadget/ether.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/gadget/ether.c	2003-10-26 02:49:55.000000000 -0800
@@ -23,8 +23,8 @@
 // #define VERBOSE
 
 #include <linux/config.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
@@ -87,11 +87,12 @@
 #endif
 
 /* 2.5 modified and renamed these */
-
+#ifndef	INIT_WORK
 #define work_struct		tq_struct
 #define INIT_WORK		INIT_TQUEUE
 #define schedule_work		schedule_task
 #define	flush_scheduled_work	flush_scheduled_tasks
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -117,28 +118,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* This driver keeps a variable number of requests queued, more at
- * high speeds.  (Numbers are just educated guesses, untuned.)
- * Shrink the queue if memory is tight, or make it bigger to
- * handle bigger traffic bursts between IRQs (assuming hw dma queues)
- */
-
-static unsigned qmult = 4;
-
-#define HS_FACTOR	5
-
-#define qlen(gadget) \
-	(qmult*((gadget->speed == USB_SPEED_HIGH) ? HS_FACTOR : 1))
-
-/* defer IRQs on highspeed TX */
-#define TX_DELAY	8
-
-
-MODULE_PARM (qmult, "i");
-MODULE_PARM_DESC (qmult, "rx/tx buffering factor");
-
-/*-------------------------------------------------------------------------*/
-
 /* Thanks to NetChip Technologies for donating this product ID.
  *
  * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
@@ -187,6 +166,7 @@
  */
 #ifdef	CONFIG_USB_ETH_NET2280
 #define CHIP			"net2280"
+#define DEFAULT_QLEN		4		/* has dma chaining */
 #define DRIVER_VERSION_NUM	0x0111
 #define EP0_MAXPACKET		64
 static const char EP_OUT_NAME [] = "ep-a";
@@ -232,7 +212,7 @@
 /* supports remote wakeup, but this driver doesn't */
 
 /* no hw optimizations to apply */
-#define hw_optimize(g) do {} while (0);
+#define hw_optimize(g) do {} while (0)
 #endif
 
 /*
@@ -255,7 +235,28 @@
 /* doesn't support remote wakeup? */
 
 /* no hw optimizations to apply */
-#define hw_optimize(g) do {} while (0);
+#define hw_optimize(g) do {} while (0)
+#endif
+
+/*
+ * Toshiba TC86C001 ("Goku-S") UDC
+ *
+ * This has three semi-configurable full speed bulk/interrupt endpoints.
+ */
+#ifdef	CONFIG_USB_ETH_GOKU
+#define CHIP			"goku"
+#define DRIVER_VERSION_NUM	0x0116
+#define EP0_MAXPACKET		8
+static const char EP_OUT_NAME [] = "ep1-bulk";
+#define EP_OUT_NUM	1
+static const char EP_IN_NAME [] = "ep2-bulk";
+#define EP_IN_NUM	2
+static const char EP_STATUS_NAME [] = "ep3-bulk";
+#define EP_STATUS_NUM	3
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* doesn't support remote wakeup */
+
+#define hw_optimize(g) do {} while (0)
 #endif
 
 /*-------------------------------------------------------------------------*/
@@ -313,9 +314,32 @@
 
 /*-------------------------------------------------------------------------*/
 
+#ifndef DEFAULT_QLEN
+#define DEFAULT_QLEN	2	/* double buffering by default */
+#endif
+
+#ifdef HIGHSPEED
+
+static unsigned qmult = 5;
+MODULE_PARM (qmult, "i");
+
+
+/* for dual-speed hardware, use deeper queues at highspeed */
+#define qlen(gadget) \
+	(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
+
+/* also defer IRQs on highspeed TX */
+#define TX_DELAY	DEFAULT_QLEN
+
+#else	/* !HIGHSPEED ... full speed: */
+#define qlen(gadget) DEFAULT_QLEN
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
 #define xprintk(d,level,fmt,args...) \
-	printk(level "%s %s: " fmt , shortname , (d)->gadget->dev.bus_id , \
-		## args)
+	printk(level "%s: " fmt , (d)->net->name , ## args)
 
 #ifdef DEBUG
 #undef DEBUG
@@ -892,6 +916,8 @@
 
 static void eth_reset_config (struct eth_dev *dev)
 {
+	struct usb_request	*req;
+
 	if (dev->config == 0)
 		return;
 
@@ -900,17 +926,30 @@
 	netif_stop_queue (dev->net);
 	netif_carrier_off (dev->net);
 
-	/* just disable endpoints, forcing completion of pending i/o.
-	 * all our completion handlers free their requests in this case.
+	/* disable endpoints, forcing (synchronous) completion of
+	 * pending i/o.  then free the requests.
 	 */
 	if (dev->in_ep) {
 		usb_ep_disable (dev->in_ep);
+		while (likely (!list_empty (&dev->tx_reqs))) {
+			req = container_of (dev->tx_reqs.next,
+						struct usb_request, list);
+			list_del (&req->list);
+			usb_ep_free_request (dev->in_ep, req);
+		}
 		dev->in_ep = 0;
 	}
 	if (dev->out_ep) {
 		usb_ep_disable (dev->out_ep);
+		while (likely (!list_empty (&dev->rx_reqs))) {
+			req = container_of (dev->rx_reqs.next,
+						struct usb_request, list);
+			list_del (&req->list);
+			usb_ep_free_request (dev->out_ep, req);
+		}
 		dev->out_ep = 0;
 	}
+
 #ifdef	EP_STATUS_NUM
 	if (dev->status_ep) {
 		usb_ep_disable (dev->status_ep);
@@ -1676,7 +1715,7 @@
 {
 	struct eth_dev		*dev = (struct eth_dev *) net->priv;
 
-	DEBUG (dev, "%s\n", __FUNCTION__);
+	VDEBUG (dev, "%s\n", __FUNCTION__);
 	netif_stop_queue (net);
 
 	DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
@@ -1690,6 +1729,7 @@
 		usb_ep_disable (dev->out_ep);
 		if (netif_carrier_ok (dev->net)) {
 			DEBUG (dev, "host still using in/out endpoints\n");
+			// FIXME idiom may leave toggle wrong here
 			usb_ep_enable (dev->in_ep, dev->in);
 			usb_ep_enable (dev->out_ep, dev->out);
 		}
@@ -1708,7 +1748,6 @@
 eth_unbind (struct usb_gadget *gadget)
 {
 	struct eth_dev		*dev = get_gadget_data (gadget);
-	struct usb_request	*req;
 
 	DEBUG (dev, "unbind\n");
 
@@ -1721,19 +1760,6 @@
 		dev->req = 0;
 	}
 
-	while (!list_empty (&dev->tx_reqs)) {
-		req = container_of (dev->tx_reqs.next,
-					struct usb_request, list);
-		list_del (&req->list);
-		usb_ep_free_request (dev->in_ep, req);
-	}
-	while (!list_empty (&dev->rx_reqs)) {
-		req = container_of (dev->rx_reqs.next,
-					struct usb_request, list);
-		list_del (&req->list);
-		usb_ep_free_request (dev->out_ep, req);
-	}
-
 	unregister_netdev (dev->net);
 	dev_put (dev->net);
 
@@ -1816,10 +1842,6 @@
 	dev->gadget = gadget;
 	set_gadget_data (gadget, dev);
 	gadget->ep0->driver_data = dev;
-	INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n", driver_desc);
-#ifdef	DEV_CONFIG_CDC
-	INFO (dev, "CDC host enet %s\n", ethaddr);
-#endif
 	
 	/* two kinds of host-initiated state changes:
 	 *  - iff DATA transfer is active, carrier is "on"
@@ -1830,8 +1852,16 @@
 
  	// SET_NETDEV_DEV (dev->net, &gadget->dev);
  	status = register_netdev (dev->net);
- 	if (status == 0)
+ 	if (status == 0) {
+
+		INFO (dev, "%s, " CHIP ", version: " DRIVER_VERSION "\n",
+				driver_desc);
+#ifdef	DEV_CONFIG_CDC
+		INFO (dev, "CDC host enet %s\n", ethaddr);
+#endif
  		return status;
+	}
+	pr_debug("%s: register_netdev failed, %d\n", shortname, status);
 fail:
 	eth_unbind (gadget);
 	return status;
diff -urN linux-2.4.22-bk41/drivers/usb/gadget/zero.c linux-2.4.22-bk42/drivers/usb/gadget/zero.c
--- linux-2.4.22-bk41/drivers/usb/gadget/zero.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/gadget/zero.c	2003-10-26 02:49:55.000000000 -0800
@@ -63,8 +63,8 @@
 // #define VERBOSE
 
 #include <linux/config.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
@@ -181,7 +181,7 @@
 /* supports remote wakeup, but this driver doesn't */
 
 /* no hw optimizations to apply */
-#define hw_optimize(g) do {} while (0);
+#define hw_optimize(g) do {} while (0)
 #endif
 
 /*
@@ -208,7 +208,26 @@
 /* doesn't support remote wakeup? */
 
 /* no hw optimizations to apply */
-#define hw_optimize(g) do {} while (0);
+#define hw_optimize(g) do {} while (0)
+#endif
+
+/*
+ * Toshiba TC86C001 ("Goku-S") UDC
+ *
+ * This has three semi-configurable full speed bulk/interrupt endpoints.
+ */
+#ifdef	CONFIG_USB_ZERO_GOKU
+#define CHIP			"goku"
+#define DRIVER_VERSION_NUM	0x0116
+#define EP0_MAXPACKET		8
+static const char EP_OUT_NAME [] = "ep1-bulk";
+#define EP_OUT_NUM	1
+static const char EP_IN_NAME [] = "ep2-bulk";
+#define EP_IN_NUM	2
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* doesn't support remote wakeup */
+
+#define hw_optimize(g) do {} while (0)
 #endif
 
 /*-------------------------------------------------------------------------*/
diff -urN linux-2.4.22-bk41/drivers/usb/hc_simple.c linux-2.4.22-bk42/drivers/usb/hc_simple.c
--- linux-2.4.22-bk41/drivers/usb/hc_simple.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/hc_simple.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1072 +0,0 @@
-/*-------------------------------------------------------------------------*/
-/*-------------------------------------------------------------------------*
- * simple generic USB HCD frontend Version 0.9.5 (10/28/2001)
- * for embedded HCs (SL811HS)
- * 
- * USB URB handling, hci_ hcs_
- * URB queueing, qu_
- * Transfer scheduling, sh_
- * 
- *
- *-------------------------------------------------------------------------*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *-------------------------------------------------------------------------*/
-
-/* main lock for urb access */
-static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED;
-
-/*-------------------------------------------------------------------------*/
-/*-------------------------------------------------------------------------*/
-/* URB HCD API function layer
- * * * */
-
-/***************************************************************************
- * Function Name : hcs_urb_queue
- *
- * This function initializes the urb status and length before queueing the 
- * urb. 
- *
- * Input:  hci = data structure for the host controller
- *         urb = USB request block data structure 
- *
- * Return: 0 
- **************************************************************************/
-static inline int hcs_urb_queue (hci_t * hci, struct urb * urb)
-{
-	int i;
-
-	DBGFUNC ("enter hcs_urb_queue\n");
-	if (usb_pipeisoc (urb->pipe)) {
-		DBGVERBOSE ("hcs_urb_queue: isoc pipe\n");
-		for (i = 0; i < urb->number_of_packets; i++) {
-			urb->iso_frame_desc[i].actual_length = 0;
-			urb->iso_frame_desc[i].status = -EXDEV;
-		}
-
-		/* urb->next hack : 1 .. resub, 0 .. single shot */
-		/* urb->interval = urb->next ? 1 : 0; */
-	}
-
-	urb->status = -EINPROGRESS;
-	urb->actual_length = 0;
-	urb->error_count = 0;
-
-	if (usb_pipecontrol (urb->pipe))
-		hc_flush_data_cache (hci, urb->setup_packet, 8);
-	if (usb_pipeout (urb->pipe))
-		hc_flush_data_cache (hci, urb->transfer_buffer,
-				     urb->transfer_buffer_length);
-
-	qu_queue_urb (hci, urb);
-
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : hcs_return_urb
- *
- * This function the return path of URB back to the USB core. It calls the
- * the urb complete function if exist, and also handles the resubmition of
- * interrupt URBs.
- *
- * Input:  hci = data structure for the host controller
- *         urb = USB request block data structure 
- *         resub_ok = resubmit flag: 1 = submit urb again, 0 = not submit 
- *
- * Return: 0 
- **************************************************************************/
-static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
-{
-	struct usb_device *dev = urb->dev;
-	int resubmit = 0;
-
-	DBGFUNC ("enter hcs_return_urb, urb pointer = 0x%x, "
-		 "transferbuffer point = 0x%x, "
-		 " setup packet pointer = 0x%x, context pointer = 0x%x \n",
-		 (__u32 *) urb, (__u32 *) urb->transfer_buffer,
-		 (__u32 *) urb->setup_packet, (__u32 *) urb->context);
-	if (urb_debug)
-		urb_print (urb, "RET", usb_pipeout (urb->pipe));
-
-	resubmit = urb->interval && resub_ok;
-
-	urb->dev = urb->hcpriv = NULL;
-
-	if (urb->complete) {
-		urb->complete (urb);	/* call complete */
-	}
-
-	if (resubmit) {
-		/* requeue the URB */
-		urb->dev = dev;
-		hcs_urb_queue (hci, urb);
-	}
-
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : hci_submit_urb
- *
- * This function is called by the USB core API when an URB is available to
- * process.  This function does the following
- *
- * 1) Check the validity of the URB
- * 2) Parse the device number from the URB
- * 3) Pass the URB to the root hub routine if its intended for the hub, else
- *    queue the urb for the attached device. 
- *
- * Input: urb = USB request block data structure 
- *
- * Return: 0 if success or error code 
- **************************************************************************/
-static int hci_submit_urb (struct urb * urb)
-{
-	hci_t *hci;
-	unsigned int pipe = urb->pipe;
-	unsigned long flags;
-	int ret;
-
-	DBGFUNC ("enter hci_submit_urb, pipe = 0x%x\n", urb->pipe);
-	if (!urb->dev || !urb->dev->bus || urb->hcpriv)
-		return -EINVAL;
-
-	if (usb_endpoint_halted
-	    (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) {
-		printk ("hci_submit_urb: endpoint_halted\n");
-		return -EPIPE;
-	}
-	hci = (hci_t *) urb->dev->bus->hcpriv;
-
-	/* a request to the virtual root hub */
-
-	if (usb_pipedevice (pipe) == hci->rh.devnum) {
-		if (urb_debug > 1)
-			urb_print (urb, "SUB-RH", usb_pipein (pipe));
-
-		return rh_submit_urb (urb);
-	}
-
-	/* queue the URB to its endpoint-queue */
-
-	spin_lock_irqsave (&usb_urb_lock, flags);
-	ret = hcs_urb_queue (hci, urb);
-	if (ret != 0) {
-		/* error on return */
-		DBGERR
-		    ("hci_submit_urb: return err, ret = 0x%x, urb->status = 0x%x\n",
-		     ret, urb->status);
-	}
-
-	spin_unlock_irqrestore (&usb_urb_lock, flags);
-
-	return ret;
-
-}
-
-/***************************************************************************
- * Function Name : hci_unlink_urb
- *
- * This function mark the URB to unlink
- *
- * Input: urb = USB request block data structure 
- *
- * Return: 0 if success or error code 
- **************************************************************************/
-static int hci_unlink_urb (struct urb * urb)
-{
-	unsigned long flags;
-	hci_t *hci;
-	DECLARE_WAITQUEUE (wait, current);
-	void *comp = NULL;
-
-	DBGFUNC ("enter hci_unlink_urb\n");
-
-	if (!urb)		/* just to be sure */
-		return -EINVAL;
-
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-
-	hci = (hci_t *) urb->dev->bus->hcpriv;
-
-	/* a request to the virtual root hub */
-	if (usb_pipedevice (urb->pipe) == hci->rh.devnum) {
-		return rh_unlink_urb (urb);
-	}
-
-	if (urb_debug)
-		urb_print (urb, "UNLINK", 1);
-
-	spin_lock_irqsave (&usb_urb_lock, flags);
-
-	if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
-		/* URB active? */
-
-		if (urb->
-		    transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) {
-			/* asynchron with callback */
-
-			list_del (&urb->urb_list);	/* relink the urb to the del list */
-			list_add (&urb->urb_list, &hci->del_list);
-			spin_unlock_irqrestore (&usb_urb_lock, flags);
-
-		} else {
-			/* synchron without callback */
-
-			add_wait_queue (&hci->waitq, &wait);
-
-			set_current_state (TASK_UNINTERRUPTIBLE);
-			comp = urb->complete;
-			urb->complete = NULL;
-
-			list_del (&urb->urb_list);	/* relink the urb to the del list */
-			list_add (&urb->urb_list, &hci->del_list);
-
-			spin_unlock_irqrestore (&usb_urb_lock, flags);
-
-			schedule_timeout (HZ / 50);
-
-			if (!list_empty (&urb->urb_list))
-				list_del (&urb->urb_list);
-
-			urb->complete = comp;
-			urb->hcpriv = NULL;
-			remove_wait_queue (&hci->waitq, &wait);
-		}
-	} else {
-		/* hcd does not own URB but we keep the driver happy anyway */
-		spin_unlock_irqrestore (&usb_urb_lock, flags);
-
-		if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
-			urb->status = -ENOENT;
-			urb->actual_length = 0;
-			urb->complete (urb);
-			urb->status = 0;
-		} else {
-			urb->status = -ENOENT;
-		}
-	}
-
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : hci_alloc_dev
- *
- * This function allocates private data space for the usb device and 
- * initialize the endpoint descriptor heads.
- *
- * Input: usb_dev = pointer to the usb device 
- *
- * Return: 0 if success or error code 
- **************************************************************************/
-static int hci_alloc_dev (struct usb_device *usb_dev)
-{
-	struct hci_device *dev;
-	int i;
-
-	DBGFUNC ("enter hci_alloc_dev\n");
-	dev = kmalloc (sizeof (*dev), GFP_KERNEL);
-	if (!dev)
-		return -ENOMEM;
-
-	memset (dev, 0, sizeof (*dev));
-
-	for (i = 0; i < 32; i++) {
-		INIT_LIST_HEAD (&(dev->ed[i].urb_queue));
-		dev->ed[i].pipe_head = NULL;
-	}
-
-	usb_dev->hcpriv = dev;
-
-	DBGVERBOSE ("USB HC dev alloc %d bytes\n", sizeof (*dev));
-
-	return 0;
-
-}
-
-/***************************************************************************
- * Function Name : hci_free_dev
- *
- * This function de-allocates private data space for the usb devic
- *
- * Input: usb_dev = pointer to the usb device 
- *
- * Return: 0  
- **************************************************************************/
-static int hci_free_dev (struct usb_device *usb_dev)
-{
-	DBGFUNC ("enter hci_free_dev\n");
-
-	if (usb_dev->hcpriv)
-		kfree (usb_dev->hcpriv);
-
-	usb_dev->hcpriv = NULL;
-
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : hci_get_current_frame_number
- *
- * This function get the current USB frame number
- *
- * Input: usb_dev = pointer to the usb device 
- *
- * Return: frame number  
- **************************************************************************/
-static int hci_get_current_frame_number (struct usb_device *usb_dev)
-{
-	hci_t *hci = usb_dev->bus->hcpriv;
-	DBGFUNC ("enter hci_get_current_frame_number, frame = 0x%x \r\n",
-		 hci->frame_number);
-
-	return (hci->frame_number);
-}
-
-/***************************************************************************
- * List of all io-functions 
- **************************************************************************/
-
-static struct usb_operations hci_device_operations = {
-	allocate:		hci_alloc_dev,
-	deallocate:		hci_free_dev,
-	get_frame_number:	hci_get_current_frame_number,
-	submit_urb:		hci_submit_urb,
-	unlink_urb:		hci_unlink_urb,
-};
-
-/***************************************************************************
- * URB queueing:
- * 
- * For each type of transfer (INTR, BULK, ISO, CTRL) there is a list of 
- * active URBs.
- * (hci->intr_list, hci->bulk_list, hci->iso_list, hci->ctrl_list)
- * For every endpoint the head URB of the queued URBs is linked to one of 
- * those lists.
- * 
- * The rest of the queued URBs of an endpoint are linked into a 
- * private URB list for each endpoint. (hci_dev->ed [endpoint_io].urb_queue)
- * hci_dev->ed [endpoint_io].pipe_head .. points to the head URB which is 
- * in one of the active URB lists.
- * 
- * The index of an endpoint consists of its number and its direction.
- * 
- * The state of an intr and iso URB is 0. 
- * For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK
- * Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet)
- * 
- **************************************************************************/
-
-/***************************************************************************
- * Function Name : qu_urb_timeout
- *
- * This function is called when the URB timeout. The function unlinks the 
- * URB. 
- *
- * Input: lurb: URB 
- *
- * Return: none  
- **************************************************************************/
-#ifdef HC_URB_TIMEOUT
-static void qu_urb_timeout (unsigned long lurb)
-{
-	struct urb *urb = (struct urb *) lurb;
-
-	DBGFUNC ("enter qu_urb_timeout\n");
-	urb->transfer_flags |= USB_TIMEOUT_KILLED;
-	hci_unlink_urb (urb);
-}
-#endif
-
-/***************************************************************************
- * Function Name : qu_pipeindex
- *
- * This function gets the index of the pipe.   
- *
- * Input: pipe: the urb pipe 
- *
- * Return: index  
- **************************************************************************/
-static inline int qu_pipeindex (__u32 pipe)
-{
-	DBGFUNC ("enter qu_pipeindex\n");
-	return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ? 0 : usb_pipeout (pipe));
-}
-
-/***************************************************************************
- * Function Name : qu_seturbstate
- *
- * This function set the state of the URB.  
- * 
- * control pipe: 3 states -- Setup, data, status
- * interrupt and bulk pipe: 1 state -- data    
- *
- * Input: urb = USB request block data structure 
- *        state = the urb state
- *
- * Return: none  
- **************************************************************************/
-static inline void qu_seturbstate (struct urb * urb, int state)
-{
-	DBGFUNC ("enter qu_seturbstate\n");
-	urb->pipe &= ~0x1f;
-	urb->pipe |= state & 0x1f;
-}
-
-/***************************************************************************
- * Function Name : qu_urbstate
- *
- * This function get the current state of the URB.  
- * 
- * Input: urb = USB request block data structure 
- *
- * Return: none  
- **************************************************************************/
-static inline int qu_urbstate (struct urb * urb)
-{
-
-	DBGFUNC ("enter qu_urbstate\n");
-
-	return urb->pipe & 0x1f;
-}
-
-/***************************************************************************
- * Function Name : qu_queue_active_urb
- *
- * This function adds the urb to the appropriate active urb list and set
- * the urb state.
- * 
- * There are four active lists: isochoronous list, interrupt list, 
- * control list, and bulk list.
- * 
- * Input: hci = data structure for the host controller 
- *        urb = USB request block data structure 
- *        ed = endpoint descriptor
- *
- * Return: none  
- **************************************************************************/
-static inline void qu_queue_active_urb (hci_t * hci, struct urb * urb, epd_t * ed)
-{
-	int urb_state = 0;
-	DBGFUNC ("enter qu_queue_active_urb\n");
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-		list_add (&urb->urb_list, &hci->ctrl_list);
-		urb_state = US_CTRL_SETUP;
-		break;
-
-	case PIPE_BULK:
-		list_add (&urb->urb_list, &hci->bulk_list);
-		if ((urb->transfer_flags & USB_ZERO_PACKET)
-		    && urb->transfer_buffer_length > 0
-		    &&
-		    ((urb->transfer_buffer_length %
-		      usb_maxpacket (urb->dev, urb->pipe,
-				     usb_pipeout (urb->pipe))) == 0)) {
-			urb_state = US_BULK0;
-		}
-		break;
-
-	case PIPE_INTERRUPT:
-		urb->start_frame = hci->frame_number;
-		list_add (&urb->urb_list, &hci->intr_list);
-		break;
-
-	case PIPE_ISOCHRONOUS:
-		list_add (&urb->urb_list, &hci->iso_list);
-		break;
-	}
-
-#ifdef HC_URB_TIMEOUT
-	if (urb->timeout) {
-		ed->timeout.data = (unsigned long) urb;
-		ed->timeout.expires = urb->timeout + jiffies;
-		ed->timeout.function = qu_urb_timeout;
-		add_timer (&ed->timeout);
-	}
-#endif
-
-	qu_seturbstate (urb, urb_state);
-}
-
-/***************************************************************************
- * Function Name : qu_queue_urb
- *
- * This function adds the urb to the endpoint descriptor list 
- * 
- * Input: hci = data structure for the host controller 
- *        urb = USB request block data structure 
- *
- * Return: none  
- **************************************************************************/
-static int qu_queue_urb (hci_t * hci, struct urb * urb)
-{
-	struct hci_device *hci_dev = usb_to_hci (urb->dev);
-	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
-
-	DBGFUNC ("Enter qu_queue_urb\n");
-
-	/* for ISOC transfers calculate start frame index */
-
-	if (usb_pipeisoc (urb->pipe) && urb->transfer_flags & USB_ISO_ASAP) {
-		urb->start_frame = ((ed->pipe_head) ? (ed->last_iso + 1) : hci_get_current_frame_number (urb-> dev) + 1) & 0xffff;
-	}
-
-	if (ed->pipe_head) {
-		__list_add (&urb->urb_list, ed->urb_queue.prev,
-			    &(ed->urb_queue));
-	} else {
-		ed->pipe_head = urb;
-		qu_queue_active_urb (hci, urb, ed);
-		if (++hci->active_urbs == 1)
-			hc_start_int (hci);
-	}
-
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : qu_next_urb
- *
- * This function removes the URB from the queue and add the next URB to 
- * active list. 
- * 
- * Input: hci = data structure for the host controller 
- *        urb = USB request block data structure 
- *        resub_ok = resubmit flag
- *
- * Return: pointer to the next urb  
- **************************************************************************/
-static struct urb *qu_next_urb (hci_t * hci, struct urb * urb, int resub_ok)
-{
-	struct hci_device *hci_dev = usb_to_hci (urb->dev);
-	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
-
-	DBGFUNC ("enter qu_next_urb\n");
-	list_del (&urb->urb_list);
-	INIT_LIST_HEAD (&urb->urb_list);
-	if (ed->pipe_head == urb) {
-
-#ifdef HC_URB_TIMEOUT
-		if (urb->timeout)
-			del_timer (&ed->timeout);
-#endif
-
-		if (!--hci->active_urbs)
-			hc_stop_int (hci);
-
-		if (!list_empty (&ed->urb_queue)) {
-			urb = list_entry (ed->urb_queue.next, struct urb, urb_list);
-			list_del (&urb->urb_list);
-			INIT_LIST_HEAD (&urb->urb_list);
-			ed->pipe_head = urb;
-			qu_queue_active_urb (hci, urb, ed);
-		} else {
-			ed->pipe_head = NULL;
-			urb = NULL;
-		}
-	}
-	return urb;
-}
-
-/***************************************************************************
- * Function Name : qu_return_urb
- *
- * This function is part of the return path.   
- * 
- * Input: hci = data structure for the host controller 
- *        urb = USB request block data structure 
- *        resub_ok = resubmit flag
- *
- * Return: pointer to the next urb  
- **************************************************************************/
-static struct urb *qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
-{
-	struct urb *next_urb;
-
-	DBGFUNC ("enter qu_return_rub\n");
-	next_urb = qu_next_urb (hci, urb, resub_ok);
-	hcs_return_urb (hci, urb, resub_ok);
-	return next_urb;
-}
-
-/***************************************************************************
- * Function Name : sh_scan_iso_urb_list
- *
- * This function goes throught the isochronous urb list and schedule the 
- * the transfer.   
- *
- * Note: This function has not tested yet
- * 
- * Input: hci = data structure for the host controller 
- *        list_lh = pointer to the isochronous list 
- *        frame_number = the frame number 
- *
- * Return: 0 = unsuccessful; 1 = successful  
- **************************************************************************/
-static int sh_scan_iso_urb_list (hci_t * hci, struct list_head *list_lh,
-				 int frame_number)
-{
-	struct list_head *lh = list_lh->next;
-	struct urb *urb;
-
-	DBGFUNC ("enter sh_scan_iso_urb_list\n");
-	hci->td_array->len = 0;
-
-	while (lh != list_lh) {
-		urb = list_entry (lh, struct urb, urb_list);
-		lh = lh->next;
-		if (((frame_number - urb->start_frame) & 0x7ff) <
-		    urb->number_of_packets) {
-			if (!sh_add_packet (hci, urb)) {
-				return 0;
-			} else {
-				if (((frame_number -
-				      urb->start_frame) & 0x7ff) > 0x400) {
-					if (qu_urbstate (urb) > 0)
-						urb = qu_return_urb (hci, urb, 1);
-					else
-						urb = qu_next_urb (hci, urb, 1);
-
-					if (lh == list_lh && urb)
-						lh = &urb->urb_list;
-				}
-			}
-		}
-	}
-	return 1;
-}
-
-/***************************************************************************
- * Function Name : sh_scan_urb_list
- *
- * This function goes through the urb list and schedule the 
- * the transaction.   
- * 
- * Input: hci = data structure for the host controller 
- *        list_lh = pointer to the isochronous list 
- *
- * Return: 0 = unsuccessful; 1 = successful  
- **************************************************************************/
-static int sh_scan_urb_list (hci_t * hci, struct list_head *list_lh)
-{
-	struct list_head *lh = NULL;
-	struct urb *urb;
-
-	if (list_lh == NULL) {
-		DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n");
-	}
-
-	DBGFUNC ("enter sh_scan_urb_list: frame# \n");
-
-	list_for_each (lh, list_lh) {
-		urb = list_entry (lh, struct urb, urb_list);
-		if (urb == NULL)
-			return 1;
-		if (!usb_pipeint (urb->pipe)
-		    || (((hci->frame_number - urb->start_frame)
-			 & 0x7ff) >= urb->interval)) {
-			DBGVERBOSE ("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n",
-				    urb->start_frame, hci->frame_number, urb->interval,
-				    usb_pipeint (urb->pipe));
-			if (!sh_add_packet (hci, urb)) {
-				return 0;
-			} else {
-				DBGVERBOSE ("INT: start: %d fr_no: %d int: %d pint: %d\n",
-					    urb->start_frame, hci->frame_number,
-					    urb->interval, usb_pipeint (urb->pipe));
-				urb->start_frame = hci->frame_number;
-				return 0;
-
-			}
-		}
-	}
-	return 1;
-}
-
-/***************************************************************************
- * Function Name : sh_shedule_trans
- *
- * This function schedule the USB transaction.
- * This function will process the endpoint in the following order: 
- * interrupt, control, and bulk.    
- * 
- * Input: hci = data structure for the host controller 
- *        isSOF = flag indicate if Start Of Frame has occurred 
- *
- * Return: 0   
- **************************************************************************/
-static int sh_schedule_trans (hci_t * hci, int isSOF)
-{
-	int units_left = 1;
-	struct list_head *lh;
-
-	if (hci == NULL) {
-		DBGERR ("sh_schedule_trans: hci == NULL\n");
-		return 0;
-	}
-	if (hci->td_array == NULL) {
-		DBGERR ("sh_schedule_trans: hci->td_array == NULL\n");
-		return 0;
-	}
-
-	if (hci->td_array->len != 0) {
-		DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n",
-			hci->td_array->len);
-	}
-
-	/* schedule the next available interrupt transfer or the next
-	 * stage of the interrupt transfer */
-
-	if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) {
-		units_left = sh_scan_urb_list (hci, &hci->intr_list);
-	}
-
-	/* schedule the next available control transfer or the next
-	 * stage of the control transfer */
-
-	if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) {
-		units_left = sh_scan_urb_list (hci, &hci->ctrl_list);
-	}
-
-	/* schedule the next available bulk transfer or the next
-	 * stage of the bulk transfer */
-
-	if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) {
-		sh_scan_urb_list (hci, &hci->bulk_list);
-
-		/* be fair to each BULK URB (move list head around) 
-		 * only when the new SOF happens */
-
-		lh = hci->bulk_list.next;
-		list_del (&hci->bulk_list);
-		list_add (&hci->bulk_list, lh);
-	}
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : sh_add_packet
- *
- * This function forms the packet and transmit the packet. This function
- * will handle all endpoint type: isochoronus, interrupt, control, and 
- * bulk.
- * 
- * Input: hci = data structure for the host controller 
- *        urb = USB request block data structure 
- *
- * Return: 0 = unsucessful; 1 = successful   
- **************************************************************************/
-static int sh_add_packet (hci_t * hci, struct urb * urb)
-{
-	__u8 *data = NULL;
-	int len = 0;
-	int toggle = 0;
-	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-	int endpoint = usb_pipeendpoint (urb->pipe);
-	int address = usb_pipedevice (urb->pipe);
-	int slow = (((urb->pipe) >> 26) & 1);
-	int out = usb_pipeout (urb->pipe);
-	int pid = 0;
-	int ret;
-	int i = 0;
-	int iso = 0;
-
-	DBGFUNC ("enter sh_add_packet\n");
-	if (maxps == 0)
-		maxps = 8;
-
-	/* calculate len, toggle bit and add the transaction */
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_ISOCHRONOUS:
-		pid = out ? PID_OUT : PID_IN;
-		iso = 1;
-		i = hci->frame_number - urb->start_frame;
-		data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-		len = urb->iso_frame_desc[i].length;
-		break;
-
-	case PIPE_BULK:	/* BULK and BULK0 */
-	case PIPE_INTERRUPT:
-		pid = out ? PID_OUT : PID_IN;
-		len = urb->transfer_buffer_length - urb->actual_length;
-		data = urb->transfer_buffer + urb->actual_length;
-		toggle = usb_gettoggle (urb->dev, endpoint, out);
-		break;
-
-	case PIPE_CONTROL:
-		switch (qu_urbstate (urb)) {
-		case US_CTRL_SETUP:
-			len = 8;
-			pid = PID_SETUP;
-			data = urb->setup_packet;
-			toggle = 0;
-			break;
-
-		case US_CTRL_DATA:
-			if (!hci->last_packet_nak) {
-				/* The last packet received is not a nak:
-				 * reset the nak count
-				 */
-
-				hci->nakCnt = 0;
-			}
-			if (urb->transfer_buffer_length != 0) {
-				pid = out ? PID_OUT : PID_IN;
-				len = urb->transfer_buffer_length - urb->actual_length;
-				data = urb->transfer_buffer + urb->actual_length;
-				toggle = (urb->actual_length & maxps) ? 0 : 1;
-				usb_settoggle (urb->dev,
-					       usb_pipeendpoint (urb->pipe),
-					       usb_pipeout (urb->pipe), toggle);
-				break;
-			} else {
-				/* correct state and fall through */
-				qu_seturbstate (urb, US_CTRL_ACK);
-			}
-
-		case US_CTRL_ACK:
-			len = 0;
-
-			/* reply in opposite direction */
-			pid = !out ? PID_OUT : PID_IN;
-			toggle = 1;
-			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-				       usb_pipeout (urb->pipe), toggle);
-			break;
-		}
-	}
-
-	ret =
-	    hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint,
-			  address, pid, iso, qu_urbstate (urb));
-
-	DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x "
-		    "max:%d\n len:%d ret:%d data:%p left:%d\n",
-		    address, endpoint, pid, toggle, iso, slow,
-		    maxps, len, ret, data, hci->hp.units_left);
-
-	if (ret >= 0) {
-		hci->td_array->td[hci->td_array->len].urb = urb;
-		hci->td_array->td[hci->td_array->len].len = ret;
-		hci->td_array->td[hci->td_array->len].iso_index = i;
-		hci->td_array->len++;
-		hci->active_trans = 1;
-		return 1;
-	}
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : cc_to_error
- *
- * This function maps the SL811HS hardware error code to the linux USB error
- * code.
- * 
- * Input: cc = hardware error code 
- *
- * Return: USB error code   
- **************************************************************************/
-static int cc_to_error (int cc)
-{
-	int errCode = 0;
-	if (cc & SL11H_STATMASK_ERROR) {
-		errCode |= -EILSEQ;
-	} else if (cc & SL11H_STATMASK_OVF) {
-		errCode |= -EOVERFLOW;
-	} else if (cc & SL11H_STATMASK_STALL) {
-		errCode |= -EPIPE;
-	}
-	return errCode;
-}
-
-/***************************************************************************
- * Function Name : sh_done_list
- *
- * This function process the packet when it has done finish transfer.
- * 
- * 1) It handles hardware error
- * 2) It updates the URB state
- * 3) If the USB transaction is complete, it start the return stack path.
- * 
- * Input: hci = data structure for the host controller 
- *        isExcessNak = flag tells if there excess NAK condition occurred 
- *
- * Return:  urb_state or -1 if the transaction has complete   
- **************************************************************************/
-static int sh_done_list (hci_t * hci, int *isExcessNak)
-{
-	int actbytes = 0;
-	int active = 0;
-	void *data = NULL;
-	int cc;
-	int maxps;
-	int toggle;
-	struct urb *urb;
-	int urb_state = 0;
-	int ret = 1;		/* -1 parse abbort, 1 parse ok, 0 last element */
-	int trans = 0;
-	int len;
-	int iso_index = 0;
-	int out;
-	int pid = 0;
-	int debugLen = 0;
-
-	*isExcessNak = 0;
-
-	DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n",
-		 hci->td_array->len);
-
-	debugLen = hci->td_array->len;
-	if (debugLen > 1)
-		DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n",
-			hci->td_array->len);
-
-	for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS;
-	     trans++) {
-		urb = hci->td_array->td[trans].urb;
-		len = hci->td_array->td[trans].len;
-		out = usb_pipeout (urb->pipe);
-
-		if (usb_pipeisoc (urb->pipe)) {
-			iso_index = hci->td_array->td[trans].iso_index;
-			data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset;
-			toggle = 0;
-		} else {
-			data = urb->transfer_buffer + urb->actual_length;
-			toggle = usb_gettoggle (urb->dev,
-						usb_pipeendpoint (urb->pipe),
-						usb_pipeout (urb->pipe));
-
-		}
-		urb_state = qu_urbstate (urb);
-		pid = out ? PID_OUT : PID_IN;
-		ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len,
-				      pid, urb_state);
-		maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-
-		if (maxps == 0)
-			maxps = 8;
-
-		active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1)));
-
-		/* If the transfer is not bulk in, then it is necessary to get all
-		 * data specify by the urb->transfer_len.
-		 */
-
-		if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe)))
-			active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes);
-
-		if (urb->transfer_buffer_length == urb->actual_length + actbytes)
-			active = 0;
-
-		if ((cc &
-		     (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT |
-		      SL11H_STATMASK_OVF | SL11H_STATMASK_STALL))
-		    && !(cc & SL11H_STATMASK_NAK)) {
-			if (++urb->error_count > 3) {
-				DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n",
-					urb->error_count, cc);
-				urb_state = 0;
-				active = 0;
-			} else {
-				DBGERR ("done_list: packet err, cc = 0x%x, "
-					" urb->length = 0x%x, actual_len = 0x%x,"
-					" urb_state =0x%x\n",
-					cc, urb->transfer_buffer_length,
-					urb->actual_length, urb_state);
-//			if (cc & SL11H_STATMASK_STALL) {
-				/* The USB function is STALLED on a control pipe (0), 
-				 * then it needs to send the SETUP command again to 
-				 * clear the STALL condition
-				 */
-
-//				if (usb_pipeendpoint (urb->pipe) == 0) {
-//					urb_state = 2;  
-//					active = 0;
-//				}
-//			} else   
-				active = 1;
-			}
-		} else {
-			if (cc & SL11H_STATMASK_NAK) {
-				if (hci->nakCnt < 0x10000) {
-					hci->nakCnt++;
-					hci->last_packet_nak = 1;
-					active = 1;
-					*isExcessNak = 0;
-				} else {
-					DBGERR ("done_list: nak count exceed limit\n");
-					active = 0;
-					*isExcessNak = 1;
-					hci->nakCnt = 0;
-				}
-			} else {
-				hci->nakCnt = 0;
-				hci->last_packet_nak = 0;
-			}
-
-			if (urb_state != US_CTRL_SETUP) {
-				/* no error */
-				urb->actual_length += actbytes;
-				usb_settoggle (urb->dev,
-					       usb_pipeendpoint (urb->pipe),
-					       usb_pipeout (urb->pipe), toggle);
-			}
-			if (usb_pipeisoc (urb->pipe)) {
-				urb->iso_frame_desc[iso_index].actual_length = actbytes;
-				urb->iso_frame_desc[iso_index].status = cc_to_error (cc);
-				active = (iso_index < urb->number_of_packets);
-			}
-		}
-		if (!active) {
-			if (!urb_state) {
-				urb->status = cc_to_error (cc);
-				if (urb->status) {
-					DBGERR ("error on received packet: urb->status = 0x%x\n",
-						urb->status);
-				}
-				hci->td_array->len = 0;
-				qu_return_urb (hci, urb, 1);
-				return -1;
-			} else {
-				/* We do not want to decrement the urb_state if exceeded nak,
-				 * because we need to finish the data stage of the control 
-				 * packet 
-				 */
-
-				if (!(*isExcessNak))
-					urb_state--;
-				qu_seturbstate (urb, urb_state);
-			}
-		}
-	}
-
-	if (urb_state < 0)
-		DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n",
-			urb_state);
-	if (debugLen != hci->td_array->len) {
-		DBGERR ("ERROR: done_list, debugLen!= td_array->len,"
-			"debugLen = 0x%x, hci->td_array->len = 0x%x\n",
-			debugLen, hci->td_array->len);
-	}
-
-	hci->td_array->len = 0;
-
-	return urb_state;
-}
diff -urN linux-2.4.22-bk41/drivers/usb/hc_simple.h linux-2.4.22-bk42/drivers/usb/hc_simple.h
--- linux-2.4.22-bk41/drivers/usb/hc_simple.h	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/hc_simple.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,231 +0,0 @@
-/*-------------------------------------------------------------------------*/
-/* list of all controllers using this driver 
- * */
-
-static LIST_HEAD (hci_hcd_list);
-
-/* URB states (urb_state) */
-/* isoc, interrupt single state */
-
-/* bulk transfer main state and 0-length packet */
-#define US_BULK		0
-#define US_BULK0	1
-/* three setup states */
-#define US_CTRL_SETUP	2
-#define US_CTRL_DATA	1
-#define US_CTRL_ACK	0
-
-/*-------------------------------------------------------------------------*/
-/* HC private part of a device descriptor
- * */
-
-#define NUM_EDS 32
-
-typedef struct epd {
-	struct urb *pipe_head;
-	struct list_head urb_queue;
-//	int urb_state;
-	struct timer_list timeout;
-	int last_iso;		/* timestamp of last queued ISOC transfer */
-
-} epd_t;
-
-struct hci_device {
-	epd_t ed[NUM_EDS];
-};
-
-/*-------------------------------------------------------------------------*/
-/* Virtual Root HUB 
- */
-
-#define usb_to_hci(usb)	((struct hci_device *)(usb)->hcpriv)
-
-struct virt_root_hub {
-	int devnum;		/* Address of Root Hub endpoint */
-	void *urb;		/* interrupt URB of root hub */
-	int send;		/* active flag */
-	int interval;		/* intervall of roothub interrupt transfers */
-	struct timer_list rh_int_timer;	/* intervall timer for rh interrupt EP */
-};
-
-#if 1
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h and USB spec) */
-
-/* destination of request */
-#define RH_INTERFACE		0x01
-#define RH_ENDPOINT		0x02
-#define RH_OTHER		0x03
-
-#define RH_CLASS		0x20
-#define RH_VENDOR		0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS		0x0080
-#define RH_CLEAR_FEATURE	0x0100
-#define RH_SET_FEATURE		0x0300
-#define RH_SET_ADDRESS		0x0500
-#define RH_GET_DESCRIPTOR	0x0680
-#define RH_SET_DESCRIPTOR	0x0700
-#define RH_GET_CONFIGURATION	0x0880
-#define RH_SET_CONFIGURATION	0x0900
-#define RH_GET_STATE		0x0280
-#define RH_GET_INTERFACE	0x0A80
-#define RH_SET_INTERFACE	0x0B00
-#define RH_SYNC_FRAME		0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP		0x2000
-
-/* Hub port features */
-#define RH_PORT_CONNECTION	0x00
-#define RH_PORT_ENABLE		0x01
-#define RH_PORT_SUSPEND		0x02
-#define RH_PORT_OVER_CURRENT	0x03
-#define RH_PORT_RESET		0x04
-#define RH_PORT_POWER		0x08
-#define RH_PORT_LOW_SPEED	0x09
-
-#define RH_C_PORT_CONNECTION	0x10
-#define RH_C_PORT_ENABLE	0x11
-#define RH_C_PORT_SUSPEND	0x12
-#define RH_C_PORT_OVER_CURRENT	0x13
-#define RH_C_PORT_RESET		0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER	0x00
-#define RH_C_HUB_OVER_CURRENT	0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP	0x00
-#define RH_ENDPOINT_STALL	0x01
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-/* struct for each HC 
- */
-
-#define MAX_TRANS	32
-
-typedef struct td {
-	struct urb *urb;
-	__u16 len;
-	__u16 iso_index;
-} td_t;
-
-typedef struct td_array {
-	int len;
-	td_t td[MAX_TRANS];
-} td_array_t;
-
-typedef struct hci {
-	struct virt_root_hub rh;	/* roothub */
-	wait_queue_head_t waitq;	/* deletion of URBs and devices needs a waitqueue */
-	int active;			/* HC is operating */
-
-	struct list_head ctrl_list;	/* set of ctrl endpoints */
-	struct list_head bulk_list;	/* set of bulk endpoints */
-	struct list_head iso_list;	/* set of isoc endpoints */
-	struct list_head intr_list;	/* ordered (tree) set of int endpoints */
-	struct list_head del_list;	/* set of entpoints to be deleted */
-
-	td_array_t *td_array;
-	td_array_t a_td_array;
-	td_array_t i_td_array[2];
-
-	struct list_head hci_hcd_list;	/* list of all hci_hcd */
-	struct usb_bus *bus;		/* our bus */
-
-//	int trans;			/* number of transactions pending */
-	int active_urbs;
-	int active_trans;
-	int frame_number;		/* frame number */
-	hcipriv_t hp;			/* individual part of hc type */
-	int nakCnt;
-	int last_packet_nak;
-
-} hci_t;
-
-/*-------------------------------------------------------------------------*/
-/* condition (error) CC codes and mapping OHCI like
- */
-
-#define TD_CC_NOERROR		0x00
-#define TD_CC_CRC		0x01
-#define TD_CC_BITSTUFFING	0x02
-#define TD_CC_DATATOGGLEM	0x03
-#define TD_CC_STALL		0x04
-#define TD_DEVNOTRESP		0x05
-#define TD_PIDCHECKFAIL		0x06
-#define TD_UNEXPECTEDPID	0x07
-#define TD_DATAOVERRUN		0x08
-#define TD_DATAUNDERRUN		0x09
-#define TD_BUFFEROVERRUN	0x0C
-#define TD_BUFFERUNDERRUN	0x0D
-#define TD_NOTACCESSED		0x0F
-
-
-/* urb interface functions */
-static int hci_get_current_frame_number (struct usb_device *usb_dev);
-static int hci_unlink_urb (struct urb * urb);
-
-static int qu_queue_urb (hci_t * hci, struct urb * urb);
-
-/* root hub */
-static int rh_init_int_timer (struct urb * urb);
-static int rh_submit_urb (struct urb * urb);
-static int rh_unlink_urb (struct urb * urb);
-
-/* schedule functions */
-static int sh_add_packet (hci_t * hci, struct urb * urb);
-
-/* hc specific functions */
-static inline void hc_flush_data_cache (hci_t * hci, void *data, int len);
-static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
-				  int *cc, int *toggle, int length, int pid,
-				  int urb_state);
-static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
-				int maxps, int slow, int endpoint, int address,
-				int pid, int format, int urb_state);
-
-static void hc_start_int (hci_t * hci);
-static void hc_stop_int (hci_t * hci);
-static void SL811Write (hci_t * hci, char offset, char data);
-
-/* debug| print the main components of an URB     
- * small: 0) header + data packets 1) just header */
-
-static void urb_print (struct urb * urb, char *str, int small)
-{
-	unsigned int pipe = urb->pipe;
-	int i, len;
-
-	if (!urb->dev || !urb->dev->bus) {
-		dbg ("%s URB: no dev", str);
-		return;
-	}
-
-	printk ("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)\n",
-		str, hci_get_current_frame_number (urb->dev),
-		usb_pipedevice (pipe), usb_pipeendpoint (pipe),
-		usb_pipeout (pipe) ? 'O' : 'I',
-		usb_pipetype (pipe) < 2 ? (usb_pipeint (pipe) ? "INTR" : "ISOC")
-		: (usb_pipecontrol (pipe) ? "CTRL" : "BULK"), urb->transfer_flags,
-		urb->actual_length, urb->transfer_buffer_length, urb->status,
-		urb->status);
-	if (!small) {
-		if (usb_pipecontrol (pipe)) {
-			printk (__FILE__ ": cmd(8):");
-			for (i = 0; i < 8; i++)
-				printk (" %02x", ((__u8 *) urb->setup_packet)[i]);
-			printk ("\n");
-		}
-		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
-			printk (__FILE__ ": data(%d/%d):", urb->actual_length,
-				urb->transfer_buffer_length);
-			len = usb_pipeout (pipe) ? urb-> transfer_buffer_length : urb->actual_length;
-			for (i = 0; i < 2096 && i < len; i++)
-				printk (" %02x", ((__u8 *) urb->transfer_buffer)[i]);
-			printk ("%s stat:%d\n", i < len ? "..." : "",
-				urb->status);
-		}
-	}
-}
diff -urN linux-2.4.22-bk41/drivers/usb/hc_sl811.c linux-2.4.22-bk42/drivers/usb/hc_sl811.c
--- linux-2.4.22-bk41/drivers/usb/hc_sl811.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.22-bk42/drivers/usb/hc_sl811.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1359 +0,0 @@
-/*-------------------------------------------------------------------------*/
-/*-------------------------------------------------------------------------*
- * SL811HS USB HCD for Linux Version 0.1 (10/28/2001)
- * 
- * requires (includes) hc_simple.[hc] simple generic HCD frontend
- *  
- * COPYRIGHT(C) 2001 by CYPRESS SEMICONDUCTOR INC.
- *
- *-------------------------------------------------------------------------*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *-------------------------------------------------------------------------*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/list.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <linux/usb.h>
-#include "../core/hcd.h"
-
-#undef HC_URB_TIMEOUT
-#undef HC_SWITCH_INT
-#undef HC_ENABLE_ISOC
-
-#define SL811_DEBUG_ERR
-
-#ifdef SL811_DEBUG_ERR
-#define DBGERR(fmt, args...) printk(fmt,## args)
-#else
-#define DBGERR(fmt, args...)
-#endif
-
-#ifdef SL811_DEBUG
-#define DBG(fmt, args...) printk(fmt,## args)
-#else
-#define DBG(fmt, args...)
-#endif
-
-#ifdef SL811_DEBUG_FUNC
-#define DBGFUNC(fmt, args...) printk(fmt,## args)
-#else
-#define DBGFUNC(fmt, args...)
-#endif
-
-#ifdef SL811_DEBUG_DATA
-#define DBGDATAR(fmt, args...) printk(fmt,## args)
-#define DBGDATAW(fmt, args...) printk(fmt,## args)
-#else
-#define DBGDATAR(fmt, args...)
-#define DBGDATAW(fmt, args...)
-#endif
-
-#ifdef SL811_DEBUG_VERBOSE
-#define DBGVERBOSE(fmt, args...) printk(fmt,## args)
-#else
-#define DBGVERBOSE(fmt, args...)
-#endif
-
-#define TRUE 1
-#define FALSE 0
-
-#define HC_SWITCH_INT
-#include "hc_sl811.h"
-#include "hc_simple.h"
-
-static int urb_debug = 0;
-
-#include "hc_simple.c"
-#include "hc_sl811_rh.c"
-
-/* The base_addr, data_reg_addr, and irq number are board specific.
- * The current values are design to run on the Accelent SA1110 IDP
- * NOTE: values need to modify for different development boards 
- */
-
-static int base_addr = 0xd3800000;
-static int data_reg_addr = 0xd3810000;
-static int irq = 34;
-
-/* forware declaration */
-
-int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
-		      int toggle, int slow, int urb_state);
-
-static int sofWaitCnt = 0;
-
-MODULE_PARM (urb_debug, "i");
-MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)");
-
-MODULE_PARM (base_addr, "i");
-MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000");
-MODULE_PARM (data_reg_addr, "i");
-MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000");
-MODULE_PARM (irq, "i");
-MODULE_PARM_DESC (irq, "IRQ 34 (default)");
-
-static int hc_reset (hci_t * hci);
-
-/***************************************************************************
- * Function Name : SL811Read
- *
- * Read a byte of data from the SL811H/SL11H
- *
- * Input:  hci = data structure for the host controller
- *         offset = address of SL811/SL11H register or memory
- *
- * Return: data 
- **************************************************************************/
-char SL811Read (hci_t * hci, char offset)
-{
-	hcipriv_t *hp = &hci->hp;
-	char data;
-	writeb (offset, hp->hcport);
-	wmb ();
-	data = readb (hp->hcport2);
-	rmb ();
-	return (data);
-}
-
-/***************************************************************************
- * Function Name : SL811Write
- *
- * Write a byte of data to the SL811H/SL11H
- *
- * Input:  hci = data structure for the host controller
- *         offset = address of SL811/SL11H register or memory
- *         data  = the data going to write to SL811H
- *
- * Return: none 
- **************************************************************************/
-void SL811Write (hci_t * hci, char offset, char data)
-{
-	hcipriv_t *hp = &hci->hp;
-	writeb (offset, hp->hcport);
-	writeb (data, hp->hcport2);
-	wmb ();
-}
-
-/***************************************************************************
- * Function Name : SL811BufRead
- *
- * Read consecutive bytes of data from the SL811H/SL11H buffer
- *
- * Input:  hci = data structure for the host controller
- *         offset = SL811/SL11H register offset
- *         buf = the buffer where the data will store
- *         size = number of bytes to read
- *
- * Return: none 
- **************************************************************************/
-void SL811BufRead (hci_t * hci, short offset, char *buf, short size)
-{
-	hcipriv_t *hp = &hci->hp;
-	if (size <= 0)
-		return;
-	writeb ((char) offset, hp->hcport);
-	wmb ();
-	DBGDATAR ("SL811BufRead: offset = 0x%x, data = ", offset);
-	while (size--) {
-		*buf++ = (char) readb (hp->hcport2);
-		DBGDATAR ("0x%x ", *(buf - 1));
-		rmb ();
-	}
-	DBGDATAR ("\n");
-}
-
-/***************************************************************************
- * Function Name : SL811BufWrite
- *
- * Write consecutive bytes of data to the SL811H/SL11H buffer
- *
- * Input:  hci = data structure for the host controller
- *         offset = SL811/SL11H register offset
- *         buf = the data buffer 
- *         size = number of bytes to write
- *
- * Return: none 
- **************************************************************************/
-void SL811BufWrite (hci_t * hci, short offset, char *buf, short size)
-{
-	hcipriv_t *hp = &hci->hp;
-	if (size <= 0)
-		return;
-	writeb ((char) offset, hp->hcport);
-	wmb ();
-	DBGDATAW ("SL811BufWrite: offset = 0x%x, data = ", offset);
-	while (size--) {
-		DBGDATAW ("0x%x ", *buf);
-		writeb (*buf, hp->hcport2);
-		wmb ();
-		buf++;
-	}
-	DBGDATAW ("\n");
-}
-
-/***************************************************************************
- * Function Name : regTest
- *
- * This routine test the Read/Write functionality of SL811HS registers  
- *
- * 1) Store original register value into a buffer
- * 2) Write to registers with a RAMP pattern. (10, 11, 12, ..., 255)
- * 3) Read from register
- * 4) Compare the written value with the read value and make sure they are 
- *    equivalent
- * 5) Restore the original register value 
- *
- * Input:  hci = data structure for the host controller
- *   
- *
- * Return: TRUE = passed; FALSE = failed 
- **************************************************************************/
-int regTest (hci_t * hci)
-{
-	int i, data, result = TRUE;
-	char buf[256];
-
-	DBGFUNC ("Enter regTest\n");
-	for (i = 0x10; i < 256; i++) {
-		/* save the original buffer */
-		buf[i] = (char) SL811Read (hci, i);
-
-		/* Write the new data to the buffer */
-		SL811Write (hci, i, i);
-	}
-
-	/* compare the written data */
-	for (i = 0x10; i < 256; i++) {
-		data = SL811Read (hci, i);
-		if (data != i) {
-			DBGERR ("Pattern test failed!! value = 0x%x, s/b 0x%x\n",
-				data, i);
-			result = FALSE;
-		}
-	}
-
-	/* restore the data */
-	for (i = 0x10; i < 256; i++) {
-		SL811Write (hci, i, buf[i]);
-	}
-
-	return (result);
-}
-
-/***************************************************************************
- * Function Name : regShow
- *
- * Display all SL811HS register values
- *
- * Input:  hci = data structure for the host controller
- *
- * Return: none 
- **************************************************************************/
-void regShow (hci_t * hci)
-{
-	int i;
-	for (i = 0; i < 256; i++) {
-		printk ("offset %d: 0x%x\n", i, SL811Read (hci, i));
-	}
-}
-
-/************************************************************************
- * Function Name : USBReset
- *  
- * This function resets SL811HS controller and detects the speed of
- * the connecting device				  
- *
- * Input:  hci = data structure for the host controller
- *                
- * Return: 0 = no device attached; 1 = USB device attached
- *                
- ***********************************************************************/
-static int USBReset (hci_t * hci)
-{
-	int status;
-	hcipriv_t *hp = &hci->hp;
-
-	DBGFUNC ("enter USBReset\n");
-
-	SL811Write (hci, SL11H_CTLREG2, 0xae);
-
-	// setup master and full speed
-
-	SL811Write (hci, SL11H_CTLREG1, 0x08);	// reset USB
-	mdelay (20);		// 20ms                             
-	SL811Write (hci, SL11H_CTLREG1, 0);	// remove SE0        
-
-	for (status = 0; status < 100; status++)
-		SL811Write (hci, SL11H_INTSTATREG, 0xff);	// clear all interrupt bits
-
-	status = SL811Read (hci, SL11H_INTSTATREG);
-
-	if (status & 0x40)	// Check if device is removed
-	{
-		DBG ("USBReset: Device removed\n");
-		SL811Write (hci, SL11H_INTENBLREG,
-			    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
-			    SL11H_INTMASK_INSRMV);
-		hp->RHportStatus->portStatus &=
-		    ~(PORT_CONNECT_STAT | PORT_ENABLE_STAT);
-
-		return 0;
-	}
-
-	SL811Write (hci, SL11H_BUFLNTHREG_B, 0);	//zero lenth
-	SL811Write (hci, SL11H_PIDEPREG_B, 0x50);	//send SOF to EP0       
-	SL811Write (hci, SL11H_DEVADDRREG_B, 0x01);	//address0
-	SL811Write (hci, SL11H_SOFLOWREG, 0xe0);
-
-	if (!(status & 0x80)) {
-		/* slow speed device connect directly to root-hub */
-
-		DBG ("USBReset: low speed Device attached\n");
-		SL811Write (hci, SL11H_CTLREG1, 0x8);
-		mdelay (20);
-		SL811Write (hci, SL11H_SOFTMRREG, 0xee);
-		SL811Write (hci, SL11H_CTLREG1, 0x21);
-
-		/* start the SOF or EOP */
-
-		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
-		hp->RHportStatus->portStatus |=
-		    (PORT_CONNECT_STAT | PORT_LOW_SPEED_DEV_ATTACH_STAT);
-
-		/* clear all interrupt bits */
-
-		for (status = 0; status < 20; status++)
-			SL811Write (hci, SL11H_INTSTATREG, 0xff);
-	} else {
-		/* full speed device connect directly to root hub */
-
-		DBG ("USBReset: full speed Device attached\n");
-		SL811Write (hci, SL11H_CTLREG1, 0x8);
-		mdelay (20);
-		SL811Write (hci, SL11H_SOFTMRREG, 0xae);
-		SL811Write (hci, SL11H_CTLREG1, 0x01);
-
-		/* start the SOF or EOP */
-
-		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
-		hp->RHportStatus->portStatus |= (PORT_CONNECT_STAT);
-		hp->RHportStatus->portStatus &= ~PORT_LOW_SPEED_DEV_ATTACH_STAT;
-
-		/* clear all interrupt bits */
-
-		SL811Write (hci, SL11H_INTSTATREG, 0xff);
-
-	}
-
-	/* enable all interrupts */
-	SL811Write (hci, SL11H_INTENBLREG,
-		    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
-		    SL11H_INTMASK_INSRMV);
-
-	return 1;
-}
-
-/*-------------------------------------------------------------------------*/
-/* tl functions */
-static inline void hc_mark_last_trans (hci_t * hci)
-{
-	hcipriv_t *hp = &hci->hp;
-	__u8 *ptd = hp->tl;
-
-	dbg ("enter hc_mark_last_trans\n");
-	if (ptd == NULL) {
-		printk ("hc_mark_last_trans: ptd = null\n");
-		return;
-	}
-	if (hp->xferPktLen > 0)
-		*(ptd + hp->tl_last) |= (1 << 3);
-}
-
-static inline void hc_flush_data_cache (hci_t * hci, void *data, int len)
-{
-}
-
-/************************************************************************
- * Function Name : hc_add_trans
- *  
- * This function sets up the SL811HS register and transmit the USB packets.
- * 
- * 1) Determine if enough time within the current frame to send the packet
- * 2) Load the data into the SL811HS register
- * 3) Set the appropriate command to the register and trigger the transmit
- *
- * Input:  hci = data structure for the host controller
- *         len = data length
- *         data = transmitting data
- *         toggle = USB toggle bit, either 0 or 1
- *         maxps = maximum packet size for this endpoint
- *         slow = speed of the device
- *         endpoint = endpoint number
- *         address = USB address of the device
- *         pid = packet ID
- *         format = 
- *         urb_state = the current stage of USB transaction
- *       
- * Return: 0 = no time left to schedule the transfer
- *         1 = success 
- *                
- ***********************************************************************/
-static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
-				int maxps, int slow, int endpoint, int address,
-				int pid, int format, int urb_state)
-{
-	hcipriv_t *hp = &hci->hp;
-	__u16 speed;
-	int ii, jj, kk;
-
-	DBGFUNC ("enter hc_addr_trans: len =0x%x, toggle:0x%x, endpoing:0x%x,"
-		 " addr:0x%x, pid:0x%x,format:0x%x\n", len, toggle, endpoint,
-		 i address, pid, format);
-
-	if (len > maxps) {
-		len = maxps;
-	}
-
-	speed = hp->RHportStatus->portStatus;
-	if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) {
-//      ii = (8*7*8 + 6*3) * len + 800; 
-		ii = 8 * 8 * len + 1024;
-	} else {
-		if (slow) {
-//          ii = (8*7*8 + 6*3) * len + 800; 
-			ii = 8 * 8 * len + 2048;
-		} else
-//          ii = (8*7 + 6*3)*len + 110;
-			ii = 8 * len + 256;
-	}
-
-	ii += 2 * 10 * len;
-
-	jj = SL811Read (hci, SL11H_SOFTMRREG);
-	kk = (jj & 0xFF) * 64 - ii;
-
-	if (kk < 0) {
-		DBGVERBOSE
-		    ("hc_add_trans: no bandwidth for schedule, ii = 0x%x,"
-		     "jj = 0x%x, len =0x%x, active_trans = 0x%x\n", ii, jj, len,
-		     hci->active_trans);
-		return (-1);
-	}
-
-	if (pid != PID_IN) {
-		/* Load data into hc */
-
-		SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len);
-	}
-
-	/* transmit */
-
-	SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len,
-			  toggle, slow, urb_state);
-
-	return len;
-}
-
-/************************************************************************
- * Function Name : hc_parse_trans
- *  
- * This function checks the status of the transmitted or received packet
- * and copy the data from the SL811HS register into a buffer.
- *
- * 1) Check the status of the packet 
- * 2) If successful, and IN packet then copy the data from the SL811HS register
- *    into a buffer
- *
- * Input:  hci = data structure for the host controller
- *         actbytes = pointer to actual number of bytes
- *         data = data buffer
- *         cc = packet status
- *         length = the urb transmit length
- *         pid = packet ID
- *         urb_state = the current stage of USB transaction
- *       
- * Return: 0 
- ***********************************************************************/
-static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
-				  int *cc, int *toggle, int length, int pid,
-				  int urb_state)
-{
-	__u8 addr;
-	__u8 len;
-
-	DBGFUNC ("enter hc_parse_trans\n");
-
-	/* get packet status; convert ack rcvd to ack-not-rcvd */
-
-	*cc = (int) SL811Read (hci, SL11H_PKTSTATREG);
-
-	if (*cc &
-	    (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF |
-	     SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) {
-		if (*cc & SL11H_STATMASK_OVF)
-			DBGERR ("parse trans: error recv ack, cc = 0x%x, TX_BASE_Len = "
-				"0x%x, TX_count=0x%x\n", *cc,
-				SL811Read (hci, SL11H_BUFLNTHREG),
-				SL811Read (hci, SL11H_XFERCNTREG));
-
-	} else {
-		DBGVERBOSE ("parse trans: recv ack, cc = 0x%x, len = 0x%x, \n",
-			    *cc, length);
-
-		/* Successful data */
-		if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) {
-
-			/* Find the base address */
-			addr = SL811Read (hci, SL11H_BUFADDRREG);
-
-			/* Find the Transmit Length */
-			len = SL811Read (hci, SL11H_BUFLNTHREG);
-
-			/* The actual data length = xmit length reg - xfer count reg */
-			*actbytes = len - SL811Read (hci, SL11H_XFERCNTREG);
-
-			if ((data != NULL) && (*actbytes > 0)) {
-				SL811BufRead (hci, addr, data, *actbytes);
-
-			} else if ((data == NULL) && (*actbytes <= 0)) {
-				DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n",
-					*actbytes);
-				return 0;
-			}
-		} else if (pid == PID_OUT) {
-			*actbytes = length;
-		} else {
-			// printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid);
-		}
-		*toggle = !*toggle;
-	}
-
-	return 0;
-}
-
-/************************************************************************
- * Function Name : hc_start_int
- *  
- * This function enables SL811HS interrupts
- *
- * Input:  hci = data structure for the host controller
- *       
- * Return: none 
- ***********************************************************************/
-static void hc_start_int (hci_t * hci)
-{
-#ifdef HC_SWITCH_INT
-	int mask =
-	    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
-	    SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET;
-	SL811Write (hci, IntEna, mask);
-#endif
-}
-
-/************************************************************************
- * Function Name : hc_stop_int
- *  
- * This function disables SL811HS interrupts
- *
- * Input:  hci = data structure for the host controller
- *       
- * Return: none 
- ***********************************************************************/
-static void hc_stop_int (hci_t * hci)
-{
-#ifdef HC_SWITCH_INT
-	SL811Write (hci, SL11H_INTSTATREG, 0xff);
-//  SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV);
-
-#endif
-}
-
-/************************************************************************
- * Function Name : handleInsRmvIntr
- *  
- * This function handles the insertion or removal of device on  SL811HS. 
- * It resets the controller and updates the port status
- *
- * Input:  hci = data structure for the host controller
- *       
- * Return: none 
- ***********************************************************************/
-void handleInsRmvIntr (hci_t * hci)
-{
-	hcipriv_t *hp = &hci->hp;
-
-	USBReset (hci);
-
-	/* Changes in connection status */
-
-	hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE;
-
-	/* Port Enable or Disable */
-
-	if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) {
-		/* device is connected to the port:
-		 *    1) Enable port 
-		 *    2) Resume ?? 
-		 */
-//               hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
-
-		/* Over Current is not supported by the SL811 HW ?? */
-
-		/* How about the Port Power ?? */
-
-	} else {
-		/* Device has disconnect:
-		 *    1) Disable port
-		 */
-
-		hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT);
-		hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
-
-	}
-}
-
-/*****************************************************************
- *
- * Function Name: SL11StartXaction
- *  
- * This functions load the registers with appropriate value and 
- * transmit the packet.				  
- *
- * Input:  hci = data structure for the host controller
- *         addr = USB address of the device
- *         epaddr = endpoint number
- *         pid = packet ID
- *         len = data length
- *         toggle = USB toggle bit, either 0 or 1
- *         slow = speed of the device
- *         urb_state = the current stage of USB transaction
- *
- * Return: 0 = error; 1 = successful
- *                
- *****************************************************************/
-int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
-		      int toggle, int slow, int urb_state)
-{
-
-	hcipriv_t *hp = &hci->hp;
-	__u8 cmd = 0;
-	__u8 setup_data[4];
-	__u16 speed;
-
-	speed = hp->RHportStatus->portStatus;
-	if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) {
-		cmd |= SL11H_HCTLMASK_PREAMBLE;
-	}
-	switch (pid) {
-	case PID_SETUP:
-		cmd &= SL11H_HCTLMASK_PREAMBLE;
-		cmd |=
-		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
-		     SL11H_HCTLMASK_WRITE);
-		break;
-
-	case PID_OUT:
-		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
-		cmd |=
-		    (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
-		     SL11H_HCTLMASK_WRITE);
-		if (toggle) {
-			cmd |= SL11H_HCTLMASK_SEQ;
-		}
-		break;
-
-	case PID_IN:
-		cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
-		cmd |= (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP);
-		break;
-
-	default:
-		DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);
-		return 0;
-	}
-	setup_data[0] = SL11H_DATA_START;
-	setup_data[1] = len;
-	setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));
-	setup_data[3] = addr & 0x7F;
-
-	SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4);
-
-	SL811Write (hci, SL11H_HOSTCTLREG, cmd);
-
-#if 0
-	/* The SL811 has a hardware flaw when hub devices sends out
-	 * SE0 between packets. It has been found in a TI chipset and
-	 * cypress hub chipset. It causes the SL811 to hang
-	 * The workaround is to re-issue the preample again.
-	 */
-
-	if ((cmd & SL11H_HCTLMASK_PREAMBLE)) {
-		SL811Write (hci, SL11H_PIDEPREG_B, 0xc0);
-		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1);	// send the premable
-	}
-#endif
-	return 1;
-}
-
-/*****************************************************************
- *
- * Function Name: hc_interrupt
- *
- * Interrupt service routine. 
- *
- * 1) determine the causes of interrupt
- * 2) clears all interrupts
- * 3) calls appropriate function to service the interrupt
- *
- * Input:  irq = interrupt line associated with the controller 
- *         hci = data structure for the host controller
- *         r = holds the snapshot of the processor's context before 
- *             the processor entered interrupt code. (not used here) 
- *
- * Return value  : None.
- *                
- *****************************************************************/
-static void hc_interrupt (int irq, void *__hci, struct pt_regs *r)
-{
-	char ii;
-	hci_t *hci = __hci;
-	int isExcessNak = 0;
-	int urb_state = 0;
-	char tmpIrq = 0;
-
-	/* Get value from interrupt status register */
-
-	ii = SL811Read (hci, SL11H_INTSTATREG);
-
-	if (ii & SL11H_INTMASK_INSRMV) {
-		/* Device insertion or removal detected for the USB port */
-
-		SL811Write (hci, SL11H_INTENBLREG, 0);
-		SL811Write (hci, SL11H_CTLREG1, 0);
-		mdelay (100);	// wait for device stable 
-		handleInsRmvIntr (hci);
-		return;
-	}
-
-	/* Clear all interrupts */
-
-	SL811Write (hci, SL11H_INTSTATREG, 0xff);
-
-	if (ii & SL11H_INTMASK_XFERDONE) {
-		/* USB Done interrupt occurred */
-
-		urb_state = sh_done_list (hci, &isExcessNak);
-#ifdef WARNING
-		if (hci->td_array->len > 0)
-			printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",
-				hci->td_array->len);
-#endif
-		if (hci->td_array->len == 0 && !isExcessNak
-		    && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {
-			if (urb_state == 0) {
-				/* All urb_state has not been finished yet! 
-				 * continue with the current urb transaction 
-				 */
-
-				if (hci->last_packet_nak == 0) {
-					if (!usb_pipecontrol
-					    (hci->td_array->td[0].urb->pipe))
-						sh_add_packet (hci, hci->td_array-> td[0].urb);
-				}
-			} else {
-				/* The last transaction has completed:
-				 * schedule the next transaction 
-				 */
-
-				sh_schedule_trans (hci, 0);
-			}
-		}
-		SL811Write (hci, SL11H_INTSTATREG, 0xff);
-		return;
-	}
-
-	if (ii & SL11H_INTMASK_SOFINTR) {
-		hci->frame_number = (hci->frame_number + 1) % 2048;
-		if (hci->td_array->len == 0)
-			sh_schedule_trans (hci, 1);
-		else {
-			if (sofWaitCnt++ > 100) {
-				/* The last transaction has not completed.
-				 * Need to retire the current td, and let
-				 * it transmit again later on.
-				 * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER 
-				 *  GET TO THIS POINT)
-				 */
-
-				DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n",
-					hci->td_array->len);
-				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,
-					   "INTERRUPT", 0);
-				sh_done_list (hci, &isExcessNak);
-				SL811Write (hci, SL11H_INTSTATREG, 0xff);
-				hci->td_array->len = 0;
-				sofWaitCnt = 0;
-			}
-		}
-		tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);
-		if (tmpIrq) {
-			DBG ("IRQ occurred while service SOF: irq = 0x%x\n",
-			     tmpIrq);
-
-			/* If we receive a DONE IRQ after schedule, need to 
-			 * handle DONE IRQ again 
-			 */
-
-			if (tmpIrq & SL11H_INTMASK_XFERDONE) {
-				DBGERR ("IRQ occurred while service SOF: irq = 0x%x\n",
-					tmpIrq);
-				urb_state = sh_done_list (hci, &isExcessNak);
-			}
-			SL811Write (hci, SL11H_INTSTATREG, 0xff);
-		}
-	} else {
-		DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);
-	}
-
-	SL811Write (hci, SL11H_INTSTATREG, 0xff);
-	return;
-}
-
-/*****************************************************************
- *
- * Function Name: hc_reset
- *
- * This function does register test and resets the SL811HS 
- * controller.
- *
- * Input:  hci = data structure for the host controller
- *
- * Return value  : 0
- *                
- *****************************************************************/
-static int hc_reset (hci_t * hci)
-{
-	int attachFlag = 0;
-
-	DBGFUNC ("Enter hc_reset\n");
-	regTest (hci);
-	attachFlag = USBReset (hci);
-	if (attachFlag) {
-		setPortChange (hci, PORT_CONNECT_CHANGE);
-	}
-	return (0);
-}
-
-/*****************************************************************
- *
- * Function Name: hc_alloc_trans_buffer
- *
- * This function allocates all transfer buffer  
- *
- * Input:  hci = data structure for the host controller
- *
- * Return value  : 0
- *                
- *****************************************************************/
-static int hc_alloc_trans_buffer (hci_t * hci)
-{
-	hcipriv_t *hp = &hci->hp;
-	int maxlen;
-
-	hp->itl0_len = 0;
-	hp->itl1_len = 0;
-	hp->atl_len = 0;
-
-	hp->itl_buffer_len = 1024;
-	hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len;	/* 2048 */
-
-	maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;
-
-	hp->tl = kmalloc (maxlen, GFP_KERNEL);
-
-	if (!hp->tl)
-		return -ENOMEM;
-
-	memset (hp->tl, 0, maxlen);
-	return 0;
-}
-
-/*****************************************************************
- *
- * Function Name: getPortStatusAndChange
- *
- * This function gets the ports status from SL811 and format it 
- * to a USB request format
- *
- * Input:  hci = data structure for the host controller
- *
- * Return value  : port status and change
- *                
- *****************************************************************/
-static __u32 getPortStatusAndChange (hci_t * hci)
-{
-	hcipriv_t *hp = &hci->hp;
-	__u32 portstatus;
-
-	DBGFUNC ("enter getPorStatusAndChange\n");
-
-	portstatus = hp->RHportStatus->portChange << 16 | hp->RHportStatus->portStatus;
-
-	return (portstatus);
-}
-
-/*****************************************************************
- *
- * Function Name: setPortChange
- *
- * This function set the bit position of portChange.
- *
- * Input:  hci = data structure for the host controller
- *         bitPos = the bit position
- *
- * Return value  : none 
- *                
- *****************************************************************/
-static void setPortChange (hci_t * hci, __u16 bitPos)
-{
-	hcipriv_t *hp = &hci->hp;
-
-	switch (bitPos) {
-	case PORT_CONNECT_STAT:
-		hp->RHportStatus->portChange |= bitPos;
-		break;
-
-	case PORT_ENABLE_STAT:
-		hp->RHportStatus->portChange |= bitPos;
-		break;
-
-	case PORT_RESET_STAT:
-		hp->RHportStatus->portChange |= bitPos;
-		break;
-
-	case PORT_POWER_STAT:
-		hp->RHportStatus->portChange |= bitPos;
-		break;
-
-	case PORT_SUSPEND_STAT:
-		hp->RHportStatus->portChange |= bitPos;
-		break;
-
-	case PORT_OVER_CURRENT_STAT:
-		hp->RHportStatus->portChange |= bitPos;
-		break;
-	}
-}
-
-/*****************************************************************
- *
- * Function Name: clrPortChange
- *
- * This function clear the bit position of portChange.
- *
- * Input:  hci = data structure for the host controller
- *         bitPos = the bit position
- *
- * Return value  : none 
- *                
- *****************************************************************/
-static void clrPortChange (hci_t * hci, __u16 bitPos)
-{
-	hcipriv_t *hp = &hci->hp;
-	switch (bitPos) {
-	case PORT_CONNECT_CHANGE:
-		hp->RHportStatus->portChange &= ~bitPos;
-		break;
-
-	case PORT_ENABLE_CHANGE:
-		hp->RHportStatus->portChange &= ~bitPos;
-		break;
-
-	case PORT_RESET_CHANGE:
-		hp->RHportStatus->portChange &= ~bitPos;
-		break;
-
-	case PORT_SUSPEND_CHANGE:
-		hp->RHportStatus->portChange &= ~bitPos;
-		break;
-
-	case PORT_OVER_CURRENT_CHANGE:
-		hp->RHportStatus->portChange &= ~bitPos;
-		break;
-	}
-}
-
-/*****************************************************************
- *
- * Function Name: clrPortStatus
- *
- * This function clear the bit position of portStatus.
- *
- * Input:  hci = data structure for the host controller
- *         bitPos = the bit position
- *
- * Return value  : none 
- *                
- *****************************************************************/
-static void clrPortStatus (hci_t * hci, __u16 bitPos)
-{
-	hcipriv_t *hp = &hci->hp;
-	switch (bitPos) {
-	case PORT_ENABLE_STAT:
-		hp->RHportStatus->portStatus &= ~bitPos;
-		break;
-
-	case PORT_RESET_STAT:
-		hp->RHportStatus->portStatus &= ~bitPos;
-		break;
-
-	case PORT_POWER_STAT:
-		hp->RHportStatus->portStatus &= ~bitPos;
-		break;
-
-	case PORT_SUSPEND_STAT:
-		hp->RHportStatus->portStatus &= ~bitPos;
-		break;
-	}
-}
-
-/*****************************************************************
- *
- * Function Name: setPortStatus
- *
- * This function set the bit position of portStatus.
- *
- * Input:  hci = data structure for the host controller
- *         bitPos = the bit position
- *
- * Return value  : none 
- *                
- *****************************************************************/
-static void setPortStatus (hci_t * hci, __u16 bitPos)
-{
-	hcipriv_t *hp = &hci->hp;
-	switch (bitPos) {
-	case PORT_ENABLE_STAT:
-		hp->RHportStatus->portStatus |= bitPos;
-		break;
-
-	case PORT_RESET_STAT:
-		hp->RHportStatus->portStatus |= bitPos;
-		break;
-
-	case PORT_POWER_STAT:
-		hp->RHportStatus->portStatus |= bitPos;
-		break;
-
-	case PORT_SUSPEND_STAT:
-		hp->RHportStatus->portStatus |= bitPos;
-		break;
-	}
-}
-
-/*****************************************************************
- *
- * Function Name: hc_start
- *
- * This function starts the root hub functionality. 
- *
- * Input:  hci = data structure for the host controller
- *
- * Return value  : 0 
- *                
- *****************************************************************/
-static int hc_start (hci_t * hci)
-{
-	DBGFUNC ("Enter hc_start\n");
-
-	rh_connect_rh (hci);
-
-	return 0;
-}
-
-/*****************************************************************
- *
- * Function Name: hc_alloc_hci
- *
- * This function allocates all data structure and store in the 
- * private data structure. 
- *
- * Input:  hci = data structure for the host controller
- *
- * Return value  : 0 
- *                
- *****************************************************************/
-static hci_t *__devinit hc_alloc_hci (void)
-{
-	hci_t *hci;
-	hcipriv_t *hp;
-	portstat_t *ps;
-	struct usb_bus *bus;
-
-	DBGFUNC ("Enter hc_alloc_hci\n");
-	hci = (hci_t *) kmalloc (sizeof (hci_t), GFP_KERNEL);
-	if (!hci)
-		return NULL;
-
-	memset (hci, 0, sizeof (hci_t));
-
-	hp = &hci->hp;
-
-	hp->irq = -1;
-	hp->hcport = -1;
-
-	/* setup root hub port status */
-
-	ps = (portstat_t *) kmalloc (sizeof (portstat_t), GFP_KERNEL);
-
-	if (!ps)
-		return NULL;
-	ps->portStatus = PORT_STAT_DEFAULT;
-	ps->portChange = PORT_CHANGE_DEFAULT;
-	hp->RHportStatus = ps;
-
-	hci->nakCnt = 0;
-	hci->last_packet_nak = 0;
-
-	hci->a_td_array.len = 0;
-	hci->i_td_array[0].len = 0;
-	hci->i_td_array[1].len = 0;
-	hci->td_array = &hci->a_td_array;
-	hci->active_urbs = 0;
-	hci->active_trans = 0;
-	INIT_LIST_HEAD (&hci->hci_hcd_list);
-	list_add (&hci->hci_hcd_list, &hci_hcd_list);
-	init_waitqueue_head (&hci->waitq);
-
-	INIT_LIST_HEAD (&hci->ctrl_list);
-	INIT_LIST_HEAD (&hci->bulk_list);
-	INIT_LIST_HEAD (&hci->iso_list);
-	INIT_LIST_HEAD (&hci->intr_list);
-	INIT_LIST_HEAD (&hci->del_list);
-
-	bus = usb_alloc_bus (&hci_device_operations);
-	if (!bus) {
-		kfree (hci);
-		return NULL;
-	}
-
-	hci->bus = bus;
-	bus->bus_name = "sl811";
-	bus->hcpriv = (void *) hci;
-
-	return hci;
-}
-
-/*****************************************************************
- *
- * Function Name: hc_release_hci
- *
- * This function De-allocate all resources  
- *
- * Input:  hci = data structure for the host controller
- *
- * Return value  : 0 
- *                
- *****************************************************************/
-static void hc_release_hci (hci_t * hci)
-{
-	hcipriv_t *hp = &hci->hp;
-
-	DBGFUNC ("Enter hc_release_hci\n");
-
-	/* disconnect all devices */
-	if (hci->bus->root_hub)
-		usb_disconnect (&hci->bus->root_hub);
-
-	hc_reset (hci);
-
-	if (hp->tl)
-		kfree (hp->tl);
-
-	if (hp->hcport > 0) {
-		release_region (hp->hcport, 2);
-		hp->hcport = 0;
-	}
-
-	if (hp->irq >= 0) {
-		free_irq (hp->irq, hci);
-		hp->irq = -1;
-	}
-
-	usb_deregister_bus (hci->bus);
-	usb_free_bus (hci->bus);
-
-	list_del (&hci->hci_hcd_list);
-	INIT_LIST_HEAD (&hci->hci_hcd_list);
-
-	kfree (hci);
-}
-
-/*****************************************************************
- *
- * Function Name: init_irq
- *
- * This function is board specific.  It sets up the interrupt to 
- * be an edge trigger and trigger on the rising edge  
- *
- * Input: none 
- *
- * Return value  : none 
- *                
- *****************************************************************/
-void init_irq (void)
-{
-	GPDR &= ~(1 << 13);
-	set_GPIO_IRQ_edge (1 << 13, GPIO_RISING_EDGE);
-}
-
-/*****************************************************************
- *
- * Function Name: hc_found_hci
- *
- * This function request IO memory regions, request IRQ, and
- * allocate all other resources. 
- *
- * Input: addr = first IO address
- *        addr2 = second IO address
- *        irq = interrupt number 
- *
- * Return: 0 = success or error condition 
- *                
- *****************************************************************/
-static int __devinit hc_found_hci (int addr, int addr2, int irq)
-{
-	hci_t *hci;
-	hcipriv_t *hp;
-
-	DBGFUNC ("Enter hc_found_hci\n");
-	hci = hc_alloc_hci ();
-	if (!hci) {
-		return -ENOMEM;
-	}
-
-	init_irq ();
-	hp = &hci->hp;
-
-	if (!request_region (addr, 256, "SL811 USB HOST")) {
-		DBGERR ("request address %d failed", addr);
-		hc_release_hci (hci);
-		return -EBUSY;
-	}
-	hp->hcport = addr;
-	if (!hp->hcport) {
-		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport);
-	}
-
-	if (!request_region (addr2, 256, "SL811 USB HOST")) {
-		DBGERR ("request address %d failed", addr2);
-		hc_release_hci (hci);
-		return -EBUSY;
-	}
-	hp->hcport2 = addr2;
-	if (!hp->hcport2) {
-		DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport2);
-	}
-
-	if (hc_alloc_trans_buffer (hci)) {
-		hc_release_hci (hci);
-		return -ENOMEM;
-	}
-
-	usb_register_bus (hci->bus);
-
-	if (request_irq (irq, hc_interrupt, 0, "SL811", hci) != 0) {
-		DBGERR ("request interrupt %d failed", irq);
-		hc_release_hci (hci);
-		return -EBUSY;
-	}
-	hp->irq = irq;
-
-	printk (KERN_INFO __FILE__ ": USB SL811 at %x, addr2 = %x, IRQ %d\n",
-		addr, addr2, irq);
-	hc_reset (hci);
-
-	if (hc_start (hci) < 0) {
-		DBGERR ("can't start usb-%x", addr);
-		hc_release_hci (hci);
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-/*****************************************************************
- *
- * Function Name: hci_hcd_init
- *
- * This is an init function, and it is the first function being called
- *
- * Input: none 
- *
- * Return: 0 = success or error condition 
- *                
- *****************************************************************/
-static int __init hci_hcd_init (void)
-{
-	int ret;
-
-	DBGFUNC ("Enter hci_hcd_init\n");
-	ret = hc_found_hci (base_addr, data_reg_addr, irq);
-
-	return ret;
-}
-
-/*****************************************************************
- *
- * Function Name: hci_hcd_cleanup
- *
- * This is a cleanup function, and it is called when module is 
- * unloaded. 
- *
- * Input: none 
- *
- * Return: none 
- *                
- *****************************************************************/
-static void __exit hci_hcd_cleanup (void)
-{
-	struct list_head *hci_l;
-	hci_t *hci;
-
-	DBGFUNC ("Enter hci_hcd_cleanup\n");
-	for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) {
-		hci = list_entry (hci_l, hci_t, hci_hcd_list);
-		hci_l = hci_l->next;
-		hc_release_hci (hci);
-	}
-}
-
-module_init (hci_hcd_init);
-module_exit (hci_hcd_cleanup);
-
-MODULE_AUTHOR ("Pei Liu <pbl@cypress.com>");
-MODULE_DESCRIPTION ("USB SL811HS Host Controller Driver");
diff -urN linux-2.4.22-bk41/drivers/usb/hc_sl811.h linux-2.4.22-bk42/drivers/usb/hc_sl811.h
--- linux-2.4.22-bk41/drivers/usb/hc_sl811.h	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/hc_sl811.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,385 +0,0 @@
-/*
- * SL811HS HCD (Host Controller Driver) for USB.
- * 
- * COPYRIGHT (C) by CYPRESS SEMICONDUCTOR INC 
- * 
- *
- */
-
-#define GET_FRAME_NUMBER(hci)	READ_REG32 (hci, HcFmNumber)
-
-/*
- * Maximum number of root hub ports
- */
-#define MAX_ROOT_PORTS		15	/* maximum OHCI root hub ports */
-
-/* control and status registers */
-#define HcRevision		0x00
-#define HcControl		0x01
-#define HcCommandStatus		0x02
-#define HcInterruptStatus	0x03
-#define HcInterruptEnable	0x04
-#define HcInterruptDisable	0x05
-#define HcFmInterval		0x0D
-#define HcFmRemaining		0x0E
-#define HcFmNumber		0x0F
-#define HcLSThreshold		0x11
-#define HcRhDescriptorA		0x12
-#define HcRhDescriptorB		0x13
-#define HcRhStatus		0x14
-#define HcRhPortStatus		0x15
-
-#define HcHardwareConfiguration 0x20
-#define HcDMAConfiguration	0x21
-#define HcTransferCounter	0x22
-#define HcuPInterrupt		0x24
-#define HcuPInterruptEnable	0x25
-#define HcChipID		0x27
-#define HcScratch		0x28
-#define HcSoftwareReset		0x29
-#define HcITLBufferLength	0x2A
-#define HcATLBufferLength	0x2B
-#define HcBufferStatus		0x2C
-#define HcReadBackITL0Length	0x2D
-#define HcReadBackITL1Length	0x2E
-#define HcITLBufferPort		0x40
-#define HcATLBufferPort		0x41
-
-/* OHCI CONTROL AND STATUS REGISTER MASKS */
-
-/*
- * HcControl (control) register masks
- */
-#define OHCI_CTRL_HCFS		(3 << 6)	/* BUS state mask */
-#define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
-#define OHCI_CTRL_RWE		(1 << 10)	/* remote wakeup enable */
-
-/* pre-shifted values for HCFS */
-#define OHCI_USB_RESET		(0 << 6)
-#define OHCI_USB_RESUME		(1 << 6)
-#define OHCI_USB_OPER		(2 << 6)
-#define OHCI_USB_SUSPEND	(3 << 6)
-
-/*
- * HcCommandStatus (cmdstatus) register masks
- */
-#define OHCI_HCR	(1 << 0)	/* host controller reset */
-#define OHCI_SO		(3 << 16)	/* scheduling overrun count */
-
-/*
- * masks used with interrupt registers:
- * HcInterruptStatus (intrstatus)
- * HcInterruptEnable (intrenable)
- * HcInterruptDisable (intrdisable)
- */
-#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
-
-#define OHCI_INTR_SF	(1 << 2)	/* start frame */
-#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
-#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
-#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
-#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
-#define OHCI_INTR_ATD	(1 << 7)	/* scheduling overrun */
-
-#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
-
-/*
- * HcHardwareConfiguration
- */
-#define InterruptPinEnable	(1 << 0)
-#define InterruptPinTrigger	(1 << 1)
-#define InterruptOutputPolarity	(1 << 2)
-#define DataBusWidth16		(1 << 3)
-#define DREQOutputPolarity	(1 << 5)
-#define DACKInputPolarity	(1 << 6)
-#define EOTInputPolarity	(1 << 7)
-#define DACKMode		(1 << 8)
-#define AnalogOCEnable		(1 << 10)
-#define SuspendClkNotStop	(1 << 11)
-#define DownstreamPort15KRSel	(1 << 12)
-
-/* 
- * HcDMAConfiguration
- */
-#define DMAReadWriteSelect 	(1 << 0)
-#define ITL_ATL_DataSelect	(1 << 1)
-#define DMACounterSelect	(1 << 2)
-#define DMAEnable		(1 << 4)
-#define BurstLen_1		0
-#define BurstLen_4		(1 << 5)
-#define BurstLen_8		(2 << 5)
-
-/*
- * HcuPInterrupt
- */
-#define SOFITLInt		(1 << 0)
-#define ATLInt			(1 << 1)
-#define AllEOTInterrupt		(1 << 2)
-#define OPR_Reg			(1 << 4)
-#define HCSuspended		(1 << 5)
-#define ClkReady		(1 << 6)
-
-/*
- * HcBufferStatus
- */
-#define ITL0BufferFull		(1 << 0)
-#define ITL1BufferFull		(1 << 1)
-#define ATLBufferFull		(1 << 2)
-#define ITL0BufferDone		(1 << 3)
-#define ITL1BufferDone		(1 << 4)
-#define ATLBufferDone		(1 << 5)
-
-/* OHCI ROOT HUB REGISTER MASKS */
-
-/* roothub.portstatus [i] bits */
-#define RH_PS_CCS            0x00000001	/* current connect status */
-#define RH_PS_PES            0x00000002	/* port enable status */
-#define RH_PS_PSS            0x00000004	/* port suspend status */
-#define RH_PS_POCI           0x00000008	/* port over current indicator */
-#define RH_PS_PRS            0x00000010	/* port reset status */
-#define RH_PS_PPS            0x00000100	/* port power status */
-#define RH_PS_LSDA           0x00000200	/* low speed device attached */
-#define RH_PS_CSC            0x00010000	/* connect status change */
-#define RH_PS_PESC           0x00020000	/* port enable status change */
-#define RH_PS_PSSC           0x00040000	/* port suspend status change */
-#define RH_PS_OCIC           0x00080000	/* over current indicator change */
-#define RH_PS_PRSC           0x00100000	/* port reset status change */
-
-/* roothub.status bits */
-#define RH_HS_LPS		0x00000001	/* local power status */
-#define RH_HS_OCI		0x00000002	/* over current indicator */
-#define RH_HS_DRWE		0x00008000	/* device remote wakeup enable */
-#define RH_HS_LPSC		0x00010000	/* local power status change */
-#define RH_HS_OCIC		0x00020000	/* over current indicator change */
-#define RH_HS_CRWE		0x80000000	/* clear remote wakeup enable */
-
-/* roothub.b masks */
-#define RH_B_DR			0x0000ffff	/* device removable flags */
-#define RH_B_PPCM		0xffff0000	/* port power control mask */
-
-/* roothub.a masks */
-#define	RH_A_NDP		(0xff << 0)	/* number of downstream ports */
-#define	RH_A_PSM		(1 << 8)	/* power switching mode */
-#define	RH_A_NPS		(1 << 9)	/* no power switching */
-#define	RH_A_DT			(1 << 10)	/* device type (mbz) */
-#define	RH_A_OCPM		(1 << 11)	/* over current protection mode */
-#define	RH_A_NOCP		(1 << 12)	/* no over current protection */
-#define	RH_A_POTPGT		(0xff << 24)	/* power on to power good time */
-
-#define URB_DEL 1
-
-#define PORT_STAT_DEFAULT		0x0100
-#define PORT_CONNECT_STAT  		0x1
-#define PORT_ENABLE_STAT		0x2
-#define PORT_SUSPEND_STAT		0x4
-#define PORT_OVER_CURRENT_STAT		0x8
-#define PORT_RESET_STAT			0x10
-#define PORT_POWER_STAT			0x100
-#define PORT_LOW_SPEED_DEV_ATTACH_STAT	0x200
-
-#define PORT_CHANGE_DEFAULT		0x0
-#define PORT_CONNECT_CHANGE		0x1
-#define PORT_ENABLE_CHANGE		0x2
-#define PORT_SUSPEND_CHANGE		0x4
-#define PORT_OVER_CURRENT_CHANGE	0x8
-#define PORT_RESET_CHANGE		0x10
-
-/* Port Status Request info */
-
-typedef struct portstat {
-	__u16 portChange;
-	__u16 portStatus;
-} portstat_t;
-
-typedef struct hcipriv {
-	int irq;
-	int disabled;		/* e.g. got a UE, we're hung */
-	atomic_t resume_count;	/* defending against multiple resumes */
-	struct ohci_regs *regs;	/* OHCI controller's memory */
-	int hcport;		/* I/O base address */
-	int hcport2;		/* I/O data reg addr */
-
-	struct portstat *RHportStatus;	/* root hub port status */
-
-	int intrstatus;
-	__u32 hc_control;	/* copy of the hc control reg */
-
-	int frame;
-
-	__u8 *tl;
-	int xferPktLen;
-	int atl_len;
-	int atl_buffer_len;
-	int itl0_len;
-	int itl1_len;
-	int itl_buffer_len;
-	int itl_index;
-	int tl_last;
-	int units_left;
-
-} hcipriv_t;
-struct hci;
-
-#define cClt        0		// Control
-#define cISO        1		// ISO
-#define cBULK       2		// BULK
-#define cInt        3		// Interrupt
-#define ISO_BIT     0x10
-
-/*-------------------------------------------------------------------------
- * EP0 use for configuration and Vendor Specific command interface
- *------------------------------------------------------------------------*/
-#define cMemStart       0x10
-#define EP0Buf          0x40	/* SL11H/SL811H memory start at 0x40 */
-#define EP0Len          0x40	/* Length of config buffer EP0Buf */
-#define EP1Buf          0x60
-#define EP1Len          0x40
-
-/*-------------------------------------------------------------------------
- * SL11H/SL811H memory from 80h-ffh use as ping-pong buffer.
- *------------------------------------------------------------------------*/
-#define uBufA           0x80	/* buffer A address for DATA0 */
-#define uBufB           0xc0	/* buffer B address for DATA1 */
-#define uXferLen        0x40	/* xfer length */
-#define sMemSize        0xc0	/* Total SL11 memory size */
-#define cMemEnd         256
-
-/*-------------------------------------------------------------------------
- * SL811H Register Control memory map
- * --Note: 
- *      --SL11H only has one control register set from 0x00-0x04
- *      --SL811H has two control register set from 0x00-0x04 and 0x08-0x0c
- *------------------------------------------------------------------------*/
-
-#define EP0Control      0x00
-#define EP0Address      0x01
-#define EP0XferLen      0x02
-#define EP0Status       0x03
-#define EP0Counter      0x04
-
-#define EP1Control      0x08
-#define EP1Address      0x09
-#define EP1XferLen      0x0a
-#define EP1Status       0x0b
-#define EP1Counter      0x0c
-
-#define CtrlReg         0x05
-#define IntEna          0x06
-			 // 0x07 is reserved
-#define IntStatus       0x0d
-#define cDATASet        0x0e
-#define cSOFcnt         0x0f
-#define IntMask         0x57	/* Reset|DMA|EP0|EP2|EP1 for IntEna */
-#define HostMask        0x47	/* Host request command  for IntStatus */
-#define ReadMask        0xd7	/* Read mask interrupt   for IntStatus */
-
-/*-------------------------------------------------------------------------
- * Standard Chapter 9 definition
- *-------------------------------------------------------------------------
- */
-#define GET_STATUS      0x00
-#define CLEAR_FEATURE   0x01
-#define SET_FEATURE     0x03
-#define SET_ADDRESS     0x05
-#define GET_DESCRIPTOR  0x06
-#define SET_DESCRIPTOR  0x07
-#define GET_CONFIG      0x08
-#define SET_CONFIG      0x09
-#define GET_INTERFACE   0x0a
-#define SET_INTERFACE   0x0b
-#define SYNCH_FRAME     0x0c
-
-#define DEVICE          0x01
-#define CONFIGURATION   0x02
-#define STRING          0x03
-#define INTERFACE       0x04
-#define ENDPOINT        0x05
-
-/*-------------------------------------------------------------------------
- * SL11H/SL811H definition
- *-------------------------------------------------------------------------
- */
-#define DATA0_WR	0x07	// (Arm+Enable+tranmist to Host+DATA0)
-#define DATA1_WR	0x47	// (Arm+Enable+tranmist to Host on DATA1)
-#define ZDATA0_WR	0x05	// (Arm+Transaction Ignored+tranmist to Host+DATA0)
-#define ZDATA1_WR	0x45	// (Arm+Transaction Ignored+tranmist to Host+DATA1)
-#define DATA0_RD	0x03	// (Arm+Enable+received from Host+DATA0)
-#define DATA1_RD	0x43	// (Arm+Enable+received from Host+DATA1)
-
-#define PID_SETUP	0x2d	// USB Specification 1.1 Standard Definition
-#define PID_SOF		0xA5
-#define PID_IN		0x69
-#define PID_OUT		0xe1
-
-#define MAX_RETRY	0xffff
-#define TIMEOUT		5		/* 2 mseconds */
-
-#define SL11H_HOSTCTLREG	0
-#define SL11H_BUFADDRREG	1
-#define SL11H_BUFLNTHREG	2
-#define SL11H_PKTSTATREG	3	/* read */
-#define SL11H_PIDEPREG		3	/* write */
-#define SL11H_XFERCNTREG	4	/* read */
-#define SL11H_DEVADDRREG	4	/* write */
-#define SL11H_CTLREG1		5
-#define SL11H_INTENBLREG	6
-
-#define SL11H_HOSTCTLREG_B	8
-#define SL11H_BUFADDRREG_B	9
-#define SL11H_BUFLNTHREG_B	0x0A
-#define SL11H_PKTSTATREG_B	0x0B	/* read */
-#define SL11H_PIDEPREG_B	0x0B	/* write */
-#define SL11H_XFERCNTREG_B	0x0C	/* read */
-#define SL11H_DEVADDRREG_B	0x0C	/* write */
-
-#define SL11H_INTSTATREG	0x0D	/* write clears bitwise */
-#define SL11H_HWREVREG		0x0E	/* read */
-#define SL11H_SOFLOWREG		0x0E	/* write */
-#define SL11H_SOFTMRREG		0x0F	/* read */
-#define SL11H_CTLREG2		0x0F	/* write */
-#define SL11H_DATA_START	0x10
-
-/* Host control register bits (addr 0) */
-#define SL11H_HCTLMASK_ARM	1
-#define SL11H_HCTLMASK_ENBLEP	2
-#define SL11H_HCTLMASK_WRITE	4
-#define SL11H_HCTLMASK_ISOCH	0x10
-#define SL11H_HCTLMASK_AFTERSOF	0x20
-#define SL11H_HCTLMASK_SEQ	0x40
-#define SL11H_HCTLMASK_PREAMBLE	0x80
-
-/* Packet status register bits (addr 3) */
-#define SL11H_STATMASK_ACK	1
-#define SL11H_STATMASK_ERROR	2
-#define SL11H_STATMASK_TMOUT	4
-#define SL11H_STATMASK_SEQ	8
-#define SL11H_STATMASK_SETUP	0x10
-#define SL11H_STATMASK_OVF	0x20
-#define SL11H_STATMASK_NAK	0x40
-#define SL11H_STATMASK_STALL	0x80
-
-/* Control register 1 bits (addr 5) */
-#define SL11H_CTL1MASK_DSBLSOF	1
-#define SL11H_CTL1MASK_NOTXEOF2	4
-#define SL11H_CTL1MASK_DSTATE	0x18
-#define SL11H_CTL1MASK_NSPD	0x20
-#define SL11H_CTL1MASK_SUSPEND	0x40
-#define SL11H_CTL1MASK_CLK12	0x80
-
-#define SL11H_CTL1VAL_RESET	8
-
-/* Interrut enable (addr 6) and interrupt status register bits (addr 0xD) */
-#define SL11H_INTMASK_XFERDONE	1
-#define SL11H_INTMASK_SOFINTR	0x10
-#define SL11H_INTMASK_INSRMV	0x20
-#define SL11H_INTMASK_USBRESET	0x40
-#define SL11H_INTMASK_DSTATE	0x80	/* only in status reg */
-
-/* HW rev and SOF lo register bits (addr 0xE) */
-#define SL11H_HWRMASK_HWREV	0xF0
-
-/* SOF counter and control reg 2 (addr 0xF) */
-#define SL11H_CTL2MASK_SOFHI	0x3F
-#define SL11H_CTL2MASK_DSWAP	0x40
-#define SL11H_CTL2MASK_HOSTMODE	0xae
-
diff -urN linux-2.4.22-bk41/drivers/usb/hc_sl811_rh.c linux-2.4.22-bk42/drivers/usb/hc_sl811_rh.c
--- linux-2.4.22-bk41/drivers/usb/hc_sl811_rh.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/hc_sl811_rh.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,526 +0,0 @@
-
-/*-------------------------------------------------------------------------*/
-/*-------------------------------------------------------------------------*
- * SL811HS virtual root hub
- *  
- * based on usb-ohci.c by R. Weissgaerber et al.
- *-------------------------------------------------------------------------*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-#undef DEBUG
-#endif
-static __u32 getPortStatusAndChange (hci_t * hci);
-static void setPortStatus (hci_t * hci, __u16 bitPos);
-static void setPortChange (hci_t * hci, __u16 bitPos);
-static void clrPortStatus (hci_t * hci, __u16 bitPos);
-static void clrPortChange (hci_t * hci, __u16 bitPos);
-static int USBReset (hci_t * hci);
-static int cc_to_error (int cc);
-
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub 
- *-------------------------------------------------------------------------*/
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] = {
-	0x12,			/*  __u8  bLength; */
-	0x01,			/*  __u8  bDescriptorType; Device */
-	0x10,			/*  __u16 bcdUSB; v1.1 */
-	0x01,
-	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  bDeviceSubClass; */
-	0x00,			/*  __u8  bDeviceProtocol; */
-	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,			/*  __u16 idVendor; */
-	0x00,
-	0x00,			/*  __u16 idProduct; */
-	0x00,
-	0x00,			/*  __u16 bcdDevice; */
-	0x00,
-	0x00,			/*  __u8  iManufacturer; */
-	0x02,			/*  __u8  iProduct; */
-	0x01,			/*  __u8  iSerialNumber; */
-	0x01			/*  __u8  bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] = {
-	0x09,			/*  __u8  bLength; */
-	0x02,			/*  __u8  bDescriptorType; Configuration */
-	0x19,			/*  __u16 wTotalLength; */
-	0x00,
-	0x01,			/*  __u8  bNumInterfaces; */
-	0x01,			/*  __u8  bConfigurationValue; */
-	0x00,			/*  __u8  iConfiguration; */
-	0x40,			/*  __u8  bmAttributes; 
-				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 
-				   4..0: resvd */
-	0x00,			/*  __u8  MaxPower; */
-
-	/* interface */
-	0x09,			/*  __u8  if_bLength; */
-	0x04,			/*  __u8  if_bDescriptorType; Interface */
-	0x00,			/*  __u8  if_bInterfaceNumber; */
-	0x00,			/*  __u8  if_bAlternateSetting; */
-	0x01,			/*  __u8  if_bNumEndpoints; */
-	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  if_bInterfaceSubClass; */
-	0x00,			/*  __u8  if_bInterfaceProtocol; */
-	0x00,			/*  __u8  if_iInterface; */
-
-	/* endpoint */
-	0x07,			/*  __u8  ep_bLength; */
-	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
-	0x02,			/*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
-	0x00,
-	0xff			/*  __u8  ep_bInterval; 255 ms */
-};
-
-/* Hub class-specific descriptor is constructed dynamically */
-
-/***************************************************************************
- * Function Name : rh_send_irq
- * 
- * This function examine the port change in the virtual root hub.
- * 
- * Note: This function assumes only one port exist in the root hub.
- *
- * Input:  hci = data structure for the host controller
- *         rh_data = The pointer to port change data
- *         rh_len = length of the data in bytes
- *
- * Return: length of data  
- **************************************************************************/
-static int rh_send_irq (hci_t * hci, void *rh_data, int rh_len)
-{
-	int num_ports;
-	int i;
-	int ret;
-	int len;
-	__u8 data[8];
-
-	DBGFUNC ("enter rh_send_irq: \n");
-
-	/* Assuming the root hub has one port.  This value need to change if
-	 * there are more than one port for the root hub
-	 */
-
-	num_ports = 1;
-
-	/* The root hub status is not implemented, it basically has two fields:
-	 *     -- Local Power Status
-	 *     -- Over Current Indicator
-	 *     -- Local Power Change
-	 *     -- Over Current Indicator
-	 *
-	 * Right now, It is assume the power is good and no changes 
-	 */
-
-	*(__u8 *) data = 0;
-
-	ret = *(__u8 *) data;
-
-	/* Has the port status change within the root hub: It checks for
-	 *      -- Port Connect Status change
-	 *      -- Port Enable Change
-	 */
-
-	for (i = 0; i < num_ports; i++) {
-		*(__u8 *) (data + (i + 1) / 8) |=
-		    (((getPortStatusAndChange (hci) >> 16) & (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1 : 0) << ((i + 1) % 8);
-		ret += *(__u8 *) (data + (i + 1) / 8);
-
-		/* After the port change is read, it should be reset so the next time 
-		 * is it doesn't trigger a change again */
-
-	}
-	len = i / 8 + 1;
-
-	if (ret > 0) {
-		memcpy (rh_data, data, min (len, min (rh_len, (int)sizeof (data))));
-		return len;
-	}
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : rh_int_timer_do
- * 
- * This function is called when the timer expires.  It gets the the port 
- * change data and pass along to the upper protocol.
- * 
- * Note:  The virtual root hub interrupt pipe are polled by the timer
- *        every "interval" ms
- *
- * Input:  ptr = ptr to the urb
- *
- * Return: none  
- **************************************************************************/
-static void rh_int_timer_do (unsigned long ptr)
-{
-	int len;
-	struct urb *urb = (struct urb *) ptr;
-	hci_t *hci = urb->dev->bus->hcpriv;
-
-	DBGFUNC ("enter rh_int_timer_do\n");
-
-	if (hci->rh.send) {
-		len = rh_send_irq (hci, urb->transfer_buffer,
-				   urb->transfer_buffer_length);
-		if (len > 0) {
-			urb->actual_length = len;
-			if (urb_debug == 2)
-				urb_print (urb, "RET-t(rh)",
-					   usb_pipeout (urb->pipe));
-
-			if (urb->complete) {
-				urb->complete (urb);
-			}
-		}
-	}
-
-	/* re-activate the timer */
-	rh_init_int_timer (urb);
-}
-
-/***************************************************************************
- * Function Name : rh_init_int_timer
- * 
- * This function creates a timer that act as interrupt pipe in the
- * virtual hub.   
- * 
- * Note:  The virtual root hub's interrupt pipe are polled by the timer
- *        every "interval" ms
- *
- * Input: urb = USB request block 
- *
- * Return: 0  
- **************************************************************************/
-static int rh_init_int_timer (struct urb * urb)
-{
-	hci_t *hci = urb->dev->bus->hcpriv;
-	hci->rh.interval = urb->interval;
-
-	init_timer (&hci->rh.rh_int_timer);
-	hci->rh.rh_int_timer.function = rh_int_timer_do;
-	hci->rh.rh_int_timer.data = (unsigned long) urb;
-	hci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
-	add_timer (&hci->rh.rh_int_timer);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* helper macro */
-#define OK(x) 			len = (x); break
-
-/***************************************************************************
- * Function Name : rh_submit_urb
- * 
- * This function handles all USB request to the the virtual root hub
- * 
- * Input: urb = USB request block 
- *
- * Return: 0  
- **************************************************************************/
-static int rh_submit_urb (struct urb * urb)
-{
-	struct usb_device *usb_dev = urb->dev;
-	hci_t *hci = usb_dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-	void *data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int status = TD_CC_NOERROR;
-	__u32 datab[4];
-	__u8 *data_buf = (__u8 *) datab;
-
-	__u16 bmRType_bReq;
-	__u16 wValue;
-	__u16 wIndex;
-	__u16 wLength;
-
-	DBGFUNC ("enter rh_submit_urb\n");
-	if (usb_pipeint (pipe)) {
-		hci->rh.urb = urb;
-		hci->rh.send = 1;
-		hci->rh.interval = urb->interval;
-		rh_init_int_timer (urb);
-		urb->status = cc_to_error (TD_CC_NOERROR);
-
-		return 0;
-	}
-
-	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
-	wValue = le16_to_cpu (cmd->wValue);
-	wIndex = le16_to_cpu (cmd->wIndex);
-	wLength = le16_to_cpu (cmd->wLength);
-
-	DBG ("rh_submit_urb, req = %d(%x) len=%d",
-	     bmRType_bReq, bmRType_bReq, wLength);
-
-	switch (bmRType_bReq) {
-		/* Request Destination:
-		   without flags: Device, 
-		   RH_INTERFACE: interface, 
-		   RH_ENDPOINT: endpoint,
-		   RH_CLASS means HUB here, 
-		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
-		 */
-
-	case RH_GET_STATUS:
-		*(__u16 *) data_buf = cpu_to_le16 (1);
-		OK (2);
-
-	case RH_GET_STATUS | RH_INTERFACE:
-		*(__u16 *) data_buf = cpu_to_le16 (0);
-		OK (2);
-
-	case RH_GET_STATUS | RH_ENDPOINT:
-		*(__u16 *) data_buf = cpu_to_le16 (0);
-		OK (2);
-
-	case RH_GET_STATUS | RH_CLASS:
-		*(__u32 *) data_buf = cpu_to_le32 (0);
-		OK (4);
-
-	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-		*(__u32 *) data_buf =
-		    cpu_to_le32 (getPortStatusAndChange (hci));
-		OK (4);
-
-	case RH_CLEAR_FEATURE | RH_ENDPOINT:
-		switch (wValue) {
-		case (RH_ENDPOINT_STALL):
-			OK (0);
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_CLASS:
-		switch (wValue) {
-		case RH_C_HUB_LOCAL_POWER:
-			OK (0);
-
-		case (RH_C_HUB_OVER_CURRENT):
-			/* Over Current Not Implemented */
-			OK (0);
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_ENABLE):
-			clrPortStatus (hci, PORT_ENABLE_STAT);
-			OK (0);
-
-		case (RH_PORT_SUSPEND):
-			clrPortStatus (hci, PORT_SUSPEND_STAT);
-			OK (0);
-
-		case (RH_PORT_POWER):
-			clrPortStatus (hci, PORT_POWER_STAT);
-			OK (0);
-
-		case (RH_C_PORT_CONNECTION):
-			clrPortChange (hci, PORT_CONNECT_STAT);
-			OK (0);
-
-		case (RH_C_PORT_ENABLE):
-			clrPortChange (hci, PORT_ENABLE_STAT);
-			OK (0);
-
-		case (RH_C_PORT_SUSPEND):
-			clrPortChange (hci, PORT_SUSPEND_STAT);
-			OK (0);
-
-		case (RH_C_PORT_OVER_CURRENT):
-			clrPortChange (hci, PORT_OVER_CURRENT_STAT);
-			OK (0);
-
-		case (RH_C_PORT_RESET):
-			clrPortChange (hci, PORT_RESET_STAT);
-			OK (0);
-		}
-		break;
-
-	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_SUSPEND):
-			setPortStatus (hci, PORT_SUSPEND_STAT);
-			OK (0);
-
-		case (RH_PORT_RESET):
-			setPortStatus (hci, PORT_RESET_STAT);
-			// USBReset(hci);
-			clrPortChange (hci,
-				       PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE
-				       | PORT_SUSPEND_CHANGE |
-				       PORT_OVER_CURRENT_CHANGE);
-			setPortChange (hci, PORT_RESET_CHANGE);
-			clrPortStatus (hci, PORT_RESET_STAT);
-			setPortStatus (hci, PORT_ENABLE_STAT);
-
-			OK (0);
-
-		case (RH_PORT_POWER):
-			setPortStatus (hci, PORT_POWER_STAT);
-			OK (0);
-
-		case (RH_PORT_ENABLE):
-			setPortStatus (hci, PORT_ENABLE_STAT);
-			OK (0);
-		}
-		break;
-
-	case RH_SET_ADDRESS:
-		hci->rh.devnum = wValue;
-		OK (0);
-
-	case RH_GET_DESCRIPTOR:
-		DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue);
-		switch ((wValue & 0xff00) >> 8) {
-		case (0x01):	/* device descriptor */
-			len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength));
-			data_buf = root_hub_dev_des;
-			OK (len);
-
-		case (0x02):	/* configuration descriptor */
-			len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength));
-			data_buf = root_hub_config_des;
-			OK (len);
-
-		case (0x03):	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff, (int) (long) 0,
-						   "SL811HS", data, wLength);
-			if (len > 0) {
-				data_buf = data;
-				OK (min (leni, len));
-			}
-
-		default:
-			status = SL11H_STATMASK_STALL;
-		}
-		break;
-
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		data_buf[0] = 9;	// min length;
-		data_buf[1] = 0x29;
-		data_buf[2] = 1;	// # of downstream port
-		data_buf[3] = 0;
-		datab[1] = 0;
-		data_buf[5] = 50;	// 100 ms for port reset
-		data_buf[7] = 0xfc;	// which port is attachable
-		if (data_buf[2] < 7) {
-			data_buf[8] = 0xff;
-		} else {
-		}
-
-		len = min (leni, min ((__u16)data_buf[0], wLength));
-		OK (len);
-
-	case RH_GET_CONFIGURATION:
-		*(__u8 *) data_buf = 0x01;
-		OK (1);
-
-	case RH_SET_CONFIGURATION:
-		OK (0);
-
-	default:
-		DBGERR ("unsupported root hub command");
-		status = SL11H_STATMASK_STALL;
-	}
-
-	len = min (len, leni);
-	if (data != data_buf)
-		memcpy (data, data_buf, len);
-	urb->actual_length = len;
-	urb->status = cc_to_error (status);
-
-	urb->hcpriv = NULL;
-	urb->dev = NULL;
-	if (urb->complete) {
-		urb->complete (urb);
-	}
-
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : rh_unlink_urb
- * 
- * This function unlinks the URB 
- * 
- * Input: urb = USB request block 
- *
- * Return: 0  
- **************************************************************************/
-static int rh_unlink_urb (struct urb * urb)
-{
-	hci_t *hci = urb->dev->bus->hcpriv;
-
-	DBGFUNC ("enter rh_unlink_urb\n");
-	if (hci->rh.urb == urb) {
-		hci->rh.send = 0;
-		del_timer (&hci->rh.rh_int_timer);
-		hci->rh.urb = NULL;
-
-		urb->hcpriv = NULL;
-		usb_put_dev (urb->dev);
-		urb->dev = NULL;
-		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-			urb->status = -ECONNRESET;
-			if (urb->complete) {
-				urb->complete (urb);
-			}
-		} else
-			urb->status = -ENOENT;
-	}
-	return 0;
-}
-
-/***************************************************************************
- * Function Name : rh_connect_rh
- * 
- * This function connect the virtual root hub to the USB stack 
- * 
- * Input: urb = USB request block 
- *
- * Return: 0  
- **************************************************************************/
-static int rh_connect_rh (hci_t * hci)
-{
-	struct usb_device *usb_dev;
-
-	hci->rh.devnum = 0;
-	usb_dev = usb_alloc_dev (NULL, hci->bus);
-	if (!usb_dev)
-		return -ENOMEM;
-
-	hci->bus->root_hub = usb_dev;
-	usb_connect (usb_dev);
-	if (usb_new_device (usb_dev) != 0) {
-		usb_free_dev (usb_dev);
-		return -ENODEV;
-	}
-
-	return 0;
-}
diff -urN linux-2.4.22-bk41/drivers/usb/host/Config.in linux-2.4.22-bk42/drivers/usb/host/Config.in
--- linux-2.4.22-bk41/drivers/usb/host/Config.in	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk42/drivers/usb/host/Config.in	2003-10-26 02:49:55.000000000 -0800
@@ -12,6 +12,8 @@
    define_bool CONFIG_USB_UHCI_ALT n
 fi
 dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
-if [ "$CONFIG_ARM" = "y" ]; then
-   dep_tristate '  SL811HS Alternate (support isosynchronous mode)' CONFIG_USB_SL811HS_ALT $CONFIG_USB
+if [ "$CONFIG_ARM" = "y" -o "$CONFIG_X86" = "y" ]; then
+   # Cypress embedded USB controller on StrongARM or on x86 in PC/104
+   dep_tristate '  SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  SL811HS (x86, StrongARM) support, old driver' CONFIG_USB_SL811HS $CONFIG_USB $CONFIG_EXPERIMENTAL
 fi
diff -urN linux-2.4.22-bk41/drivers/usb/host/Makefile linux-2.4.22-bk42/drivers/usb/host/Makefile
--- linux-2.4.22-bk41/drivers/usb/host/Makefile	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk42/drivers/usb/host/Makefile	2003-10-26 02:49:55.000000000 -0800
@@ -10,6 +10,7 @@
 obj-$(CONFIG_USB_UHCI)				+= usb-uhci.o
 obj-$(CONFIG_USB_OHCI)				+= usb-ohci.o
 obj-$(CONFIG_USB_SL811HS_ALT)  			+= sl811.o
+obj-$(CONFIG_USB_SL811HS)  			+= hc_sl811.o
 
 # Extract lists of the multi-part drivers.
 # The 'int-*' lists are the intermediate files used to build the multi's.
diff -urN linux-2.4.22-bk41/drivers/usb/host/ehci-dbg.c linux-2.4.22-bk42/drivers/usb/host/ehci-dbg.c
--- linux-2.4.22-bk41/drivers/usb/host/ehci-dbg.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk42/drivers/usb/host/ehci-dbg.c	2003-10-26 02:49:55.000000000 -0800
@@ -471,7 +471,7 @@
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < ehci->periodic_size; i++) {
 		p = ehci->pshadow [i];
-		if (!p.ptr)
+		if (likely (!p.ptr))
 			continue;
 		tag = Q_NEXT_TYPE (ehci->periodic [i]);
 
@@ -491,7 +491,7 @@
 						break;
 				}
 				/* show more info the first time around */
-				if (temp == seen_count) {
+				if (temp == seen_count && p.ptr) {
 					u32	scratch = cpu_to_le32p (
 							&p.qh->hw_info1);
 
@@ -509,8 +509,10 @@
 						seen [seen_count++].qh = p.qh;
 				} else
 					temp = 0;
-				tag = Q_NEXT_TYPE (p.qh->hw_next);
-				p = p.qh->qh_next;
+				if (p.qh) {
+					tag = Q_NEXT_TYPE (p.qh->hw_next);
+					p = p.qh->qh_next;
+				}
 				break;
 			case Q_TYPE_FSTN:
 				temp = snprintf (next, size,
diff -urN linux-2.4.22-bk41/drivers/usb/host/ehci-q.c linux-2.4.22-bk42/drivers/usb/host/ehci-q.c
--- linux-2.4.22-bk41/drivers/usb/host/ehci-q.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/host/ehci-q.c	2003-10-26 02:49:55.000000000 -0800
@@ -189,7 +189,7 @@
 		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
 
 		/* S-mask in a QH means it's an interrupt urb */
-		if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
+		if ((qh->hw_info2 & __constant_cpu_to_le32 (0x00ff)) != 0) {
 
 			/* ... update hc-wide periodic stats (for usbfs) */
 			hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
@@ -257,7 +257,7 @@
  * Chases up to qh->hw_current.  Returns number of completions called,
  * indicating how much "real" work we did.
  */
-#define HALT_BIT cpu_to_le32(QTD_STS_HALT)
+#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
 static unsigned
 qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
 {
@@ -410,10 +410,14 @@
 
 	return count;
 }
-#undef HALT_BIT
 
 /*-------------------------------------------------------------------------*/
 
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
 /*
  * reverse of qh_urb_transaction:  free a list of TDs.
  * used for cleanup after errors, before HC sees an URB's TDs.
@@ -494,7 +498,7 @@
 		token |= (1 /* "in" */ << 8);
 	/* else it's already initted to "out" pid (0 << 8) */
 
-	maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
+	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
 
 	/*
 	 * buffer gets wrapped in one or more qtds;
@@ -597,11 +601,6 @@
 // That'd mean updating how usbcore talks to HCDs. (2.5?)
 
 
-// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
-#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
-// ... and packet size, for any kind of endpoint descriptor
-#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
-
 /*
  * Each QH holds a qtd list; a QH is used for everything except iso.
  *
@@ -766,7 +765,7 @@
 		}
 	}
 
-	qh->hw_token &= ~__constant_cpu_to_le32 (QTD_STS_HALT);
+	qh->hw_token &= ~HALT_BIT;
 
 	/* splice right after start */
 	qh->qh_next = head->qh_next;
@@ -782,6 +781,8 @@
 
 /*-------------------------------------------------------------------------*/
 
+#define	QH_ADDR_MASK	__constant_le32_to_cpu(0x7f)
+
 /*
  * For control/bulk/interrupt, return QH with these TDs appended.
  * Allocates and initializes the QH if necessary.
@@ -816,12 +817,13 @@
 		/* control qh may need patching after enumeration */
 		if (unlikely (epnum == 0)) {
 			/* set_address changes the address */
-			if (le32_to_cpu (qh->hw_info1 & 0x7f) == 0)
+			if ((qh->hw_info1 & QH_ADDR_MASK) == 0)
 				qh->hw_info1 |= cpu_to_le32 (
 						usb_pipedevice (urb->pipe));
 
 			/* for full speed, ep0 maxpacket can grow */
-			else if (!(qh->hw_info1 & cpu_to_le32 (0x3 << 12))) {
+			else if (!(qh->hw_info1
+					& __constant_cpu_to_le32 (0x3 << 12))) {
 				u32	info, max;
 
 				info = le32_to_cpu (qh->hw_info1);
@@ -835,7 +837,7 @@
 
                         /* usb_reset_device() briefly reverts to address 0 */
                         if (usb_pipedevice (urb->pipe) == 0)
-                                qh->hw_info1 &= cpu_to_le32(~0x7f);
+                                qh->hw_info1 &= ~QH_ADDR_MASK;
 		}
 
 		/* NOTE:  changing config or interface setting is not
@@ -875,7 +877,7 @@
 			 * HC is allowed to fetch the old dummy (4.10.2).
 			 */
 			token = qtd->hw_token;
-			qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
+			qtd->hw_token = HALT_BIT;
 			wmb ();
 			dummy = qh->dummy;
 
diff -urN linux-2.4.22-bk41/drivers/usb/host/ehci.h linux-2.4.22-bk42/drivers/usb/host/ehci.h
--- linux-2.4.22-bk41/drivers/usb/host/ehci.h	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk42/drivers/usb/host/ehci.h	2003-10-26 02:49:55.000000000 -0800
@@ -325,6 +325,7 @@
 	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
 	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
 	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
+	u32			*hw_next;	/* (all types) */
 	void			*ptr;
 };
 
diff -urN linux-2.4.22-bk41/drivers/usb/host/hc_simple.c linux-2.4.22-bk42/drivers/usb/host/hc_simple.c
--- linux-2.4.22-bk41/drivers/usb/host/hc_simple.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/host/hc_simple.c	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,1089 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * simple generic USB HCD frontend Version 0.9.5 (10/28/2001)
+ * for embedded HCs (SL811HS)
+ * 
+ * USB URB handling, hci_ hcs_
+ * URB queueing, qu_
+ * Transfer scheduling, sh_
+ * 
+ *
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *-------------------------------------------------------------------------*/
+
+/* main lock for urb access */
+static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED;
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+/* URB HCD API function layer
+ * * * */
+
+/***************************************************************************
+ * Function Name : hcs_urb_queue
+ *
+ * This function initializes the urb status and length before queueing the 
+ * urb. 
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *
+ * Return: 0 
+ **************************************************************************/
+static inline int hcs_urb_queue (hci_t * hci, struct urb * urb)
+{
+	int i;
+
+	DBGFUNC ("enter hcs_urb_queue\n");
+	if (usb_pipeisoc (urb->pipe)) {
+		DBGVERBOSE ("hcs_urb_queue: isoc pipe\n");
+		for (i = 0; i < urb->number_of_packets; i++) {
+			urb->iso_frame_desc[i].actual_length = 0;
+			urb->iso_frame_desc[i].status = -EXDEV;
+		}
+
+		/* urb->next hack : 1 .. resub, 0 .. single shot */
+		/* urb->interval = urb->next ? 1 : 0; */
+	}
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->error_count = 0;
+
+	if (usb_pipecontrol (urb->pipe))
+		hc_flush_data_cache (hci, urb->setup_packet, 8);
+	if (usb_pipeout (urb->pipe))
+		hc_flush_data_cache (hci, urb->transfer_buffer,
+				     urb->transfer_buffer_length);
+
+	qu_queue_urb (hci, urb);
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hcs_return_urb
+ *
+ * This function the return path of URB back to the USB core. It calls the
+ * the urb complete function if exist, and also handles the resubmition of
+ * interrupt URBs.
+ *
+ * Input:  hci = data structure for the host controller
+ *         urb = USB request block data structure 
+ *         resub_ok = resubmit flag: 1 = submit urb again, 0 = not submit 
+ *
+ * Return: 0 
+ **************************************************************************/
+static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct usb_device *dev = urb->dev;
+	int resubmit = 0;
+
+	DBGFUNC ("enter hcs_return_urb, urb pointer = %p, "
+		 "transferbuffer point = %p, "
+		 " setup packet pointer = %p, context pointer = %p \n",
+		 (__u32 *) urb, (__u32 *) urb->transfer_buffer,
+		 (__u32 *) urb->setup_packet, (__u32 *) urb->context);
+	if (urb_debug)
+		urb_print (urb, "RET", usb_pipeout (urb->pipe));
+
+	resubmit = urb->interval && resub_ok;
+
+	urb->dev = urb->hcpriv = NULL;
+
+	if (urb->complete) {
+		urb->complete (urb);	/* call complete */
+	}
+
+	if (resubmit) {
+		/* requeue the URB */
+		urb->dev = dev;
+		hcs_urb_queue (hci, urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_submit_urb
+ *
+ * This function is called by the USB core API when an URB is available to
+ * process.  This function does the following
+ *
+ * 1) Check the validity of the URB
+ * 2) Parse the device number from the URB
+ * 3) Pass the URB to the root hub routine if its intended for the hub, else
+ *    queue the urb for the attached device. 
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_submit_urb (struct urb * urb)
+{
+	hci_t *hci;
+	unsigned int pipe = urb->pipe;
+	unsigned long flags;
+	int ret;
+
+	DBGFUNC ("enter hci_submit_urb, pipe = 0x%x\n", urb->pipe);
+	if (!urb->dev || !urb->dev->bus || urb->hcpriv)
+		return -EINVAL;
+
+	if (usb_endpoint_halted
+	    (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) {
+		printk ("hci_submit_urb: endpoint_halted\n");
+		return -EPIPE;
+	}
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+
+	if (usb_pipedevice (pipe) == hci->rh.devnum) {
+		if (urb_debug > 1)
+			urb_print (urb, "SUB-RH", usb_pipein (pipe));
+
+		return rh_submit_urb (urb);
+	}
+
+	/* queue the URB to its endpoint-queue */
+
+	spin_lock_irqsave (&usb_urb_lock, flags);
+	ret = hcs_urb_queue (hci, urb);
+	if (ret != 0) {
+		/* error on return */
+		DBGERR
+		    ("hci_submit_urb: return err, ret = 0x%x, urb->status = 0x%x\n",
+		     ret, urb->status);
+	}
+
+	spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+	return ret;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_unlink_urb
+ *
+ * This function mark the URB to unlink
+ *
+ * Input: urb = USB request block data structure 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_unlink_urb (struct urb * urb)
+{
+	unsigned long flags;
+	hci_t *hci;
+	DECLARE_WAITQUEUE (wait, current);
+	void *comp = NULL;
+
+	DBGFUNC ("enter hci_unlink_urb\n");
+
+	if (!urb)		/* just to be sure */
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	hci = (hci_t *) urb->dev->bus->hcpriv;
+
+	/* a request to the virtual root hub */
+	if (usb_pipedevice (urb->pipe) == hci->rh.devnum) {
+		return rh_unlink_urb (urb);
+	}
+
+	if (urb_debug)
+		urb_print (urb, "UNLINK", 1);
+
+	spin_lock_irqsave (&usb_urb_lock, flags);
+
+	if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) {
+		/* URB active? */
+
+		if (urb->
+		    transfer_flags & (USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED)) {
+			/* asynchron with callback */
+
+			list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		} else {
+			/* synchron without callback */
+
+			add_wait_queue (&hci->waitq, &wait);
+
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			comp = urb->complete;
+			urb->complete = NULL;
+
+/* --> crash --> */	list_del (&urb->urb_list);	/* relink the urb to the del list */
+			list_add (&urb->urb_list, &hci->del_list);
+
+			spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+			schedule_timeout (HZ / 50);
+
+			if (!list_empty (&urb->urb_list))
+				list_del (&urb->urb_list);
+
+			urb->complete = comp;
+			urb->hcpriv = NULL;
+			remove_wait_queue (&hci->waitq, &wait);
+		}
+	} else {
+		/* hcd does not own URB but we keep the driver happy anyway */
+		spin_unlock_irqrestore (&usb_urb_lock, flags);
+
+		if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
+			urb->status = -ENOENT;
+			urb->actual_length = 0;
+			urb->complete (urb);
+			urb->status = 0;
+		} else {
+			urb->status = -ENOENT;
+		}
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_alloc_dev
+ *
+ * This function allocates private data space for the usb device and 
+ * initialize the endpoint descriptor heads.
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0 if success or error code 
+ **************************************************************************/
+static int hci_alloc_dev (struct usb_device *usb_dev)
+{
+	struct hci_device *dev;
+	int i;
+
+	DBGFUNC ("enter hci_alloc_dev\n");
+	dev = kmalloc (sizeof (*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset (dev, 0, sizeof (*dev));
+
+	for (i = 0; i < 32; i++) {
+		INIT_LIST_HEAD (&(dev->ed[i].urb_queue));
+		dev->ed[i].pipe_head = NULL;
+	}
+
+	usb_dev->hcpriv = dev;
+
+	DBGVERBOSE ("USB HC dev alloc %d bytes\n", sizeof (*dev));
+
+	return 0;
+
+}
+
+/***************************************************************************
+ * Function Name : hci_free_dev
+ *
+ * This function de-allocates private data space for the usb devic
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int hci_free_dev (struct usb_device *usb_dev)
+{
+	DBGFUNC ("enter hci_free_dev\n");
+
+	if (usb_dev->hcpriv)
+		kfree (usb_dev->hcpriv);
+
+	usb_dev->hcpriv = NULL;
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : hci_get_current_frame_number
+ *
+ * This function get the current USB frame number
+ *
+ * Input: usb_dev = pointer to the usb device 
+ *
+ * Return: frame number  
+ **************************************************************************/
+static int hci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	hci_t *hci = usb_dev->bus->hcpriv;
+	DBGFUNC ("enter hci_get_current_frame_number, frame = 0x%x \r\n",
+		 hci->frame_number);
+
+	return (hci->frame_number);
+}
+
+/***************************************************************************
+ * List of all io-functions 
+ **************************************************************************/
+
+static struct usb_operations hci_device_operations = {
+	allocate:		hci_alloc_dev,
+	deallocate:		hci_free_dev,
+	get_frame_number:	hci_get_current_frame_number,
+	submit_urb:		hci_submit_urb,
+	unlink_urb:		hci_unlink_urb,
+};
+
+/***************************************************************************
+ * URB queueing:
+ * 
+ * For each type of transfer (INTR, BULK, ISO, CTRL) there is a list of 
+ * active URBs.
+ * (hci->intr_list, hci->bulk_list, hci->iso_list, hci->ctrl_list)
+ * For every endpoint the head URB of the queued URBs is linked to one of 
+ * those lists.
+ * 
+ * The rest of the queued URBs of an endpoint are linked into a 
+ * private URB list for each endpoint. (hci_dev->ed [endpoint_io].urb_queue)
+ * hci_dev->ed [endpoint_io].pipe_head .. points to the head URB which is 
+ * in one of the active URB lists.
+ * 
+ * The index of an endpoint consists of its number and its direction.
+ * 
+ * The state of an intr and iso URB is 0. 
+ * For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK
+ * Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet)
+ * 
+ **************************************************************************/
+
+/***************************************************************************
+ * Function Name : qu_urb_timeout
+ *
+ * This function is called when the URB timeout. The function unlinks the 
+ * URB. 
+ *
+ * Input: lurb: URB 
+ *
+ * Return: none  
+ **************************************************************************/
+#ifdef HC_URB_TIMEOUT
+static void qu_urb_timeout (unsigned long lurb)
+{
+	struct urb *urb = (struct urb *) lurb;
+
+	DBGFUNC ("enter qu_urb_timeout\n");
+	urb->transfer_flags |= USB_TIMEOUT_KILLED;
+	hci_unlink_urb (urb);
+}
+#endif
+
+/***************************************************************************
+ * Function Name : qu_pipeindex
+ *
+ * This function gets the index of the pipe.   
+ *
+ * Input: pipe: the urb pipe 
+ *
+ * Return: index  
+ **************************************************************************/
+static inline int qu_pipeindex (__u32 pipe)
+{
+	DBGFUNC ("enter qu_pipeindex\n");
+	return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ? 0 : usb_pipeout (pipe));
+}
+
+/***************************************************************************
+ * Function Name : qu_seturbstate
+ *
+ * This function set the state of the URB.  
+ * 
+ * control pipe: 3 states -- Setup, data, status
+ * interrupt and bulk pipe: 1 state -- data    
+ *
+ * Input: urb = USB request block data structure 
+ *        state = the urb state
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_seturbstate (struct urb * urb, int state)
+{
+	DBGFUNC ("enter qu_seturbstate\n");
+	urb->pipe &= ~0x1f;
+	urb->pipe |= state & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_urbstate
+ *
+ * This function get the current state of the URB.  
+ * 
+ * Input: urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static inline int qu_urbstate (struct urb * urb)
+{
+
+	DBGFUNC ("enter qu_urbstate\n");
+
+	return urb->pipe & 0x1f;
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_active_urb
+ *
+ * This function adds the urb to the appropriate active urb list and set
+ * the urb state.
+ * 
+ * There are four active lists: isochoronous list, interrupt list, 
+ * control list, and bulk list.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        ed = endpoint descriptor
+ *
+ * Return: none  
+ **************************************************************************/
+static inline void qu_queue_active_urb (hci_t * hci, struct urb * urb, epd_t * ed)
+{
+	int urb_state = 0;
+	DBGFUNC ("enter qu_queue_active_urb\n");
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+		list_add (&urb->urb_list, &hci->ctrl_list);
+		urb_state = US_CTRL_SETUP;
+		break;
+
+	case PIPE_BULK:
+		list_add (&urb->urb_list, &hci->bulk_list);
+		if ((urb->transfer_flags & USB_ZERO_PACKET)
+		    && urb->transfer_buffer_length > 0
+		    &&
+		    ((urb->transfer_buffer_length %
+		      usb_maxpacket (urb->dev, urb->pipe,
+				     usb_pipeout (urb->pipe))) == 0)) {
+			urb_state = US_BULK0;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		urb->start_frame = hci->frame_number;
+		list_add (&urb->urb_list, &hci->intr_list);
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		list_add (&urb->urb_list, &hci->iso_list);
+		break;
+	}
+
+#ifdef HC_URB_TIMEOUT
+	if (urb->timeout) {
+		ed->timeout.data = (unsigned long) urb;
+		ed->timeout.expires = urb->timeout + jiffies;
+		ed->timeout.function = qu_urb_timeout;
+		add_timer (&ed->timeout);
+	}
+#endif
+
+	qu_seturbstate (urb, urb_state);
+}
+
+/***************************************************************************
+ * Function Name : qu_queue_urb
+ *
+ * This function adds the urb to the endpoint descriptor list 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: none  
+ **************************************************************************/
+static int qu_queue_urb (hci_t * hci, struct urb * urb)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("Enter qu_queue_urb\n");
+
+	/* for ISOC transfers calculate start frame index */
+
+	if (usb_pipeisoc (urb->pipe) && urb->transfer_flags & USB_ISO_ASAP) {
+		urb->start_frame = ((ed->pipe_head) ? (ed->last_iso + 1) : hci_get_current_frame_number (urb-> dev) + 1) & 0xffff;
+	}
+
+	if (ed->pipe_head) {
+		__list_add (&urb->urb_list, ed->urb_queue.prev,
+			    &(ed->urb_queue));
+	} else {
+		ed->pipe_head = urb;
+		qu_queue_active_urb (hci, urb, ed);
+		if (++hci->active_urbs == 1)
+			hc_start_int (hci);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : qu_next_urb
+ *
+ * This function removes the URB from the queue and add the next URB to 
+ * active list. 
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_next_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct hci_device *hci_dev = usb_to_hci (urb->dev);
+	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];
+
+	DBGFUNC ("enter qu_next_urb\n");
+	list_del (&urb->urb_list);
+	INIT_LIST_HEAD (&urb->urb_list);
+	if (ed->pipe_head == urb) {
+
+#ifdef HC_URB_TIMEOUT
+		if (urb->timeout)
+			del_timer (&ed->timeout);
+#endif
+
+		if (!--hci->active_urbs)
+			hc_stop_int (hci);
+
+		if (!list_empty (&ed->urb_queue)) {
+			urb = list_entry (ed->urb_queue.next, struct urb, urb_list);
+			list_del (&urb->urb_list);
+			INIT_LIST_HEAD (&urb->urb_list);
+			ed->pipe_head = urb;
+			qu_queue_active_urb (hci, urb, ed);
+		} else {
+			ed->pipe_head = NULL;
+			urb = NULL;
+		}
+	}
+	return urb;
+}
+
+/***************************************************************************
+ * Function Name : qu_return_urb
+ *
+ * This function is part of the return path.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *        resub_ok = resubmit flag
+ *
+ * Return: pointer to the next urb  
+ **************************************************************************/
+static struct urb *qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok)
+{
+	struct urb *next_urb;
+
+	DBGFUNC ("enter qu_return_rub\n");
+	next_urb = qu_next_urb (hci, urb, resub_ok);
+	hcs_return_urb (hci, urb, resub_ok);
+	return next_urb;
+}
+
+#if 0 /* unused now (hne) */
+/***************************************************************************
+ * Function Name : sh_scan_iso_urb_list
+ *
+ * This function goes throught the isochronous urb list and schedule the 
+ * the transfer.   
+ *
+ * Note: This function has not tested yet
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *        frame_number = the frame number 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_iso_urb_list (hci_t * hci, struct list_head *list_lh,
+				 int frame_number)
+{
+	struct list_head *lh = list_lh->next;
+	struct urb *urb;
+
+	DBGFUNC ("enter sh_scan_iso_urb_list\n");
+	hci->td_array->len = 0;
+
+	while (lh != list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		lh = lh->next;
+		if (((frame_number - urb->start_frame) & 0x7ff) <
+		    urb->number_of_packets) {
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				if (((frame_number -
+				      urb->start_frame) & 0x7ff) > 0x400) {
+					if (qu_urbstate (urb) > 0)
+						urb = qu_return_urb (hci, urb, 1);
+					else
+						urb = qu_next_urb (hci, urb, 1);
+
+					if (lh == list_lh && urb)
+						lh = &urb->urb_list;
+				}
+			}
+		}
+	}
+	return 1;
+}
+#endif // if0
+
+/***************************************************************************
+ * Function Name : sh_scan_urb_list
+ *
+ * This function goes through the urb list and schedule the 
+ * the transaction.   
+ * 
+ * Input: hci = data structure for the host controller 
+ *        list_lh = pointer to the isochronous list 
+ *
+ * Return: 0 = unsuccessful; 1 = successful  
+ **************************************************************************/
+static int sh_scan_urb_list (hci_t * hci, struct list_head *list_lh)
+{
+	struct list_head *lh = NULL;
+	struct urb *urb;
+
+	if (list_lh == NULL) {
+		DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n");
+	}
+
+	DBGFUNC ("enter sh_scan_urb_list: frame# \n");
+
+	list_for_each (lh, list_lh) {
+		urb = list_entry (lh, struct urb, urb_list);
+		if (urb == NULL)
+			return 1;
+		if (!usb_pipeint (urb->pipe)
+		    || (((hci->frame_number - urb->start_frame)
+			 & 0x7ff) >= urb->interval)) {
+			DBGVERBOSE ("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n",
+				    urb->start_frame, hci->frame_number, urb->interval,
+				    usb_pipeint (urb->pipe));
+			if (!sh_add_packet (hci, urb)) {
+				return 0;
+			} else {
+				DBGVERBOSE ("INT: start: %d fr_no: %d int: %d pint: %d\n",
+					    urb->start_frame, hci->frame_number,
+					    urb->interval, usb_pipeint (urb->pipe));
+				urb->start_frame = hci->frame_number;
+				return 0;
+
+			}
+		}
+	}
+	return 1;
+}
+
+/***************************************************************************
+ * Function Name : sh_shedule_trans
+ *
+ * This function schedule the USB transaction.
+ * This function will process the endpoint in the following order: 
+ * interrupt, control, and bulk.    
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isSOF = flag indicate if Start Of Frame has occurred 
+ *
+ * Return: 0   
+ **************************************************************************/
+static int sh_schedule_trans (hci_t * hci, int isSOF)
+{
+	int units_left = 1;
+	struct list_head *lh;
+
+	if (hci == NULL) {
+		DBGERR ("sh_schedule_trans: hci == NULL\n");
+		return 0;
+	}
+	if (hci->td_array == NULL) {
+		DBGERR ("sh_schedule_trans: hci->td_array == NULL\n");
+		return 0;
+	}
+
+	if (hci->td_array->len != 0) {
+		DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n",
+			hci->td_array->len);
+	}
+
+	/* schedule the next available interrupt transfer or the next
+	 * stage of the interrupt transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) {
+		units_left = sh_scan_urb_list (hci, &hci->intr_list);
+	}
+
+	/* schedule the next available control transfer or the next
+	 * stage of the control transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) {
+		units_left = sh_scan_urb_list (hci, &hci->ctrl_list);
+	}
+
+	/* schedule the next available bulk transfer or the next
+	 * stage of the bulk transfer */
+
+	if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) {
+		sh_scan_urb_list (hci, &hci->bulk_list);
+
+		/* be fair to each BULK URB (move list head around) 
+		 * only when the new SOF happens */
+
+		lh = hci->bulk_list.next;
+		list_del (&hci->bulk_list);
+		list_add (&hci->bulk_list, lh);
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : sh_add_packet
+ *
+ * This function forms the packet and transmit the packet. This function
+ * will handle all endpoint type: isochoronus, interrupt, control, and 
+ * bulk.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        urb = USB request block data structure 
+ *
+ * Return: 0 = unsucessful; 1 = successful   
+ **************************************************************************/
+static int sh_add_packet (hci_t * hci, struct urb * urb)
+{
+	__u8 *data = NULL;
+	int len = 0;
+	int toggle = 0;
+	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	int endpoint = usb_pipeendpoint (urb->pipe);
+	int address = usb_pipedevice (urb->pipe);
+	int slow = (((urb->pipe) >> 26) & 1);
+	int out = usb_pipeout (urb->pipe);
+	int pid = 0;
+	int ret;
+	int i = 0;
+	int iso = 0;
+
+	DBGFUNC ("enter sh_add_packet\n");
+	if (maxps == 0)
+		maxps = 8;
+
+	/* calculate len, toggle bit and add the transaction */
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_ISOCHRONOUS:
+		pid = out ? PID_OUT : PID_IN;
+		iso = 1;
+		i = hci->frame_number - urb->start_frame;
+		data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		len = urb->iso_frame_desc[i].length;
+		break;
+
+	case PIPE_BULK:	/* BULK and BULK0 */
+	case PIPE_INTERRUPT:
+		pid = out ? PID_OUT : PID_IN;
+		len = urb->transfer_buffer_length - urb->actual_length;
+		data = urb->transfer_buffer + urb->actual_length;
+		toggle = usb_gettoggle (urb->dev, endpoint, out);
+		break;
+
+	case PIPE_CONTROL:
+		switch (qu_urbstate (urb)) {
+		case US_CTRL_SETUP:
+			len = 8;
+			pid = PID_SETUP;
+			data = urb->setup_packet;
+			toggle = 0;
+			break;
+
+		case US_CTRL_DATA:
+			if (!hci->last_packet_nak) {
+				/* The last packet received is not a nak:
+				 * reset the nak count
+				 */
+
+				hci->nakCnt = 0;
+			}
+			if (urb->transfer_buffer_length != 0) {
+				pid = out ? PID_OUT : PID_IN;
+				len = urb->transfer_buffer_length - urb->actual_length;
+				data = urb->transfer_buffer + urb->actual_length;
+				toggle = (urb->actual_length & maxps) ? 0 : 1;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+				break;
+			} else {
+				/* correct state and fall through */
+				qu_seturbstate (urb, US_CTRL_ACK);
+			}
+
+		case US_CTRL_ACK:
+			len = 0;
+
+			/* reply in opposite direction */
+			pid = !out ? PID_OUT : PID_IN;
+			toggle = 1;
+			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+				       usb_pipeout (urb->pipe), toggle);
+			break;
+		}
+	}
+
+	ret =
+	    hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint,
+			  address, pid, iso, qu_urbstate (urb));
+
+	DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x "
+		    "max:%d\n len:%d ret:%d data:%p left:%d\n",
+		    address, endpoint, pid, toggle, iso, slow,
+		    maxps, len, ret, data, hci->hp.units_left);
+
+	if (ret >= 0) {
+		hci->td_array->td[hci->td_array->len].urb = urb;
+		hci->td_array->td[hci->td_array->len].len = ret;
+		hci->td_array->td[hci->td_array->len].iso_index = i;
+		hci->td_array->len++;
+		hci->active_trans = 1;
+		return 1;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : cc_to_error
+ *
+ * This function maps the SL811HS hardware error code to the linux USB error
+ * code.
+ * 
+ * Input: cc = hardware error code 
+ *
+ * Return: USB error code   
+ **************************************************************************/
+static int cc_to_error (int cc)
+{
+	int errCode = 0;
+	if (cc & SL11H_STATMASK_ERROR) {
+		errCode |= -EILSEQ;
+	} else if (cc & SL11H_STATMASK_OVF) {
+		errCode |= -EOVERFLOW;
+	} else if (cc & SL11H_STATMASK_STALL) {
+		errCode |= -EPIPE;
+	}
+	return errCode;
+}
+
+/***************************************************************************
+ * Function Name : sh_done_list
+ *
+ * This function process the packet when it has done finish transfer.
+ * 
+ * 1) It handles hardware error
+ * 2) It updates the URB state
+ * 3) If the USB transaction is complete, it start the return stack path.
+ * 
+ * Input: hci = data structure for the host controller 
+ *        isExcessNak = flag tells if there excess NAK condition occurred 
+ *
+ * Return:  urb_state or -1 if the transaction has complete   
+ **************************************************************************/
+static int sh_done_list (hci_t * hci, int *isExcessNak)
+{
+	int actbytes = 0;
+	int active = 0;
+	void *data = NULL;
+	int cc;
+	int maxps;
+	int toggle;
+	struct urb *urb;
+	int urb_state = 0;
+	int ret = 1;		/* -1 parse abbort, 1 parse ok, 0 last element */
+	int trans = 0;
+	int len;
+	int iso_index = 0;
+	int out;
+	int pid = 0;
+	int debugLen = 0;
+
+	*isExcessNak = 0;
+
+	DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n",
+		 hci->td_array->len);
+
+	debugLen = hci->td_array->len;
+	if (debugLen > 1)
+		DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n",
+			hci->td_array->len);
+
+	for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS;
+	     trans++) {
+		urb = hci->td_array->td[trans].urb;
+		/* FIXME: */
+		/* +++ I'm sorry, can't handle NULL-Pointers 21.11.2002 (hne) */
+		if (!urb) {
+			DBGERR ("sh_done_list: urb = NULL\n");
+			continue;
+		}
+		if (!urb->dev || !urb->pipe) {
+			if (!urb->dev) DBGERR ("sh_done_list: urb->dev = NULL\n");
+			if (!urb->pipe) DBGERR ("sh_done_list: urb->pipe = NULL\n");
+			continue;
+		}
+		/* --- 21.11.2002 (hne) */
+		
+		len = hci->td_array->td[trans].len;
+		out = usb_pipeout (urb->pipe);
+
+		if (usb_pipeisoc (urb->pipe)) {
+			iso_index = hci->td_array->td[trans].iso_index;
+			data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset;
+			toggle = 0;
+		} else {
+			data = urb->transfer_buffer + urb->actual_length;
+			/* +++ Crash (hne)  urb->dev == NULL !!! */
+			toggle = usb_gettoggle (urb->dev,
+						usb_pipeendpoint (urb->pipe),
+						usb_pipeout (urb->pipe));
+			/* --- Crash (hne)  urb->dev == NULL !!! */
+
+		}
+		urb_state = qu_urbstate (urb);
+		pid = out ? PID_OUT : PID_IN;
+		ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len,
+				      pid, urb_state);
+		maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+
+		if (maxps == 0)
+			maxps = 8;
+
+		active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1)));
+
+		/* If the transfer is not bulk in, then it is necessary to get all
+		 * data specify by the urb->transfer_len.
+		 */
+
+		if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe)))
+			active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes);
+
+		if (urb->transfer_buffer_length == urb->actual_length + actbytes)
+			active = 0;
+
+		if ((cc &
+		     (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT |
+		      SL11H_STATMASK_OVF | SL11H_STATMASK_STALL))
+		    && !(cc & SL11H_STATMASK_NAK)) {
+			if (++urb->error_count > 3) {
+				DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n",
+					urb->error_count, cc);
+				urb_state = 0;
+				active = 0;
+			} else {
+				DBGERR ("done_list: packet err, cc=0x%x, "
+					" urb->length=0x%x, actual_len=0x%x,"
+					" urb_state=0x%x\n",
+					cc, urb->transfer_buffer_length,
+					urb->actual_length, urb_state);
+//			if (cc & SL11H_STATMASK_STALL) {
+				/* The USB function is STALLED on a control pipe (0), 
+				 * then it needs to send the SETUP command again to 
+				 * clear the STALL condition
+				 */
+
+//				if (usb_pipeendpoint (urb->pipe) == 0) {
+//					urb_state = 2;  
+//					active = 0;
+//				}
+//			} else   
+				active = 1;
+			}
+		} else {
+			if (cc & SL11H_STATMASK_NAK) {
+				if (hci->nakCnt < 0x10000) {
+					hci->nakCnt++;
+					hci->last_packet_nak = 1;
+					active = 1;
+					*isExcessNak = 0;
+				} else {
+					DBGERR ("done_list: nak count exceed limit\n");
+					active = 0;
+					*isExcessNak = 1;
+					hci->nakCnt = 0;
+				}
+			} else {
+				hci->nakCnt = 0;
+				hci->last_packet_nak = 0;
+			}
+
+			if (urb_state != US_CTRL_SETUP) {
+				/* no error */
+				urb->actual_length += actbytes;
+				usb_settoggle (urb->dev,
+					       usb_pipeendpoint (urb->pipe),
+					       usb_pipeout (urb->pipe), toggle);
+			}
+			if (usb_pipeisoc (urb->pipe)) {
+				urb->iso_frame_desc[iso_index].actual_length = actbytes;
+				urb->iso_frame_desc[iso_index].status = cc_to_error (cc);
+				active = (iso_index < urb->number_of_packets);
+			}
+		}
+		if (!active) {
+			if (!urb_state) {
+				urb->status = cc_to_error (cc);
+				if (urb->status) {
+					DBGERR ("error on received packet: urb->status = 0x%x\n",
+						urb->status);
+				}
+				hci->td_array->len = 0;
+				qu_return_urb (hci, urb, 1);
+				return -1;
+			} else {
+				/* We do not want to decrement the urb_state if exceeded nak,
+				 * because we need to finish the data stage of the control 
+				 * packet 
+				 */
+
+				if (!(*isExcessNak))
+					urb_state--;
+				qu_seturbstate (urb, urb_state);
+			}
+		}
+	}
+
+	if (urb_state < 0)
+		DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n",
+			urb_state);
+	if (debugLen != hci->td_array->len) {
+		DBGERR ("ERROR: done_list, debugLen!= td_array->len,"
+			"debugLen = 0x%x, hci->td_array->len = 0x%x\n",
+			debugLen, hci->td_array->len);
+	}
+
+	hci->td_array->len = 0;
+
+	return urb_state;
+}
diff -urN linux-2.4.22-bk41/drivers/usb/host/hc_simple.h linux-2.4.22-bk42/drivers/usb/host/hc_simple.h
--- linux-2.4.22-bk41/drivers/usb/host/hc_simple.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/host/hc_simple.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,230 @@
+/*-------------------------------------------------------------------------*/
+/* list of all controllers using this driver 
+ * */
+
+static LIST_HEAD (hci_hcd_list);
+
+/* URB states (urb_state) */
+/* isoc, interrupt single state */
+
+/* bulk transfer main state and 0-length packet */
+#define US_BULK		0
+#define US_BULK0	1
+/* three setup states */
+#define US_CTRL_SETUP	2
+#define US_CTRL_DATA	1
+#define US_CTRL_ACK	0
+
+/*-------------------------------------------------------------------------*/
+/* HC private part of a device descriptor
+ * */
+
+#define NUM_EDS 32
+
+typedef struct epd {
+	struct urb *pipe_head;
+	struct list_head urb_queue;
+//	int urb_state;
+	struct timer_list timeout;
+	int last_iso;		/* timestamp of last queued ISOC transfer */
+
+} epd_t;
+
+struct hci_device {
+	epd_t ed[NUM_EDS];
+};
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root HUB 
+ */
+
+#define usb_to_hci(usb)	((struct hci_device *)(usb)->hcpriv)
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;		/* interrupt URB of root hub */
+	int send;		/* active flag */
+	int interval;		/* intervall of roothub interrupt transfers */
+	struct timer_list rh_int_timer;	/* intervall timer for rh interrupt EP */
+};
+
+#if 1
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h and USB spec) */
+
+/* destination of request */
+#define RH_INTERFACE		0x01
+#define RH_ENDPOINT		0x02
+#define RH_OTHER		0x03
+
+#define RH_CLASS		0x20
+#define RH_VENDOR		0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	0x00
+#define RH_PORT_ENABLE		0x01
+#define RH_PORT_SUSPEND		0x02
+#define RH_PORT_OVER_CURRENT	0x03
+#define RH_PORT_RESET		0x04
+#define RH_PORT_POWER		0x08
+#define RH_PORT_LOW_SPEED	0x09
+
+#define RH_C_PORT_CONNECTION	0x10
+#define RH_C_PORT_ENABLE	0x11
+#define RH_C_PORT_SUSPEND	0x12
+#define RH_C_PORT_OVER_CURRENT	0x13
+#define RH_C_PORT_RESET		0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	0x00
+#define RH_C_HUB_OVER_CURRENT	0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	0x00
+#define RH_ENDPOINT_STALL	0x01
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+/* struct for each HC 
+ */
+
+#define MAX_TRANS	32
+
+typedef struct td {
+	struct urb *urb;
+	__u16 len;
+	__u16 iso_index;
+} td_t;
+
+typedef struct td_array {
+	int len;
+	td_t td[MAX_TRANS];
+} td_array_t;
+
+typedef struct hci {
+	struct virt_root_hub rh;	/* roothub */
+	wait_queue_head_t waitq;	/* deletion of URBs and devices needs a waitqueue */
+	int active;			/* HC is operating */
+
+	struct list_head ctrl_list;	/* set of ctrl endpoints */
+	struct list_head bulk_list;	/* set of bulk endpoints */
+	struct list_head iso_list;	/* set of isoc endpoints */
+	struct list_head intr_list;	/* ordered (tree) set of int endpoints */
+	struct list_head del_list;	/* set of entpoints to be deleted */
+
+	td_array_t *td_array;
+	td_array_t a_td_array;
+	td_array_t i_td_array[2];
+
+	struct list_head hci_hcd_list;	/* list of all hci_hcd */
+	struct usb_bus *bus;		/* our bus */
+
+//	int trans;			/* number of transactions pending */
+	int active_urbs;
+	int active_trans;
+	int frame_number;		/* frame number */
+	hcipriv_t hp;			/* individual part of hc type */
+	int nakCnt;
+	int last_packet_nak;
+
+} hci_t;
+
+/*-------------------------------------------------------------------------*/
+/* condition (error) CC codes and mapping OHCI like
+ */
+
+#define TD_CC_NOERROR		0x00
+#define TD_CC_CRC		0x01
+#define TD_CC_BITSTUFFING	0x02
+#define TD_CC_DATATOGGLEM	0x03
+#define TD_CC_STALL		0x04
+#define TD_DEVNOTRESP		0x05
+#define TD_PIDCHECKFAIL		0x06
+#define TD_UNEXPECTEDPID	0x07
+#define TD_DATAOVERRUN		0x08
+#define TD_DATAUNDERRUN		0x09
+#define TD_BUFFEROVERRUN	0x0C
+#define TD_BUFFERUNDERRUN	0x0D
+#define TD_NOTACCESSED		0x0F
+
+
+/* urb interface functions */
+static int hci_get_current_frame_number (struct usb_device *usb_dev);
+static int hci_unlink_urb (struct urb * urb);
+
+static int qu_queue_urb (hci_t * hci, struct urb * urb);
+
+/* root hub */
+static int rh_init_int_timer (struct urb * urb);
+static int rh_submit_urb (struct urb * urb);
+static int rh_unlink_urb (struct urb * urb);
+
+/* schedule functions */
+static int sh_add_packet (hci_t * hci, struct urb * urb);
+
+/* hc specific functions */
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len);
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state);
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state);
+
+static void hc_start_int (hci_t * hci);
+static void hc_stop_int (hci_t * hci);
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header */
+
+static void urb_print (struct urb * urb, char *str, int small)
+{
+	unsigned int pipe = urb->pipe;
+	int i, len;
+
+	if (!urb->dev || !urb->dev->bus) {
+		dbg ("%s URB: no dev", str);
+		return;
+	}
+
+	printk ("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)\n",
+		str, hci_get_current_frame_number (urb->dev),
+		usb_pipedevice (pipe), usb_pipeendpoint (pipe),
+		usb_pipeout (pipe) ? 'O' : 'I',
+		usb_pipetype (pipe) < 2 ? (usb_pipeint (pipe) ? "INTR" : "ISOC")
+		: (usb_pipecontrol (pipe) ? "CTRL" : "BULK"), urb->transfer_flags,
+		urb->actual_length, urb->transfer_buffer_length, urb->status,
+		urb->status);
+	if (!small) {
+		if (usb_pipecontrol (pipe)) {
+			printk (__FILE__ ": cmd(8):");
+			for (i = 0; i < 8; i++)
+				printk (" %02x", ((__u8 *) urb->setup_packet)[i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (__FILE__ ": data(%d/%d):", urb->actual_length,
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe) ? urb-> transfer_buffer_length : urb->actual_length;
+			for (i = 0; i < 2096 && i < len; i++)
+				printk (" %02x", ((__u8 *) urb->transfer_buffer)[i]);
+			printk ("%s stat:%d\n", i < len ? "..." : "",
+				urb->status);
+		}
+	}
+}
diff -urN linux-2.4.22-bk41/drivers/usb/host/hc_sl811.c linux-2.4.22-bk42/drivers/usb/host/hc_sl811.c
--- linux-2.4.22-bk41/drivers/usb/host/hc_sl811.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/host/hc_sl811.c	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,1484 @@
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS USB HCD for Linux Version 0.1 (10/28/2001) 0.3 (11/23/2003)
+ *
+ * requires (includes) hc_simple.[hc] simple generic HCD frontend
+ *
+ * COPYRIGHT(C) 2001 by CYPRESS SEMICONDUCTOR INC.
+ *
+ * ! This driver have end of live! Please use hcd/sl811.c instand !
+ *
+ * 05.06.2003 HNE
+ * Support x86 architecture now.
+ * Set "bus->bus_name" at init.
+ * hc_reset,regTest: Don't load driver, if pattern-Test failed (better error returns)
+ *
+ * 06.06.2003 HNE
+ * Moved regTest from hc_reset to hc_found_hci. So we check registers
+ * only at start, and not at unload. Only all Register show, if full Debug.
+ *
+ * 22.09.2003 HNE
+ * Do not write SL11H_INTSTATREG in loop, use delay instand.
+ * If device disconnected, wait only for next insert interrupt (no Idle-Interrpts).
+ *
+ * 29.09.2003 HNE
+ * Moving hc_sl811-arm.h and hc_sl811-x86.h to include/asm-.../hc_sl811-hw.h
+ *
+ * 03.10.2003 HNE
+ * Low level only for port io into hardware-include.
+ * GPRD as parameter (ARM only).
+
+ * ToDo:
+ * Separate IO-Base for second controller (see sl811.c)
+ * Only as module tested! Compiled in Version not tested!
+ *
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *-------------------------------------------------------------------------*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/usb.h>
+
+#define MODNAME "HC_SL811"
+
+#undef HC_URB_TIMEOUT
+#undef HC_SWITCH_INT
+#undef HC_ENABLE_ISOC
+
+// #define SL811_DEBUG
+#define SL811_DEBUG_ERR
+// #define SL811_DEBUG_IRQ
+// #define SL811_DEBUG_VERBOSE
+
+#ifdef SL811_DEBUG_ERR
+#define DBGERR(fmt, args...) printk(fmt,## args)
+#else
+#define DBGERR(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG
+#define DBG(fmt, args...) printk(fmt,## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_FUNC
+#define DBGFUNC(fmt, args...) printk(fmt,## args)
+#else
+#define DBGFUNC(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_DATA
+#define DBGDATAR(fmt, args...) printk(fmt,## args)
+#define DBGDATAW(fmt, args...) printk(fmt,## args)
+#else
+#define DBGDATAR(fmt, args...)
+#define DBGDATAW(fmt, args...)
+#endif
+
+#ifdef SL811_DEBUG_VERBOSE
+#define DBGVERBOSE(fmt, args...) printk(fmt,## args)
+#else
+#define DBGVERBOSE(fmt, args...)
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#define HC_SWITCH_INT
+#include "hc_sl811.h"
+#include "hc_simple.h"
+
+static int urb_debug = 0;
+
+#include "hc_simple.c"
+#include "hc_sl811_rh.c"
+
+/* Include hardware and board depens */
+#include <asm/hc_sl811-hw.h>
+
+/* forware declaration */
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state);
+
+static int sofWaitCnt = 0;
+
+MODULE_PARM (urb_debug, "i");
+MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)");
+
+static int hc_reset (hci_t * hci);
+
+/***************************************************************************
+ * Function Name : SL811Read
+ *
+ * Read a byte of data from the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *
+ * Return: data
+ **************************************************************************/
+
+static __u8 inline SL811Read (hci_t *hci, __u8 offset)
+{
+	hcipriv_t *hp = &hci->hp;
+#ifdef SL811_DEBUG_ERR
+	if (!hp->hcport)
+		DBGERR ("SL811Read: Error port not set!\n");
+#endif
+	sl811_write_index (hp, offset);
+	return (sl811_read_data (hp));
+}
+
+/***************************************************************************
+ * Function Name : SL811Write
+ *
+ * Write a byte of data to the SL811H/SL11H
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = address of SL811/SL11H register or memory
+ *         data  = the data going to write to SL811H
+ *
+ * Return: none
+ **************************************************************************/
+
+static void inline SL811Write (hci_t *hci, __u8 offset, __u8 data)
+{
+	hcipriv_t *hp = &hci->hp;
+#ifdef SL811_DEBUG_ERR
+	if (!hp->hcport)
+		DBGERR ("SL811Write: Error port not set!\n");
+#endif
+	sl811_write_index_data (hp, offset, data);
+}
+
+
+/***************************************************************************
+ * Function Name : SL811BufRead
+ *
+ * Read consecutive bytes of data from the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the buffer where the data will store
+ *         size = number of bytes to read
+ *
+ * Return: none
+ **************************************************************************/
+
+static void SL811BufRead (hci_t *hci, __u8 offset, __u8 *buf, __u8 size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if( size <= 0)
+		return;
+#ifdef SL811_DEBUG_ERR
+	if (!hp->hcport)
+		DBGERR ("SL811BufRead: Error port not set!\n");
+#endif
+	sl811_write_index (hp, offset);
+	DBGDATAR ("SL811BufRead: io=%X offset = %02x, data = ", hp->hcport, offset);
+	while (size--) {
+		*buf++ = sl811_read_data(hp);
+		DBGDATAR ("%02x ", *(buf-1));
+	}
+	DBGDATAR ("\n");
+}
+
+/***************************************************************************
+ * Function Name : SL811BufWrite
+ *
+ * Write consecutive bytes of data to the SL811H/SL11H buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         offset = SL811/SL11H register offset
+ *         buf = the data buffer 
+ *         size = number of bytes to write
+ *
+ * Return: none 
+ **************************************************************************/
+
+static void SL811BufWrite(hci_t *hci, __u8 offset, __u8 *buf, __u8 size)
+{
+	hcipriv_t *hp = &hci->hp;
+	if(size<=0)
+		return;
+#ifdef SL811_DEBUG_ERR
+	if (!hp->hcport)
+		DBGERR ("SL811BufWrite: Error port not set!\n");
+#endif
+	sl811_write_index (hp, offset);
+	DBGDATAW ("SL811BufWrite: io=%X offset = %02x, data = ", hp->hcport, offset);
+	while (size--) {
+		DBGDATAW ("%02x ", *buf);
+		sl811_write_data (hp, *buf);
+		buf++;
+	}
+	DBGDATAW ("\n");
+}
+
+/***************************************************************************
+ * Function Name : regTest
+ *
+ * This routine test the Read/Write functionality of SL811HS registers
+ *
+ * 1) Store original register value into a buffer
+ * 2) Write to registers with a RAMP pattern. (10, 11, 12, ..., 255)
+ * 3) Read from register
+ * 4) Compare the written value with the read value and make sure they are 
+ *    equivalent
+ * 5) Restore the original register value 
+ *
+ * Input:  hci = data structure for the host controller
+ *   
+ *
+ * Return: TRUE = passed; FALSE = failed 
+ **************************************************************************/
+int regTest (hci_t * hci)
+{
+	int i, result = TRUE;
+	__u8 buf[256], data;
+
+	DBGFUNC ("Enter regTest\n");
+	for (i = 0x10; i < 256; i++) {
+		/* save the original buffer */
+		buf[i] = SL811Read (hci, i);
+
+		/* Write the new data to the buffer */
+		SL811Write (hci, i, i);
+	}
+
+	/* compare the written data */
+	for (i = 0x10; i < 256; i++) {
+		data = SL811Read (hci, i);
+		if (data != i) {
+			DBGERR ("Pattern test failed!! value = 0x%x, s/b 0x%x\n",
+				data, i);
+			result = FALSE;
+
+			/* If no Debug, show only first failed Address */
+			if (!urb_debug)
+			    break;
+		}
+	}
+
+	/* restore the data */
+	for (i = 0x10; i < 256; i++) {
+		SL811Write (hci, i, buf[i]);
+	}
+
+	return (result);
+}
+
+#if 0 /* unused (hne) */
+/***************************************************************************
+ * Function Name : regShow
+ *
+ * Display all SL811HS register values
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return: none 
+ **************************************************************************/
+static void regShow (hci_t * hci)
+{
+	int i;
+	for (i = 0; i < 256; i++) {
+		printk ("offset %d: 0x%x\n", i, SL811Read (hci, i));
+	}
+}
+#endif // if0
+
+/************************************************************************
+ * Function Name : USBReset
+ *  
+ * This function resets SL811HS controller and detects the speed of
+ * the connecting device				  
+ *
+ * Input:  hci = data structure for the host controller
+ *                
+ * Return: 0 = no device attached; 1 = USB device attached
+ *                
+ ***********************************************************************/
+/* [2.4.22] sl811_hc_reset */
+static int USBReset (hci_t * hci)
+{
+	int status;
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("enter USBReset\n");
+
+	SL811Write (hci, SL11H_CTLREG2, 0xae);
+
+	// setup master and full speed
+
+	SL811Write (hci, SL11H_CTLREG1, 0x08);	// reset USB
+	mdelay (20);		// 20ms                             
+	SL811Write (hci, SL11H_CTLREG1, 0);	// remove SE0        
+
+	/* disable all interrupts (18.09.2003) */
+	SL811Write (hci, SL11H_INTENBLREG, 0);
+
+	/* 19.09.2003 [2.4.22] */
+	mdelay(2);
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);	// clear all interrupt bits
+	status = SL811Read (hci, SL11H_INTSTATREG);
+
+	if (status & SL11H_INTMASK_USBRESET)	// Check if device is removed (0x40)
+	{
+		DBG ("USBReset: Device removed %03X\n", hci->hp.hcport);
+		/* 19.09.2003 [2.4.22] only IRQ for insert...
+		SL811Write (hci, SL11H_INTENBLREG,
+			    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+			    SL11H_INTMASK_INSRMV);
+		*/
+		SL811Write (hci, SL11H_INTENBLREG,
+			    SL11H_INTMASK_INSRMV);
+		hp->RHportStatus->portStatus &=
+		    ~(PORT_CONNECT_STAT | PORT_ENABLE_STAT);
+
+		return 0;
+	}
+
+	// Send SOF to address 0, endpoint 0.
+	SL811Write (hci, SL11H_BUFLNTHREG_B, 0);	//zero lenth
+	SL811Write (hci, SL11H_PIDEPREG_B, 0x50);	//send SOF to EP0       
+	SL811Write (hci, SL11H_DEVADDRREG_B, 0x01);	//address0
+	SL811Write (hci, SL11H_SOFLOWREG, 0xe0);
+
+	if (!(status & SL11H_INTMASK_DSTATE)) {	/* 0x80 */
+		/* slow speed device connect directly to root-hub */
+
+		DBG ("USBReset: low speed Device attached %03X\n", hci->hp.hcport);
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		// SL811Write (hci, SL11H_SOFTMRREG, 0xee);	/* the same, but better reading (hne) */
+		SL811Write (hci, SL11H_CTLREG2, 0xee);
+		SL811Write (hci, SL11H_CTLREG1, 0x21);
+
+		hp->RHportStatus->portStatus |=
+		    (PORT_CONNECT_STAT | PORT_LOW_SPEED_DEV_ATTACH_STAT);
+
+	} else {
+		/* full speed device connect directly to root hub */
+
+		DBG ("USBReset: full speed Device attached %03X \n", hci->hp.hcport);
+		SL811Write (hci, SL11H_CTLREG1, 0x8);
+		mdelay (20);
+		// SL811Write (hci, SL11H_SOFTMRREG, 0xae);	/* the same, but better reading (hne) */
+		SL811Write (hci, SL11H_CTLREG2, 0xae);
+		SL811Write (hci, SL11H_CTLREG1, 0x01);
+
+		hp->RHportStatus->portStatus |= (PORT_CONNECT_STAT);
+		hp->RHportStatus->portStatus &= ~PORT_LOW_SPEED_DEV_ATTACH_STAT;
+
+	}
+
+	/* start the SOF or EOP */
+	SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01);
+
+	/* clear all interrupt bits */
+	/* 19.09.2003 [2.4.22] */
+	mdelay(2);
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	/* enable all interrupts */
+	SL811Write (hci, SL11H_INTENBLREG,
+		    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+		    SL11H_INTMASK_INSRMV);
+
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+/* tl functions */
+static inline void hc_mark_last_trans (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u8 *ptd = hp->tl;
+
+	dbg ("enter hc_mark_last_trans\n");
+	if (ptd == NULL) {
+		printk ("hc_mark_last_trans: ptd = null\n");
+		return;
+	}
+	if (hp->xferPktLen > 0)
+		*(ptd + hp->tl_last) |= (1 << 3);
+}
+
+static inline void hc_flush_data_cache (hci_t * hci, void *data, int len)
+{
+}
+
+/************************************************************************
+ * Function Name : hc_add_trans
+ *  
+ * This function sets up the SL811HS register and transmit the USB packets.
+ * 
+ * 1) Determine if enough time within the current frame to send the packet
+ * 2) Load the data into the SL811HS register
+ * 3) Set the appropriate command to the register and trigger the transmit
+ *
+ * Input:  hci = data structure for the host controller
+ *         len = data length
+ *         data = transmitting data
+ *         toggle = USB toggle bit, either 0 or 1
+ *         maxps = maximum packet size for this endpoint
+ *         slow = speed of the device
+ *         endpoint = endpoint number
+ *         address = USB address of the device
+ *         pid = packet ID
+ *         format = 
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 = no time left to schedule the transfer
+ *         1 = success 
+ *                
+ ***********************************************************************/
+static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
+				int maxps, int slow, int endpoint, int address,
+				int pid, int format, int urb_state)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u16 speed;
+	int ii, jj, kk;
+
+	DBGFUNC ("enter hc_add_trans: len=0x%x, toggle:0x%x, endpoing:0x%x,"
+		 " addr:0x%x, pid:0x%x,format:0x%x\n", len, toggle, endpoint,
+		 address, pid, format);
+
+	if (len > maxps) {
+		len = maxps;
+	}
+
+	speed = hp->RHportStatus->portStatus;
+	if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) {
+//      ii = (8*7*8 + 6*3) * len + 800; 
+		ii = 8 * 8 * len + 1024;
+	} else {
+		if (slow) {
+//          ii = (8*7*8 + 6*3) * len + 800; 
+			ii = 8 * 8 * len + 2048;
+		} else
+//          ii = (8*7 + 6*3)*len + 110;
+			ii = 8 * len + 256;
+	}
+
+	ii += 2 * 10 * len;
+
+	jj = SL811Read (hci, SL11H_SOFTMRREG);
+
+	/* Read back SOF counter HIGH (bit0-bit5 only) 26.11.2002 (hne) */
+	// kk = (jj & 0xFF) * 64 - ii;
+	kk = (jj & (64-1)) * 64 - ii;
+
+	if (kk < 0) {
+		DBGVERBOSE
+		    ("hc_add_trans: no bandwidth for schedule, ii = 0x%x,"
+		     "jj = 0x%x, len =0x%x, active_trans = 0x%x\n", ii, jj, len,
+		     hci->active_trans);
+		return (-1);
+	}
+
+	if (pid != PID_IN) {
+		/* Load data into hc */
+
+		SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len);
+	}
+
+	/* transmit */
+
+	SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len,
+			  toggle, slow, urb_state);
+
+	return len;
+}
+
+/************************************************************************
+ * Function Name : hc_parse_trans
+ *  
+ * This function checks the status of the transmitted or received packet
+ * and copy the data from the SL811HS register into a buffer.
+ *
+ * 1) Check the status of the packet 
+ * 2) If successful, and IN packet then copy the data from the SL811HS register
+ *    into a buffer
+ *
+ * Input:  hci = data structure for the host controller
+ *         actbytes = pointer to actual number of bytes
+ *         data = data buffer
+ *         cc = packet status
+ *         length = the urb transmit length
+ *         pid = packet ID
+ *         urb_state = the current stage of USB transaction
+ *       
+ * Return: 0 
+ ***********************************************************************/
+static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
+				  int *cc, int *toggle, int length, int pid,
+				  int urb_state)
+{
+	__u8 addr;
+	__u8 len;
+	__u8 pkt_stat;
+
+	DBGFUNC ("enter hc_parse_trans\n");
+
+	/* get packet status; convert ack rcvd to ack-not-rcvd */
+
+	*cc = pkt_stat \
+	    = SL811Read (hci, SL11H_PKTSTATREG);
+
+	if (pkt_stat &
+	    (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF |
+	     SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) {
+		if (*cc & SL11H_STATMASK_OVF)
+			DBGERR ("parse trans: error recv ack, cc = 0x%x/0x%x, TX_BASE_Len = "
+				"0x%x, TX_count=0x%x\n", pkt_stat,
+				SL811Read (hci, SL11H_PKTSTATREG),
+				SL811Read (hci, SL11H_BUFLNTHREG),
+				SL811Read (hci, SL11H_XFERCNTREG));
+		else 
+			DBGVERBOSE ("parse trans: error recv ack, cc = 0x%x/0x%x\n",
+				pkt_stat, SL811Read (hci, SL11H_PKTSTATREG));
+	} else {
+		DBGVERBOSE ("parse trans: recv ack, cc=0x%x, len=0x%x, pid=0x%x, urb=%d\n",
+			    pkt_stat, length, pid, urb_state);
+
+		/* Successful data */
+		if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) {
+
+			/* Find the base address */
+			addr = SL811Read (hci, SL11H_BUFADDRREG);
+
+			/* Find the Transmit Length */
+			len = SL811Read (hci, SL11H_BUFLNTHREG);
+
+			/* The actual data length = xmit length reg - xfer count reg */
+			*actbytes = len - SL811Read (hci, SL11H_XFERCNTREG);
+
+			if ((data != NULL) && (*actbytes > 0)) {
+				SL811BufRead (hci, addr, data, *actbytes);
+
+			} else if ((data == NULL) && (*actbytes <= 0)) {
+				DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n",
+					*actbytes);
+				return 0;
+			}
+		} else if (pid == PID_OUT) {
+			*actbytes = length;
+		} else {
+			// printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid);
+		}
+		*toggle = !*toggle;
+	}
+
+	return 0;
+}
+
+/************************************************************************
+ * Function Name : hc_start_int
+ *  
+ * This function enables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_start_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	int mask =
+	    SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
+	    SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET;
+	SL811Write (hci, IntEna, mask);
+#endif
+}
+
+/************************************************************************
+ * Function Name : hc_stop_int
+ *  
+ * This function disables SL811HS interrupts
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+static void hc_stop_int (hci_t * hci)
+{
+#ifdef HC_SWITCH_INT
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+//  SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV);
+
+#endif
+}
+
+/************************************************************************
+ * Function Name : handleInsRmvIntr
+ *  
+ * This function handles the insertion or removal of device on  SL811HS. 
+ * It resets the controller and updates the port status
+ *
+ * Input:  hci = data structure for the host controller
+ *       
+ * Return: none 
+ ***********************************************************************/
+void handleInsRmvIntr (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	USBReset (hci);
+
+	/* Changes in connection status */
+
+	hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE;
+
+	/* Port Enable or Disable */
+
+	if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) {
+		/* device is connected to the port:
+		 *    1) Enable port 
+		 *    2) Resume ?? 
+		 */
+//               hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+		/* Over Current is not supported by the SL811 HW ?? */
+
+		/* How about the Port Power ?? */
+
+	} else {
+		/* Device has disconnect:
+		 *    1) Disable port
+		 */
+
+		hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT);
+		hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
+
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: SL11StartXaction
+ *  
+ * This functions load the registers with appropriate value and 
+ * transmit the packet.				  
+ *
+ * Input:  hci = data structure for the host controller
+ *         addr = USB address of the device
+ *         epaddr = endpoint number
+ *         pid = packet ID
+ *         len = data length
+ *         toggle = USB toggle bit, either 0 or 1
+ *         slow = speed of the device
+ *         urb_state = the current stage of USB transaction
+ *
+ * Return: 0 = error; 1 = successful
+ *                
+ *****************************************************************/
+int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
+		      int toggle, int slow, int urb_state)
+{
+
+	hcipriv_t *hp = &hci->hp;
+	__u8 cmd = 0;
+	__u8 setup_data[4];
+	__u16 speed;
+
+	speed = hp->RHportStatus->portStatus;
+	if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) {
+		cmd |= SL11H_HCTLMASK_PREAMBLE;
+	}
+	switch (pid) {
+	case PID_SETUP:
+		// cmd &= SL11H_HCTLMASK_PREAMBLE;	/* 26.11.2002 (hne) */
+		cmd |= SL11H_HCTLMASK_ARM
+		     | SL11H_HCTLMASK_ENBLEP
+		     | SL11H_HCTLMASK_WRITE;
+		DBGVERBOSE ("SL811 Xaction: SETUP cmd=%02X\n", cmd);
+		break;
+
+	case PID_OUT:
+		// cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE); /* (hne) 26.11.2002 */
+		cmd |= SL11H_HCTLMASK_ARM
+		     | SL11H_HCTLMASK_ENBLEP
+		     | SL11H_HCTLMASK_WRITE;
+		if (toggle) {
+			cmd |= SL11H_HCTLMASK_SEQ;
+		}
+		DBGVERBOSE ("SL811 Xaction: OUT cmd=%02X\n", cmd);
+		break;
+
+	case PID_IN:
+		// cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);	/* (hne) 26.11.2002 */
+		cmd |= SL11H_HCTLMASK_ARM
+		     | SL11H_HCTLMASK_ENBLEP;
+		DBGVERBOSE ("SL811 Xaction: IN cmd=%02x\n", cmd);
+		break;
+
+	default:
+		DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);
+		return 0;
+	}
+	setup_data[0] = SL11H_DATA_START;			/* 01:SL11H_BUFADDRREG */
+	setup_data[1] = len;					/* 02:SL11H_BUFLNTHREG */
+	setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));	/* 03:SL11H_PIDEPREG */
+	setup_data[3] = addr & 0x7F;				/* 04:SL11H_DEVADDRREG */
+
+	SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4);
+
+	// SL811Write (hci, SL11H_PIDEPREG, cmd);			/* 03: grrr (hne) */
+	SL811Write (hci, SL11H_HOSTCTLREG, cmd);		/* 00: 26.11.2002 (hne) */
+
+#if 0
+	/* The SL811 has a hardware flaw when hub devices sends out
+	 * SE0 between packets. It has been found in a TI chipset and
+	 * cypress hub chipset. It causes the SL811 to hang
+	 * The workaround is to re-issue the preample again.
+	 */
+
+	if ((cmd & SL11H_HCTLMASK_PREAMBLE)) {
+		SL811Write (hci, SL11H_PIDEPREG_B, 0xc0);
+		SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1);	// send the premable
+	}
+#endif
+	return 1;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_interrupt
+ *
+ * Interrupt service routine. 
+ *
+ * 1) determine the causes of interrupt
+ * 2) clears all interrupts
+ * 3) calls appropriate function to service the interrupt
+ *
+ * Input:  irq = interrupt line associated with the controller 
+ *         hci = data structure for the host controller
+ *         r = holds the snapshot of the processor's context before 
+ *             the processor entered interrupt code. (not used here) 
+ *
+ * Return value  : None.
+ *                
+ *****************************************************************/
+static void hc_interrupt (int irq, void *__hci, struct pt_regs *r)
+{
+	__u8 ii;
+	hci_t *hci = __hci;
+	int isExcessNak = 0;
+	int urb_state = 0;
+	// __u8 tmpIrq = 0;
+	int irq_loop = 16;	/* total irq handled at one hardware irq */
+
+#ifdef SL811_DEBUG_IRQ
+	hcipriv_t *hp = &hci->hp;
+	unsigned char sta1, sta2;
+
+	outb (SL11H_INTSTATREG, 0x220);	// Interrupt-Status register, controller1
+	sta1 = (__u8) inb (0x220+1);
+
+	outb (SL11H_INTSTATREG, 0x222);	// Interrupt-Status register, controller2
+	sta2 = (__u8) inb (0x222+1);
+#endif
+
+    do {
+	/* Get value from interrupt status register */
+
+	ii = SL811Read (hci, SL11H_INTSTATREG);
+
+	/* All interrupts handled? (hne) */
+	if ( !(ii & (SL11H_INTMASK_INSRMV /* | SL11H_INTMASK_USBRESET */ |
+		     SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR)) )
+	{
+#ifdef SL811_DEBUG_IRQ
+	// printk ("%Xh IRQ ista=%02X not me\n", hp->hcport, ii);
+
+	    if ( sta1 != 0x80 && sta1 != 0x90 &&
+		 sta2 != 0x80 && sta2 != 0x90 )
+		printk ("%Xh IRQ sta=%02X,%02X\n", hp->hcport, sta1, sta2);
+#endif
+		return;
+	}
+
+	/* Interrupt will be handle now (18.09.2003 2.4.22) */
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	/* SOF-outputs are to slow. No debug any SOF */
+	if ( !(ii & SL11H_INTMASK_SOFINTR) )
+	    DBGVERBOSE ("SL811 ISR: %s%s%s%s io=%03X\n",
+		(ii & SL11H_INTMASK_XFERDONE) ?	" DONE": "",
+		(ii & SL11H_INTMASK_SOFINTR) ?	" SOFINTR": "",
+		(ii & SL11H_INTMASK_INSRMV) ? 	" INSRMV": "",
+		(ii & SL11H_INTMASK_USBRESET) ? " USBRESET": "",
+		hci->hp.hcport );
+
+	// if (ii & (SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET)) {
+	// Found in 2.5.75 (19.09.2003)
+	// "SL11H_INTMASK_USBRESET" is always on, if no device connected!
+	if (ii & SL11H_INTMASK_INSRMV) {
+		/* Device insertion or removal detected for the USB port */
+		/* Disable all interrupts */
+		SL811Write (hci, SL11H_INTENBLREG, 0);
+		/* No SOF, Full speed */
+		SL811Write (hci, SL11H_CTLREG1, 0);
+
+		mdelay (100);	// wait for device stable 
+		handleInsRmvIntr (hci);
+		return;
+	}
+
+	/* Clear all interrupts */
+	// SL811Write (hci, SL11H_INTSTATREG, 0xff);
+
+	if (ii & SL11H_INTMASK_XFERDONE) {
+
+		/* USB Done interrupt occurred */
+		// DBGVERBOSE ("xsta=%02X\n", SL811Read (hci, SL11H_PKTSTATREG));
+
+		urb_state = sh_done_list (hci, &isExcessNak);
+#ifdef WARNING
+		if (hci->td_array->len > 0)
+			printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",
+				hci->td_array->len);
+#endif
+		if (hci->td_array->len == 0 && !isExcessNak
+		    && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {
+			if (urb_state == 0) {
+				/* All urb_state has not been finished yet! 
+				 * continue with the current urb transaction 
+				 */
+
+				if (hci->last_packet_nak == 0) {
+					if (!usb_pipecontrol
+					    (hci->td_array->td[0].urb->pipe))
+						sh_add_packet (hci, hci->td_array-> td[0].urb);
+				}
+			} else {
+				/* The last transaction has completed:
+				 * schedule the next transaction 
+				 */
+
+				sh_schedule_trans (hci, 0);
+			}
+		}
+		/* +++ (hne)
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		--- */
+		return;
+	}
+
+	if (ii & SL11H_INTMASK_SOFINTR) {
+		hci->frame_number = (hci->frame_number + 1) % 2048;
+		if (hci->td_array->len == 0)
+			sh_schedule_trans (hci, 1);
+		else {
+			if (sofWaitCnt++ > 100) {
+				/* The last transaction has not completed.
+				 * Need to retire the current td, and let
+				 * it transmit again later on.
+				 * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER 
+				 *  GET TO THIS POINT)
+				 */
+
+				DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b:0 io=%03X\n",
+					hci->td_array->len,
+					hci->hp.hcport	);
+				urb_print (hci->td_array->td[hci->td_array->len - 1].urb,
+					   "INTERRUPT", 0);
+				/* FIXME: Here sh_done_list was call with urb->dev=NULL 21.11.2002 (hne) */
+				sh_done_list (hci, &isExcessNak);
+				/* +++ (hne)
+				SL811Write (hci, SL11H_INTSTATREG, 0xff);
+				--- */
+				hci->td_array->len = 0;
+				sofWaitCnt = 0;
+			}
+		}
+
+#if 0 /* grrr! This READ clears my XFERDONE interrupt! Its better handle this in a loop. (hne) */
+		tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);
+		if (tmpIrq) {
+			DBG ("IRQ occurred while service SOF: irq = 0x%x\n",
+			     tmpIrq);
+
+			/* If we receive a DONE IRQ after schedule, need to 
+			 * handle DONE IRQ again 
+			 */
+
+			if (tmpIrq & SL11H_INTMASK_XFERDONE) {
+				DBGERR ("XFERDONE occurred while service SOF: irq = 0x%x\n",
+					tmpIrq);
+				urb_state = sh_done_list (hci, &isExcessNak);
+			}
+			SL811Write (hci, SL11H_INTSTATREG, 0xff);
+		}
+#endif
+	} else {
+		DBG ("SL811 ISR: unknown, int=0x%x io=%03X\n", ii, hci->hp.hcport);
+		return;
+	}
+
+	/* +++ (hne)
+	SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	--- */
+
+	/* loop, if any interrupts can read (hne) */
+    } while (--irq_loop);
+    
+	return;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_reset
+ *
+ * This function does register test and resets the SL811HS 
+ * controller.
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_reset (hci_t * hci)
+{
+	int attachFlag = 0;
+
+	DBGFUNC ("Enter hc_reset\n");
+	attachFlag = USBReset (hci);
+	if (attachFlag) {
+		setPortChange (hci, PORT_CONNECT_CHANGE);
+	}
+	return (0);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_trans_buffer
+ *
+ * This function allocates all transfer buffer  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0
+ *                
+ *****************************************************************/
+static int hc_alloc_trans_buffer (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	int maxlen;
+
+	hp->itl0_len = 0;
+	hp->itl1_len = 0;
+	hp->atl_len = 0;
+
+	hp->itl_buffer_len = 1024;
+	hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len;	/* 2048 */
+
+	maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;
+
+	hp->tl = kmalloc (maxlen, GFP_KERNEL);
+
+	if (!hp->tl)
+		return -ENOMEM;
+
+	memset (hp->tl, 0, maxlen);
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: getPortStatusAndChange
+ *
+ * This function gets the ports status from SL811 and format it 
+ * to a USB request format
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : port status and change
+ *                
+ *****************************************************************/
+static __u32 getPortStatusAndChange (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+	__u32 portstatus;
+
+	DBGFUNC ("enter getPorStatusAndChange\n");
+
+	portstatus = hp->RHportStatus->portChange << 16 | hp->RHportStatus->portStatus;
+
+	return (portstatus);
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortChange
+ *
+ * This function set the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	switch (bitPos) {
+	case PORT_CONNECT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_STAT:
+		hp->RHportStatus->portChange |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortChange
+ *
+ * This function clear the bit position of portChange.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortChange (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_CONNECT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_ENABLE_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_RESET_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+
+	case PORT_OVER_CURRENT_CHANGE:
+		hp->RHportStatus->portChange &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: clrPortStatus
+ *
+ * This function clear the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void clrPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus &= ~bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: setPortStatus
+ *
+ * This function set the bit position of portStatus.
+ *
+ * Input:  hci = data structure for the host controller
+ *         bitPos = the bit position
+ *
+ * Return value  : none 
+ *                
+ *****************************************************************/
+static void setPortStatus (hci_t * hci, __u16 bitPos)
+{
+	hcipriv_t *hp = &hci->hp;
+	switch (bitPos) {
+	case PORT_ENABLE_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_RESET_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_POWER_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+
+	case PORT_SUSPEND_STAT:
+		hp->RHportStatus->portStatus |= bitPos;
+		break;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_start
+ *
+ * This function starts the root hub functionality. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static int hc_start (hci_t * hci)
+{
+	DBGFUNC ("Enter hc_start\n");
+
+	rh_connect_rh (hci);
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_alloc_hci
+ *
+ * This function allocates all data structure and store in the 
+ * private data structure. 
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static hci_t *__devinit hc_alloc_hci (void)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+	portstat_t *ps;
+	struct usb_bus *bus;
+
+	DBGFUNC ("Enter hc_alloc_hci\n");
+	hci = (hci_t *) kmalloc (sizeof (hci_t), GFP_KERNEL);
+	if (!hci)
+		return NULL;
+
+	memset (hci, 0, sizeof (hci_t));
+
+	hp = &hci->hp;
+
+	hp->irq = -1;
+	hp->hcport = -1;
+
+	/* setup root hub port status */
+
+	ps = (portstat_t *) kmalloc (sizeof (portstat_t), GFP_KERNEL);
+
+	if (!ps)
+		return NULL;
+	ps->portStatus = PORT_STAT_DEFAULT;
+	ps->portChange = PORT_CHANGE_DEFAULT;
+	hp->RHportStatus = ps;
+
+	hci->nakCnt = 0;
+	hci->last_packet_nak = 0;
+
+	hci->a_td_array.len = 0;
+	hci->i_td_array[0].len = 0;
+	hci->i_td_array[1].len = 0;
+	hci->td_array = &hci->a_td_array;
+	hci->active_urbs = 0;
+	hci->active_trans = 0;
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+	list_add (&hci->hci_hcd_list, &hci_hcd_list);
+	init_waitqueue_head (&hci->waitq);
+
+	INIT_LIST_HEAD (&hci->ctrl_list);
+	INIT_LIST_HEAD (&hci->bulk_list);
+	INIT_LIST_HEAD (&hci->iso_list);
+	INIT_LIST_HEAD (&hci->intr_list);
+	INIT_LIST_HEAD (&hci->del_list);
+
+	bus = usb_alloc_bus (&hci_device_operations);
+	if (!bus) {
+		kfree (hci);
+		return NULL;
+	}
+
+	hci->bus = bus;
+	bus->bus_name = "sl811";
+	bus->hcpriv = (void *) hci;
+
+	return hci;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_release_hci
+ *
+ * This function De-allocate all resources  
+ *
+ * Input:  hci = data structure for the host controller
+ *
+ * Return value  : 0 
+ *                
+ *****************************************************************/
+static void hc_release_hci (hci_t * hci)
+{
+	hcipriv_t *hp = &hci->hp;
+
+	DBGFUNC ("Enter hc_release_hci\n");
+
+	/* disconnect all devices */
+	if (hci->bus->root_hub)
+		usb_disconnect (&hci->bus->root_hub);
+
+	hc_reset (hci);
+
+	if (hp->hcport) {
+		// Disable all Interrupts
+		SL811Write (hci, SL11H_INTENBLREG, 0x00);
+
+		// Remove all Interrups
+		mdelay(2);
+		SL811Write (hci, SL11H_INTSTATREG, 0xff);
+	}
+
+	if (hp->tl)
+		kfree (hp->tl);
+
+	sl811_release_regions(hp);
+
+	if (hp->irq >= 0) {
+		free_irq (hp->irq, hci);
+		hp->irq = -1;
+	}
+
+	usb_deregister_bus (hci->bus);
+	usb_free_bus (hci->bus);
+
+	list_del (&hci->hci_hcd_list);
+	INIT_LIST_HEAD (&hci->hci_hcd_list);
+
+	kfree (hci);
+}
+
+/*****************************************************************
+ *
+ * Function Name: hc_found_hci
+ *
+ * This function request IO memory regions, request IRQ, and
+ * allocate all other resources. 
+ *
+ * Input: addr = first IO address
+ *        addr2 = second IO address
+ *        irq = interrupt number 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __devinit hc_found_hci (int irq, int iobase1, int iobase2)
+{
+	hci_t *hci;
+	hcipriv_t *hp;
+
+	DBGFUNC ("Enter hc_found_hci\n");
+	hci = hc_alloc_hci ();
+	if (!hci) {
+		return -ENOMEM;
+	}
+
+	init_irq ();
+	hp = &hci->hp;
+
+	if (sl811_request_regions (hp, iobase1, iobase2)) {
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+
+	if (!regTest (hci)) {
+	    DBGERR (KERN_ERR "regTest: Controller fault!\n");
+		hc_release_hci (hci);
+	    return -ENXIO;	/* No such device or address */
+	}
+
+	if (hc_alloc_trans_buffer (hci)) {
+		hc_release_hci (hci);
+		return -ENOMEM;
+	}
+
+	usb_register_bus (hci->bus);
+
+	if (request_irq (irq, hc_interrupt, SA_SHIRQ, MODNAME, hci) != 0) {
+		DBGERR ("request interrupt %d failed", irq);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+	hp->irq = irq;
+
+	printk (KERN_INFO __FILE__ ": USB SL811 at %x,%x, IRQ %d\n",
+		hp->hcport, hp->hcport2, irq);
+
+	#ifdef SL811_DEBUG_VERBOSE
+	{
+	    __u8 u = SL811Read (hci, SL11H_HWREVREG);
+	    
+	    DBGVERBOSE ("SL811 HW: %02Xh ", u);
+	    switch (u & 0xF0) {
+	    case 0x00: DBGVERBOSE ("SL11H\n");		break;
+	    case 0x10: DBGVERBOSE ("SL811HS rev1.2\n");	break;
+	    case 0x20: DBGVERBOSE ("SL811HS rev1.5\n");	break;
+	    default:   DBGVERBOSE ("unknown!\n");
+	    }
+	}
+	#endif // SL811_DEBUG_VERBOSE
+
+	if (hc_reset (hci)) {
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+
+	if (hc_start (hci) < 0) {
+		DBGERR ("can't start usb-%x", hp->hcport);
+		hc_release_hci (hci);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_init
+ *
+ * This is an init function, and it is the first function being called
+ *
+ * Input: none 
+ *
+ * Return: 0 = success or error condition 
+ *                
+ *****************************************************************/
+static int __init hci_hcd_init (void)
+{
+	int ret;
+#ifndef __arm__
+	int io_offset = 0;
+#endif // !__arm__
+
+	DBGFUNC ("Enter hci_hcd_init\n");
+	DBGVERBOSE ("SL811 VERBOSE enabled\n");
+
+#ifdef __arm__
+	ret = hc_found_hci (irq, base_addr, data_reg_addr);
+#else // __arm__
+
+	// registering "another instance"
+	for (io_offset = 0; io_offset < MAX_CONTROLERS * 2; io_offset += 2) {
+
+		ret = hc_found_hci (irq, io_base + io_offset, 0);
+		if (ret)
+			return (ret);
+
+	} /* endfor */
+#endif // __arm__
+
+	return ret;
+}
+
+/*****************************************************************
+ *
+ * Function Name: hci_hcd_cleanup
+ *
+ * This is a cleanup function, and it is called when module is 
+ * unloaded. 
+ *
+ * Input: none 
+ *
+ * Return: none 
+ *                
+ *****************************************************************/
+static void __exit hci_hcd_cleanup (void)
+{
+	struct list_head *hci_l;
+	hci_t *hci;
+
+	DBGFUNC ("Enter hci_hcd_cleanup\n");
+	for (hci_l = hci_hcd_list.next; hci_l != &hci_hcd_list;) {
+		hci = list_entry (hci_l, hci_t, hci_hcd_list);
+		hci_l = hci_l->next;
+		hc_release_hci (hci);
+	}
+}
+
+module_init (hci_hcd_init);
+module_exit (hci_hcd_cleanup);
+
+MODULE_AUTHOR ("Pei Liu <pbl@cypress.com>, Henry Nestler <hne@ist1.de>");
+MODULE_DESCRIPTION ("USB SL811HS Host Controller Driver");
diff -urN linux-2.4.22-bk41/drivers/usb/host/hc_sl811.h linux-2.4.22-bk42/drivers/usb/host/hc_sl811.h
--- linux-2.4.22-bk41/drivers/usb/host/hc_sl811.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/host/hc_sl811.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,386 @@
+/*
+ * SL811HS HCD (Host Controller Driver) for USB.
+ * 
+ * COPYRIGHT (C) by CYPRESS SEMICONDUCTOR INC 
+ * 
+ *
+ */
+
+#define GET_FRAME_NUMBER(hci)	READ_REG32 (hci, HcFmNumber)
+
+/*
+ * Maximum number of root hub ports
+ */
+#define MAX_ROOT_PORTS		15	/* maximum OHCI root hub ports */
+
+/* control and status registers */
+#define HcRevision		0x00
+#define HcControl		0x01
+#define HcCommandStatus		0x02
+#define HcInterruptStatus	0x03
+#define HcInterruptEnable	0x04
+#define HcInterruptDisable	0x05
+#define HcFmInterval		0x0D
+#define HcFmRemaining		0x0E
+#define HcFmNumber		0x0F
+#define HcLSThreshold		0x11
+#define HcRhDescriptorA		0x12
+#define HcRhDescriptorB		0x13
+#define HcRhStatus		0x14
+#define HcRhPortStatus		0x15
+
+#define HcHardwareConfiguration 0x20
+#define HcDMAConfiguration	0x21
+#define HcTransferCounter	0x22
+#define HcuPInterrupt		0x24
+#define HcuPInterruptEnable	0x25
+#define HcChipID		0x27
+#define HcScratch		0x28
+#define HcSoftwareReset		0x29
+#define HcITLBufferLength	0x2A
+#define HcATLBufferLength	0x2B
+#define HcBufferStatus		0x2C
+#define HcReadBackITL0Length	0x2D
+#define HcReadBackITL1Length	0x2E
+#define HcITLBufferPort		0x40
+#define HcATLBufferPort		0x41
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_HCFS		(3 << 6)	/* BUS state mask */
+#define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE		(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#define OHCI_USB_RESET		(0 << 6)
+#define OHCI_USB_RESUME		(1 << 6)
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_SO		(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_ATD	(1 << 7)	/* scheduling overrun */
+
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+/*
+ * HcHardwareConfiguration
+ */
+#define InterruptPinEnable	(1 << 0)
+#define InterruptPinTrigger	(1 << 1)
+#define InterruptOutputPolarity	(1 << 2)
+#define DataBusWidth16		(1 << 3)
+#define DREQOutputPolarity	(1 << 5)
+#define DACKInputPolarity	(1 << 6)
+#define EOTInputPolarity	(1 << 7)
+#define DACKMode		(1 << 8)
+#define AnalogOCEnable		(1 << 10)
+#define SuspendClkNotStop	(1 << 11)
+#define DownstreamPort15KRSel	(1 << 12)
+
+/* 
+ * HcDMAConfiguration
+ */
+#define DMAReadWriteSelect 	(1 << 0)
+#define ITL_ATL_DataSelect	(1 << 1)
+#define DMACounterSelect	(1 << 2)
+#define DMAEnable		(1 << 4)
+#define BurstLen_1		0
+#define BurstLen_4		(1 << 5)
+#define BurstLen_8		(2 << 5)
+
+/*
+ * HcuPInterrupt
+ */
+#define SOFITLInt		(1 << 0)
+#define ATLInt			(1 << 1)
+#define AllEOTInterrupt		(1 << 2)
+#define OPR_Reg			(1 << 4)
+#define HCSuspended		(1 << 5)
+#define ClkReady		(1 << 6)
+
+/*
+ * HcBufferStatus
+ */
+#define ITL0BufferFull		(1 << 0)
+#define ITL1BufferFull		(1 << 1)
+#define ATLBufferFull		(1 << 2)
+#define ITL0BufferDone		(1 << 3)
+#define ITL1BufferDone		(1 << 4)
+#define ATLBufferDone		(1 << 5)
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001	/* current connect status */
+#define RH_PS_PES            0x00000002	/* port enable status */
+#define RH_PS_PSS            0x00000004	/* port suspend status */
+#define RH_PS_POCI           0x00000008	/* port over current indicator */
+#define RH_PS_PRS            0x00000010	/* port reset status */
+#define RH_PS_PPS            0x00000100	/* port power status */
+#define RH_PS_LSDA           0x00000200	/* low speed device attached */
+#define RH_PS_CSC            0x00010000	/* connect status change */
+#define RH_PS_PESC           0x00020000	/* port enable status change */
+#define RH_PS_PSSC           0x00040000	/* port suspend status change */
+#define RH_PS_OCIC           0x00080000	/* over current indicator change */
+#define RH_PS_PRSC           0x00100000	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS		0x00000001	/* local power status */
+#define RH_HS_OCI		0x00000002	/* over current indicator */
+#define RH_HS_DRWE		0x00008000	/* device remote wakeup enable */
+#define RH_HS_LPSC		0x00010000	/* local power status change */
+#define RH_HS_OCIC		0x00020000	/* over current indicator change */
+#define RH_HS_CRWE		0x80000000	/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR			0x0000ffff	/* device removable flags */
+#define RH_B_PPCM		0xffff0000	/* port power control mask */
+
+/* roothub.a masks */
+#define	RH_A_NDP		(0xff << 0)	/* number of downstream ports */
+#define	RH_A_PSM		(1 << 8)	/* power switching mode */
+#define	RH_A_NPS		(1 << 9)	/* no power switching */
+#define	RH_A_DT			(1 << 10)	/* device type (mbz) */
+#define	RH_A_OCPM		(1 << 11)	/* over current protection mode */
+#define	RH_A_NOCP		(1 << 12)	/* no over current protection */
+#define	RH_A_POTPGT		(0xff << 24)	/* power on to power good time */
+
+#define URB_DEL 1
+
+#define PORT_STAT_DEFAULT		0x0100
+#define PORT_CONNECT_STAT  		0x1
+#define PORT_ENABLE_STAT		0x2
+#define PORT_SUSPEND_STAT		0x4
+#define PORT_OVER_CURRENT_STAT		0x8
+#define PORT_RESET_STAT			0x10
+#define PORT_POWER_STAT			0x100
+#define PORT_LOW_SPEED_DEV_ATTACH_STAT	0x200
+
+#define PORT_CHANGE_DEFAULT		0x0
+#define PORT_CONNECT_CHANGE		0x1
+#define PORT_ENABLE_CHANGE		0x2
+#define PORT_SUSPEND_CHANGE		0x4
+#define PORT_OVER_CURRENT_CHANGE	0x8
+#define PORT_RESET_CHANGE		0x10
+
+/* Port Status Request info */
+
+typedef struct portstat {
+	__u16 portChange;
+	__u16 portStatus;
+} portstat_t;
+
+typedef struct hcipriv {
+	int irq;
+	int disabled;		/* e.g. got a UE, we're hung */
+	atomic_t resume_count;	/* defending against multiple resumes */
+	struct ohci_regs *regs;	/* OHCI controller's memory */
+	int hcport;		/* I/O base address */
+	int hcport2;		/* I/O data reg addr */
+
+	struct portstat *RHportStatus;	/* root hub port status */
+
+	int intrstatus;
+	__u32 hc_control;	/* copy of the hc control reg */
+
+	int frame;
+
+	__u8 *tl;
+	int xferPktLen;
+	int atl_len;
+	int atl_buffer_len;
+	int itl0_len;
+	int itl1_len;
+	int itl_buffer_len;
+	int itl_index;
+	int tl_last;
+	int units_left;
+
+} hcipriv_t;
+struct hci;
+
+#define cClt        0		// Control
+#define cISO        1		// ISO
+#define cBULK       2		// BULK
+#define cInt        3		// Interrupt
+#define ISO_BIT     0x10
+
+/*-------------------------------------------------------------------------
+ * EP0 use for configuration and Vendor Specific command interface
+ *------------------------------------------------------------------------*/
+#define cMemStart       0x10
+#define EP0Buf          0x40	/* SL11H/SL811H memory start at 0x40 */
+#define EP0Len          0x40	/* Length of config buffer EP0Buf */
+#define EP1Buf          0x60
+#define EP1Len          0x40
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H memory from 80h-ffh use as ping-pong buffer.
+ *------------------------------------------------------------------------*/
+#define uBufA           0x80	/* buffer A address for DATA0 */
+#define uBufB           0xc0	/* buffer B address for DATA1 */
+#define uXferLen        0x40	/* xfer length */
+#define sMemSize        0xc0	/* Total SL11 memory size */
+#define cMemEnd         256
+
+/*-------------------------------------------------------------------------
+ * SL811H Register Control memory map
+ * --Note: 
+ *      --SL11H only has one control register set from 0x00-0x04
+ *      --SL811H has two control register set from 0x00-0x04 and 0x08-0x0c
+ *------------------------------------------------------------------------*/
+
+#define EP0Control      0x00
+#define EP0Address      0x01
+#define EP0XferLen      0x02
+#define EP0Status       0x03
+#define EP0Counter      0x04
+
+#define EP1Control      0x08
+#define EP1Address      0x09
+#define EP1XferLen      0x0a
+#define EP1Status       0x0b
+#define EP1Counter      0x0c
+
+#define CtrlReg         0x05
+#define IntEna          0x06
+			 // 0x07 is reserved
+#define IntStatus       0x0d
+#define cDATASet        0x0e
+#define cSOFcnt         0x0f
+#define IntMask         0x57	/* Reset|DMA|EP0|EP2|EP1 for IntEna */
+#define HostMask        0x47	/* Host request command  for IntStatus */
+#define ReadMask        0xd7	/* Read mask interrupt   for IntStatus */
+
+/*-------------------------------------------------------------------------
+ * Standard Chapter 9 definition
+ *-------------------------------------------------------------------------
+ */
+#define GET_STATUS      0x00
+#define CLEAR_FEATURE   0x01
+#define SET_FEATURE     0x03
+#define SET_ADDRESS     0x05
+#define GET_DESCRIPTOR  0x06
+#define SET_DESCRIPTOR  0x07
+#define GET_CONFIG      0x08
+#define SET_CONFIG      0x09
+#define GET_INTERFACE   0x0a
+#define SET_INTERFACE   0x0b
+#define SYNCH_FRAME     0x0c
+
+#define DEVICE          0x01
+#define CONFIGURATION   0x02
+#define STRING          0x03
+#define INTERFACE       0x04
+#define ENDPOINT        0x05
+
+/*-------------------------------------------------------------------------
+ * SL11H/SL811H definition
+ *-------------------------------------------------------------------------
+ */
+#define DATA0_WR	0x07	// (Arm+Enable+tranmist to Host+DATA0)
+#define DATA1_WR	0x47	// (Arm+Enable+tranmist to Host on DATA1)
+#define ZDATA0_WR	0x05	// (Arm+Transaction Ignored+tranmist to Host+DATA0)
+#define ZDATA1_WR	0x45	// (Arm+Transaction Ignored+tranmist to Host+DATA1)
+#define DATA0_RD	0x03	// (Arm+Enable+received from Host+DATA0)
+#define DATA1_RD	0x43	// (Arm+Enable+received from Host+DATA1)
+
+#define PID_SETUP	0x2d	// USB Specification 1.1 Standard Definition
+#define PID_SOF		0xA5
+#define PID_IN		0x69
+#define PID_OUT		0xe1
+
+#define MAX_RETRY	0xffff
+#define TIMEOUT		5		/* 2 mseconds */
+
+#define SL11H_HOSTCTLREG	0
+#define SL11H_BUFADDRREG	1
+#define SL11H_BUFLNTHREG	2
+#define SL11H_PKTSTATREG	3	/* read */
+#define SL11H_PIDEPREG		3	/* write */
+#define SL11H_XFERCNTREG	4	/* read */
+#define SL11H_DEVADDRREG	4	/* write */
+#define SL11H_CTLREG1		5
+#define SL11H_INTENBLREG	6
+
+// You should not use these registers
+ #define SL11H_HOSTCTLREG_B	8
+// #define SL11H_BUFADDRREG_B	9
+ #define SL11H_BUFLNTHREG_B	0x0A
+// #define SL11H_PKTSTATREG_B	0x0B	/* read */
+ #define SL11H_PIDEPREG_B	0x0B	/* write */
+// #define SL11H_XFERCNTREG_B	0x0C	/* read */
+ #define SL11H_DEVADDRREG_B	0x0C	/* write */
+
+#define SL11H_INTSTATREG	0x0D	/* write clears bitwise */
+#define SL11H_HWREVREG		0x0E	/* read */
+#define SL11H_SOFLOWREG		0x0E	/* write */
+#define SL11H_SOFTMRREG		0x0F	/* read */
+#define SL11H_CTLREG2		0x0F	/* write */
+#define SL11H_DATA_START	0x10
+
+/* Host control register bits (addr 0) */
+#define SL11H_HCTLMASK_ARM	1
+#define SL11H_HCTLMASK_ENBLEP	2
+#define SL11H_HCTLMASK_WRITE	4
+#define SL11H_HCTLMASK_ISOCH	0x10
+#define SL11H_HCTLMASK_AFTERSOF	0x20
+#define SL11H_HCTLMASK_SEQ	0x40
+#define SL11H_HCTLMASK_PREAMBLE	0x80
+
+/* Packet status register bits (addr 3) */
+#define SL11H_STATMASK_ACK	1
+#define SL11H_STATMASK_ERROR	2
+#define SL11H_STATMASK_TMOUT	4
+#define SL11H_STATMASK_SEQ	8
+#define SL11H_STATMASK_SETUP	0x10
+#define SL11H_STATMASK_OVF	0x20
+#define SL11H_STATMASK_NAK	0x40
+#define SL11H_STATMASK_STALL	0x80
+
+/* Control register 1 bits (addr 5) */
+#define SL11H_CTL1MASK_DSBLSOF	1
+#define SL11H_CTL1MASK_NOTXEOF2	4
+#define SL11H_CTL1MASK_DSTATE	0x18
+#define SL11H_CTL1MASK_NSPD	0x20
+#define SL11H_CTL1MASK_SUSPEND	0x40
+#define SL11H_CTL1MASK_CLK12	0x80
+
+#define SL11H_CTL1VAL_RESET	8
+
+/* Interrut enable (addr 6) and interrupt status register bits (addr 0xD) */
+#define SL11H_INTMASK_XFERDONE	1
+#define SL11H_INTMASK_SOFINTR	0x10
+#define SL11H_INTMASK_INSRMV	0x20
+#define SL11H_INTMASK_USBRESET	0x40
+#define SL11H_INTMASK_DSTATE	0x80	/* only in status reg */
+
+/* HW rev and SOF lo register bits (addr 0xE) */
+#define SL11H_HWRMASK_HWREV	0xF0
+
+/* SOF counter and control reg 2 (addr 0xF) */
+#define SL11H_CTL2MASK_SOFHI	0x3F
+#define SL11H_CTL2MASK_DSWAP	0x40
+#define SL11H_CTL2MASK_HOSTMODE	0xae
+
diff -urN linux-2.4.22-bk41/drivers/usb/host/hc_sl811_rh.c linux-2.4.22-bk42/drivers/usb/host/hc_sl811_rh.c
--- linux-2.4.22-bk41/drivers/usb/host/hc_sl811_rh.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/host/hc_sl811_rh.c	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,536 @@
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*
+ * SL811HS virtual root hub
+ *  
+ * based on usb-ohci.c by R. Weissgaerber et al.
+ *-------------------------------------------------------------------------*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#undef DEBUG
+#endif
+static __u32 getPortStatusAndChange (hci_t * hci);
+static void setPortStatus (hci_t * hci, __u16 bitPos);
+static void setPortChange (hci_t * hci, __u16 bitPos);
+static void clrPortStatus (hci_t * hci, __u16 bitPos);
+static void clrPortChange (hci_t * hci, __u16 bitPos);
+static int USBReset (hci_t * hci);
+static int cc_to_error (int cc);
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x10,			/*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes; 
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 
+				   4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x02,			/*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+/* [Hub class-specific descriptor is constructed dynamically] */
+/* copied from "dynamic source". (hne) */
+static __u8 root_hub_hub_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x01,			/*  __u8  bNbrPorts; */
+	0x00,			/* __u16  wHubCharacteristics; */
+	0x00,
+	0x50,			/*  __u8  bPwrOn2pwrGood; 100ms for port reset */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0xfc, /* ??? HNE */	/*  __u8  DeviceRemovable; *** 7 Ports max *** */ /* which port is attachable (HNE) */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+
+/***************************************************************************
+ * Function Name : rh_send_irq
+ * 
+ * This function examine the port change in the virtual root hub.
+ * 
+ * Note: This function assumes only one port exist in the root hub.
+ *
+ * Input:  hci = data structure for the host controller
+ *         rh_data = The pointer to port change data
+ *         rh_len = length of the data in bytes
+ *
+ * Return: length of data  
+ **************************************************************************/
+static int rh_send_irq (hci_t * hci, void *rh_data, int rh_len)
+{
+	int num_ports;
+	int i;
+	int ret;
+	int len;
+	__u8 data[8];
+
+	DBGFUNC ("enter rh_send_irq: \n");
+
+	/* Assuming the root hub has one port.  This value need to change if
+	 * there are more than one port for the root hub
+	 */
+
+	num_ports = 1;
+
+	/* The root hub status is not implemented, it basically has two fields:
+	 *     -- Local Power Status
+	 *     -- Over Current Indicator
+	 *     -- Local Power Change
+	 *     -- Over Current Indicator
+	 *
+	 * Right now, It is assume the power is good and no changes 
+	 */
+
+	*(__u8 *) data = 0;
+
+	ret = *(__u8 *) data;
+
+	/* Has the port status change within the root hub: It checks for
+	 *      -- Port Connect Status change
+	 *      -- Port Enable Change
+	 */
+
+	for (i = 0; i < num_ports; i++) {
+		*(__u8 *) (data + (i + 1) / 8) |=
+		    (((getPortStatusAndChange (hci) >> 16) & (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1 : 0) << ((i + 1) % 8);
+		ret += *(__u8 *) (data + (i + 1) / 8);
+
+		/* After the port change is read, it should be reset so the next time 
+		 * is it doesn't trigger a change again */
+
+	}
+	len = i / 8 + 1;
+
+	if (ret > 0) {
+		memcpy (rh_data, data, min (len, (int)min (rh_len, (int)sizeof (data))));
+		return len;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_int_timer_do
+ * 
+ * This function is called when the timer expires.  It gets the the port 
+ * change data and pass along to the upper protocol.
+ * 
+ * Note:  The virtual root hub interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input:  ptr = ptr to the urb
+ *
+ * Return: none  
+ **************************************************************************/
+static void rh_int_timer_do (unsigned long ptr)
+{
+	int len;
+	struct urb *urb = (struct urb *) ptr;
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_int_timer_do\n");
+
+	if (hci->rh.send) {
+		len = rh_send_irq (hci, urb->transfer_buffer,
+				   urb->transfer_buffer_length);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb_debug == 2)
+				urb_print (urb, "RET-t(rh)",
+					   usb_pipeout (urb->pipe));
+
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		}
+	}
+
+	/* re-activate the timer */
+	rh_init_int_timer (urb);
+}
+
+/***************************************************************************
+ * Function Name : rh_init_int_timer
+ * 
+ * This function creates a timer that act as interrupt pipe in the
+ * virtual hub.   
+ * 
+ * Note:  The virtual root hub's interrupt pipe are polled by the timer
+ *        every "interval" ms
+ *
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_init_int_timer (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+	hci->rh.interval = urb->interval;
+
+	init_timer (&hci->rh.rh_int_timer);
+	hci->rh.rh_int_timer.function = rh_int_timer_do;
+	hci->rh.rh_int_timer.data = (unsigned long) urb;
+	hci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer (&hci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* helper macro */
+#define OK(x) 			len = (x); break
+
+/***************************************************************************
+ * Function Name : rh_submit_urb
+ * 
+ * This function handles all USB request to the the virtual root hub
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_submit_urb (struct urb * urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	hci_t *hci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = TD_CC_NOERROR;
+	__u32 datab[4];
+	__u8 *data_buf = (__u8 *) datab;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	DBGFUNC ("enter rh_submit_urb\n");
+	if (usb_pipeint (pipe)) {
+		hci->rh.urb = urb;
+		hci->rh.send = 1;
+		hci->rh.interval = urb->interval;
+		rh_init_int_timer (urb);
+		urb->status = cc_to_error (TD_CC_NOERROR);
+
+		return 0;
+	}
+
+	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue = le16_to_cpu (cmd->wValue);
+	wIndex = le16_to_cpu (cmd->wIndex);
+	wLength = le16_to_cpu (cmd->wLength);
+
+	DBG ("rh_submit_urb, req = %d(%x) len=%d",
+	     bmRType_bReq, bmRType_bReq, wLength);
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data_buf = cpu_to_le16 (1);
+		OK (2);
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data_buf = cpu_to_le16 (0);
+		OK (2);
+
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data_buf = cpu_to_le32 (0);
+		OK (4);
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		*(__u32 *) data_buf =
+		    cpu_to_le32 (getPortStatusAndChange (hci));
+		OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_LOCAL_POWER:
+			OK (0);
+
+		case (RH_C_HUB_OVER_CURRENT):
+			/* Over Current Not Implemented */
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			clrPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_PORT_SUSPEND):
+			clrPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_POWER):
+			clrPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_C_PORT_CONNECTION):
+			clrPortChange (hci, PORT_CONNECT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_ENABLE):
+			clrPortChange (hci, PORT_ENABLE_STAT);
+			OK (0);
+
+		case (RH_C_PORT_SUSPEND):
+			clrPortChange (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_C_PORT_OVER_CURRENT):
+			clrPortChange (hci, PORT_OVER_CURRENT_STAT);
+			OK (0);
+
+		case (RH_C_PORT_RESET):
+			clrPortChange (hci, PORT_RESET_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			setPortStatus (hci, PORT_SUSPEND_STAT);
+			OK (0);
+
+		case (RH_PORT_RESET):
+			setPortStatus (hci, PORT_RESET_STAT);
+			// USBReset(hci);
+			clrPortChange (hci,
+				       PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE
+				       | PORT_SUSPEND_CHANGE |
+				       PORT_OVER_CURRENT_CHANGE);
+			setPortChange (hci, PORT_RESET_CHANGE);
+			clrPortStatus (hci, PORT_RESET_STAT);
+			setPortStatus (hci, PORT_ENABLE_STAT);
+
+			OK (0);
+
+		case (RH_PORT_POWER):
+			setPortStatus (hci, PORT_POWER_STAT);
+			OK (0);
+
+		case (RH_PORT_ENABLE):
+			setPortStatus (hci, PORT_ENABLE_STAT);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		hci->rh.devnum = wValue;
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue);
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength));
+			data_buf = root_hub_dev_des;
+			OK (len);
+
+		case (0x02):	/* configuration descriptor */
+			len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength));
+			data_buf = root_hub_config_des;
+			OK (len);
+
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff, (int) (long) 0,
+						   "SL811HS", data, wLength);
+			if (len > 0) {
+				data_buf = data;
+				OK (min (leni, len));
+			}
+
+		default:
+			status = SL11H_STATMASK_STALL;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		len = min_t(unsigned int, leni,
+			  min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
+		memcpy (data_buf, root_hub_hub_des, len);
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data_buf = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+
+	default:
+		DBGERR ("unsupported root hub command");
+		status = SL11H_STATMASK_STALL;
+	}
+
+	len = min (len, leni);
+	if (data != data_buf)
+		memcpy (data, data_buf, len);
+	urb->actual_length = len;
+	urb->status = cc_to_error (status);
+
+	urb->hcpriv = NULL;
+	urb->dev = NULL;
+	if (urb->complete) {
+		urb->complete (urb);
+	}
+
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_unlink_urb
+ * 
+ * This function unlinks the URB 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_unlink_urb (struct urb * urb)
+{
+	hci_t *hci = urb->dev->bus->hcpriv;
+
+	DBGFUNC ("enter rh_unlink_urb\n");
+	if (hci->rh.urb == urb) {
+		hci->rh.send = 0;
+		del_timer (&hci->rh.rh_int_timer);
+		hci->rh.urb = NULL;
+
+		urb->hcpriv = NULL;
+		/* ---
+		usb_put_dev (urb->dev);
+
+		Can not found this function, copy from old source and other source.
+		usbnet.c us this to. Its a macro to usb_dec_dev_use. (hne)
+		--- */
+		usb_dec_dev_use(urb->dev);
+		urb->dev = NULL;
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urb->status = -ECONNRESET;
+			if (urb->complete) {
+				urb->complete (urb);
+			}
+		} else
+			urb->status = -ENOENT;
+	}
+	return 0;
+}
+
+/***************************************************************************
+ * Function Name : rh_connect_rh
+ * 
+ * This function connect the virtual root hub to the USB stack 
+ * 
+ * Input: urb = USB request block 
+ *
+ * Return: 0  
+ **************************************************************************/
+static int rh_connect_rh (hci_t * hci)
+{
+	struct usb_device *usb_dev;
+
+	hci->rh.devnum = 0;
+	usb_dev = usb_alloc_dev (NULL, hci->bus);
+	if (!usb_dev)
+		return -ENOMEM;
+
+	hci->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev);
+		return -ENODEV;
+	}
+
+	return 0;
+}
diff -urN linux-2.4.22-bk41/drivers/usb/host/sl811.c linux-2.4.22-bk42/drivers/usb/host/sl811.c
--- linux-2.4.22-bk41/drivers/usb/host/sl811.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk42/drivers/usb/host/sl811.c	2003-10-26 02:49:55.000000000 -0800
@@ -3,18 +3,43 @@
  *
  * Copyright (c) 2003/06, Courage Co., Ltd.
  *
- * Based on: 
+ * Based on:
  *	1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
  * 	  Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
  * 	  Adam Richter, Gregory P. Smith;
-  	2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ * 	2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ *	3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
  *
- * It's now support isosynchronous mode and more effective than hc_sl811.o
+ * It's now support isochornous mode and more effective than hc_sl811.o
+ * Support x86 architecture now.
+ *
+ * 19.09.2003 (05.06.2003) HNE
+ * sl811_alloc_hc: Set "bus->bus_name" at init.
+ * sl811_reg_test (hc_reset,regTest):
+ *   Stop output at first failed pattern.
+ * Down-Grade for Kernel 2.4.20 and from 2.4.22
+ * Splitt hardware depens into file sl811-x86.h and sl811-arm.h.
+ *
+ * 22.09.2003 HNE
+ * sl811_found_hc: First patterntest, than interrupt enable.
+ * Do nothing, if patterntest failed. Release io, if failed.
+ * Stop Interrupts first, than remove handle. (Old blocked Shred IRQ)
+ * Alternate IO-Base for second Controller (CF/USB1).
+ *
+ * 24.09.2003 HNE
+ * Remove all arm specific source (moved into include/asm/sl811-hw.h).
+ *
+ * 03.10.2003 HNE
+ * Low level only for port io into hardware-include.
+
  *
  * To do:
  *	1.Modify the timeout part, it's some messy
  *	2.Use usb-a and usb-b set in Ping-Pong mode
- 	
+ *	o Floppy do not work.
+ *	o driver crash, if io region can't register
+ * 	o Only as module tested! Compiled in Version not tested!
+
  * 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
@@ -41,13 +66,10 @@
 #include "../hub.h"
 #include "sl811.h"
 
-#define DRIVER_VERSION "v0.28"
-#define DRIVER_AUTHOR "Yin Aihua <yinah@couragetech.com.cn>"
-#define DRIVER_DESC "Sl811 USB Host Controller Driver"
-
-static int sl811_addr_io = 0xf100000e;
-static int sl811_data_io = 0xf100000f;
-static int sl811_irq = 44;
+#define DRIVER_VERSION "v0.30"
+#define MODNAME "SL811"
+#define DRIVER_AUTHOR "Yin Aihua <yinah@couragetech.com.cn>, Henry Nestler <hne@ist1.de>"
+#define DRIVER_DESC "Sl811 USB Host Controller Alternate Driver"
 
 static LIST_HEAD(sl811_hcd_list);
 
@@ -57,70 +79,53 @@
  * 2, error maybe occur in normal
  * 3, useful and detail debug information
  * 4, function level enter and level inforamtion
- * 5, endless information will output because of timer function or interrupt 
+ * 5, endless information will output because of timer function or interrupt
  */
 static int debug = 0;
-
-MODULE_PARM(sl811_addr_io,"i");
-MODULE_PARM_DESC(sl811_addr_io,"sl811 address io port 0xf100000e");
-MODULE_PARM(sl811_data_io,"i");
-MODULE_PARM_DESC(sl811_data_io,"sl811 data io port 0xf100000f");
-MODULE_PARM(sl811_irq,"i");
-MODULE_PARM_DESC(sl811_irq,"sl811 irq 44(default)");
 MODULE_PARM(debug,"i");
 MODULE_PARM_DESC(debug,"debug level");
 
+#include <asm/sl811-hw.h>	/* Include hardware and board depens */
+
 static void sl811_rh_int_timer_do(unsigned long ptr);
-static void sl811_transfer_done(struct sl811_hc *hc, int sof); 
+static void sl811_transfer_done(struct sl811_hc *hc, int sof);
 
 /*
  * Read	a byte of data from the	SL811H/SL11H
  */
-static __u8 sl811_read(struct sl811_hc *hc,	__u8 offset)
+static __u8 inline sl811_read(struct sl811_hc *hc, __u8 offset)
 {
-	__u8 data;
-
-	writeb(offset, hc->addr_io);
-	wmb();
-	data = readb(hc->data_io);
-	rmb();
-
-	return data;
+	sl811_write_index (hc, offset);
+	return (sl811_read_data (hc));
 }
 
 /*
  * Write a byte	of data	to the SL811H/SL11H
  */
-static void sl811_write(struct sl811_hc *hc, __u8 offset, __u8 data)
+static void inline sl811_write(struct sl811_hc *hc, __u8 offset, __u8 data)
 {
-	writeb(offset, hc->addr_io);
-	writeb(data, hc->data_io);
-	wmb();
+	sl811_write_index_data (hc, offset, data);
 }
 
 /*
  * Read	consecutive bytes of data from the SL811H/SL11H	buffer
  */
-static void sl811_read_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
+static void inline sl811_read_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
 {
-	writeb(offset, hc->addr_io);
-	wmb();
+	sl811_write_index (hc, offset);
 	while (size--) {
-		*buf++ = readb(hc->data_io);
-		rmb();
+		*buf++ = sl811_read_data(hc);
 	}
 }
 
 /*
  * Write consecutive bytes of data to the SL811H/SL11H buffer
  */
-static void sl811_write_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
+static void inline sl811_write_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size)
 {
-	writeb(offset, hc->addr_io);
-	wmb();
+	sl811_write_index (hc, offset);
 	while (size--) {
-		writeb(*buf, hc->data_io);
-		wmb();
+		sl811_write_data (hc, *buf);
 		buf++;
 	}
 }
@@ -147,6 +152,10 @@
 		if (data != i) {
 			PDEBUG(1, "Pattern test failed!! value = 0x%x, s/b 0x%x", data, i);
 			result = -1;
+
+			/* If no Debug, show only first failed Address */
+			if (!debug)
+			    break;
 		}
 	}
 
@@ -160,6 +169,7 @@
 /*
  * Display all SL811HS register	values
  */
+#if 0 /* unused (hne) */
 static void sl811_reg_show(struct sl811_hc *hc)
 {
 	int i;
@@ -167,6 +177,7 @@
 	for (i = 0; i <	256; i++)
 		PDEBUG(4, "offset %d: 0x%x", i, sl811_read(hc, i));
 }
+#endif
 
 /*
  * This	function enables SL811HS interrupts
@@ -796,9 +807,9 @@
 
 static void sl811_print_td(int level, struct sl811_td *td)
 {
-	 PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n 
-		dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n 
-		buf = %p, bustime = %d, td_status = %d\n", 
+	 PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n "
+		"dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n "
+		"buf = %p, bustime = %d, td_status = %d\n", 
 		td, td->ctrl, td->addr, td->len, td->pidep,
 		td->dev, td->status, td->left, td->errcnt, td->done,
 		td->buf, td->bustime, td->td_status);
@@ -845,7 +856,7 @@
 		if (urbp->cur_td == NULL)
 			urbp->cur_td = urbp->first_td = td;	
 	}
-	
+
 	urbp->last_td = td;	
 	
 	PDEBUG(4, "leave success");
@@ -2397,7 +2408,7 @@
 	struct sl811_td *next_td;
 #ifdef SL811_DEBUG
 	static struct sl811_td *repeat_td = NULL;
-	static repeat_cnt = 1;
+	static int repeat_cnt = 1;
 #endif	
 	if (++hc->frame_number > 1024)
 		hc->frame_number = 0;
@@ -2464,7 +2475,7 @@
 
 	mdelay(20);
 	
-	// Disable hardware SOF generation.
+	// Disable hardware SOF generation, clear all irq status.
 	sl811_write(hc,	SL811_CTRL1, 0);
 	mdelay(2);
 	sl811_write(hc, SL811_INTRSTS, 0xff); 
@@ -2532,7 +2543,7 @@
 
 	status = sl811_read(hc, SL811_INTRSTS);
 	if (status == 0)
-		return ;
+		return ; /* Not me */
 
 	sl811_write(hc,	SL811_INTRSTS, 0xff);
 
@@ -2603,6 +2614,7 @@
 	}
 
 	hc->bus	= bus;
+	bus->bus_name = MODNAME;
 	bus->hcpriv = hc;
 
 	return hc;
@@ -2619,14 +2631,23 @@
 	if (hc->bus->root_hub)
 		usb_disconnect(&hc->bus->root_hub);
 
-	if (hc->addr_io)
-		release_region(hc->addr_io, 1);
-
-	if (hc->data_io)
-		release_region(hc->data_io, 1);
-
+	// Stop interrupt handle
 	if (hc->irq)
 		free_irq(hc->irq, hc);
+	hc->irq = 0;
+
+	/* Stop interrupt for sharing, but only, if PatternTest ok */
+	if (hc->addr_io) {
+		/* Disable Interrupts */
+		sl811_write(hc,	SL811_INTR, 0);
+
+		/* Remove all Interrupt events */
+		mdelay(2);
+		sl811_write(hc,	SL811_INTRSTS, 0xff);
+	}
+
+	/* free io regions */
+	sl811_release_regions(hc);
 
 	usb_deregister_bus(hc->bus);
 	usb_free_bus(hc->bus);
@@ -2638,16 +2659,6 @@
 }
 
 /*
- * This	function is board specific.  It	sets up	the interrupt to
- * be an edge trigger and trigger on the rising	edge
- */
-static void sl811_init_irq(void)
-{
-	GPDR &=	~(1<<23);
-	set_GPIO_IRQ_edge(1<<23, GPIO_RISING_EDGE);
-}
-
-/*
  * This	function request IO memory regions, request IRQ, and
  * allocate all	other resources.
  *
@@ -2667,40 +2678,47 @@
 	if (!hc)
 		return -ENOMEM;
 
-	sl811_init_irq();
-
-	if (!request_region(addr_io, 1, "SL811 USB HOST")) {
-		PDEBUG(1, "request address %d failed", addr_io);
+	if (sl811_request_regions (hc, addr_io, data_io, MODNAME)) {
+		PDEBUG(1, "ioport %X,%X is in use!", addr_io, data_io);
 		sl811_release_hc(hc);
 		return -EBUSY;
 	}
-	hc->addr_io =	addr_io;
 
-	if (!request_region(data_io, 1, "SL811 USB HOST")) {
-		PDEBUG(1, "request address %d failed", data_io);
-		sl811_release_hc (hc);
-		return -EBUSY;
+	if (sl811_reg_test(hc)) {
+		PDEBUG(1, "SL811 register test failed!");
+		sl811_release_hc(hc);
+		return -ENODEV;
+	}
+	
+#ifdef SL811_DEBUG_VERBOSE
+	{
+	    __u8 u = SL811Read (hci, SL11H_HWREVREG);
+	    
+	    // Show the hardware revision of chip
+	    PDEBUG(1, "SL811 HW: %02Xh", u);
+	    switch (u & 0xF0) {
+	    case 0x00: PDEBUG(1, "SL11H");		break;
+	    case 0x10: PDEBUG(1, "SL811HS rev1.2");	break;
+	    case 0x20: PDEBUG(1, "SL811HS rev1.5");	break;
+	    default:   PDEBUG(1, "Revision unknown!");
+	    }
 	}
-	hc->data_io =	data_io;
+#endif // SL811_DEBUG_VERBOSE
+
+	sl811_init_irq();
 
 	usb_register_bus(hc->bus);
 
-	if (request_irq(irq, sl811_interrupt, 0, "SL811", hc)) {
+	if (request_irq(irq, sl811_interrupt, SA_SHIRQ, MODNAME, hc)) {
 		PDEBUG(1, "request interrupt %d failed", irq);
 		sl811_release_hc(hc);
 		return -EBUSY;
 	}
 	hc->irq	= irq;
 
-	printk(KERN_INFO __FILE__ ": USB SL811 at %x, addr2 = %x, IRQ %d\n",
+	printk(KERN_INFO __FILE__ ": USB SL811 at %x,%x, IRQ %d\n",
 		addr_io, data_io, irq);
 
-	if (sl811_reg_test(hc)) {
-		PDEBUG(1, "SL811 register test failed!");
-		sl811_release_hc(hc);
-		return -ENODEV;
-	}
-	
 	sl811_hc_reset(hc);
 	sl811_connect_rh(hc);
 	
@@ -2714,13 +2732,21 @@
  */
 static int __init sl811_hcd_init(void)
 {
-	int ret;
-
-	PDEBUG(5, "etner");
+	int ret = -ENODEV;
+        int count;
+	
+	PDEBUG(5, "enter");
 
 	info(DRIVER_VERSION " : " DRIVER_DESC);
-	
-	ret = sl811_found_hc(sl811_addr_io, sl811_data_io, sl811_irq);
+
+        // registering some instance
+	for (count = 0; count < MAX_CONTROLERS; count++) {
+		if (io[count]) {
+			ret = sl811_found_hc(io[count], io[count]+OFFSET_DATA_REG, irq[count]);
+			if (ret)
+				return (ret);
+		}
+	}
 
 	return ret;
 }
diff -urN linux-2.4.22-bk41/drivers/usb/scanner.c linux-2.4.22-bk42/drivers/usb/scanner.c
--- linux-2.4.22-bk41/drivers/usb/scanner.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/scanner.c	2003-10-26 02:49:55.000000000 -0800
@@ -378,6 +378,14 @@
  *      Sergey Vlasov.
  *    - Clean up irq urb when not enough memory is available (Sergey Vlasov).
  *
+ * 0.4.15  2003-10-03
+ *    - Added vendor/product ids for Canon, HP, Microtek, Mustek, Siemens, UMAX, and
+ *      Visioneer scanners.
+ *    - Added test for USB_CLASS_CDC_DATA which is used by some fingerprint scanners
+ *    - Use static declarations for usb_scanner_init/usb_scanner_exit 
+ *      (Daniele Bellucci).
+ *
+ *
  * TODO
  *    - Performance
  *    - Select/poll methods
@@ -921,6 +929,7 @@
 
 	if (interface[0].bInterfaceClass != USB_CLASS_VENDOR_SPEC &&
 	    interface[0].bInterfaceClass != USB_CLASS_PER_INTERFACE &&
+	    interface[0].bInterfaceClass != USB_CLASS_CDC_DATA &&
 	    interface[0].bInterfaceClass != SCN_CLASS_SCANJET) {
 		dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].bInterfaceClass);
 		return NULL;
@@ -1159,13 +1168,13 @@
 				 we match a user defined vendor/product ID. */
 };
 
-void __exit
+static void __exit
 usb_scanner_exit(void)
 {
 	usb_deregister(&scanner_driver);
 }
 
-int __init
+static int __init
 usb_scanner_init (void)
 {
         if (usb_register(&scanner_driver) < 0)
diff -urN linux-2.4.22-bk41/drivers/usb/scanner.h linux-2.4.22-bk42/drivers/usb/scanner.h
--- linux-2.4.22-bk41/drivers/usb/scanner.h	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/scanner.h	2003-10-26 02:49:55.000000000 -0800
@@ -44,7 +44,7 @@
 
 // #define DEBUG
 
-#define DRIVER_VERSION "0.4.14"
+#define DRIVER_VERSION "0.4.15"
 #define DRIVER_DESC "USB Scanner Driver"
 
 #include <linux/usb.h>
@@ -123,7 +123,10 @@
 	{ USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */
 	{ USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
 	{ USB_DEVICE(0x04a9, 0x220f) },	/* CanoScan 8000F */
+	{ USB_DEVICE(0x04a9, 0x2210) },	/* CanoScan 9900F */
+	{ USB_DEVICE(0x04a9, 0x2212) },	/* CanoScan 5000F */
 	{ USB_DEVICE(0x04a9, 0x2213) },	/* LIDE 50 */
+	{ USB_DEVICE(0x04a9, 0x2215) },	/* CanoScan 3000 */
 	{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
 	/* Colorado -- See Primax/Colorado below */
 	/* Compaq */
@@ -159,7 +162,9 @@
 	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* ScanJet 5300C - NOT SUPPORTED - use hpusbscsi driver */
 	{ USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */
 	//	{ USB_DEVICE(0x03f0, 0x0801) },	/* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */
+	{ USB_DEVICE(0x03f0, 0x0805) },	/* ScanJet 4470c */
 	{ USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */
+	{ USB_DEVICE(0x03f0, 0x0a01) },	/* ScanJet 2400c */
 	{ USB_DEVICE(0x03F0, 0x1005) },	/* ScanJet 5400C */
 	{ USB_DEVICE(0x03F0, 0x1105) },	/* ScanJet 5470C */
 	{ USB_DEVICE(0x03f0, 0x1205) }, /* ScanJet 5550C */
@@ -178,9 +183,11 @@
 	/* Memorex */
 	{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
 	/* Microtek */
+	{ USB_DEVICE(0x05da, 0x20a7) },	/* ScanMaker 5600 */
 	{ USB_DEVICE(0x05da, 0x20c9) }, /* ScanMaker 6700 */
 	{ USB_DEVICE(0x05da, 0x30ce) },	/* ScanMaker 3800 */
 	{ USB_DEVICE(0x05da, 0x30cf) },	/* ScanMaker 4800 */
+	{ USB_DEVICE(0x05da, 0x30d4) },	/* ScanMaker 3830 + 3840 */
 	{ 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 */
@@ -215,6 +222,7 @@
 	{ USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */
 	{ USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */
 	{ USB_DEVICE(0x055f, 0x0401) },	/* P 3600 A3 Pro */
+	{ USB_DEVICE(0x055f, 0x0409) },	/* BearPaw 2448TA Pro */
 	{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
 	{ USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */
 	//	{ USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus (see Artec) */
@@ -280,6 +288,9 @@
 	{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
 	{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
 	{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
+	/* Siemens */
+	{ USB_DEVICE(0x0681, 0x0005) },	/* ID Mouse Professional */
+	{ USB_DEVICE(0x0681, 0x0010) },	/* Cherry FingerTIP ID Board - Sensor */
 	/* SYSCAN */
 	{ USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */
 	/* Trust */
@@ -290,6 +301,7 @@
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
 	{ USB_DEVICE(0x1606, 0x0060) }, /* Astra 3400U/3450U */
+	{ USB_DEVICE(0x1606, 0x0070) },	/* Astra 4400 */
 	{ USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */
 	{ USB_DEVICE(0x1606, 0x0160) }, /* Astra 5400U */  
 	{ USB_DEVICE(0x1606, 0x0230) },	/* Astra 2200U */
@@ -297,7 +309,8 @@
 	{ USB_DEVICE(0x04a7, 0x0211) },	/* OneTouch 7600 USB */
 	{ USB_DEVICE(0x04a7, 0x0221) },	/* OneTouch 5300 USB */
 	{ USB_DEVICE(0x04a7, 0x0224) },	/* OneTouch 4800 USB */
-	{ USB_DEVICE(0x04a7, 0x0226) },	/* OneTouch 5300 USB */
+	{ USB_DEVICE(0x04a7, 0x0226) },	/* OneTouch 5800 USB */
+	{ USB_DEVICE(0x04a7, 0x022c) },	/* OneTouch 9020 USB */
 	{ USB_DEVICE(0x04a7, 0x0231) },	/* 6100 USB */
 	{ USB_DEVICE(0x04a7, 0x0311) },	/* 6200 EPP/USB */
 	{ USB_DEVICE(0x04a7, 0x0321) },	/* OneTouch 8100 EPP/USB */
diff -urN linux-2.4.22-bk41/drivers/usb/serial/ftdi_sio.c linux-2.4.22-bk42/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.22-bk41/drivers/usb/serial/ftdi_sio.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/serial/ftdi_sio.c	2003-10-26 02:49:55.000000000 -0800
@@ -17,6 +17,15 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (21/Oct/2003) Ian Abbott
+ *      Renamed some VID/PID macros for Matrix Orbital and Perle Systems
+ *      devices.  Removed Matrix Orbital and Perle Systems devices from the
+ *      8U232AM device table, but left them in the FT232BM table, as they are
+ *      known to use only FT232BM.
+ *
+ * (17/Oct/2003) Scott Allen
+ *      Added vid/pid for Perle Systems UltraPort USB serial converters
+ *
  * (21/Sep/2003) Ian Abbott
  *      Added VID/PID for Omnidirectional Control Technology US101 USB to
  *      RS-232 adapter (also rebadged as Dick Smith Electronics XH6381).
@@ -236,7 +245,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.3.4"
+#define DRIVER_VERSION "v1.3.5"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
@@ -276,13 +285,6 @@
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0, 0x3ff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) },
@@ -349,13 +351,14 @@
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
-	{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) },
 	{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) },
@@ -435,13 +438,14 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
-	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID) },
-	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID) },
-	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID) },
-	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID) },
-	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID) },
-	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID) },
-	{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
+	{ USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
diff -urN linux-2.4.22-bk41/drivers/usb/serial/ftdi_sio.h linux-2.4.22-bk42/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.22-bk41/drivers/usb/serial/ftdi_sio.h	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/serial/ftdi_sio.h	2003-10-26 02:49:55.000000000 -0800
@@ -50,7 +50,6 @@
  * The following are the values for the Matrix Orbital LCD displays,
  * which are the FT232BM ( similar to the 8U232AM )
  */
-#define FTDI_MTXORB_VID                FTDI_VID        /* Matrix Orbital Product Id */
 #define FTDI_MTXORB_0_PID      0xFA00  /* Matrix Orbital Product Id */
 #define FTDI_MTXORB_1_PID      0xFA01  /* Matrix Orbital Product Id */
 #define FTDI_MTXORB_2_PID      0xFA02  /* Matrix Orbital Product Id */
@@ -60,6 +59,12 @@
 #define FTDI_MTXORB_6_PID      0xFA06  /* Matrix Orbital Product Id */
 
 /*
+ * The following are the values for the Perle Systems
+ * UltraPort USB serial converters
+ */
+#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0	/* Perle UltraPort Product Id */
+
+/*
  * The following are the values for the Sealevel SeaLINK+ adapters.
  * (Original list sent by Tuan Hoang.  Ian Abbott renamed the macros and
  * removed some PIDs that don't seem to match any existing products.)
diff -urN linux-2.4.22-bk41/drivers/usb/serial/visor.c linux-2.4.22-bk42/drivers/usb/serial/visor.c
--- linux-2.4.22-bk41/drivers/usb/serial/visor.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/serial/visor.c	2003-10-26 02:49:55.000000000 -0800
@@ -195,6 +195,7 @@
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
@@ -223,6 +224,7 @@
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },
+	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
diff -urN linux-2.4.22-bk41/drivers/usb/serial/visor.h linux-2.4.22-bk42/drivers/usb/serial/visor.h
--- linux-2.4.22-bk41/drivers/usb/serial/visor.h	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/serial/visor.h	2003-10-26 02:49:55.000000000 -0800
@@ -20,6 +20,7 @@
 #define HANDSPRING_VENDOR_ID		0x082d
 #define HANDSPRING_VISOR_ID		0x0100
 #define HANDSPRING_TREO_ID		0x0200
+#define HANDSPRING_TREO600_ID		0x0300
 
 #define PALM_VENDOR_ID			0x0830
 #define PALM_M500_ID			0x0001
diff -urN linux-2.4.22-bk41/drivers/usb/storage/unusual_devs.h linux-2.4.22-bk42/drivers/usb/storage/unusual_devs.h
--- linux-2.4.22-bk41/drivers/usb/storage/unusual_devs.h	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/storage/unusual_devs.h	2003-10-26 02:49:55.000000000 -0800
@@ -548,10 +548,10 @@
  * - They don't like the INQUIRY command. So we must handle this command
  *   of the SCSI layer ourselves.
  */
-UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x5009,
+UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999,
 		"Casio",
 		"QV DigitalCamera",
-		US_SC_8070, US_PR_CB, NULL,
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
 /* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/
@@ -631,6 +631,16 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY),
 
+/*
+ * Entry for Jenoptik JD 5200z3
+ *
+ * email: car.busse@gmx.de
+ */
+UNUSUAL_DEV(  0x0d96, 0x5200, 0x0001, 0x0200,
+		"Jenoptik",
+		"JD 5200 z3",
+		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+		
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
  * Entry is needed only for the initializer function override.
diff -urN linux-2.4.22-bk41/drivers/usb/usbnet.c linux-2.4.22-bk42/drivers/usb/usbnet.c
--- linux-2.4.22-bk41/drivers/usb/usbnet.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/usbnet.c	2003-10-26 02:49:55.000000000 -0800
@@ -381,14 +381,14 @@
 
 #ifdef DEBUG
 #define devdbg(usbnet, fmt, arg...) \
-	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
+	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name , ## arg)
 #else
 #define devdbg(usbnet, fmt, arg...) do {} while(0)
 #endif
 
 #define devinfo(usbnet, fmt, arg...) \
 	do { if ((usbnet)->msg_level >= 1) \
-	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg); \
+	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name , ## arg); \
 	} while (0)
 
 
diff -urN linux-2.4.22-bk41/drivers/usb/w9968cf.c linux-2.4.22-bk42/drivers/usb/w9968cf.c
--- linux-2.4.22-bk41/drivers/usb/w9968cf.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/w9968cf.c	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,3989 @@
+/***************************************************************************
+ * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
+ *                                                                         *
+ * Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>            *
+ *                                                                         *
+ * - Memory management code from bttv driver by Ralph Metzler,             *
+ *   Marcus Metzler and Gerd Knorr.                                        *
+ * - I2C interface to kernel, high-level CMOS sensor control routines and  *
+ *   some symbolic names from OV511 driver by Mark W. McClelland.          *
+ * - Low-level I2C fast write function by Piotr Czerczak.                  *
+ * - Low-level I2C read function by Frédéric Jouault.                      *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/wrapper.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "w9968cf.h"
+#include "w9968cf_decoder.h"
+
+EXPORT_NO_SYMBOLS;
+
+
+
+/****************************************************************************
+ * Modules paramaters                                                       *
+ ****************************************************************************/
+
+static u8 vppmod_load = W9968CF_VPPMOD_LOAD;
+static u8 simcams = W9968CF_SIMCAMS;
+static int video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /* -1=first free */
+static u16 packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_PACKET_SIZE};
+static u8 max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BUFFERS};
+static u8 double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                             W9968CF_DOUBLE_BUFFER};
+static u8 clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
+static u8 filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FILTER_TYPE};
+static u8 largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
+static u8 decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                             W9968CF_DECOMPRESSION};
+static u8 upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
+static u8 force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
+static u8 force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
+static u8 autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
+static u8 autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
+static u8 lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LIGHTFREQ};
+static u8 bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
+                             W9968CF_BANDINGFILTER};
+static int clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
+static u8 backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
+static u8 mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
+static u8 sensor_mono[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_SENSOR_MONO};
+static u16 brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BRIGHTNESS};
+static u16 hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
+static u16 colour[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
+static u16 contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CONTRAST};
+static u16 whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_WHITENESS};
+#ifdef W9968CF_DEBUG
+static u8 debug = W9968CF_DEBUG_LEVEL;
+static u8 specific_debug = W9968CF_SPECIFIC_DEBUG;
+#endif
+
+MODULE_AUTHOR("Luca Risolia <luca_ing@libero.it>");
+
+MODULE_DESCRIPTION("Video4Linux driver for "
+                   "W996[87]CF JPEG USB Dual Mode Camera Chip");
+
+MODULE_SUPPORTED_DEVICE("Video");
+
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(vppmod_load, "i");
+MODULE_PARM(simcams, "i");
+MODULE_PARM(video_nr, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(packet_size, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(max_buffers, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(double_buffer, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(clamping, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(filter_type, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(largeview, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(decompression, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(upscaling, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(force_palette, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(force_rgb, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "i");
+MODULE_PARM(autobright, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(autoexp, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(lightfreq, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(bandingfilter, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(clockdiv, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(backlight, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(mirror, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(sensor_mono, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(brightness, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(hue, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(colour, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(contrast, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+MODULE_PARM(whiteness, "0-" __MODULE_STRING(W9968CF_MAX_DEVICES) "l");
+#ifdef W9968CF_DEBUG
+MODULE_PARM(debug, "i");
+MODULE_PARM(specific_debug, "i");
+#endif
+
+MODULE_PARM_DESC(vppmod_load, 
+                 "\n<0|1> Automatic 'w9968cf-vpp' module loading."
+                 "\n0 disable, 1 enable."
+                 "\nIf enabled, every time an application attempts to open a"
+                 "\ncamera, 'insmod' searches for the video post-processing"
+                 "\nmodule in the system and loads it automatically (if"
+                 "\npresent). The 'w9968cf-vpp' module adds extra image"
+                 "\nmanipulation functions to the 'w9968cf' module, like"
+                 "\nsoftware up-scaling,colour conversions and video decoding."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_VPPMOD_LOAD)"."
+                 "\n");
+MODULE_PARM_DESC(simcams, 
+                 "\n<n> Number of cameras allowed to stream simultaneously."
+                 "\nn may vary from 0 to "
+                 __MODULE_STRING(W9968CF_MAX_DEVICES)"."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
+                 "\n");
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify " __MODULE_STRING(W9968CF_MAX_DEVICES)
+                 " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+MODULE_PARM_DESC(packet_size,
+                 "\n<n[,...]> Specify the maximum data payload"
+                 "\nsize in bytes for alternate settings, for each device."
+                 "\nn is scaled between 63 and 1023 "
+                 "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
+                 "\n");
+MODULE_PARM_DESC(max_buffers,
+                 "\n<n[,...]> Only for advanced users."
+                 "\nSpecify the maximum number of video frame buffers"
+                 "\nto allocate for each device, from 2 to "
+                 __MODULE_STRING(W9968CF_MAX_BUFFERS)
+                 ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
+                 "\n");
+MODULE_PARM_DESC(double_buffer, 
+                 "\n<0|1[,...]> "
+                 "Hardware double buffering: 0 disabled, 1 enabled."
+                 "\nIt should be enabled if you want smooth video output: if"
+                 "\nyou obtain out of sync. video, disable it at all, or try"
+                 "\nto decrease the 'clockdiv' module paramater value."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(clamping, 
+                 "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(filter_type, 
+                 "\n<0|1|2[,...]> Video filter type."
+                 "\n0 none, 1 (1-2-1) 3-tap filter, "
+                 "2 (2-3-6-3-2) 5-tap filter."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
+                 " for every device."
+                 "\nThe filter is used to reduce noise and aliasing artifacts"
+                 "\nproduced by the CCD or CMOS sensor, and the scaling"
+                 " process."
+                 "\n");
+MODULE_PARM_DESC(largeview, 
+                 "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(upscaling, 
+                 "\n<0|1[,...]> Software scaling (for non-compressed video):"
+                 "\n0 disabled, 1 enabled."
+                 "\nDisable it if you have a slow CPU or you don't have"
+                 " enough memory."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
+                 " for every device."
+                 "\nIf 'w9968cf-vpp' is not loaded, this paramater is"
+                 " set to 0.");
+MODULE_PARM_DESC(decompression,
+                 "\n<0|1|2[,...]> Software video decompression:"
+                 "\n- 0 disables decompression (doesn't allow formats needing"
+                 " decompression)"
+                 "\n- 1 forces decompression (allows formats needing"
+                 " decompression only);"
+                 "\n- 2 allows any permitted formats."
+                 "\nFormats supporting compressed video are YUV422P and"
+                 " YUV420P/YUV420 "
+                 "\nin any resolutions where both width and height are "
+                 "a multiple of 16."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
+                 " for every device."
+                 "\nIf 'w9968cf-vpp' is not loaded, forcing decompression is "
+                 "\nnot allowed; in this case this paramater is set to 2.");
+MODULE_PARM_DESC(force_palette,
+                 "\n<0"
+                 "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
+                 "[,...]>"
+                 " Force picture palette."
+                 "\nIn order:"
+                 "\n- 0 allows any of the following formats:"
+                 "\n- UYVY    16 bpp - Original video, compression disabled"
+                 "\n- YUV420  12 bpp - Original video, compression enabled"
+                 "\n- YUV422P 16 bpp - Original video, compression enabled"
+                 "\n- YUV420P 12 bpp - Original video, compression enabled"
+                 "\n- YUVY    16 bpp - Software conversion from UYVY"
+                 "\n- YUV422  16 bpp - Software conversion from UYVY"
+                 "\n- GREY     8 bpp - Software conversion from UYVY"
+                 "\n- RGB555  16 bpp - Software conversion from UYVY"
+                 "\n- RGB565  16 bpp - Software conversion from UYVY"
+                 "\n- RGB24   24 bpp - Software conversion from UYVY"
+                 "\n- RGB32   32 bpp - Software conversion from UYVY"
+                 "\nWhen not 0, this paramater will override 'decompression'."
+                 "\nDefault value is 0 for every device."
+                 "\nInitial palette is "
+                 __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
+                 "\nIf 'w9968cf-vpp' is not loaded, this paramater is"
+                 " set to 9 (UYVY).");
+MODULE_PARM_DESC(force_rgb, 
+                 "\n<0|1[,...]> Read RGB video data instead of BGR:"
+                 "\n 1 = use RGB component ordering."
+                 "\n 0 = use BGR component ordering."
+                 "\nThis parameter has effect when using RGBX palettes only."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(autobright,
+                 "\n<0|1[,...]> CMOS sensor automatically changes brightness:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(autoexp,
+                 "\n<0|1[,...]> CMOS sensor automatically changes exposure:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(lightfreq,
+                 "\n<50|60[,...]> Light frequency in Hz:"
+                 "\n 50 for European and Asian lighting,"
+                 " 60 for American lighting."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(bandingfilter,
+                 "\n<0|1[,...]> Banding filter to reduce effects of"
+                 " fluorescent lighting:"
+                 "\n 0 disabled, 1 enabled."
+                 "\nThis filter tries to reduce the pattern of horizontal"
+                 "\nlight/dark bands caused by some (usually fluorescent)"
+                 " lighting."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(clockdiv,
+                 "\n<-1|n[,...]> "
+                 "Force pixel clock divisor to a specific value (for experts):"
+                 "\n  n may vary from 0 to 127."
+                 "\n -1 for automatic value."
+                 "\nSee also the 'double_buffer' module paramater."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(backlight,
+                 "\n<0|1[,...]> Objects are lit from behind:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(mirror,
+                 "\n<0|1[,...]> Reverse image horizontally:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(sensor_mono,
+                 "\n<0|1[,...]> The OV CMOS sensor is monochrome:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_SENSOR_MONO)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(brightness, 
+                 "\n<n[,...]> Set picture brightness (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
+                 " for every device."
+                 "\nThis parameter has no effect if 'autobright' is enabled."
+                 "\n");
+MODULE_PARM_DESC(hue, 
+                 "\n<n[,...]> Set picture hue (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(colour, 
+                 "\n<n[,...]> Set picture saturation (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(contrast, 
+                 "\n<n[,...]> Set picture contrast (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(whiteness, 
+                 "\n<n[,...]> Set picture whiteness (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
+                 " for every device."
+                 "\n");
+#ifdef W9968CF_DEBUG
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 6:"
+                 "\n0 = none (be cautious)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = configuration or general messages"
+                 "\n4 = warnings"
+                 "\n5 = called functions"
+                 "\n6 = function internals"
+                 "\nLevel 5 and 6 are useful for testing only, when just "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
+                 "\n");
+MODULE_PARM_DESC(specific_debug,
+                 "\n<0|1> Enable or disable specific debugging messages:"
+                 "\n0 = print messages concerning every level"
+                 " <= 'debug' level."
+                 "\n1 = print messages concerning the level"
+                 " indicated by 'debug'."
+                 "\nDefault value is "
+                 __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
+                 "\n");
+#endif /* W9968CF_DEBUG */
+
+
+
+/****************************************************************************
+ * Some prototypes                                                          *
+ ****************************************************************************/
+
+/* Video4linux interface */
+static struct file_operations w9968cf_fops;
+static int w9968cf_open(struct inode*, struct file*);
+static int w9968cf_release(struct inode*, struct file*);
+static ssize_t w9968cf_read(struct file*, char*, size_t, loff_t*);
+static int w9968cf_mmap(struct file*, struct vm_area_struct*);
+static int w9968cf_ioctl(struct inode*, struct file*,
+                         unsigned int, unsigned long);
+static int w9968cf_do_ioctl(struct w9968cf_device*, unsigned int, void*);
+
+/* /proc interface */
+#if defined(CONFIG_VIDEO_PROC_FS)
+static void w9968cf_proc_create(void);
+static void w9968cf_proc_destroy(void);
+static void w9968cf_proc_create_dev(struct w9968cf_device*);
+static void w9968cf_proc_destroy_dev(struct w9968cf_device*);
+static int w9968cf_proc_read_global(char*, char**, off_t, int, int*, void*);
+static int w9968cf_proc_read_dev(char*, char**, off_t, int, int*, void*);
+#else
+static inline void w9968cf_proc_create(void) {}
+static inline void w9968cf_proc_destroy(void) {}
+static inline void w9968cf_proc_create_dev(struct w9968cf_device* cam) {}
+static inline void w9968cf_proc_destroy_dev(struct w9968cf_device* cam) {}
+#endif
+
+/* USB-specific */
+static void w9968cf_urb_complete(struct urb *urb);
+static int w9968cf_start_transfer(struct w9968cf_device*);
+static int w9968cf_stop_transfer(struct w9968cf_device*);
+static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
+static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
+static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
+static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
+static int w9968cf_read_sb(struct w9968cf_device*);
+static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
+
+
+/* Low-level I2C (SMBus) I/O */
+static int w9968cf_smbus_start(struct w9968cf_device*);
+static int w9968cf_smbus_stop(struct w9968cf_device*);
+static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
+static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
+static int w9968cf_smbus_write_ack(struct w9968cf_device*);
+static int w9968cf_smbus_read_ack(struct w9968cf_device*);
+static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
+                                      u16 address, u8* value);
+static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, 
+                                           u8 subaddress, u8* value);
+static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
+                                       u16 address, u8 subaddress);
+static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
+                                                u16 address, u8 subaddress,
+                                                u8 value);
+
+/* I2C interface to kernel */
+static int w9968cf_i2c_init(struct w9968cf_device*);
+static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, 
+                                  unsigned short flags, char read_write, 
+                                  u8 command, int size, union i2c_smbus_data*);
+static u32 w9968cf_i2c_func(struct i2c_adapter*);
+static int w9968cf_i2c_attach_inform(struct i2c_client*);
+static int w9968cf_i2c_detach_inform(struct i2c_client*);
+static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
+                               unsigned long arg);
+static void w9968cf_i2c_inc_use(struct i2c_adapter*);
+static void w9968cf_i2c_dec_use(struct i2c_adapter*);
+
+/* Memory management */
+static inline unsigned long kvirt_to_pa(unsigned long adr);
+static void* rvmalloc(unsigned long size);
+static void rvfree(void *mem, unsigned long size);
+static void w9968cf_deallocate_memory(struct w9968cf_device*);
+static int  w9968cf_allocate_memory(struct w9968cf_device*);
+static inline unsigned long w9968cf_get_max_bufsize(struct w9968cf_device*);
+
+/* High-level CMOS sensor control functions */
+static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
+static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
+static inline int w9968cf_sensor_cmd(struct w9968cf_device*, 
+                                     unsigned int cmd, void *arg);
+static void w9968cf_sensor_configure(struct w9968cf_device*);
+static int w9968cf_sensor_change_settings(struct w9968cf_device*);
+static int w9968cf_sensor_get_picture(struct w9968cf_device*, 
+                                      struct video_picture*);
+static int w9968cf_sensor_set_picture(struct w9968cf_device*, 
+                                      struct video_picture pict);
+
+/* Other helper functions */
+static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
+                                     enum w9968cf_model_id, 
+                                     const unsigned short dev_nr);
+static int w9968cf_turn_on_led(struct w9968cf_device*);
+static int w9968cf_init_chip(struct w9968cf_device*);
+static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
+static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
+static inline u16 w9968cf_valid_palette(u16 palette);
+static inline u16 w9968cf_valid_depth(u16 palette);
+static inline u8 w9968cf_need_decompression(u16 palette);
+static int w9968cf_postprocess_frame(struct w9968cf_device*, 
+                                     struct w9968cf_frame_t*);
+static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
+static void w9968cf_init_framelist(struct w9968cf_device*);
+static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
+static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
+static void w9968cf_release_resources(struct w9968cf_device*);
+
+/* Intermodule communication */
+static int w9968cf_vppmod_detect(void);
+static void w9968cf_vppmod_release(void);
+
+/* Pointers to registered video post-processing functions */
+static void (*w9968cf_vpp_init_decoder)(void);
+static int (*w9968cf_vpp_check_headers)(const unsigned char*,
+                                        const unsigned long);
+static int (*w9968cf_vpp_decode)(const char*, const unsigned, 
+                                 const unsigned, const unsigned, char*);
+static void (*w9968cf_vpp_swap_yuvbytes)(void*, unsigned long);
+static void (*w9968cf_vpp_uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
+static void (*w9968cf_vpp_scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
+
+
+
+/****************************************************************************
+ * Symbolic names                                                           *
+ ****************************************************************************/
+
+/* Used to represent a list of values and their respective symbolic names */
+struct w9968cf_symbolic_list {
+	const int num;
+	const char *name;
+};
+
+/*-------------------------------------------------------------------------- 
+  Returns the name of the matching element in the symbolic_list array. The
+  end of the list must be marked with an element that has a NULL name.
+  --------------------------------------------------------------------------*/
+static inline const char * 
+symbolic(struct w9968cf_symbolic_list list[], const int num)
+{
+	int i;
+
+	for (i = 0; list[i].name != NULL; i++)
+		if (list[i].num == num)
+			return (list[i].name);
+
+	return "Unknown";
+}
+
+static struct w9968cf_symbolic_list camlist[] = {
+	{ W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
+	{ W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
+
+	/* Other cameras (having the same descriptors as Generic W996[87]CF) */
+	{ W9968CF_MOD_ADPA5R, "Aroma Digi Pen ADG-5000 Refurbished" },
+	{ W9986CF_MOD_AU, "AVerTV USB" },
+	{ W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
+	{ W9968CF_MOD_DLLDK, "Die Lebon LDC-D35A Digital Kamera" },
+	{ W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
+	{ W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
+
+	{  -1, NULL }
+};
+
+static struct w9968cf_symbolic_list senlist[] = {
+	{ CC_OV76BE,   "OV76BE" },
+	{ CC_OV7610,   "OV7610" },
+	{ CC_OV7620,   "OV7620" },
+	{ CC_OV7620AE, "OV7620AE" },
+	{ CC_OV6620,   "OV6620" },
+	{ CC_OV6630,   "OV6630" },
+	{ CC_OV6630AE, "OV6630AE" },
+	{ CC_OV6630AF, "OV6630AF" },
+	{ -1, NULL }
+};
+
+/* Video4Linux1 palettes */
+static struct w9968cf_symbolic_list v4l1_plist[] = {
+	{ VIDEO_PALETTE_GREY,    "GREY" },
+	{ VIDEO_PALETTE_HI240,   "HI240" },
+	{ VIDEO_PALETTE_RGB565,  "RGB565" },
+	{ VIDEO_PALETTE_RGB24,   "RGB24" },
+	{ VIDEO_PALETTE_RGB32,   "RGB32" },
+	{ VIDEO_PALETTE_RGB555,  "RGB555" },
+	{ VIDEO_PALETTE_YUV422,  "YUV422" },
+	{ VIDEO_PALETTE_YUYV,    "YUYV" },
+	{ VIDEO_PALETTE_UYVY,    "UYVY" },
+	{ VIDEO_PALETTE_YUV420,  "YUV420" },
+	{ VIDEO_PALETTE_YUV411,  "YUV411" },
+	{ VIDEO_PALETTE_RAW,     "RAW" },
+	{ VIDEO_PALETTE_YUV422P, "YUV422P" },
+	{ VIDEO_PALETTE_YUV411P, "YUV411P" },
+	{ VIDEO_PALETTE_YUV420P, "YUV420P" },
+	{ VIDEO_PALETTE_YUV410P, "YUV410P" },
+	{ -1, NULL }
+};
+
+/* Decoder error codes: */
+static struct w9968cf_symbolic_list decoder_errlist[] = {
+	{ W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
+	{ W9968CF_DEC_ERR_BUF_OVERFLOW,   "Buffer overflow" },
+	{ W9968CF_DEC_ERR_NO_SOI,         "SOI marker not found" },     
+	{ W9968CF_DEC_ERR_NO_SOF0,        "SOF0 marker not found" },
+	{ W9968CF_DEC_ERR_NO_SOS,         "SOS marker not found" },
+	{ W9968CF_DEC_ERR_NO_EOI,         "EOI marker not found" },
+	{ -1, NULL }
+};
+
+/* URB error codes: */
+static struct w9968cf_symbolic_list urb_errlist[] = {
+	{ -ENOMEM,    "No memory for allocation of internal structures" },
+	{ -ENOSPC,    "The host controller's bandwidth is already consumed" },
+	{ -ENOENT,    "URB was canceled by unlink_urb" },
+	{ -EXDEV,     "ISO transfer only partially completed" },
+	{ -EAGAIN,    "Too match scheduled for the future" },
+	{ -ENXIO,     "URB already queued" },
+	{ -EFBIG,     "Too much ISO frames requested" },
+	{ -ENOSR,     "Buffer error (overrun)" },
+	{ -EPIPE,     "Specified endpoint is stalled (device not responding)"},
+	{ -EOVERFLOW, "Babble (bad cable?)" },
+	{ -EPROTO,    "Bit-stuff error (bad cable?)" },
+	{ -EILSEQ,    "CRC/Timeout" },
+	{ -ETIMEDOUT, "NAK (device does not respond)" },
+	{ -1, NULL }
+};
+
+
+
+/****************************************************************************
+ * Memory management functions                                              *
+ ****************************************************************************/
+
+/* Shameless copy from bttv-driver.c */
+
+/* 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)
+{
+	unsigned long kva, ret;
+
+	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+	ret = __pa(kva);
+	return ret;
+}
+
+
+static void* rvmalloc(unsigned long size)
+{
+	void* mem;
+	unsigned long adr;
+
+	size = PAGE_ALIGN(size);
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		mem_map_reserve(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	return mem;
+}
+
+
+static void rvfree(void* mem, unsigned long size)
+{
+	unsigned long adr;
+
+	if (!mem)
+		return;
+
+	adr = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vfree(mem);
+}
+/* End of shameless copy */
+
+
+/*--------------------------------------------------------------------------
+  Return the maximum size (in bytes) of a frame buffer.
+  --------------------------------------------------------------------------*/
+static inline unsigned long w9968cf_get_max_bufsize(struct w9968cf_device* cam)
+{
+	u8 bpp = (w9968cf_vppmod_present) ? 4 : 2;
+	return (cam->upscaling) ? W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp :
+	                          cam->maxwidth*cam->maxheight*bpp;
+}
+
+
+/*--------------------------------------------------------------------------
+  Deallocate previously allocated memory.
+  --------------------------------------------------------------------------*/
+static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
+{
+	u8 i;
+
+	/* Free the isochronous transfer buffers */
+	for (i = 0; i < W9968CF_URBS; i++) {
+		kfree(cam->transfer_buffer[i]);
+		cam->transfer_buffer[i] = NULL;
+	}
+
+	/* Free temporary frame buffer */
+	if (cam->frame_tmp.buffer) {
+		rvfree(cam->frame_tmp.buffer, W9968CF_HW_BUF_SIZE);
+		cam->frame_tmp.buffer = NULL;
+	}
+
+	/* Free helper buffer */
+	if (cam->vpp_buffer) {
+		rvfree(cam->vpp_buffer, w9968cf_get_max_bufsize(cam));
+		cam->vpp_buffer = NULL;
+	}
+	
+	/* Free video frame buffers */
+	if (cam->frame[0].buffer) {
+		rvfree(cam->frame[0].buffer, 
+		       cam->nbuffers * w9968cf_get_max_bufsize(cam));
+		cam->frame[0].buffer = NULL;
+	}
+
+	cam->nbuffers = 0;
+
+	DBG(5, "Memory successfully deallocated.")
+}
+
+
+/*--------------------------------------------------------------------------
+  Allocate memory buffers for USB transfers and video frames.
+  This function is called by open() only.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_allocate_memory(struct w9968cf_device* cam)
+{
+	const unsigned long bufsize = w9968cf_get_max_bufsize(cam);
+	const u16 p_size = wMaxPacketSize[cam->altsetting-1];
+	void* buff = NULL;
+	u8 i;
+
+	/* NOTE: Deallocation is done elsewhere in case of error */
+
+	/* Allocate memory for the isochronous transfer buffers */
+	for (i = 0; i < W9968CF_URBS; i++) {
+		if (!(cam->transfer_buffer[i] =
+		      kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
+			DBG(1, "Couldn't allocate memory for the isochronous "
+			       "transfer buffers (%d bytes).", 
+			    p_size * W9968CF_ISO_PACKETS)
+			return -ENOMEM;
+		}
+		memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size);
+	}
+
+	/* Allocate memory for the temporary frame buffer */
+	if (!(cam->frame_tmp.buffer = rvmalloc(W9968CF_HW_BUF_SIZE))) {
+		DBG(1, "Couldn't allocate memory for the temporary "
+		       "video frame buffer (%i bytes).", W9968CF_HW_BUF_SIZE)
+		return -ENOMEM;
+	}
+
+	/* Allocate memory for the helper buffer */
+	if (w9968cf_vppmod_present) {
+		if (!(cam->vpp_buffer = rvmalloc(bufsize))) {
+			DBG(1, "Couldn't allocate memory for the helper buffer"
+			       " (%li bytes).", bufsize)
+			return -ENOMEM;
+		}
+	} else
+		cam->vpp_buffer = NULL;
+
+	/* Allocate memory for video frame buffers */	
+	cam->nbuffers = cam->max_buffers;
+	while (cam->nbuffers >= 2) {
+		if ((buff = rvmalloc(cam->nbuffers * bufsize)))
+			break;
+		else
+			cam->nbuffers--;
+	}
+
+	if (!buff) {
+		DBG(1, "Couldn't allocate memory for the video frame buffers.")
+		cam->nbuffers = 0;
+		return -ENOMEM;
+	}
+
+	if (cam->nbuffers != cam->max_buffers)
+		DBG(2, "Couldn't allocate memory for %d video frame buffers. "
+		       "Only memory for %d buffers has been allocated.",
+		    cam->max_buffers, cam->nbuffers)
+
+	for (i = 0; i < cam->nbuffers; i++) {
+		cam->frame[i].buffer = buff + i*bufsize;
+		/* Circular list */
+		if (i != cam->nbuffers-1)
+			cam->frame[i].next = &cam->frame[i+1];
+		else
+			cam->frame[i].next = &cam->frame[0];
+		cam->frame[i].status = F_UNUSED;
+	}
+
+	DBG(5, "Memory successfully allocated.")
+	return 0;
+}
+
+
+
+/****************************************************************************
+ * /proc interface                                                          *
+ ****************************************************************************/
+
+#if defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry* w9968cf_proc_entry, * w9968cf_proc_entry_global;
+extern struct proc_dir_entry* video_proc_entry;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+/*--------------------------------------------------------------------------
+  Read /proc/video/w9968cf/global 
+  --------------------------------------------------------------------------*/
+static int 
+w9968cf_proc_read_global(char* page, char** start, off_t offset,
+                         int count, int* eof, void* data)
+{
+	struct list_head *list = (struct list_head*)data, *ptr;
+	struct w9968cf_device* cam;
+	char* out = page;
+	int len;
+	u8 ncams = 0;
+
+	if (down_interruptible(&w9968cf_devlist_sem))
+		return -ERESTARTSYS;
+
+	/* How many connected cameras ? */
+	list_for_each(ptr, list)
+		ncams++;
+
+	out += sprintf(out,"driver_name       : %s\n", W9968CF_MODULE_NAME);
+	out += sprintf(out,"driver_version    : %s\n", W9968CF_MODULE_VERSION);
+	out += sprintf(out,"driver_author     : %s\n", W9968CF_MODULE_AUTHOR);
+	out += sprintf(out,"author_email      : %s\n", W9968CF_AUTHOR_EMAIL);
+	out += sprintf(out,"vpp_w9968cf_module: %s\n",
+	               w9968cf_vppmod_present ? "detected" : "not detected");
+	out += sprintf(out,"max_allowed_cams  : %d\n", simcams);
+	out += sprintf(out,"registered_cameras: %d\n", ncams);
+
+	list_for_each(ptr, list) {
+		cam = list_entry(ptr, struct w9968cf_device, v4llist);
+		out += sprintf(out,"/dev/video%d       : %s\n", 
+		               cam->v4ldev.minor, symbolic(camlist, cam->id));
+	}
+
+	up(&w9968cf_devlist_sem);
+
+	len = out - page;
+	len -= offset;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	} else
+		len = count;
+
+	*start = page + offset;
+
+	return len;
+}
+
+
+/*--------------------------------------------------------------------------
+  Read /proc/video/w9968cf/dev<minor#>
+  --------------------------------------------------------------------------*/
+static int 
+w9968cf_proc_read_dev(char* page, char** start, off_t offset,
+                      int count, int* eof, void* data)
+{
+	struct w9968cf_device* cam = (struct w9968cf_device* )data;
+	int len;
+	char* out = page;
+
+	static struct video_picture pict; /* it has to be static */
+	static int rc = 0;
+
+	if (down_interruptible(&cam->procfs_sem))
+		return -ERESTARTSYS;
+
+	if (offset == 0)
+		rc = w9968cf_sensor_get_picture(cam, &pict);
+
+	out += sprintf(out,"camera_model      : %s\n",
+	               symbolic(camlist, cam->id));
+	out += sprintf(out,"sensor_model      : %s\n",
+	               symbolic(senlist, cam->sensor));
+	out += sprintf(out,"sensor_monochrome : %s\n",
+	               YES_NO(cam->sensor_mono));
+	if (cam->users)
+		out += sprintf(out,"user_program      : %s\n",cam->command);
+	out += sprintf(out,"packet_size_bytes : %d\n", 
+	               wMaxPacketSize[cam->altsetting-1]);
+	out += sprintf(out,"allocated_buffers : %d\n",cam->nbuffers);
+	out += sprintf(out,"streaming         : %s\n",YES_NO(cam->streaming));
+	out += sprintf(out,"compression       : %s\n",
+	               YES_NO(cam->vpp_flag & VPP_DECOMPRESSION));
+	out += sprintf(out,"uyvy_to_rgbx      : %s\n",
+	               YES_NO(cam->vpp_flag & VPP_UYVY_TO_RGBX));
+	out += sprintf(out,"uv-y_reordering   : %s\n", 
+	               YES_NO(cam->vpp_flag & VPP_SWAP_YUV_BYTES));
+	out += sprintf(out,"software_upscaling: %s\n",
+	               YES_NO(cam->vpp_flag & VPP_UPSCALE));
+	out += sprintf(out,"clock_divisor     : %d\n",cam->clockdiv);
+	out += sprintf(out,"palette           : %s\n", 
+	               symbolic(v4l1_plist, cam->picture.palette));
+	out += sprintf(out,"depth_bpp         : %d\n",cam->picture.depth);
+	out += sprintf(out,"x_window_offset   : %d\n",cam->window.x);
+	out += sprintf(out,"y_window_offset   : %d\n",cam->window.y);	
+	out += sprintf(out,"width             : %d\n",cam->window.width);
+	out += sprintf(out,"height            : %d\n",cam->window.height);
+	out += sprintf(out,"max_buffers       : %d\n",cam->max_buffers);
+	out += sprintf(out,"decompression     : %s\n",
+	               (!cam->decompression)? "off" :
+	               ((cam->decompression == 1) ? "force" : "on"));
+	out += sprintf(out,"force_rgb         : %s\n",YES_NO(cam->force_rgb));
+	out += sprintf(out,"video_clamping    : %s\n",YES_NO(cam->clamping));
+	out += sprintf(out,"hw_double_buffer  : %s\n",
+	               YES_NO(cam->double_buffer));
+	out += sprintf(out,"filter_type       : %s\n",
+	               (!cam->filter_type) ? "none" : 
+	               ((cam->filter_type == 1) ? "3-tap" : "5-tap"));
+	out += sprintf(out,"large_view        : %s\n",YES_NO(cam->largeview));
+	out += sprintf(out,"auto_brightness   : %s\n",YES_NO(cam->auto_brt));
+	out += sprintf(out,"auto_exposure     : %s\n",YES_NO(cam->auto_exp));
+	out += sprintf(out,"light_frequency   : %d\n",cam->lightfreq);
+	out += sprintf(out,"banding_filter    : %s\n",YES_NO(cam->bandfilt));
+	out += sprintf(out,"back_light        : %s\n",YES_NO(cam->backlight));
+	out += sprintf(out,"mirror            : %s\n",YES_NO(cam->mirror));
+	if (!rc) {
+		out += sprintf(out,"brightness        : %d\n",pict.brightness);
+		out += sprintf(out,"colour            : %d\n",pict.colour);
+		out += sprintf(out,"contrast          : %d\n",pict.contrast);
+		out += sprintf(out,"hue               : %d\n",pict.hue);
+		out += sprintf(out,"whiteness         : %d\n",pict.whiteness);
+	}
+	out += sprintf(out,"hs_polarity       : %d\n",cam->hs_polarity);
+	out += sprintf(out,"vs_polarity       : %d\n",cam->vs_polarity);
+#ifdef W9968CF_DEBUG
+	out += sprintf(out,"debug_level       : %d\n",debug);
+	out += sprintf(out,"specific_debug    : %s\n",YES_NO(specific_debug));
+#endif
+
+	len = out - page;
+	len -= offset;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) {
+			up(&cam->procfs_sem);
+			return 0;
+		}
+	} else
+		len = count;
+
+	*start = page + offset;
+
+	up(&cam->procfs_sem);
+	return len;
+}
+
+
+static void w9968cf_proc_create_dev(struct w9968cf_device* cam)
+{
+	char name[5];
+
+	if (!w9968cf_proc_entry)
+		return;
+
+	/* Create per-device readable entry */
+	sprintf(name, "dev%d", cam->v4ldev.minor);
+	cam->proc_dev = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, 
+	                                       w9968cf_proc_entry,
+	                                       w9968cf_proc_read_dev,
+	                                       (void*)cam);
+	if (!cam->proc_dev)
+		return;
+	cam->proc_dev->owner = THIS_MODULE;
+}
+
+
+static void w9968cf_proc_destroy_dev(struct w9968cf_device* cam)
+{
+	char name[5];
+
+	if (!cam->proc_dev)
+		return;
+
+	sprintf(name, "dev%d", cam->v4ldev.minor);
+
+	/* Destroy per-device entry */
+	remove_proc_entry(name, w9968cf_proc_entry);
+}
+
+
+static void w9968cf_proc_create(void)
+{
+	if (!video_proc_entry) {
+		DBG(2, "Error: /proc/video/ does not exist.")
+		return;
+	}
+
+	w9968cf_proc_entry = create_proc_entry("w9968cf", S_IFDIR,
+	                                       video_proc_entry);
+	if (!w9968cf_proc_entry) {
+		DBG(2, "Unable to create /proc/video/w9968cf/")
+		return;
+	}
+	w9968cf_proc_entry->owner = THIS_MODULE;
+
+	w9968cf_proc_entry_global = create_proc_read_entry("global", 
+	                                             S_IFREG|S_IRUGO|S_IWUSR,
+	                                             w9968cf_proc_entry,
+	                                             w9968cf_proc_read_global, 
+	                                             (void*)&w9968cf_dev_list);
+	if (w9968cf_proc_entry_global)
+		w9968cf_proc_entry_global->owner = THIS_MODULE;
+	else
+		DBG(2, "Unable to create /proc/video/w9968cf/global")
+
+	DBG(5, "/proc entries successfully created.")
+}
+
+
+static void w9968cf_proc_destroy(void)
+{
+	if (!w9968cf_proc_entry)
+		return;
+
+	if (w9968cf_proc_entry_global)
+		remove_proc_entry("global", w9968cf_proc_entry);
+
+	remove_proc_entry("w9968cf", video_proc_entry);
+
+	DBG(5, "/proc entries removed.")
+}
+
+#endif /* CONFIG_VIDEO_PROC_FS */
+
+
+
+/****************************************************************************
+ * USB-specific functions                                                   *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  This is an handler function which is called after the URBs are completed.
+  It collects multiple data packets coming from the camera by putting them
+  into frame buffers: one or more zero data length data packets are used to
+  mark the end of a video frame; the first non-zero data packet is the start
+  of the next video frame; if an error is encountered in a packet, the entire
+  video frame is discarded and grabbed again.
+  If there are no requested frames in the FIFO list, packets are collected into
+  a temporary buffer. 
+  --------------------------------------------------------------------------*/
+static void w9968cf_urb_complete(struct urb *urb)
+{
+	struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
+	struct w9968cf_frame_t** f;
+	unsigned long maxbufsize;
+	unsigned int len, status;
+	void* pos;
+	u8 i;
+	int err = 0;
+
+	if ((!cam->streaming) || cam->disconnected) {
+		DBG(4, "Got interrupt, but not streaming.")
+		return;
+	}
+
+	maxbufsize = min( (unsigned long)W9968CF_HW_BUF_SIZE, 
+	                  w9968cf_get_max_bufsize(cam) );
+
+	/* "(*f)" will be used instead of "cam->frame_current" */
+	f = &cam->frame_current;
+
+	/* If a frame has been requested and we are grabbing into  
+	   the temporary frame, we'll switch to that requested frame */
+	if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
+		if (cam->frame_tmp.status == F_GRABBING) {
+			w9968cf_pop_frame(cam, &cam->frame_current);
+			(*f)->status = F_GRABBING;
+			(*f)->length = cam->frame_tmp.length;
+			memcpy((*f)->buffer, cam->frame_tmp.buffer,
+			       (*f)->length);
+			DBG(6, "Switched from temp. frame to frame #%d", 
+			    (*f) - &cam->frame[0])
+		}
+	}
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		len    = urb->iso_frame_desc[i].actual_length;
+		status = urb->iso_frame_desc[i].status;
+		pos    = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+		if (status && len != 0) {
+			DBG(4, "URB failed, error in data packet "
+			       "(error #%d, %s).",
+			    status, symbolic(urb_errlist, status))
+			(*f)->status = F_ERROR;
+			continue;
+		}
+
+		if (len) { /* start of frame */
+
+			if ((*f)->status == F_UNUSED) {
+				(*f)->status = F_GRABBING;
+				(*f)->length = 0;
+			}
+
+			/* Buffer overflows shouldn't happen, however...*/
+			if ((*f)->length + len > maxbufsize) {
+				DBG(4, "Buffer overflow: bad data packets.")
+				(*f)->status = F_ERROR;
+			}
+
+			if ((*f)->status == F_GRABBING) {
+				memcpy((*f)->buffer + (*f)->length, pos, len);
+				(*f)->length += len;
+			}
+
+		} else if ((*f)->status == F_GRABBING) { /* end of frame */
+
+			DBG(6, "Frame #%d successfully grabbed.",
+			    ((*f)==&cam->frame_tmp ? -1 : (*f)-&cam->frame[0]))
+
+			if (cam->vpp_flag & VPP_DECOMPRESSION) {
+				err=(*w9968cf_vpp_check_headers)((*f)->buffer,
+				                                 (*f)->length);
+				if (err) {
+					DBG(4, "Skip corrupted frame: %s",
+					    symbolic(decoder_errlist, err))
+					(*f)->status = F_UNUSED;
+					continue; /* grab this frame again */
+				}
+			}
+
+			(*f)->status = F_READY;
+			(*f)->queued = 0;
+
+			/* Take a pointer to the new frame from the FIFO list.
+			   If the list is empty,we'll use the temporary frame*/
+			if (*cam->requested_frame)
+				w9968cf_pop_frame(cam, &cam->frame_current);
+			else {
+				cam->frame_current = &cam->frame_tmp;
+				(*f)->status = F_UNUSED;
+			}
+
+		} else if ((*f)->status == F_ERROR)
+			(*f)->status = F_UNUSED; /* grab it again */
+
+		PDBGG("Frame length %li | pack.#%d | pack.len. %d | state %d",
+		      (unsigned long)(*f)->length, i, len, (*f)->status)
+
+	} /* end for */
+
+	/* Resubmit this URB */
+	urb->dev = cam->usbdev;
+	urb->status = 0;
+	spin_lock(&cam->urb_lock);
+	if (cam->streaming)
+		if ((err = usb_submit_urb(urb))) {
+			cam->misconfigured = 1;
+			DBG(1, "Couldn't resubmit the URB: error %d, %s",
+			    err, symbolic(urb_errlist, err));
+		}
+	spin_unlock(&cam->urb_lock);
+
+	/* Wake up the user process */
+	if (waitqueue_active(&cam->wait_queue))
+		wake_up_interruptible(&cam->wait_queue);
+}
+
+
+/*---------------------------------------------------------------------------
+  Setup the URB structures for the isochronous transfer.
+  Submit the URBs so that the data transfer begins.
+  Return 0 on success, a negative number otherwise.
+  ---------------------------------------------------------------------------*/
+static int w9968cf_start_transfer(struct w9968cf_device* cam)
+{
+	struct usb_device *udev = cam->usbdev;
+	struct urb* urb;
+	const u16 p_size = wMaxPacketSize[cam->altsetting-1];
+	u16 w, h, d;
+	int vidcapt;
+	u32 t_size;
+	int err = 0;
+	s8 i, j;
+
+	for (i = 0; i < W9968CF_URBS; i++) {
+		urb = usb_alloc_urb(W9968CF_ISO_PACKETS);
+		cam->urb[i] = urb;
+
+		if (!urb) {
+			for (j = 0; j < i; j++)
+				usb_free_urb(cam->urb[j]);
+			DBG(1, "Couldn't allocate the URB structures.")
+			return -ENOMEM;
+		}
+
+		urb->dev = udev;
+		urb->context = (void*)cam;
+		urb->pipe = usb_rcvisocpipe(udev, 1);
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->number_of_packets = W9968CF_ISO_PACKETS;
+		urb->complete = w9968cf_urb_complete;
+		urb->transfer_buffer = cam->transfer_buffer[i];
+		urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
+		urb->interval = 1;
+		for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
+			urb->iso_frame_desc[j].offset = p_size*j;
+			urb->iso_frame_desc[j].length = p_size;
+		}
+	}
+
+	/* Transfer size per frame, in WORD ! */
+	d = cam->hw_depth;
+	w = cam->hw_width;
+	h = cam->hw_height;
+
+	t_size = (w*h*d)/16;
+
+	err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset  everything */
+	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
+
+	/* Transfer size */
+	err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
+	err += w9968cf_write_reg(cam, t_size >> 16, 0x3e);    /* high bits */
+
+	if (cam->vpp_flag & VPP_DECOMPRESSION)
+		err += w9968cf_upload_quantizationtables(cam);
+
+	vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
+	err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
+
+	err += usb_set_interface(udev, 0, cam->altsetting);
+	err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
+
+	if (err || (vidcapt < 0)) {
+		for (i = 0; i < W9968CF_URBS; i++)
+			usb_free_urb(cam->urb[i]);
+		DBG(1, "Couldn't tell the camera to start the data transfer.")
+		return err;
+	}
+
+	w9968cf_init_framelist(cam);
+
+	/* Begin to grab into the temporary buffer */
+	cam->frame_tmp.status = F_UNUSED;
+	cam->frame_tmp.queued = 0;
+	cam->frame_current = &cam->frame_tmp;
+
+	if (!(cam->vpp_flag & VPP_DECOMPRESSION))
+		DBG(5, "Isochronous transfer size: %li bytes/frame.",
+		    (unsigned long)t_size*2)
+
+	DBG(5, "Starting the isochronous transfer...")
+
+	/* Submit the URBs */
+	for (i = 0; i < W9968CF_URBS; i++) {
+		err = usb_submit_urb(cam->urb[i]);
+		if (err) {
+			for (j = i-1; j >= 0; j--)
+				if (!usb_unlink_urb(cam->urb[j]))
+					usb_free_urb(cam->urb[j]);
+			DBG(1, "Couldn't send a transfer request to the "
+			       "USB core (error #%d, %s).", err, 
+			    symbolic(urb_errlist, err))
+		}
+	}
+
+	cam->streaming = 1;
+
+	return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_stop_transfer(struct w9968cf_device* cam)
+{
+	struct usb_device *udev = cam->usbdev;
+	unsigned long lock_flags;
+	int err = 0;
+	s8 i;
+
+	/* This avoids race conditions with usb_submit_urb() 
+	   in the URB completition handler */
+	spin_lock_irqsave(&cam->urb_lock, lock_flags);
+	cam->streaming = 0;
+	spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
+
+	for (i = W9968CF_URBS-1; i >= 0; i--)
+		if (cam->urb[i])
+			if (!usb_unlink_urb(cam->urb[i])) {
+				usb_free_urb(cam->urb[i]);
+				cam->urb[i] = NULL;
+			}
+
+	if (cam->disconnected)
+		goto exit;
+
+	err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
+	err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+	err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
+	err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
+
+	if (err) {
+		DBG(2, "Failed to tell the camera to stop the isochronous "
+		       "transfer. However this is not a critical error.")
+		return -EIO;
+	}
+
+exit:
+	DBG(5, "Isochronous transfer stopped.")
+	return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write a W9968CF register. 
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
+{
+	struct usb_device* udev = cam->usbdev;
+	int res;
+
+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+	                      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+	                      value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
+
+	if (res < 0)
+		DBG(4, "Failed to write a register "
+		       "(value 0x%04X, index 0x%02X, error #%d, %s).",
+		    value, index, res, symbolic(urb_errlist, res))
+
+	return (res >= 0) ? 0 : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Read a W9968CF register. 
+  Return the register value on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
+{
+	struct usb_device* udev = cam->usbdev;
+	u16* buff = cam->control_buffer;
+	int res;
+
+	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
+	                      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+	                      0, index, (void*)buff,
+	                      2, W9968CF_USB_CTRL_TIMEOUT);
+
+	if (res < 0)
+		DBG(4, "Failed to read a register "
+		       "(index 0x%02X, error #%d, %s).",
+		    index, res, symbolic(urb_errlist, res))
+
+	return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write data to the fast serial bus registers.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
+{
+	struct usb_device* udev = cam->usbdev;
+	u16 value;
+	int res;
+
+	value = *data++;
+
+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+	                      USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+	                      value, 0x06, (void*)data, 6,
+	                      W9968CF_USB_CTRL_TIMEOUT);
+
+	if (res < 0)
+		DBG(4, "Failed to write the FSB registers "
+		       "(error #%d, %s).", res, symbolic(urb_errlist, res))
+
+	return (res >= 0) ? 0 : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write data to the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
+{
+	int err = 0;
+
+	err = w9968cf_write_reg(cam, value, 0x01);
+	udelay(W9968CF_I2C_BUS_DELAY);
+
+	return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Read data from the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_read_sb(struct w9968cf_device* cam)
+{
+	int v = 0;
+
+	v = w9968cf_read_reg(cam, 0x01);
+	udelay(W9968CF_I2C_BUS_DELAY);
+
+	return v;
+}
+
+
+/*--------------------------------------------------------------------------
+  Upload quantization tables for the JPEG compression.
+  This function is called by w9968cf_start_transfer().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
+{
+	u16 a, b;
+	int err = 0, i, j;
+
+	err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
+
+	for (i = 0, j = 0; i < 32; i++, j += 2) {
+		a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
+		b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
+		err += w9968cf_write_reg(cam, a, 0x40+i);
+		err += w9968cf_write_reg(cam, b, 0x60+i);
+	}
+	err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
+
+	return err;
+}
+
+
+
+/****************************************************************************
+ * Low-level I2C I/O functions.                                             *
+ * The adapter supports the following I2C transfer functions:               *
+ * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
+ * i2c_adap_read_byte_data()                                                *
+ * i2c_adap_read_byte()                                                     *
+ ****************************************************************************/
+
+static int w9968cf_smbus_start(struct w9968cf_device* cam)
+{
+	int err = 0;
+
+	err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+	err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+
+	return err;
+}
+
+
+static int w9968cf_smbus_stop(struct w9968cf_device* cam)
+{
+	int err = 0;
+
+	err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+	err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+
+	return err;
+}
+
+
+static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
+{
+	u8 bit;
+	int err = 0, sda;
+
+	for (bit = 0 ; bit < 8 ; bit++) {
+		sda = (v & 0x80) ? 2 : 0;
+		v <<= 1;
+		/* SDE=1, SDA=sda, SCL=0 */
+		err += w9968cf_write_sb(cam, 0x10 | sda);
+		/* SDE=1, SDA=sda, SCL=1 */
+		err += w9968cf_write_sb(cam, 0x11 | sda);
+		/* SDE=1, SDA=sda, SCL=0 */
+		err += w9968cf_write_sb(cam, 0x10 | sda);
+	}
+
+	return err;
+}
+
+
+static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
+{
+	u8 bit;
+	int err = 0;
+
+	*v = 0;
+	for (bit = 0 ; bit < 8 ; bit++) {
+		*v <<= 1;
+		err += w9968cf_write_sb(cam, 0x0013);
+		*v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
+		err += w9968cf_write_sb(cam, 0x0012);
+	}
+
+	return err;
+}
+
+
+static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
+{
+	int err = 0;
+
+	err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+	err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+	err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+
+	return err;
+}
+
+
+static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
+{
+	int err = 0, sda;
+
+	err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+	sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
+	err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+	if (sda < 0)
+		err += sda;
+	if (sda == 1) {
+		DBG(6, "Couldn't receive the ACK.")
+		err += -1;
+	}
+
+	return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
+static int 
+w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, 
+                                     u16 address, u8 subaddress,u8 value)
+{
+	u16* data = cam->data_buffer;
+	int err = 0;
+
+	 /* Enable SBUS outputs */
+	err += w9968cf_write_reg(cam, 0x0020, 0x01);
+
+	data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
+	data[0] |= (address & 0x40) ? 0x4000 : 0x0;
+	data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
+	data[1] |= (address & 0x20) ? 0x0150 : 0x0;
+	data[1] |= (address & 0x10) ? 0x5400 : 0x0;
+	data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
+	data[2] |= (address & 0x04) ? 0x0540 : 0x0;
+	data[2] |= (address & 0x02) ? 0x5000 : 0x0;
+	data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
+	data[3] |= (address & 0x01) ? 0x0054 : 0x0;
+
+	err += w9968cf_write_fsb(cam, data);
+
+	data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
+	data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
+	data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
+	data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
+	data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
+	data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
+	data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
+	data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
+	data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
+	data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
+	data[3] = 0x001d;
+
+	err += w9968cf_write_fsb(cam, data);
+
+	data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
+	data[0] |= (value & 0x40) ? 0x0540 : 0x0;
+	data[0] |= (value & 0x20) ? 0x5000 : 0x0;
+	data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
+	data[1] |= (value & 0x10) ? 0x0054 : 0x0;
+	data[1] |= (value & 0x08) ? 0x1500 : 0x0;
+	data[1] |= (value & 0x04) ? 0x4000 : 0x0;
+	data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
+	data[2] |= (value & 0x02) ? 0x0150 : 0x0;
+	data[2] |= (value & 0x01) ? 0x5400 : 0x0;
+	data[3] = 0xfe1d;
+
+	err += w9968cf_write_fsb(cam, data);
+
+	/* Disable SBUS outputs */
+	err += w9968cf_write_reg(cam, 0x0000, 0x01);
+
+	if (!err)
+		DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
+		       "value 0x%02X.", address, subaddress, value)
+	else
+		DBG(5, "I2C write byte data failed, addr.0x%04X, "
+		       "subaddr.0x%02X, value 0x%02X.", 
+	            address, subaddress, value)
+
+	return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
+static int 
+w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, 
+                                u16 address, u8 subaddress, 
+                                u8* value)
+{
+	int err = 0;
+
+	/* Serial data enable */
+	err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
+
+	err += w9968cf_smbus_start(cam);
+	err += w9968cf_smbus_write_byte(cam, address);
+	err += w9968cf_smbus_read_ack(cam);
+	err += w9968cf_smbus_write_byte(cam, subaddress);
+	err += w9968cf_smbus_read_ack(cam);
+	err += w9968cf_smbus_stop(cam);
+	err += w9968cf_smbus_start(cam);
+	err += w9968cf_smbus_write_byte(cam, address + 1);
+	err += w9968cf_smbus_read_ack(cam);
+	err += w9968cf_smbus_read_byte(cam, value);
+	err += w9968cf_smbus_write_ack(cam);
+	err += w9968cf_smbus_stop(cam);
+ 
+	/* Serial data disable */
+	err += w9968cf_write_sb(cam, 0x0000);
+
+	if (!err)
+		DBG(5, "I2C read byte data done, addr.0x%04X, "
+		       "subaddr.0x%02X, value 0x%02X.", 
+		    address, subaddress, *value)
+	else
+		DBG(5, "I2C read byte data failed, addr.0x%04X, "
+		       "subaddr.0x%02X, wrong value 0x%02X.",
+		    address, subaddress, *value)
+
+	return err;
+}
+
+
+/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
+static int 
+w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
+                           u16 address, u8* value)
+{
+	int err = 0;
+
+	/* Serial data enable */
+	err += w9968cf_write_sb(cam, 0x0013);
+
+	err += w9968cf_smbus_start(cam);
+	err += w9968cf_smbus_write_byte(cam, address + 1);
+	err += w9968cf_smbus_read_ack(cam);
+	err += w9968cf_smbus_read_byte(cam, value);
+	err += w9968cf_smbus_write_ack(cam);
+	err += w9968cf_smbus_stop(cam);
+ 
+	/* Serial data disable */
+	err += w9968cf_write_sb(cam, 0x0000);
+
+	if (!err)
+		DBG(5, "I2C read byte done, addr.0x%04X."
+		       "value 0x%02X.", address, *value)
+	else
+		DBG(5, "I2C read byte failed, addr.0x%04X."
+		       "wrong value 0x%02X.", address, *value)
+
+	return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Value [A] P */
+static int 
+w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
+                            u16 address, u8 value)
+{
+	DBG(4, "i2c_write_byte() is an unsupported transfer mode.")
+	return -EINVAL;
+}
+
+
+
+/****************************************************************************
+ * I2C interface to kernel                                                  *
+ ****************************************************************************/
+
+static int
+w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 
+                       unsigned short flags, char read_write, u8 command,
+                       int size, union i2c_smbus_data *data)
+{
+	struct w9968cf_device* cam = adapter->data;
+	u8 i, j;
+	int rc = 0, err = 0; 
+
+	switch (addr) {
+		case OV6xx0_SID:
+		case OV7xx0_SID:
+			break;
+		default:
+			DBG(4, "Rejected slave ID 0x%04X", addr)
+			return -EINVAL;
+	}
+
+	if (size == I2C_SMBUS_BYTE) {
+		/* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
+		addr <<= 1;
+
+		if (read_write == I2C_SMBUS_WRITE)
+ 			rc = w9968cf_i2c_adap_write_byte(cam, addr, command);
+		else if (read_write == I2C_SMBUS_READ) 
+			rc = w9968cf_i2c_adap_read_byte(cam,addr, &data->byte);
+
+	} else if (size == I2C_SMBUS_BYTE_DATA) {
+		addr <<= 1;
+
+		if (read_write == I2C_SMBUS_WRITE)
+ 			rc = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
+			                                  command, data->byte);
+		else if (read_write == I2C_SMBUS_READ) {
+			for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+				rc = w9968cf_i2c_adap_read_byte_data(cam, addr, 
+				                         command, &data->byte);
+				if (rc < 0) {
+					/* Work around: this seems to wake up  
+					   the EEPROM from the stall state */
+					for (j = 0; j <= 10; j++) {
+					   err += w9968cf_write_sb(cam,0x0020);
+					   err += w9968cf_write_sb(cam,0x0000);
+					   if (err)
+					   	break;
+					}
+				}
+				else
+					break;
+			}
+
+		} else
+			return -EINVAL;
+
+	} else {
+		DBG(4, "Unsupported I2C transfer mode (%d)", size)
+		return -EINVAL;
+	}
+
+	/* This works around a bug in the I2C core */
+	if (rc > 0)
+		rc = 0;
+
+	return rc;
+}
+
+
+static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
+{
+	return I2C_FUNC_SMBUS_READ_BYTE |
+	       I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+	       I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+
+static int w9968cf_i2c_attach_inform(struct i2c_client* client)
+{
+	struct w9968cf_device* cam = client->adapter->data;
+	const char* clientname = client->name;
+	int id = client->driver->id;
+
+	if (id == I2C_DRIVERID_OVCAMCHIP) {
+		int rc = 0;
+
+		cam->sensor_client = client;
+
+		rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, 
+		                        &cam->sensor_mono);
+		if (rc < 0) {
+			DBG(1, "CMOS sensor initialization failed (rc=%d)",rc);
+			cam->sensor_client = NULL;
+			return rc;
+		}
+
+		if (w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, 
+		                       &cam->sensor) < 0)
+			rc = -EIO;
+		else if (client->addr==OV7xx0_SID || client->addr==OV6xx0_SID)
+			w9968cf_sensor_configure(cam);
+		else
+			rc = -EINVAL;
+
+		if (rc < 0) {
+			cam->sensor_client = NULL;
+			cam->sensor = CC_UNKNOWN;
+			return rc;
+		}
+	} else	{
+		DBG(4, "Rejected client [%s] with [%s]", 
+		    clientname, client->driver->name)
+		return -1;
+	}
+
+	DBG(2, "I2C attach client [%s] with [%s]",
+	    clientname, client->driver->name)
+
+	return 0;
+}
+
+
+static int w9968cf_i2c_detach_inform(struct i2c_client* client)
+{
+	struct w9968cf_device* cam = client->adapter->data;
+	const char* clientname = client->name;
+
+	if (cam->sensor_client == client) {
+		cam->sensor_client = NULL;
+	}
+
+	DBG(2, "I2C detach [%s]", clientname)
+
+	return 0;
+}
+
+
+static int 
+w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
+                    unsigned long arg)
+{
+	return 0;
+}
+
+
+static void w9968cf_i2c_inc_use(struct i2c_adapter* adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+
+static void w9968cf_i2c_dec_use(struct i2c_adapter* adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+
+static int w9968cf_i2c_init(struct w9968cf_device* cam)
+{
+	int rc = 0;
+
+	static struct i2c_algorithm algo = {
+		.name =          "W996[87]CF algorithm",
+		.id =            I2C_ALGO_SMBUS,
+		.smbus_xfer =    w9968cf_i2c_smbus_xfer,
+		.algo_control =  w9968cf_i2c_control,
+		.functionality = w9968cf_i2c_func,
+	};
+
+	static struct i2c_adapter adap = {
+		.id =                I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF,
+		.inc_use =           w9968cf_i2c_inc_use,
+		.dec_use =           w9968cf_i2c_dec_use,
+		.client_register =   w9968cf_i2c_attach_inform,
+		.client_unregister = w9968cf_i2c_detach_inform,
+		.algo =              &algo,
+	};
+
+	memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
+	strcpy(cam->i2c_adapter.name, "w9968cf");
+	cam->i2c_adapter.data = cam;
+
+	DBG(6, "Registering I2C bus with kernel...")
+
+	rc = i2c_add_adapter(&cam->i2c_adapter);
+	if (rc)
+		DBG(5, "Failed to register the I2C bus.")
+	else
+		DBG(5, "I2C bus registered.")
+
+	return rc;
+}
+
+
+
+/****************************************************************************
+ * Helper functions                                                         *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  Turn on the LED on some webcams. A beep should be heard too.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_turn_on_led(struct w9968cf_device* cam)
+{
+	int err = 0;
+
+	err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
+	err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
+	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
+	err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
+	err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
+	err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
+
+	if (err)
+		DBG(2, "Couldn't turn on the LED.")
+
+	DBG(5, "LED turned on.")
+
+	return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write some registers for the device initialization.
+  This function is called once on open().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_init_chip(struct w9968cf_device* cam)
+{
+	int err = 0, rc = 0;
+
+	err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
+	err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
+
+	err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
+	err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
+
+	err += w9968cf_write_reg(cam, 0x0000, 0x20); /* Y frame buf.0, low */
+	err += w9968cf_write_reg(cam, 0x0000, 0x21); /* Y frame buf.0, high */
+	err += w9968cf_write_reg(cam, 0xb000, 0x22); /* Y frame buf.1, low */
+	err += w9968cf_write_reg(cam, 0x0004, 0x23); /* Y frame buf.1, high */
+	err += w9968cf_write_reg(cam, 0x5800, 0x24); /* U frame buf.0, low */
+	err += w9968cf_write_reg(cam, 0x0002, 0x25); /* U frame buf.0, high */
+	err += w9968cf_write_reg(cam, 0x0800, 0x26); /* U frame buf.1, low */
+	err += w9968cf_write_reg(cam, 0x0007, 0x27); /* U frame buf.1, high */
+	err += w9968cf_write_reg(cam, 0x8400, 0x28); /* V frame buf.0, low */
+	err += w9968cf_write_reg(cam, 0x0003, 0x29); /* V frame buf.0, high */
+	err += w9968cf_write_reg(cam, 0x3400, 0x2a); /* V frame buf.1, low */
+	err += w9968cf_write_reg(cam, 0x0008, 0x2b); /* V frame buf.1, high */
+
+	err += w9968cf_write_reg(cam, 0x6000, 0x32); /* JPEG bitstream buf 0 */
+	err += w9968cf_write_reg(cam, 0x0009, 0x33); /* JPEG bitstream buf 0 */
+	err += w9968cf_write_reg(cam, 0x2000, 0x34); /* JPEG bitstream buf 1 */
+	err += w9968cf_write_reg(cam, 0x000d, 0x35); /* JPEG bitstream buf 1 */
+
+	err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
+	err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
+	err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
+	err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
+
+	err += w9968cf_set_picture(cam, cam->picture); /* this before */
+	err += w9968cf_set_window(cam, cam->window);
+
+	if (err)
+		goto error;
+
+	rc = w9968cf_sensor_change_settings(cam);
+	if (rc)
+		goto error;
+
+	DBG(5, "Chip successfully initialized.");
+	
+	return 0;
+
+error:
+	DBG(1, "Chip initialization failed.")
+	if (err)
+		return err;
+	else
+		return rc;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change the picture settings of the camera.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
+{
+	u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
+	int err = 0, rc = 0;
+
+	/* Make sure we are using a valid depth */
+	pict.depth = w9968cf_valid_depth(pict.palette);
+
+	fmt = pict.palette;
+
+	hw_depth = pict.depth; /* depth used by the winbond chip */
+	hw_palette = pict.palette; /* palette used by the winbond chip */
+
+	/* VS & HS polarities */
+	reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
+
+	switch (fmt)
+	{
+		case VIDEO_PALETTE_UYVY:
+			reg_v |= 0x0000;
+			cam->vpp_flag = VPP_NONE;
+			break;
+		case VIDEO_PALETTE_YUV422P:
+			reg_v |= 0x0002;
+			cam->vpp_flag = VPP_DECOMPRESSION;
+			break;
+		case VIDEO_PALETTE_YUV420:
+		case VIDEO_PALETTE_YUV420P:
+			reg_v |= 0x0003;
+			cam->vpp_flag = VPP_DECOMPRESSION;
+			break;
+		case VIDEO_PALETTE_YUYV:
+		case VIDEO_PALETTE_YUV422:
+			reg_v |= 0x0000;
+			cam->vpp_flag = VPP_SWAP_YUV_BYTES;
+			hw_palette = VIDEO_PALETTE_UYVY;
+			break;
+		/* Original video is used instead of RGBX palettes. 
+		   Software conversion later. */
+		case VIDEO_PALETTE_GREY:
+		case VIDEO_PALETTE_RGB555:
+		case VIDEO_PALETTE_RGB565:
+		case VIDEO_PALETTE_RGB24:
+		case VIDEO_PALETTE_RGB32:
+			reg_v |= 0x0000; /* UYVY 16 bit is used */
+			hw_depth = 16;
+			hw_palette = VIDEO_PALETTE_UYVY;
+			cam->vpp_flag = VPP_UYVY_TO_RGBX;
+			break;
+	}
+
+	/* FIXME: 'hardware double buffer' doesn't work when compressed video
+	          is enabled (corrupted frames). */
+	if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
+		reg_v |= 0x0080;
+
+	if (cam->clamping)
+		reg_v |= 0x0020;
+
+	if (cam->filter_type == 1)
+		reg_v |= 0x0008;
+	else if (cam->filter_type == 2)
+		reg_v |= 0x000c;
+
+	err = w9968cf_write_reg(cam, reg_v, 0x16);
+	if (err)
+		goto error;
+
+	rc = w9968cf_sensor_set_picture(cam, pict);
+	if (rc)
+		goto error;
+
+	/* If all went well, update the device data structure */
+	memcpy(&cam->picture, &pict, sizeof(pict));
+	cam->hw_depth = hw_depth;
+	cam->hw_palette = hw_palette;
+
+	/* Settings changed, so we clear the frame buffers */
+	memset(cam->frame[0].buffer, 0, 
+	       cam->nbuffers*w9968cf_get_max_bufsize(cam));
+
+	DBG(4, "Palette is %s, depth is %d bpp.",
+	    symbolic(v4l1_plist, pict.palette), pict.depth)
+
+	return 0;
+
+error:
+	DBG(1, "Failed to change picture settings.")
+	if (err)
+		return err;
+	else 
+		return rc;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change the capture area size of the camera.
+  This function _must_ be called _after_ w9968cf_set_picture().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
+{
+	u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
+	unsigned long fw, fh;
+	struct ovcamchip_window s_win;
+	int err=0, rc=0;
+
+	/* Work around to avoid FP arithmetics */
+	#define __SC(x) ((x) << 10)
+	#define __UNSC(x) ((x) >> 10)
+
+	/* Make sure we are using a supported resolution */
+	if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, 
+	                                      (u16*)&win.height)))
+		goto error;
+
+	/* Scaling factors */
+	fw = __SC(win.width) / cam->maxwidth;
+	fh = __SC(win.height) / cam->maxheight;
+
+	/* Set up the width and height values used by the chip */
+	if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
+		cam->vpp_flag |= VPP_UPSCALE;
+		/* Calculate largest w,h mantaining the same w/h ratio */
+		w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
+		h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+		if (w < cam->minwidth) /* just in case */
+			w = cam->minwidth;
+		if (h < cam->minheight) /* just in case */
+			h = cam->minheight;
+	} else {
+		cam->vpp_flag &= ~VPP_UPSCALE;
+		w = win.width;
+		h = win.height;
+	}
+
+	/* x,y offsets of the cropped area */
+	scx = cam->start_cropx;
+	scy = cam->start_cropy;
+
+	/* Calculate cropped area manteining the right w/h ratio */
+	if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
+		cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
+		ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+	} else {
+		cw = w;
+		ch = h;
+	}
+
+	/* Setup the sensor window */
+	s_win.format = SENSOR_FORMAT;
+	s_win.width = cam->maxwidth;
+	s_win.height = cam->maxheight;
+	s_win.quarter = 0; /* full progressive video */
+
+	/* Center it */
+	s_win.x = (s_win.width - cw) / 2;
+	s_win.y = (s_win.height - ch) / 2;
+
+	/* Clock divisor */
+	if (cam->clockdiv >= 0)
+		s_win.clockdiv = cam->clockdiv; /* manual override */
+	else
+		switch (cam->sensor) {
+			case CC_OV6620:
+				s_win.clockdiv = 0;
+				break;
+			case CC_OV6630:
+				s_win.clockdiv = 0;
+				break;
+			case CC_OV76BE:
+			case CC_OV7610:
+			case CC_OV7620:
+				s_win.clockdiv = 0;
+				break;
+			default:
+				s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
+		}
+
+	/* We have to scale win.x and win.y offsets */	
+	if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
+	     || (cam->vpp_flag & VPP_UPSCALE) ) {
+		ax = __SC(win.x)/fw;
+		ay = __SC(win.y)/fh;
+	} else {
+		ax = win.x;
+		ay = win.y;
+	}
+
+	if ((ax + cw) > cam->maxwidth)
+		ax = cam->maxwidth - cw;
+
+	if ((ay + ch) > cam->maxheight)
+		ay = cam->maxheight - ch;
+
+	/* Adjust win.x, win.y */
+	if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
+	     || (cam->vpp_flag & VPP_UPSCALE) ) {
+		win.x = __UNSC(ax*fw);
+		win.y = __UNSC(ay*fh);
+	} else {
+		win.x = ax;
+		win.y = ay;
+	}
+
+	/* Offsets used by the chip */
+	x = ax + s_win.x;
+	y = ay + s_win.y;
+
+	/* Go ! */
+	if ((rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
+		goto error;
+
+	err += w9968cf_write_reg(cam, scx + x, 0x10);
+	err += w9968cf_write_reg(cam, scy + y, 0x11);
+	err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
+	err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
+	err += w9968cf_write_reg(cam, w, 0x14);
+	err += w9968cf_write_reg(cam, h, 0x15);
+
+	/* JPEG width & height */
+	err += w9968cf_write_reg(cam, w, 0x30);
+	err += w9968cf_write_reg(cam, h, 0x31);
+
+	/* Y & UV frame buffer strides (in WORD) */
+	if (cam->vpp_flag & VPP_DECOMPRESSION) {
+		err += w9968cf_write_reg(cam, w/2, 0x2c);
+		err += w9968cf_write_reg(cam, w/4, 0x2d);
+	} else
+		err += w9968cf_write_reg(cam, w, 0x2c);
+
+	if (err)
+		goto error;
+
+	/* If all went well, update the device data structure */
+	memcpy(&cam->window, &win, sizeof(win));
+	cam->hw_width = w;
+	cam->hw_height = h;
+
+	/* Settings changed, so we clear the frame buffers */
+	memset(cam->frame[0].buffer, 0, 
+	       cam->nbuffers*w9968cf_get_max_bufsize(cam));
+
+	DBG(4, "The capture area is %dx%d, Offset (x,y)=(%d,%d).", 
+	    win.width, win.height, win.x, win.y)
+
+	PDBGG("x=%d ,y=%d, w=%d, h=%d, ax=%d, ay=%d, s_win.x=%d, s_win.y=%d, "
+	      "cw=%d, ch=%d, win.x=%d ,win.y=%d, win.width=%d, win.height=%d",
+	      x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
+	      win.width, win.height)
+
+	return 0;
+
+error:
+	DBG(1, "Failed to change the capture area size.")
+	if (err)
+		return err;
+	else
+		return rc;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return non-zero if the palette is supported, 0 otherwise.
+  --------------------------------------------------------------------------*/
+static inline u16 w9968cf_valid_palette(u16 palette)
+{
+	u8 i = 0;
+	while (w9968cf_formatlist[i].palette != 0) {
+		if (palette == w9968cf_formatlist[i].palette)
+			return palette;
+		i++;
+	}
+	return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return the depth corresponding to the given palette.
+  Palette _must_ be supported !
+  --------------------------------------------------------------------------*/
+static inline u16 w9968cf_valid_depth(u16 palette)
+{
+	u8 i=0;
+	while (w9968cf_formatlist[i].palette != palette)
+		i++;
+
+	return w9968cf_formatlist[i].depth;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return non-zero if the format requires decompression, 0 otherwise.
+  --------------------------------------------------------------------------*/
+static inline u8 w9968cf_need_decompression(u16 palette)
+{
+	u8 i = 0;
+	while (w9968cf_formatlist[i].palette != 0) {
+		if (palette == w9968cf_formatlist[i].palette)
+			return w9968cf_formatlist[i].compression;
+		i++;
+	}
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------- 
+  Adjust the asked values for window width and height.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int 
+w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
+{
+	u16 maxw, maxh;
+
+	if ((*width < cam->minwidth) || (*height < cam->minheight))
+		return -ERANGE;
+
+	maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION)
+	       && w9968cf_vppmod_present ? W9968CF_MAX_WIDTH : cam->maxwidth;
+	maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION)
+	       && w9968cf_vppmod_present ? W9968CF_MAX_HEIGHT : cam->maxheight;
+
+	if (*width > maxw)
+		*width = maxw;
+	if (*height > maxh)
+		*height = maxh;
+
+	if (cam->vpp_flag & VPP_DECOMPRESSION) {
+		*width  &= ~15L; /* multiple of 16 */
+		*height &= ~15L;
+	}
+
+	PDBGG("Window size adjusted w=%d, h=%d ", *width, *height)
+
+	return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Initialize the FIFO list of requested frames.
+  --------------------------------------------------------------------------*/
+static void w9968cf_init_framelist(struct w9968cf_device* cam)
+{
+	u8 i;
+
+	for (i = 0; i < cam->nbuffers; i++) {
+		cam->requested_frame[i] = NULL;
+		cam->frame[i].queued = 0;
+		cam->frame[i].status = F_UNUSED;
+	}
+}
+
+
+/*--------------------------------------------------------------------------
+  Add a frame in the FIFO list of requested frames.
+  This function is called in process context.
+  --------------------------------------------------------------------------*/
+static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
+{
+	u8 f;
+	unsigned long lock_flags;
+
+	spin_lock_irqsave(&cam->flist_lock, lock_flags);
+
+	for (f=0; cam->requested_frame[f] != NULL; f++);
+	cam->requested_frame[f] = &cam->frame[f_num];
+	cam->frame[f_num].queued = 1;
+	cam->frame[f_num].status = F_UNUSED; /* clear the status */
+
+	spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
+
+	DBG(6, "Frame #%d pushed into the FIFO list. Position %d.", f_num, f)
+}
+
+
+/*--------------------------------------------------------------------------
+  Read, store and remove the first pointer in the FIFO list of requested
+  frames. This function is called in interrupt context.
+  --------------------------------------------------------------------------*/
+static void 
+w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
+{
+	u8 i;
+
+	spin_lock(&cam->flist_lock);
+
+	*framep = cam->requested_frame[0];
+
+	/* Shift the list of pointers */
+	for (i = 0; i < cam->nbuffers-1; i++)
+		cam->requested_frame[i] = cam->requested_frame[i+1];
+	cam->requested_frame[i] = NULL;
+
+	spin_unlock(&cam->flist_lock);
+
+	DBG(6,"Popped frame #%d from the list.",*framep-&cam->frame[0])
+}
+
+
+/*--------------------------------------------------------------------------
+  High-level video post-processing routine on grabbed frames.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int 
+w9968cf_postprocess_frame(struct w9968cf_device* cam, 
+                          struct w9968cf_frame_t* fr)
+{
+	void *pIn = fr->buffer, *pOut = cam->vpp_buffer, *tmp;
+	u16 w = cam->window.width,
+	    h = cam->window.height,
+	    d = cam->picture.depth,
+	    fmt = cam->picture.palette,
+	    rgb = cam->force_rgb,
+	    hw_w = cam->hw_width,
+	    hw_h = cam->hw_height,
+	    hw_d = cam->hw_depth;
+	int err = 0;
+
+	#define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
+
+	if (cam->vpp_flag & VPP_DECOMPRESSION) {
+		memcpy(pOut, pIn, fr->length);
+		_PSWAP(pIn, pOut)
+		err = (*w9968cf_vpp_decode)(pIn, fr->length, hw_w, hw_h, pOut);
+		PDBGG("Compressed frame length: %li",(unsigned long)fr->length)
+		fr->length = (hw_w*hw_h*hw_d)/8;
+		_PSWAP(pIn, pOut)
+		if (err) {
+			DBG(4, "An error occurred while decoding the frame: "
+			       "%s.", symbolic(decoder_errlist, err))
+			return err;
+		} else
+			DBG(6, "Frame decoded")
+	}
+
+	if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
+		(*w9968cf_vpp_swap_yuvbytes)(pIn, fr->length);
+		DBG(6, "Original UYVY component ordering changed.")
+	}
+
+	if (cam->vpp_flag & VPP_UPSCALE) {
+		(*w9968cf_vpp_scale_up)(pIn, pOut, hw_w, hw_h, hw_d, w, h);
+		fr->length = (w*h*hw_d)/8;
+		_PSWAP(pIn, pOut)
+		DBG(6, "Vertical up-scaling done: %d,%d,%dbpp->%d,%d",
+		    hw_w, hw_h, hw_d, w, h)
+	}
+
+	if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
+		(*w9968cf_vpp_uyvy_to_rgbx)(pIn, fr->length, pOut, fmt, rgb);
+		fr->length = (w*h*d)/8;
+		_PSWAP(pIn, pOut)
+		DBG(6, "UYVY-16bit to %s conversion done.", 
+		    symbolic(v4l1_plist, fmt))
+	}
+
+	if (pOut == fr->buffer)
+		memcpy(fr->buffer, cam->vpp_buffer, fr->length);
+
+	return 0;
+}
+
+
+
+/****************************************************************************
+ * CMOS sensor control routines                                             *
+ ****************************************************************************/
+
+static int 
+w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
+{
+	struct ovcamchip_control ctl;
+	int rc;
+
+	ctl.id = cid;
+	ctl.value = val;
+
+	rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
+
+	return rc;
+}
+
+static int 
+w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int *val)
+{
+	struct ovcamchip_control ctl;
+	int rc;
+
+	ctl.id = cid;
+
+	rc = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
+	if (rc >= 0)
+		*val = ctl.value;
+
+	return rc;
+}
+
+
+static inline int
+w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void *arg)
+{
+	struct i2c_client* c = cam->sensor_client;
+
+	DBG(6, "Executing CMOS sensor command...")
+
+	if (c && c->driver->command)
+		return c->driver->command(cam->sensor_client, cmd, arg);
+	else
+		return -ENODEV;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change some settings of the CMOS sensor.
+  Returns: 0 for success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_sensor_change_settings(struct w9968cf_device* cam)
+{
+	int rc;
+
+	/* Auto brightness */
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, 
+	                                cam->auto_brt);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	/* Auto exposure */
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, 
+	                                cam->auto_exp);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	/* Banding filter */
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, 
+	                                cam->bandfilt);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	/* Light frequency */
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
+	                                cam->lightfreq);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	/* Back light */
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
+	                                cam->backlight);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	/* Mirror */
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
+	                                cam->mirror);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Get some current picture settings from the CMOS sensor.
+  Returns: 0 for success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_sensor_get_picture(struct w9968cf_device* cam, 
+                           struct video_picture* pict)
+{
+	int rc, v;
+
+	/* Don't return error if a setting is unsupported, or rest of settings
+	   will not be performed */
+
+	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+	pict->contrast = v;
+
+	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+	pict->brightness = v;
+
+	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+	pict->colour = v;
+
+	rc = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+	pict->hue = v;
+
+	pict->whiteness = W9968CF_WHITENESS; /* to do! */
+
+	DBG(5, "Got picture settings from the CMOS sensor.")
+
+	PDBGG("Brightness, contrast, hue, colour, whiteness are "
+	      "%d,%d,%d,%d,%d.", pict->brightness, pict->contrast,
+	      pict->hue, pict->colour, pict->whiteness)
+
+	return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change picture settings of the CMOS sensor.
+  Returns: 0 for success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_sensor_set_picture(struct w9968cf_device* cam, 
+                           struct video_picture pict)
+{
+	int rc;
+
+	rc = w9968cf_sensor_set_control(cam,OVCAMCHIP_CID_CONT, pict.contrast);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	if (!cam->auto_brt) {
+		rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, 
+	                                        pict.brightness);
+		if (SENSOR_FATAL_ERROR(rc))
+			return rc;
+	}
+
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, pict.colour);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	rc = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, pict.hue);
+	if (SENSOR_FATAL_ERROR(rc))
+		return rc;
+
+	PDBGG("Brightness, contrast, hue, colour, whiteness are "
+	      "%d,%d,%d,%d,%d.", pict.brightness, pict.contrast,
+	      pict.hue, pict.colour, pict.whiteness)
+
+	return 0;
+}
+
+
+
+/****************************************************************************
+ * Camera configuration                                                     *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  This function is called when the CMOS sensor is detected.
+  --------------------------------------------------------------------------*/
+static void w9968cf_sensor_configure(struct w9968cf_device* cam)
+{
+	/* NOTE: Make sure width and height are a multiple of 16 */
+
+	switch (cam->sensor_client->addr) {
+		case OV6xx0_SID:
+			cam->maxwidth = 352;
+			cam->maxheight = 288;
+			cam->minwidth = 64;
+			cam->minheight = 48;
+			break;
+		case OV7xx0_SID:
+			cam->maxwidth = 640;
+			cam->maxheight = 480;
+			cam->minwidth = 64;
+			cam->minheight = 48;
+			break;
+	}
+
+	/* These values depend on the ones in the ovxxx0.c sources */
+	switch (cam->sensor) {
+		case CC_OV7620:
+			cam->start_cropx = 287;
+			cam->start_cropy = 35;
+			/* Seems to work around a bug in the CMOS sensor */
+			cam->vs_polarity = 1;
+			cam->hs_polarity = 1;
+			break;
+		default:
+			cam->start_cropx = 320;
+			cam->start_cropy = 35;
+			cam->vs_polarity = 1;
+			cam->hs_polarity = 0;
+	}
+
+	DBG(5, "CMOS sensor %s configured.", symbolic(senlist, cam->sensor))
+}
+
+
+/*--------------------------------------------------------------------------
+  Fill some basic fields in the main device data structure.
+  This function is called once on w9968cf_usb_probe() for each recognized 
+  camera.
+  --------------------------------------------------------------------------*/
+static void
+w9968cf_configure_camera(struct w9968cf_device* cam,
+                         struct usb_device* udev,
+                         enum w9968cf_model_id mod_id,
+                         const unsigned short dev_nr)
+{
+#if defined(CONFIG_VIDEO_PROC_FS)
+	init_MUTEX(&cam->procfs_sem);
+#endif
+	init_MUTEX(&cam->fileop_sem);
+	init_waitqueue_head(&cam->open);
+	spin_lock_init(&cam->urb_lock);
+	spin_lock_init(&cam->flist_lock);
+
+	cam->users = 0;
+	cam->disconnected = 0;
+	cam->usbdev = udev;
+	cam->id = mod_id;
+	cam->sensor = CC_UNKNOWN;
+
+	strcpy(cam->v4ldev.name, symbolic(camlist, mod_id));
+	cam->v4ldev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+	cam->v4ldev.hardware = VID_HARDWARE_W9968CF;
+	cam->v4ldev.fops = &w9968cf_fops;
+	cam->v4ldev.priv = (void*)cam;
+	cam->v4ldev.minor = video_nr[dev_nr];
+
+	/* Calculate the alternate setting number (from 1 to 16)
+	   according to the 'packet_size' module parameter */
+	if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
+		packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
+	for (cam->altsetting = 1;
+	     packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
+	     cam->altsetting++);
+
+	cam->max_buffers = (max_buffers[dev_nr] < 2 || 
+	                    max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
+	                   ? W9968CF_BUFFERS : max_buffers[dev_nr];
+
+	cam->double_buffer = (double_buffer[dev_nr] == 0 || 
+	                      double_buffer[dev_nr] == 1)
+	                     ? double_buffer[dev_nr] : W9968CF_DOUBLE_BUFFER;
+
+	cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
+	                ? clamping[dev_nr] : W9968CF_CLAMPING;
+	
+	cam->filter_type = (filter_type[dev_nr] == 0 ||
+	                    filter_type[dev_nr] == 1 ||
+	                    filter_type[dev_nr] == 2)
+	                   ? filter_type[dev_nr] : W9968CF_FILTER_TYPE;
+
+	cam->capture = 1;
+
+	cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
+	                 ? largeview[dev_nr] : W9968CF_LARGEVIEW;
+
+	cam->decompression = (decompression[dev_nr] == 0 || 
+	                      decompression[dev_nr] == 1 ||
+	                      decompression[dev_nr] == 2)
+	                     ? decompression[dev_nr] : W9968CF_DECOMPRESSION;
+
+	cam->upscaling = (upscaling[dev_nr] == 0 || 
+	                  upscaling[dev_nr] == 1)
+	                 ? upscaling[dev_nr] : W9968CF_UPSCALING;
+
+	cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
+	                ? autobright[dev_nr] : W9968CF_AUTOBRIGHT;
+
+	cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
+	                ? autoexp[dev_nr] : W9968CF_AUTOEXP;
+
+	cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
+	                 ? lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
+
+	cam->bandfilt = (bandingfilter[dev_nr] == 0 || 
+	                 bandingfilter[dev_nr] == 1)
+	                ? bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
+
+	cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
+	                 ? backlight[dev_nr] : W9968CF_BACKLIGHT;
+
+	cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
+	                ? clockdiv[dev_nr] : W9968CF_CLOCKDIV;
+
+	cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
+	              ? mirror[dev_nr] : W9968CF_MIRROR;
+
+	cam->sensor_mono = (sensor_mono[dev_nr]==0 || sensor_mono[dev_nr]==1)
+	                   ? sensor_mono[dev_nr] : W9968CF_SENSOR_MONO;
+
+	cam->picture.brightness = brightness[dev_nr];
+	cam->picture.hue = hue[dev_nr];
+	cam->picture.colour = colour[dev_nr];
+	cam->picture.contrast = contrast[dev_nr];
+	cam->picture.whiteness = whiteness[dev_nr];
+	if (w9968cf_valid_palette(force_palette[dev_nr])) {
+		cam->picture.palette = force_palette[dev_nr];
+		cam->force_palette = 1;
+	} else {
+		cam->force_palette = 0;
+		if (cam->decompression == 0)
+			cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
+		else if (cam->decompression == 1)
+			cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
+		else
+			cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
+	}
+
+	cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
+	                 ? force_rgb[dev_nr] : W9968CF_FORCE_RGB;
+
+	cam->window.x = 0;
+	cam->window.y = 0;
+	cam->window.width = W9968CF_WIDTH;
+	cam->window.height = W9968CF_HEIGHT;
+	cam->window.chromakey = 0;
+	cam->window.clipcount = 0;
+	cam->window.flags = 0;
+
+	/* If the video post-processing module is not present, some paramaters
+	   must be overridden: */
+	if (!w9968cf_vppmod_present) {
+		if (cam->decompression == 1)
+			cam->decompression = 2;
+		cam->upscaling = 0;
+		if (cam->picture.palette != VIDEO_PALETTE_UYVY)
+			cam->force_palette = 0;
+		cam->picture.palette = VIDEO_PALETTE_UYVY;
+	}
+
+	cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
+
+	DBG(3, "%s configured with settings #%d:", 
+	    symbolic(camlist, cam->id), dev_nr)
+	
+	DBG(3, "- Data packet size for USB isochrnous transfer: %d bytes.",
+	    wMaxPacketSize[cam->altsetting-1])
+	
+	DBG(3, "- Number of requested video frame buffers: %d", 
+	    cam->max_buffers)
+
+	if (cam->double_buffer)
+		DBG(3, "- Hardware double buffering enabled.")
+	else 
+		DBG(3, "- Hardware double buffering disabled.")
+
+	if (cam->filter_type == 0)
+		DBG(3, "- Video filtering disabled.")
+	else if (cam->filter_type == 1)
+		DBG(3, "- Video filtering enabled: type 1-2-1.")
+	else if (cam->filter_type == 2)
+		DBG(3, "- Video filtering enabled: type 2-3-6-3-2.")
+
+	if (cam->clamping)
+		DBG(3, "- Video data clamping (CCIR-601 format) enabled.")
+	else
+		DBG(3, "- Video data clamping (CCIR-601 format) disabled.")
+
+	if (cam->largeview)
+		DBG(3, "- Large view enabled.")
+	else
+		DBG(3, "- Large view disabled.")
+
+	if ((cam->decompression) == 0 && (!cam->force_palette))
+		DBG(3, "- Decompression disabled.")
+	else if ((cam->decompression) == 1 && (!cam->force_palette))
+		DBG(3, "- Decompression forced.")
+	else if ((cam->decompression) == 2 && (!cam->force_palette))
+		DBG(3, "- Decompression allowed.")
+
+	if (cam->upscaling)
+		DBG(3, "- Software image scaling enabled.")
+	else
+		DBG(3, "- Software image scaling disabled.")
+
+	if (cam->force_palette)
+		DBG(3, "- Image palette forced to %s.",
+		    symbolic(v4l1_plist, cam->picture.palette))
+
+	if (cam->force_rgb)
+		DBG(3, "- RGB component ordering will be used instead of BGR.")
+
+	if (cam->auto_brt)
+		DBG(3, "- Auto brightness enabled.")
+	else
+		DBG(3, "- Auto brightness disabled.")
+
+	if (cam->auto_exp)
+		DBG(3, "- Auto exposure enabled.")
+	else
+		DBG(3, "- Auto exposure disabled.")
+
+	if (cam->backlight)
+		DBG(3, "- Backlight exposure algorithm enabled.")
+	else
+		DBG(3, "- Backlight exposure algorithm disabled.")
+
+	if (cam->mirror)
+		DBG(3, "- Mirror enabled.")
+	else
+		DBG(3, "- Mirror disabled.")
+
+	if (cam->bandfilt)
+		DBG(3, "- Banding filter enabled.")
+	else
+		DBG(3, "- Banding filter disabled.")
+
+	DBG(3, "- Power lighting frequency: %d", cam->lightfreq)
+
+	if (cam->clockdiv == -1)
+		DBG(3, "- Automatic clock divisor enabled.")
+	else
+		DBG(3, "- Clock divisor: %d", cam->clockdiv)
+
+	if (cam->sensor_mono)
+		DBG(3, "- CMOS sensor used as monochrome.")
+	else
+		DBG(3, "- CMOS sensor not used as monochrome.")
+}
+
+
+/*--------------------------------------------------------------------------
+  Release the resources used by the driver.
+  This function is called on disconnect 
+  (or on close if deallocation has been deferred)
+  --------------------------------------------------------------------------*/
+static void w9968cf_release_resources(struct w9968cf_device* cam)
+{
+	down(&w9968cf_devlist_sem);
+
+	DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev.minor)
+
+	w9968cf_proc_destroy_dev(cam);
+	video_unregister_device(&cam->v4ldev);
+	list_del(&cam->v4llist);
+	i2c_del_adapter(&cam->i2c_adapter);
+	w9968cf_deallocate_memory(cam);
+	kfree(cam->control_buffer);
+	kfree(cam->data_buffer);
+
+	up(&w9968cf_devlist_sem);
+
+	DBG(5, "Resources released.")
+}
+
+
+
+/****************************************************************************
+ * Video4Linux interface                                                    *
+ ****************************************************************************/
+
+static int w9968cf_open(struct inode* inode, struct file* filp)
+{
+	struct w9968cf_device* cam =
+	  (struct w9968cf_device*)video_devdata(filp)->priv;    
+	int err;
+
+	down(&cam->dev_sem);
+
+	if (cam->sensor == CC_UNKNOWN) {
+		DBG(2, "No supported CMOS sensor has been detected by the "
+		       "'ovcamchip' module for the %s (/dev/video%d). Make "
+		       "sure it is loaded *before* the 'w9968cf' module.", 
+		    symbolic(camlist, cam->id),cam->v4ldev.minor)
+		up(&cam->dev_sem);
+		return -ENODEV;
+	}
+
+	if (cam->users) {
+		DBG(2, "%s (/dev/video%d) has been already occupied by '%s'.",
+		    symbolic(camlist, cam->id),cam->v4ldev.minor, cam->command)
+		if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
+			up(&cam->dev_sem);
+			return -EWOULDBLOCK;
+		}
+		up(&cam->dev_sem);
+		err = wait_event_interruptible(cam->open, cam->disconnected ||
+		                               (cam->users == 0));
+		if (err)
+			return err;
+		if (cam->disconnected)
+			return -ENODEV;
+		down(&cam->dev_sem);
+	}
+
+	DBG(5, "Opening the %s, /dev/video%d ...",
+	    symbolic(camlist, cam->id), cam->v4ldev.minor)
+
+	cam->streaming = 0;
+	cam->misconfigured = 0;
+
+	if (!w9968cf_vppmod_present)
+		w9968cf_vppmod_detect();
+
+	if ((err = w9968cf_allocate_memory(cam)))
+		goto deallocate_memory;
+
+	if ((err = w9968cf_init_chip(cam)))
+		goto deallocate_memory;
+
+	if ((err = w9968cf_start_transfer(cam)))
+		goto deallocate_memory;
+
+	filp->private_data = (void*)cam;
+
+	cam->users++;
+	strcpy(cam->command, current->comm);
+
+	init_waitqueue_head(&cam->wait_queue);
+
+	up(&cam->dev_sem);
+
+	DBG(5, "Video device is open.")
+	return 0;
+
+deallocate_memory:
+	w9968cf_deallocate_memory(cam);
+	DBG(2, "Failed to open the video device.")
+	up(&cam->dev_sem);
+	return err;
+}
+
+
+static int w9968cf_release(struct inode* inode, struct file* filp)
+{
+	struct w9968cf_device* cam = 
+	  (struct w9968cf_device*)video_devdata(filp)->priv;
+
+	down(&cam->dev_sem); /* prevent disconnect() to be called */
+
+	w9968cf_stop_transfer(cam);
+
+	if (cam->disconnected) {
+		w9968cf_release_resources(cam);
+		up(&cam->dev_sem);
+		kfree(cam);
+		return 0;
+	}
+
+	cam->users--;
+	w9968cf_deallocate_memory(cam);
+
+	if (waitqueue_active(&cam->open))
+		wake_up_interruptible(&cam->open);
+
+	DBG(5, "Video device closed.")
+	up(&cam->dev_sem);
+	return 0;
+}
+
+
+static ssize_t
+w9968cf_read(struct file* filp, char* buf, size_t count, loff_t* f_pos)
+{
+	struct w9968cf_device* cam =
+	  (struct w9968cf_device*)video_devdata(filp)->priv;
+	struct w9968cf_frame_t* fr;
+	int err = 0;
+
+	if (filp->f_flags & O_NONBLOCK)
+		return -EWOULDBLOCK;
+
+	if (down_interruptible(&cam->fileop_sem))
+		return -ERESTARTSYS;
+
+	if (cam->disconnected) {
+		DBG(2, "Device not present.")
+		up(&cam->fileop_sem);
+		return -ENODEV;
+	}
+
+	if (cam->misconfigured) {
+		DBG(2, "The camera is misconfigured. Close and open it again.")
+		up(&cam->fileop_sem);
+		return -EIO;
+	}
+
+	if (!cam->frame[0].queued)
+		w9968cf_push_frame(cam, 0);
+
+	if (!cam->frame[1].queued)
+		w9968cf_push_frame(cam, 1);
+
+	err = wait_event_interruptible(cam->wait_queue,
+	                               cam->frame[0].status == F_READY ||
+	                               cam->frame[1].status == F_READY ||
+	                               cam->disconnected);
+	if (err) {
+		up(&cam->fileop_sem);
+		return err;
+	}
+	if (cam->disconnected) {
+		up(&cam->fileop_sem);
+		return -ENODEV;
+	}
+
+	fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
+
+	if (w9968cf_vppmod_present)
+		w9968cf_postprocess_frame(cam, fr);
+
+	if (count > fr->length)
+		count = fr->length;
+
+	if (copy_to_user(buf, fr->buffer, count)) {
+		fr->status = F_UNUSED;
+		up(&cam->fileop_sem);
+		return -EFAULT;
+	}
+	*f_pos += count;
+
+	fr->status = F_UNUSED;
+
+	DBG(5, "%d bytes read.", count)
+
+	up(&cam->fileop_sem);
+	return count;
+}
+
+
+static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+	struct w9968cf_device* cam =
+	  (struct w9968cf_device*)video_devdata(filp)->priv;
+
+	unsigned long vsize = vma->vm_end - vma->vm_start,
+	              psize = cam->nbuffers * w9968cf_get_max_bufsize(cam),
+	              start = vma->vm_start,
+	              pos = (unsigned long)cam->frame[0].buffer,
+	              page;
+
+	if (cam->disconnected) {
+		DBG(2, "Device not present.")
+		return -ENODEV;
+	}
+
+	if (cam->misconfigured) {
+		DBG(2, "The camera is misconfigured. Close and open it again.")
+		return -EIO;
+	}
+
+	PDBGG("mmapping %li bytes...", vsize)
+
+        if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
+		return -EAGAIN;
+
+	while (vsize > 0) {
+		page = kvirt_to_pa(pos) + vma->vm_pgoff;
+		if(remap_page_range(start, page, PAGE_SIZE, vma->vm_page_prot))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		vsize = (vsize > PAGE_SIZE) ? vsize-PAGE_SIZE : 0;
+	}
+
+	DBG(5, "mmap method successfully called.")
+	return 0;
+}
+
+
+static int
+w9968cf_ioctl(struct inode* inode, struct file* filp,
+              unsigned int cmd, unsigned long arg)
+{
+	struct w9968cf_device* cam =
+	  (struct w9968cf_device*)video_devdata(filp)->priv;
+	int err;
+
+	if (down_interruptible(&cam->fileop_sem))
+		return -ERESTARTSYS;
+
+	if (cam->disconnected) {
+		DBG(2, "Device not present.")
+		up(&cam->fileop_sem);
+		return -ENODEV;
+	}
+
+	if (cam->misconfigured) {
+		DBG(2, "The camera is misconfigured. Close and open it again.")
+		up(&cam->fileop_sem);
+		return -EIO;
+	}
+
+	err = w9968cf_do_ioctl(cam, cmd, (void*)arg);
+
+	up(&cam->fileop_sem);
+	return err;
+}
+
+
+static int 
+w9968cf_do_ioctl(struct w9968cf_device* cam, unsigned cmd, void* arg)
+{
+	const char* v4l1_ioctls[] = {
+		"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", 
+		"GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
+		"SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
+		"SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
+		"SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", 
+		"GVBIFMT", "SVBIFMT" 
+	};
+
+	#define V4L1_IOCTL(cmd) \
+	        ((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \
+	        v4l1_ioctls[_IOC_NR((cmd))] : "???")
+
+	switch (cmd) {
+
+	case VIDIOCGCAP: /* get video capability */
+	{
+		struct video_capability cap = {
+			.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
+			.channels = 1,
+			.audios = 0,
+			.minwidth = cam->minwidth,
+			.minheight = cam->minheight,
+		};
+		sprintf(cap.name, "W996[87]CF USB Camera #%d", 
+		        cam->v4ldev.minor);
+		cap.maxwidth = (cam->upscaling && w9968cf_vppmod_present)
+		               ? W9968CF_MAX_WIDTH : cam->maxwidth;
+		cap.maxheight = (cam->upscaling && w9968cf_vppmod_present)
+		                ? W9968CF_MAX_HEIGHT : cam->maxheight;
+
+		if (copy_to_user(arg, &cap, sizeof(cap)))
+			return -EFAULT;
+
+		DBG(5, "VIDIOCGCAP successfully called.")
+		return 0;
+	}
+
+	case VIDIOCGCHAN: /* get video channel informations */
+	{
+		struct video_channel chan;
+		if (copy_from_user(&chan, arg, sizeof(chan)))
+			return -EFAULT;
+
+		if (chan.channel != 0)
+			return -EINVAL;
+
+		strcpy(chan.name, "Camera");
+		chan.tuners = 0;
+		chan.flags = 0;
+		chan.type = VIDEO_TYPE_CAMERA;
+		chan.norm = VIDEO_MODE_AUTO;
+
+		if (copy_to_user(arg, &chan, sizeof(chan)))
+			return -EFAULT;
+
+		DBG(5, "VIDIOCGCHAN successfully called.")
+		return 0;
+	}
+
+	case VIDIOCSCHAN: /* set active channel */
+	{
+		struct video_channel chan;
+
+		if (copy_from_user(&chan, arg, sizeof(chan)))
+			return -EFAULT;
+
+		if (chan.channel != 0)
+			return -EINVAL;
+
+		DBG(5, "VIDIOCSCHAN successfully called.")
+		return 0;
+	}
+
+	case VIDIOCGPICT: /* get image properties of the picture */
+	{
+		struct video_picture pict;
+
+		if (w9968cf_sensor_get_picture(cam, &pict))
+			return -EIO;
+
+		pict.depth = cam->picture.depth;
+		pict.palette = cam->picture.palette;
+
+		if (copy_to_user(arg, &pict, sizeof(pict)))
+			return -EFAULT;
+
+		DBG(5, "VIDIOCGPICT successfully called.")
+		return 0;
+	}
+
+	case VIDIOCSPICT: /* change picture settings */
+	{
+		struct video_picture pict;
+		int err = 0;
+
+		if (copy_from_user(&pict, arg, sizeof(pict)))
+			return -EFAULT;
+
+		if ( (cam->force_palette || !w9968cf_vppmod_present) 
+		     && pict.palette != cam->picture.palette ) {
+			DBG(4, "Palette %s rejected. Only %s is allowed.",
+			    symbolic(v4l1_plist, pict.palette),
+			    symbolic(v4l1_plist, cam->picture.palette))
+			return -EINVAL;
+		}
+
+		if (!w9968cf_valid_palette(pict.palette)) {
+			DBG(4, "Palette %s not supported. VIDIOCSPICT failed.",
+			    symbolic(v4l1_plist, pict.palette))
+			return -EINVAL;
+		}
+
+		if (pict.depth != w9968cf_valid_depth(pict.palette)) {
+			DBG(4, "Depth %d bpp is not supported for %s palette. "
+			       "VIDIOCSPICT failed.", 
+			    pict.depth, symbolic(v4l1_plist, pict.palette))
+			return -EINVAL;
+		}
+
+		if (!cam->force_palette) {
+		   if (cam->decompression == 0) {
+		      if (w9968cf_need_decompression(pict.palette)) {
+		         DBG(4, "Decompression disabled: palette %s is not "
+		                "allowed. VIDIOCSPICT failed.",
+		             symbolic(v4l1_plist, pict.palette))
+		         return -EINVAL;
+		      }
+		   } else if (cam->decompression == 1) {
+		      if (!w9968cf_need_decompression(pict.palette)) {
+		         DBG(4, "Decompression forced: palette %s is not "
+		                "allowed. VIDIOCSPICT failed.",
+		             symbolic(v4l1_plist, pict.palette))
+		         return -EINVAL;
+		      }
+		   }
+		}
+
+		if (pict.palette != cam->picture.palette ||
+		    pict.depth   != cam->picture.depth)
+		{
+			if(*cam->requested_frame
+			   || cam->frame_current->queued) {
+				err = wait_event_interruptible
+				      ( cam->wait_queue,
+				        cam->disconnected ||
+				        (!*cam->requested_frame &&
+				         !cam->frame_current->queued) );
+				if (err)
+					return err;
+				if (cam->disconnected)
+					return -ENODEV;
+			}
+
+			if (w9968cf_stop_transfer(cam))
+				goto ioctl_fail;
+
+			if (w9968cf_set_picture(cam, pict))
+				goto ioctl_fail;
+
+			if (w9968cf_start_transfer(cam))
+				goto ioctl_fail;
+
+		} else if ( ((pict.brightness != cam->picture.brightness) &&
+		            (!cam->auto_brt)) ||
+		            pict.hue != cam->picture.hue ||
+		            pict.colour != cam->picture.colour ||
+		            pict.contrast != cam->picture.contrast ||
+		            pict.whiteness != cam->picture.whiteness ) {
+			if (w9968cf_sensor_set_picture(cam, pict))
+				return -EIO;
+		}
+
+		DBG(5, "VIDIOCSPICT successfully called.")
+		return 0;
+	}
+
+	case VIDIOCSWIN: /* set capture area */
+	{
+		struct video_window win;
+		int err = 0;
+
+		if (copy_from_user(&win, arg, sizeof(win)))
+			return -EFAULT;
+
+		DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%d, "
+		       "x=%d, y=%d, %dx%d", win.clipcount, win.flags,
+		    win.x, win.y, win.width, win.height)
+
+		if (win.clipcount != 0 || win.flags != 0)
+			return -EINVAL;
+
+		if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
+		                                      (u16*)&win.height))) {
+			DBG(4, "Resolution not supported (%dx%d)."
+			       "VIDIOCSWIN failed.", win.width, win.height)
+			return err;
+		}
+
+		if (win.x != cam->window.x ||
+		    win.y != cam->window.y ||
+		    win.width != cam->window.width ||
+		    win.height != cam->window.height) {
+
+			if(*cam->requested_frame
+			   || cam->frame_current->queued) {
+				err = wait_event_interruptible
+				      ( cam->wait_queue,
+				        cam->disconnected ||
+				        (!*cam->requested_frame &&
+				         !cam->frame_current->queued) );
+				if (err)
+					return err;
+				if (cam->disconnected)
+					return -ENODEV;
+			}
+
+			if (w9968cf_stop_transfer(cam))
+				goto ioctl_fail;
+
+			/* This _must_ be called before set_window() */
+			if (w9968cf_set_picture(cam, cam->picture))
+				goto ioctl_fail;
+
+			if (w9968cf_set_window(cam, win))
+				goto ioctl_fail;
+
+			if (w9968cf_start_transfer(cam))
+				goto ioctl_fail;
+		}
+
+		DBG(5, "VIDIOCSWIN successfully called. ")
+		return 0;
+	}
+
+	case VIDIOCGWIN: /* get current window properties */
+	{
+		if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
+			return -EFAULT;
+
+		DBG(5, "VIDIOCGWIN successfully called.")
+		return 0;
+	}
+
+	case VIDIOCGMBUF: /* request for memory (mapped) buffer */
+	{
+		struct video_mbuf mbuf;
+		u8 i;
+
+		mbuf.size = cam->nbuffers * w9968cf_get_max_bufsize(cam);
+		mbuf.frames = cam->nbuffers;
+		for (i = 0; i < cam->nbuffers; i++)
+			mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
+			                  (unsigned long)cam->frame[0].buffer;
+
+		if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
+			return -EFAULT;
+
+		DBG(5, "VIDIOCGMBUF successfully called.")
+		return 0;
+	}
+
+	case VIDIOCMCAPTURE: /* start the capture to a frame */
+	{
+		struct video_mmap mmap;
+		struct w9968cf_frame_t* fr;
+		int err = 0;
+
+		if (copy_from_user(&mmap, arg, sizeof(mmap)))
+			return -EFAULT;
+
+		DBG(6, "VIDIOCMCAPTURE called: frame #%d, format=%s, %dx%d",
+		    mmap.frame, symbolic(v4l1_plist, mmap.format), 
+		    mmap.width, mmap.height)
+
+		if (mmap.frame >= cam->nbuffers) {
+			DBG(4, "Invalid frame number (%d). "
+			       "VIDIOCMCAPTURE failed.", mmap.frame)
+			return -EINVAL;
+		}
+
+		if (mmap.format!=cam->picture.palette && 
+		    (cam->force_palette || !w9968cf_vppmod_present)) {
+			DBG(4, "Palette %s rejected. Only %s is allowed.",
+			    symbolic(v4l1_plist, mmap.format),
+			    symbolic(v4l1_plist, cam->picture.palette))
+			return -EINVAL;
+		}
+
+		if (!w9968cf_valid_palette(mmap.format)) {
+			DBG(4, "Palette %s not supported. "
+			       "VIDIOCMCAPTURE failed.", 
+			    symbolic(v4l1_plist, mmap.format))
+			return -EINVAL;
+		}
+
+		if (!cam->force_palette) {
+		   if (cam->decompression == 0) {
+		      if (w9968cf_need_decompression(mmap.format)) {
+		         DBG(4, "Decompression disabled: palette %s is not "
+		                "allowed. VIDIOCSPICT failed.",
+		             symbolic(v4l1_plist, mmap.format))
+		         return -EINVAL;
+		      }
+		   } else if (cam->decompression == 1) {
+		      if (!w9968cf_need_decompression(mmap.format)) {
+		         DBG(4, "Decompression forced: palette %s is not "
+		                "allowed. VIDIOCSPICT failed.",
+		             symbolic(v4l1_plist, mmap.format))
+		         return -EINVAL;
+		      }
+		   }
+		}
+
+		if (w9968cf_adjust_window_size(cam, (u16*)&mmap.width, 
+		                               (u16*)&mmap.height)) {
+			DBG(4, "Resolution not supported (%dx%d). "
+			       "VIDIOCMCAPTURE failed.",
+			    mmap.width, mmap.height)
+			return -EINVAL;
+		}
+
+		fr = &cam->frame[mmap.frame];
+
+		if (mmap.width  != cam->window.width ||
+		    mmap.height != cam->window.height ||
+		    mmap.format != cam->picture.palette) {
+
+			struct video_window win;
+			struct video_picture pict;
+
+			if(*cam->requested_frame
+			   || cam->frame_current->queued) {
+				DBG(6, "VIDIOCMCAPTURE. Change settings for "
+				       "frame #%d: %dx%d, format %s. Wait...",
+				    mmap.frame, mmap.width, mmap.height,
+			            symbolic(v4l1_plist, mmap.format))
+				err = wait_event_interruptible
+				      ( cam->wait_queue,
+				        cam->disconnected ||
+				        (!*cam->requested_frame &&
+				         !cam->frame_current->queued) );
+				if (err)
+					return err;
+				if (cam->disconnected)
+					return -ENODEV;
+			}
+
+			memcpy(&win, &cam->window, sizeof(win));
+			memcpy(&pict, &cam->picture, sizeof(pict));
+			win.width = mmap.width;
+			win.height = mmap.height;
+			pict.palette = mmap.format;
+
+			if (w9968cf_stop_transfer(cam))
+				goto ioctl_fail;
+
+			/* This before set_window */
+			if (w9968cf_set_picture(cam, pict)) 
+				goto ioctl_fail;
+
+			if (w9968cf_set_window(cam, win))
+				goto ioctl_fail;
+
+			if (w9968cf_start_transfer(cam))
+				goto ioctl_fail;
+
+		} else 	if (fr->queued) {
+
+			DBG(6, "Wait until frame #%d is free.", mmap.frame)
+			
+			err = wait_event_interruptible(cam->wait_queue, 
+			                               cam->disconnected ||
+			                               (!fr->queued));
+			if (err)
+				return err;
+			if (cam->disconnected)
+				return -ENODEV;
+		}
+
+		w9968cf_push_frame(cam, mmap.frame);
+		DBG(5, "VIDIOCMCAPTURE(%d): successfully called.", mmap.frame)
+		return 0;
+	}
+
+	case VIDIOCSYNC: /* wait until the capture of a frame is finished */
+	{
+		unsigned int f_num = *((unsigned int *) arg);
+		struct w9968cf_frame_t* fr;
+		int err = 0;
+
+		if (f_num >= cam->nbuffers) {
+			DBG(4, "Invalid frame number (%d). "
+			       "VIDIOCMCAPTURE failed.", f_num)
+			return -EINVAL;
+		}
+
+		DBG(6, "VIDIOCSYNC called for frame #%d", f_num)
+
+		fr = &cam->frame[f_num];
+
+		switch (fr->status) {
+		case F_UNUSED:
+			if (!fr->queued) {
+				DBG(4, "VIDIOSYNC: Frame #%d not requested!",
+				    f_num)
+				return -EFAULT;
+			}
+		case F_ERROR:
+		case F_GRABBING:
+			err = wait_event_interruptible(cam->wait_queue, 
+			                               (fr->status == F_READY)
+			                               || cam->disconnected);
+			if (err)
+				return err;
+			if (cam->disconnected)
+				return -ENODEV;
+			break;
+		case F_READY:
+			break;
+		}
+
+		if (w9968cf_vppmod_present)
+			w9968cf_postprocess_frame(cam, fr);
+
+		fr->status = F_UNUSED;
+
+		DBG(5, "VIDIOCSYNC(%d) successfully called.", f_num)
+		return 0;
+	}
+
+	case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
+	{
+		struct video_unit unit = {
+			.video = cam->v4ldev.minor,
+			.vbi = VIDEO_NO_UNIT,
+			.radio = VIDEO_NO_UNIT,
+			.audio = VIDEO_NO_UNIT,
+			.teletext = VIDEO_NO_UNIT,
+		};
+
+		if (copy_to_user(arg, &unit, sizeof(unit)))
+			return -EFAULT;
+
+		DBG(5, "VIDIOCGUNIT successfully called.")
+		return 0;
+	}
+
+	case VIDIOCKEY:
+		return 0;
+
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer* buffer = (struct video_buffer*)arg;
+
+		memset(buffer, 0, sizeof(struct video_buffer));
+
+		DBG(5, "VIDIOCGFBUF successfully called.")
+		return 0;
+	}
+
+	case VIDIOCGTUNER:
+	{
+		struct video_tuner tuner;
+		if (copy_from_user(&tuner, arg, sizeof(tuner)))
+			return -EFAULT;
+
+		if (tuner.tuner != 0);
+			return -EINVAL;
+
+		strcpy(tuner.name, "no_tuner");
+		tuner.rangelow = 0;
+		tuner.rangehigh = 0;
+		tuner.flags = VIDEO_TUNER_NORM;
+		tuner.mode = VIDEO_MODE_AUTO;
+		tuner.signal = 0xffff;
+
+		if (copy_to_user(arg, &tuner, sizeof(tuner)))
+			return -EFAULT;
+
+		DBG(5, "VIDIOCGTUNER successfully called.")
+		return 0;
+	}
+
+	case VIDIOCSTUNER:
+	{
+		struct video_tuner tuner;
+		if (copy_from_user(&tuner, arg, sizeof(tuner)))
+			return -EFAULT;
+
+		if (tuner.tuner != 0)
+			return -EINVAL;
+
+		if (tuner.mode != VIDEO_MODE_AUTO)
+			return -EINVAL;
+
+		DBG(5, "VIDIOCSTUNER successfully called.")
+		return 0;
+	}
+
+	case VIDIOCSFBUF:
+	case VIDIOCCAPTURE:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+	case VIDIOCSPLAYMODE:
+	case VIDIOCSWRITEMODE:
+	case VIDIOCGPLAYINFO:
+	case VIDIOCSMICROCODE:
+	case VIDIOCGVBIFMT:
+	case VIDIOCSVBIFMT:
+		DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
+		       "(type 0x%01X, "
+		       "n. 0x%01X, "
+		       "dir. 0x%01X, " 
+		       "size 0x%02X).",
+		    V4L1_IOCTL(cmd),
+		    _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
+
+		return -EINVAL;
+
+	default:
+		DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
+		       "type 0x%01X, "
+		       "n. 0x%01X, "
+		       "dir. 0x%01X, "
+		       "size 0x%02X.",
+		    V4L1_IOCTL(cmd),
+		    _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
+
+		return -ENOIOCTLCMD;
+
+	} /* end of switch */
+
+ioctl_fail:
+	cam->misconfigured = 1;
+	DBG(1, "VIDIOC%s failed because of hardware problems. "
+	       "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
+	return -EFAULT;
+}
+
+
+static struct file_operations w9968cf_fops = {
+	.owner =   THIS_MODULE,
+	.open =    w9968cf_open,
+	.release = w9968cf_release,
+	.read =    w9968cf_read,
+	.ioctl =   w9968cf_ioctl,
+	.mmap =    w9968cf_mmap,
+	.llseek =  no_llseek,
+};
+
+
+
+/****************************************************************************
+ * USB probe and V4L registration, disconnect and id_table[] definition     *
+ ****************************************************************************/
+
+static void*
+w9968cf_usb_probe(struct usb_device* udev,
+                  unsigned int ifnum, const struct usb_device_id* id)
+{
+	struct w9968cf_device* cam;
+	int err = 0;
+	enum w9968cf_model_id mod_id;
+	struct list_head* ptr;
+	u8 sc = 0; /* number of simultaneous cameras */
+	static unsigned short dev_nr = 0; /* we are handling device number n */
+
+	if (udev->descriptor.idVendor  == winbond_id_table[0].idVendor &&
+	    udev->descriptor.idProduct == winbond_id_table[0].idProduct)
+		mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
+
+	else if (udev->descriptor.idVendor  == winbond_id_table[1].idVendor &&
+	         udev->descriptor.idProduct == winbond_id_table[1].idProduct)
+		mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
+
+	else
+		return NULL;
+
+	/* We don't handle multi-config cameras */
+	if (udev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	DBG(2, "%s detected.", symbolic(camlist, mod_id))
+
+	if (simcams > W9968CF_MAX_DEVICES)
+		simcams = W9968CF_SIMCAMS;
+
+	/* How many cameras are connected ? */
+	down(&w9968cf_devlist_sem);
+	list_for_each(ptr, &w9968cf_dev_list)
+		sc++;
+	up(&w9968cf_devlist_sem);
+
+	if (sc >= simcams) {
+		DBG(2, "Device rejected: too many connected cameras "
+		       "(max. %d)", simcams)
+		return NULL;
+	}
+
+	err = usb_set_configuration(udev, 1);
+	err += usb_set_interface(udev, 0, 0);
+
+	if (err) {
+		DBG(1, "Device configuration failed.")
+		return NULL;
+	}
+
+	cam = (struct w9968cf_device*)
+	          kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
+
+	if (!cam) {
+		DBG(1, "Couldn't allocate %d bytes of kernel memory.",
+		    sizeof(struct w9968cf_device))
+		err = -ENOMEM;
+		goto fail;
+	}
+	memset(cam, 0, sizeof(*cam));
+
+	init_MUTEX(&cam->dev_sem);
+	down(&cam->dev_sem);
+
+	/* Allocate 2 bytes of memory for camera control USB transfers */
+	if (!(cam->control_buffer = (u16*)kmalloc(2, GFP_KERNEL))) {
+		DBG(1,"Couldn't allocate memory for camera control transfers.")
+		err = -ENOMEM;
+		goto fail;
+	}
+	memset(cam->control_buffer, 0, 2);
+
+	/* Allocate 8 bytes of memory for USB data transfers to the FSB */
+	if (!(cam->data_buffer = (u16*)kmalloc(8, GFP_KERNEL))) {
+		DBG(1, "Couldn't allocate memory for data "
+		       "transfers to the FSB.")
+		err = -ENOMEM;
+		goto fail;
+	}
+	memset(cam->data_buffer, 0, 8);
+
+	/* Set some basic constants */
+	w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
+
+	err = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER,
+	                            video_nr[dev_nr]);
+	if (err) {
+		DBG(1, "V4L device registration failed.")
+		if (err == -ENFILE && video_nr[dev_nr] == -1)
+			DBG(2, "Couldn't find a free /dev/videoX node.")
+		video_nr[dev_nr] = -1;
+		dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
+		goto fail;
+	}
+
+	DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev.minor)
+
+	/* Ok, add a new entry into the list of V4L registered devices */
+	down(&w9968cf_devlist_sem);
+	list_add(&cam->v4llist, &w9968cf_dev_list);
+	up(&w9968cf_devlist_sem);
+
+	dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+	w9968cf_turn_on_led(cam);
+
+	w9968cf_i2c_init(cam);
+
+	w9968cf_proc_create_dev(cam);
+
+	up(&cam->dev_sem);
+	return (void*)cam;
+
+fail: /* Free unused memory */
+	if (cam) {
+		if (cam->control_buffer)
+			kfree(cam->control_buffer);
+		if (cam->data_buffer)
+			kfree(cam->data_buffer);
+		up(&cam->dev_sem);
+		kfree(cam);
+	}
+	return NULL;
+}
+
+
+static void w9968cf_usb_disconnect(struct usb_device* udev, void* drv_context)
+{
+	struct w9968cf_device* cam = (struct w9968cf_device*)drv_context;
+
+	if (cam) {
+		/* Prevent concurrent accesses to data */
+		down(&cam->dev_sem); 
+
+		cam->streaming = 0;
+		cam->disconnected = 1;
+
+		DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
+
+		if (waitqueue_active(&cam->open))
+			wake_up_interruptible(&cam->open);
+
+		if (cam->users) {
+			DBG(2, "The device is open (/dev/video%d)! "
+			       "Process name: %s. Deregistration and memory "
+			       "deallocation are deferred on close.",
+			    cam->v4ldev.minor, cam->command)
+
+			cam->misconfigured = 1;
+
+			if (waitqueue_active(&cam->wait_queue))
+				wake_up_interruptible(&cam->wait_queue);
+		} else
+			w9968cf_release_resources(cam);
+
+		up(&cam->dev_sem);
+
+		if (!cam->users)
+			kfree(cam);
+	}
+}
+
+
+static struct usb_driver w9968cf_usb_driver = {
+	.owner =      THIS_MODULE,
+	.name =       "w9968cf",
+	.id_table =   winbond_id_table,
+	.probe =      w9968cf_usb_probe,
+	.disconnect = w9968cf_usb_disconnect,
+};
+
+
+
+/****************************************************************************
+ * Module init, exit and intermodule communication                          *
+ ****************************************************************************/
+
+static int w9968cf_vppmod_detect(void)
+{
+	w9968cf_vpp_init_decoder = inter_module_get("w9968cf_init_decoder");
+
+	if (!w9968cf_vpp_init_decoder) {
+		if (vppmod_load)
+			w9968cf_vpp_init_decoder = inter_module_get_request
+		                                  ( "w9968cf_init_decoder",
+			                            "w9968cf-vpp" );
+		if (!w9968cf_vpp_init_decoder) {
+			w9968cf_vppmod_present = 0;
+			DBG(4, "Video post-processing module not detected.")
+			return -ENODEV;
+		}
+	}
+
+	w9968cf_vpp_check_headers = inter_module_get("w9968cf_check_headers");
+	w9968cf_vpp_decode = inter_module_get("w9968cf_decode");
+	w9968cf_vpp_swap_yuvbytes = inter_module_get("w9968cf_swap_yuvbytes");
+	w9968cf_vpp_uyvy_to_rgbx = inter_module_get("w9968cf_uyvy_to_rgbx");
+	w9968cf_vpp_scale_up = inter_module_get("w9968cf_scale_up");
+
+	w9968cf_vppmod_present = 1;
+
+	/* Initialization */
+	(*w9968cf_vpp_init_decoder)();
+
+	DBG(2, "Video post-processing module detected.")
+	return 0;
+}
+
+
+static void w9968cf_vppmod_release(void)
+{
+	inter_module_put("w9968cf_init_decoder");
+	inter_module_put("w9968cf_check_headers");
+	inter_module_put("w9968cf_decode");
+	inter_module_put("w9968cf_swap_yuvbytes");
+	inter_module_put("w9968cf_uyvy_to_rgbx");
+	inter_module_put("w9968cf_scale_up");
+
+	DBG(2, "Video post-processing module released.")
+}
+
+
+static int __init w9968cf_module_init(void)
+{
+	int err;
+
+	DBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
+	DBG(3, W9968CF_MODULE_AUTHOR)
+
+	init_MUTEX(&w9968cf_devlist_sem);
+
+	w9968cf_proc_create();
+
+	w9968cf_vppmod_detect();
+
+	if ((err = usb_register(&w9968cf_usb_driver))) {
+		if (w9968cf_vppmod_present)
+			w9968cf_vppmod_release();
+		w9968cf_proc_destroy();
+		return err;
+	}
+
+	return 0;
+}
+
+
+static void __exit w9968cf_module_exit(void)
+{
+	/* w9968cf_usb_disconnect() will be called */
+	usb_deregister(&w9968cf_usb_driver);
+
+	w9968cf_proc_destroy();	
+
+	if (w9968cf_vppmod_present)
+		w9968cf_vppmod_release();
+
+	DBG(2, W9968CF_MODULE_NAME" deregistered.")
+}
+
+
+module_init(w9968cf_module_init);
+module_exit(w9968cf_module_exit);
diff -urN linux-2.4.22-bk41/drivers/usb/w9968cf.h linux-2.4.22-bk42/drivers/usb/w9968cf.h
--- linux-2.4.22-bk41/drivers/usb/w9968cf.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/w9968cf.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,321 @@
+/***************************************************************************
+ * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
+ *                                                                         *
+ * Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>            *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_H_
+#define _W9968CF_H_
+
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/config.h>
+#include <asm/semaphore.h>
+#include <asm/types.h>
+
+#include "w9968cf_externaldef.h"
+
+
+/****************************************************************************
+ * Default values                                                           *
+ ****************************************************************************/
+
+#define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
+
+/* Comment/uncomment the following line to enable/disable debugging messages */
+#define W9968CF_DEBUG
+
+/* These have effect only if W9968CF_DEBUG is defined */
+#define W9968CF_DEBUG_LEVEL    2 /* from 0 to 6. 0 for no debug informations */
+#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
+
+#define W9968CF_MAX_DEVICES    32
+#define W9968CF_SIMCAMS        W9968CF_MAX_DEVICES /* simultaneous cameras */
+
+#define W9968CF_MAX_BUFFERS   32
+#define W9968CF_BUFFERS       2 /* n. of frame buffers from 2 to MAX_BUFFERS */
+
+/* Maximum data payload sizes in bytes for alternate settings */
+static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
+                                      511, 447, 383, 319, 255, 191, 127,  63};
+#define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
+#define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
+#define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
+#define W9968CF_USB_CTRL_TIMEOUT HZ /* timeout for usb control commands */
+#define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
+
+#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
+#define W9968CF_I2C_RW_RETRIES   15 /* number of max I2C r/w retries */
+
+/* Available video formats */
+struct w9968cf_format {
+	const u16 palette;
+	const u16 depth;
+	const u8 compression;
+};
+
+static const struct w9968cf_format w9968cf_formatlist[] = {
+	{ VIDEO_PALETTE_UYVY,    16, 0 }, /* original video */
+	{ VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
+	{ VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
+	{ VIDEO_PALETTE_YUV420,  12, 1 }, /* same as YUV420P */
+	{ VIDEO_PALETTE_YUYV,    16, 0 }, /* software conversion */
+	{ VIDEO_PALETTE_YUV422,  16, 0 }, /* software conversion */
+	{ VIDEO_PALETTE_GREY,     8, 0 }, /* software conversion */
+	{ VIDEO_PALETTE_RGB555,  16, 0 }, /* software conversion */
+	{ VIDEO_PALETTE_RGB565,  16, 0 }, /* software conversion */
+	{ VIDEO_PALETTE_RGB24,   24, 0 }, /* software conversion */
+	{ VIDEO_PALETTE_RGB32,   32, 0 }, /* software conversion */
+	{ 0,                      0, 0 }  /* 0 is a terminating entry */
+};
+
+#define W9968CF_DECOMPRESSION    2 /* decomp:0=disable,1=force,2=any formats */
+#define W9968CF_PALETTE_DECOMP_OFF   VIDEO_PALETTE_UYVY    /* when decomp=0 */
+#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
+#define W9968CF_PALETTE_DECOMP_ON    VIDEO_PALETTE_UYVY    /* when decomp=2 */
+
+#define W9968CF_FORCE_RGB        0  /* read RGB instead of BGR, yes=1/no=0 */
+
+#define W9968CF_MAX_WIDTH      800 /* should be >= 640 */
+#define W9968CF_MAX_HEIGHT     600 /* should be >= 480 */
+#define W9968CF_WIDTH          320 /* from 128 to 352, multiple of 16 */
+#define W9968CF_HEIGHT         240 /* from  96 to 288, multiple of 16 */
+
+#define W9968CF_CLAMPING       0 /* 0 disable, 1 enable video data clamping */
+#define W9968CF_FILTER_TYPE    0 /* 0 disable  1 (1-2-1), 2 (2-3-6-3-2) */
+#define W9968CF_DOUBLE_BUFFER  1 /* 0 disable, 1 enable double buffer */
+#define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
+#define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
+
+#define W9968CF_SENSOR_MONO    0 /* 0 not monochrome, 1 monochrome sensor */
+#define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
+#define W9968CF_HUE            32768 /* from 0 to 65535 */
+#define W9968CF_COLOUR         32768 /* from 0 to 65535 */
+#define W9968CF_CONTRAST       50000 /* from 0 to 65535 */
+#define W9968CF_WHITENESS      32768 /* from 0 to 65535 */
+
+#define W9968CF_AUTOBRIGHT     0 /* 0 disable, 1 enable automatic brightness */
+#define W9968CF_AUTOEXP        1 /* 0 disable, 1 enable automatic exposure */
+#define W9968CF_LIGHTFREQ      50 /* light frequency. 50Hz (Europe) or 60Hz */
+#define W9968CF_BANDINGFILTER  0 /* 0 disable, 1 enable banding filter */
+#define W9968CF_BACKLIGHT      0 /* 0 or 1, 1=object is lit from behind */
+#define W9968CF_MIRROR         0 /* 0 or 1 [don't] reverse image horizontally*/
+
+#define W9968CF_CLOCKDIV         -1 /* -1 = automatic clock divisor */
+#define W9968CF_DEF_CLOCKDIVISOR  0 /* default sensor clock divisor value */
+
+
+/****************************************************************************
+ * Globals                                                                  *
+ ****************************************************************************/
+
+#define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
+                                "Dual Mode Camera Chip"
+#define W9968CF_MODULE_VERSION  "v1.22"
+#define W9968CF_MODULE_AUTHOR   "(C) 2002 2003 Luca Risolia"
+#define W9968CF_AUTHOR_EMAIL    "<luca_ing@libero.it>"
+
+static u8 w9968cf_vppmod_present; /* status flag: yes=1, no=0 */
+
+static const struct usb_device_id winbond_id_table[] = {
+	{
+		/* Creative Labs Video Blaster WebCam Go Plus */
+		USB_DEVICE(0x041e, 0x4003),
+		.driver_info = (unsigned long)"w9968cf",
+	},
+	{
+		/* Generic W996[87]CF JPEG USB Dual Mode Camera */
+		USB_DEVICE(0x1046, 0x9967),
+		.driver_info = (unsigned long)"w9968cf",
+	},
+	{ } /* terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, winbond_id_table);
+
+/* W996[87]CF camera models, internal ids: */
+enum w9968cf_model_id {
+	W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
+	W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
+	W9968CF_MOD_ADPA5R = 21, /* Aroma Digi Pen ADG-5000 Refurbished */
+	W9986CF_MOD_AU = 31,     /* AVerTV USB */
+	W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */
+	W9968CF_MOD_DLLDK = 37,  /* Die Lebon LDC-D35A Digital Kamera */
+	W9968CF_MOD_EEEMC = 40,   /* Ezonics EZ-802 EZMega Cam */
+	W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
+};
+
+enum w9968cf_frame_status {
+	F_READY,            /* finished grabbing & ready to be read/synced */
+	F_GRABBING,         /* in the process of being grabbed into */
+	F_ERROR,            /* something bad happened while processing */
+	F_UNUSED            /* unused (no VIDIOCMCAPTURE) */
+};
+
+struct w9968cf_frame_t {
+	void* buffer;
+	u32 length;
+	enum w9968cf_frame_status status;
+	struct w9968cf_frame_t* next;
+	u8 queued;
+};
+
+enum w9968cf_vpp_flag {
+	VPP_NONE = 0x00,
+	VPP_UPSCALE = 0x01,
+	VPP_SWAP_YUV_BYTES = 0x02,
+	VPP_DECOMPRESSION = 0x04,
+	VPP_UYVY_TO_RGBX = 0x08,
+};
+
+struct list_head w9968cf_dev_list; /* head of V4L registered cameras list */
+LIST_HEAD(w9968cf_dev_list);
+struct semaphore w9968cf_devlist_sem; /* semaphore for list traversal */
+
+/* Main device driver structure */
+struct w9968cf_device {
+	enum w9968cf_model_id id;   /* private device identifier */
+
+	struct video_device v4ldev; /* V4L structure */
+	struct list_head v4llist;   /* entry of the list of V4L cameras */
+
+	struct usb_device* usbdev;           /* -> main USB structure */
+	struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
+	void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
+	u16* control_buffer;                 /* -> buffer for control req.*/
+	u16* data_buffer;                    /* -> data to send to the FSB */
+
+	struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
+	struct w9968cf_frame_t frame_tmp;  /* temporary frame */
+	struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
+	struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
+	void* vpp_buffer; /* -> helper buffer for post-processing routines */
+
+	u8 max_buffers,   /* number of requested buffers */	   
+	   force_palette, /* yes=1/no=0 */
+	   force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
+	   double_buffer, /* hardware double buffering yes=1/no=0 */
+	   clamping,      /* video data clamping yes=1/no=0 */
+	   filter_type,   /* 0=disabled, 1=3 tap, 2=5 tap filter */
+	   capture,       /* 0=disabled, 1=enabled */
+	   largeview,     /* 0=disabled, 1=enabled */
+	   decompression, /* 0=disabled, 1=forced, 2=allowed */
+	   upscaling;     /* software image scaling, 0=enabled, 1=disabled */
+
+	struct video_picture picture; /* current window settings */
+	struct video_window window;   /* current picture settings */
+
+	u16 hw_depth,    /* depth (used by the chip) */
+	    hw_palette,  /* palette (used by the chip) */
+	    hw_width,    /* width (used by the chip) */
+	    hw_height,   /* height (used by the chip) */
+	    hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
+	    vs_polarity; /* 0=negative sync pulse, 1=positive sync pulse */
+
+	enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
+
+	u8 nbuffers,      /* number of allocated frame buffers */
+	   altsetting,    /* camera alternate setting */
+	   disconnected,  /* flag: yes=1, no=0 */
+	   misconfigured, /* flag: yes=1, no=0 */
+	   users,         /* flag: number of users holding the device */
+	   streaming;     /* flag: yes=1, no=0 */
+
+	int sensor; /* type of image CMOS sensor chip (CC_*) */
+
+	/* Determined by CMOS sensor type */
+	u16 maxwidth,
+	    maxheight,
+	    minwidth,
+	    minheight,
+	    start_cropx,
+	    start_cropy;
+
+	u8  auto_brt,     /* auto brightness enabled flag */
+	    auto_exp,     /* auto exposure enabled flag */
+	    backlight,    /* backlight exposure algorithm flag */
+	    mirror,       /* image is reversed horizontally */
+	    lightfreq,    /* power (lighting) frequency */
+	    bandfilt;     /* banding filter enabled flag */
+	s8  clockdiv;     /* clock divisor */
+	int sensor_mono;  /* CMOS sensor is (probably) monochrome */
+
+	/* I2C interface to kernel */
+	struct i2c_adapter i2c_adapter;
+	struct i2c_client* sensor_client;
+
+#if defined(CONFIG_VIDEO_PROC_FS)
+	/* /proc entries, relative to /proc/video/w9968cf/ */
+	struct proc_dir_entry *proc_dev;   /* readable per-device entry */
+#endif
+
+	/* Locks */
+	struct semaphore dev_sem,    /* for probe, disconnect,open and close */
+	                 fileop_sem; /* for read and ioctl */
+#if defined(CONFIG_VIDEO_PROC_FS)
+	struct semaphore procfs_sem; /* for /proc read/write calls */
+#endif
+	spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
+	           flist_lock; /* for requested frame list accesses */
+	char command[16]; /* name of the program holding the device */
+	wait_queue_head_t open, wait_queue;
+};
+
+#define W9968CF_HW_BUF_SIZE 640*480*2 /* buf. size for original video frames */
+
+#define SENSOR_FORMAT          VIDEO_PALETTE_UYVY
+#define SENSOR_FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
+
+
+/****************************************************************************
+ * Macros and other constants                                               *
+ ****************************************************************************/
+
+#undef DBG
+#ifdef W9968CF_DEBUG
+#	define DBG(level, fmt, args...) \
+{ \
+if ( ((specific_debug) && (debug == (level))) || \
+     ((!specific_debug) && (debug >= (level))) ) { \
+	if ((level) == 1) \
+		err(fmt, ## args); \
+	else if ((level) == 2 || (level) == 3) \
+		info(fmt, ## args); \
+	else if ((level) == 4) \
+		warn(fmt, ## args); \
+	else if ((level) >= 5) \
+		info("[%s,%d] " fmt, \
+		     __PRETTY_FUNCTION__, __LINE__ , ## args); \
+} \
+}
+#else
+	/* Not debugging: nothing */
+#	define DBG(level, fmt, args...) do {;} while(0);
+#endif
+
+#undef PDBG
+#undef PDBGG
+#define PDBG(fmt, args...) info("[%s, %d] "fmt, \
+	                        __PRETTY_FUNCTION__, __LINE__ , ## args);
+#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
+
+#endif /* _W9968CF_H_ */
diff -urN linux-2.4.22-bk41/drivers/usb/w9968cf_decoder.h linux-2.4.22-bk42/drivers/usb/w9968cf_decoder.h
--- linux-2.4.22-bk41/drivers/usb/w9968cf_decoder.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/w9968cf_decoder.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Video decoder for the W996[87]CF driver for Linux.                      *
+ *                                                                         *
+ * Copyright (C) 2003 by Luca Risolia <luca_ing@libero.it>                 *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_DECODER_H_
+#define _W9968CF_DECODER_H_
+
+/* Comment/uncomment this for high/low quality of compressed video */
+#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
+
+#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
+static const unsigned char Y_QUANTABLE[64] = {
+	16,  11,  10,  16,  24,  40,  51,  61,
+	12,  12,  14,  19,  26,  58,  60,  55,
+	14,  13,  16,  24,  40,  57,  69,  56,
+	14,  17,  22,  29,  51,  87,  80,  62,
+	18,  22,  37,  56,  68, 109, 103,  77,
+	24,  35,  55,  64,  81, 104, 113,  92,
+	49,  64,  78,  87, 103, 121, 120, 101,
+	72,  92,  95,  98, 112, 100, 103,  99
+};
+
+static const unsigned char UV_QUANTABLE[64] = {
+	17,  18,  24,  47,  99,  99,  99,  99,
+	18,  21,  26,  66,  99,  99,  99,  99,
+	24,  26,  56,  99,  99,  99,  99,  99,
+	47,  66,  99,  99,  99,  99,  99,  99,
+	99,  99,  99,  99,  99,  99,  99,  99,
+	99,  99,  99,  99,  99,  99,  99,  99,
+	99,  99,  99,  99,  99,  99,  99,  99,
+	99,  99,  99,  99,  99,  99,  99,  99
+};
+#else
+static const unsigned char Y_QUANTABLE[64] = {
+	 8,   5,   5,   8,  12,  20,  25,  30,
+	 6,   6,   7,   9,  13,  29,  30,  27,
+	 7,   6,   8,  12,  20,  28,  34,  28,
+	 7,   8,  11,  14,  25,  43,  40,  31,
+	 9,  11,  18,  28,  34,  54,  51,  38,
+	12,  17,  27,  32,  40,  52,  56,  46,
+	24,  32,  39,  43,  51,  60,  60,  50,
+	36,  46,  47,  49,  56,  50,  51,  49
+};
+
+static const unsigned char UV_QUANTABLE[64] = {
+	 8,   9,  12,  23,  49,  49,  49,  49,
+	 9,  10,  13,  33,  49,  49,  49,  49,
+	12,  13,  28,  49,  49,  49,  49,  49,
+	23,  33,  49,  49,  49,  49,  49,  49,
+	49,  49,  49,  49,  49,  49,  49,  49,
+	49,  49,  49,  49,  49,  49,  49,  49,
+	49,  49,  49,  49,  49,  49,  49,  49,
+	49,  49,  49,  49,  49,  49,  49,  49
+};
+#endif
+
+#define W9968CF_DEC_ERR_CORRUPTED_DATA  -1
+#define W9968CF_DEC_ERR_BUF_OVERFLOW    -2
+#define W9968CF_DEC_ERR_NO_SOI          -3
+#define W9968CF_DEC_ERR_NO_SOF0         -4
+#define W9968CF_DEC_ERR_NO_SOS          -5
+#define W9968CF_DEC_ERR_NO_EOI          -6
+
+extern void w9968cf_init_decoder(void);
+extern int w9968cf_check_headers(const unsigned char* Pin, 
+                                 const unsigned long BUF_SIZE);
+extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE, 
+                          const unsigned W, const unsigned H, char* Pout);
+
+#endif /* _W9968CF_DECODER_H_ */
diff -urN linux-2.4.22-bk41/drivers/usb/w9968cf_externaldef.h linux-2.4.22-bk42/drivers/usb/w9968cf_externaldef.h
--- linux-2.4.22-bk41/drivers/usb/w9968cf_externaldef.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/drivers/usb/w9968cf_externaldef.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * Various definitions for compatibility with external modules.            *
+ * This file is part of the W996[87]CF driver for Linux.                   *
+ *                                                                         *
+ * Copyright (C) 2002 2003 by Luca Risolia <luca_ing@libero.it>            *
+ *                                                                         *
+ * 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.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_EXTERNALDEF_H_
+#define _W9968CF_EXTERNALDEF_H_
+
+#include <linux/videodev.h>
+#include <linux/i2c.h>
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
+/* The following values have been copied from the "ovcamchip" module. */
+
+#ifndef I2C_DRIVERID_OVCAMCHIP
+#	define I2C_DRIVERID_OVCAMCHIP	0xf00f
+#endif
+
+/* Controls */
+enum {
+	OVCAMCHIP_CID_CONT,       /* Contrast */
+	OVCAMCHIP_CID_BRIGHT,     /* Brightness */
+	OVCAMCHIP_CID_SAT,        /* Saturation */
+	OVCAMCHIP_CID_HUE,        /* Hue */
+	OVCAMCHIP_CID_EXP,        /* Exposure */
+	OVCAMCHIP_CID_FREQ,       /* Light frequency */
+	OVCAMCHIP_CID_BANDFILT,   /* Banding filter */
+	OVCAMCHIP_CID_AUTOBRIGHT, /* Auto brightness */
+	OVCAMCHIP_CID_AUTOEXP,    /* Auto exposure */
+	OVCAMCHIP_CID_BACKLIGHT,  /* Back light compensation */
+	OVCAMCHIP_CID_MIRROR,     /* Mirror horizontally */
+};
+
+/* I2C addresses */
+#define OV7xx0_SID   (0x42 >> 1)
+#define OV6xx0_SID   (0xC0 >> 1)
+
+/* Sensor types */
+enum {
+	CC_UNKNOWN,
+	CC_OV76BE,
+	CC_OV7610,
+	CC_OV7620,
+	CC_OV7620AE,
+	CC_OV6620,
+	CC_OV6630,
+	CC_OV6630AE,
+	CC_OV6630AF,
+};
+
+/* API */
+struct ovcamchip_control {
+	__u32 id;
+	__s32 value;
+};
+
+struct ovcamchip_window {
+	int x;
+	int y;
+	int width;
+	int height;
+	int format;
+	int quarter;		/* Scale width and height down 2x */
+
+	/* This stuff will be removed eventually */
+	int clockdiv;		/* Clock divisor setting */
+};
+
+/* Commands. 
+   You must call OVCAMCHIP_CMD_INITIALIZE before any of other commands */
+#define OVCAMCHIP_CMD_Q_SUBTYPE  _IOR  (0x88, 0x00, int)
+#define OVCAMCHIP_CMD_INITIALIZE _IOW  (0x88, 0x01, int)
+#define OVCAMCHIP_CMD_S_CTRL     _IOW  (0x88, 0x02, struct ovcamchip_control)
+#define OVCAMCHIP_CMD_G_CTRL     _IOWR (0x88, 0x03, struct ovcamchip_control)
+#define OVCAMCHIP_CMD_S_MODE     _IOW  (0x88, 0x04, struct ovcamchip_window)
+#define OVCAMCHIP_MAX_CMD        _IO   (0x88, 0x3f)
+
+#endif /* _W9968CF_EXTERNALDEF_H_ */
diff -urN linux-2.4.22-bk41/include/asm-arm/hc_sl811-hw.h linux-2.4.22-bk42/include/asm-arm/hc_sl811-hw.h
--- linux-2.4.22-bk41/include/asm-arm/hc_sl811-hw.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/include/asm-arm/hc_sl811-hw.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,139 @@
+/*
+File: include/asm-arm/hc_sl811-hw.h
+*/
+
+/* The base_addr, data_reg_addr, and irq number are board specific.
+ * The current values are design to run on the Accelent SA1110 IDP
+ * NOTE: values need to modify for different development boards
+ */
+
+#define SIZEOF_IO_REGION	256	/* Size for request/release region */
+static int base_addr	 = 0xd3800000;
+static int data_reg_addr = 0xd3810000;
+static int irq		 = 34;		/* Also change SL811_SET_GPDR! */
+static int gprd 	 = 13;		/* also change irq  !!! */
+
+MODULE_PARM (base_addr, "i");
+MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000");
+MODULE_PARM (data_reg_addr, "i");
+MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000");
+MODULE_PARM (irq, "i");
+MODULE_PARM_DESC (irq, "IRQ 34 (default)");
+MODULE_PARM(gprd,"i");
+MODULE_PARM_DESC(gprd,"sl811 GPRD port 13(default)");
+
+/*
+ * Low level: Read from Data port [arm]
+ */
+static __u8 inline sl811_read_data (hcipriv_t *hp)
+{
+	__u8 data;
+	data = readb (hp->hcport2);
+	rmb ();
+	return (data);
+}
+
+/*
+ * Low level: Write to index register [arm]
+ */
+static void inline sl811_write_index (hcipriv_t *hp, __u8 index)
+{
+	writeb (offset, hp->hcport);
+	wmb ();
+}
+
+/*
+ * Low level: Write to Data port [arm]
+ */
+static void inline sl811_write_data (hcipriv_t *hp, __u8 data)
+{
+	writeb (data, hp->hcport2);
+}
+
+/*
+ * Low level: Write to index register and data port [arm]
+ */
+static void inline sl811_write_index_data (hcipriv_t *hp, __u8 index, __u8 data)
+{
+	writeb (offset, hp->hcport);
+	writeb (data, hp->hcport2);
+	wmb ();
+}
+
+/*****************************************************************
+ *
+ * Function Name: init_irq [arm]
+ *
+ * This function is board specific.  It sets up the interrupt to
+ * be an edge trigger and trigger on the rising edge
+ *
+ * Input: none
+ *
+ * Return value  : none
+ *
+ *****************************************************************/
+static void inline init_irq (void)
+{
+	GPDR &= ~(1 << gprd);
+	set_GPIO_IRQ_edge (1 << gprd, GPIO_RISING_EDGE);
+}
+
+/*****************************************************************
+ *
+ * Function Name: release_regions [arm]
+ *
+ * This function is board specific.  It frees all io address.
+ *
+ * Input: hcipriv_t *
+ *
+ * Return value  : none
+ *
+ *****************************************************************/
+static void inline release_regions (hcipriv_t *hp)
+{
+	if (hp->hcport > 0) {
+		release_region (hp->hcport, SIZEOF_IO_REGION);
+		hp->hcport = 0;
+	}
+
+	if (hp->hcport2 > 0) {
+		release_region (hp->hcport2, SIZEOF_IO_REGION);
+		hp->hcport2 = 0;
+	}
+}
+
+/*****************************************************************
+ *
+ * Function Name: request_regions [arm]
+ *
+ * This function is board specific. It request all io address and
+ * maps into memory (if can).
+ *
+ * Input: hcipriv_t *
+ *
+ * Return value  : 0 = OK
+ *                
+ *****************************************************************/
+static int inline request_regions (hcipriv_t *hp, int addr1, int addr2)
+{
+	if (!request_region (addr1, SIZEOF_IO_REGION, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr1);
+		return -EBUSY;
+	}
+	hp->hcport = addr1;
+	if (!hp->hcport) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", addr1);
+	}
+
+	if (!request_region (addr2, SIZEOF_IO_REGION, "SL811 USB HOST")) {
+		DBGERR ("request address %d failed", addr2);
+		return -EBUSY;
+	}
+	hp->hcport2 = addr2;
+	if (!hp->hcport2) {
+		DBGERR ("Error mapping SL811 Memory 0x%x", addr2);
+	}
+
+	return 0;
+}
+
diff -urN linux-2.4.22-bk41/include/asm-arm/sl811-hw.h linux-2.4.22-bk42/include/asm-arm/sl811-hw.h
--- linux-2.4.22-bk41/include/asm-arm/sl811-hw.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/include/asm-arm/sl811-hw.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,148 @@
+/*
+File: include/asm-arm/sl811-hw.h
+
+19.09.2003 hne@ist1.de
+Use Kernel 2.4.20 and this source from 2.4.22
+Splitt hardware depens into file sl811-x86.h and sl811-arm.h.
+Functions as inline.
+
+23.09.2003 hne
+Move Hardware depend header sl811-arm.h into include/asm-arm/sl811-hw.h.
+GPRD as parameter.
+
+24.09.2003 hne
+Use Offset from ADDR to DATA instand of direct io.
+
+03.10.2003 hne
+Low level only for port io into hardware-include.
+*/
+
+#ifndef __LINUX_SL811_HW_H
+#define __LINUX_SL811_HW_H
+
+#define MAX_CONTROLERS		1	/* Max number of sl811 controllers */
+					/* Always 1 for this architecture! */
+
+#define SIZEOF_IO_REGION	1	/* Size for request/release region */
+
+#define OFFSET_DATA_REG data_off	/* Offset from ADDR_IO to DATA_IO (future) */
+					/* Can change by arg */
+
+static int io = 0xf100000e;	/* Base addr_io */
+static int data_off = 1;	/* Offset from addr_io to addr_io */
+static int irq = 44;		/* also change gprd !!! */
+static int gprd = 23;		/* also change irq  !!! */
+
+MODULE_PARM(io,"i");
+MODULE_PARM_DESC(io,"sl811 address io port 0xf100000e");
+MODULE_PARM(data_off,"i");
+MODULE_PARM_DESC(data_off,"sl811 data io port offset from address port (default 1)");
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq,"sl811 irq 44(default)");
+MODULE_PARM(gprd,"i");
+MODULE_PARM_DESC(gprd,"sl811 GPRD port 23(default)");
+
+/*
+ * Low level: Read from Data port [arm]
+ */
+static __u8 inline sl811_read_data (struct sl811_hc *hc)
+{
+	__u8 data;
+	data = readb(hc->data_io);
+	rmb();
+	return data;
+}
+
+/*
+ * Low level: Write to index register [arm]
+ */
+static void inline sl811_write_index (struct sl811_hc *hc, __u8 index)
+{
+	writeb(index, hc->addr_io);
+	wmb();
+}
+
+/*
+ * Low level: Write to Data port [arm]
+ */
+static void inline sl811_write_data (struct sl811_hc *hc, __u8 data)
+{
+	writeb(data, hc->data_io);
+	wmb();
+}
+
+/*
+ * Low level: Write to index register and data port [arm]
+ */
+static void inline sl811_write_index_data (struct sl811_hc *hc, __u8 index, __u8 data)
+{
+	writeb(index, hc->addr_io);
+	writeb(data, hc->data_io);
+	wmb();
+}
+
+
+/*
+ * This	function is board specific.  It	sets up	the interrupt to
+ * be an edge trigger and trigger on the rising	edge
+ */
+static void inline sl811_init_irq(void)
+{
+	GPDR &=	~(1<<gprd);
+	set_GPIO_IRQ_edge(1<<gprd, GPIO_RISING_EDGE);
+}
+
+/*****************************************************************
+ *
+ * Function Name: release_regions [arm]
+ *
+ * This function is board specific. It release all io address
+ * from memory (if can).
+ *
+ * Input: struct sl811_hc * *
+ *
+ * Return value  : 0 = OK
+ *
+ *****************************************************************/
+static void inline sl811_release_regions(struct sl811_hc *hc)
+{
+	if (hc->addr_io)
+		release_region(hc->addr_io, SIZEOF_IO_REGION);
+	hc->addr_io = 0;
+
+	if (hc->data_io)
+		release_region(hc->data_io, SIZEOF_IO_REGION);
+	hc->data_io = 0;
+}
+
+/*****************************************************************
+ *
+ * Function Name: request_regions [arm]
+ *
+ * This function is board specific. It request all io address and
+ * maps into memory (if can).
+ *
+ * Input: struct sl811_hc *
+ *
+ * Return value  : 0 = OK
+ *
+ *****************************************************************/
+static int inline sl811_request_regions (struct sl811_hc *hc, int addr_io, int data_io, const char *name)
+{
+	if (!request_region(addr_io, SIZEOF_IO_REGION, name)) {
+		PDEBUG(3, "request address %d failed", addr_io);
+		return -EBUSY;
+	}
+	hc->addr_io =	addr_io;
+
+	if (!request_region(data_io, SIZEOF_IO_REGION, MODNAME)) {
+		PDEBUG(3, "request address %d failed", data_io);
+		/* release_region(hc->addr_io, SIZEOF_IO_REGION); */
+		return -EBUSY;
+	}
+	hc->data_io =	data_io;
+
+	return 0;
+}
+
+#endif // __LINUX_SL811_HW_H
diff -urN linux-2.4.22-bk41/include/asm-i386/hc_sl811-hw.h linux-2.4.22-bk42/include/asm-i386/hc_sl811-hw.h
--- linux-2.4.22-bk41/include/asm-i386/hc_sl811-hw.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/include/asm-i386/hc_sl811-hw.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,139 @@
+/*
+File: include/asm-i386/hc_sl811-hw.h
+
+18.11.2002 hne@ist1.de
+Use Kernel 2.4.19 and Prepatch 2.4.20
+Splitt hardware depenc into file hc_sl811-x86.c and hc_sl811-arm.c.
+
+20.11.2002 HNE
+READ/WRITE_(INDEX_)DATA using for fast hardware access.
+
+02.09.2003 HNE
+IO Region size only 2 (old 16)
+
+18.09.2003 HNE
+Handle multi instances. For two controller on one board.
+Portcheck in low level source (DEBUG) only.
+
+03.10.2003 HNE
+Low level only for port io into hardware-include.
+
+*/
+
+#ifdef MODULE
+
+#define MAX_CONTROLERS	2	/* Max number of SL811 controllers per module */
+static int io_base	= 0x220;
+static int irq	= 12;
+
+MODULE_PARM(io_base,"i");
+MODULE_PARM_DESC(io_base,"sl811 base address 0x220");
+MODULE_PARM(irq,"i");
+MODULE_PARM_DESC(irq,"IRQ 12 (default)");
+
+#endif // MODULE
+
+/* Define general IO Macros for our platform (hne) */
+#define SIZEOF_IO_REGION	2	/* Size for request/release region */
+
+// #define sl811_write_index(hp,i) outb ((i), hp->hcport)
+// #define sl811_write_data(hp,d) outb ((d), hp->hcport+1)
+// #define sl811_write_index_data(hp,i,d) outw ((i)|(((__u16)(d)) << 8), hp->hcport)
+// #define sl811_read_data(hp) ((__u8) inb (hp->hcport+1))
+
+/*
+ * Low level: Read from Data port [x86]
+ */
+static __u8 inline sl811_read_data (hcipriv_t *hp)
+{
+	return ((__u8) inb (hp->hcport+1));
+}
+
+/*
+ * Low level: Write to index register [x86]
+ */
+static void inline sl811_write_index (hcipriv_t *hp, __u8 index)
+{
+	outb (index, hp->hcport);
+}
+
+/*
+ * Low level: Write to Data port [x86]
+ */
+static void inline sl811_write_data (hcipriv_t *hp, __u8 data)
+{
+	outb (data, hp->hcport+1);
+}
+
+/*
+ * Low level: Write to index register and data port [x86]
+ */
+static void inline sl811_write_index_data (hcipriv_t *hp, __u8 index, __u8 data)
+{
+	outw (index|(((__u16)data) << 8), hp->hcport);
+}
+
+/*****************************************************************
+ *
+ * Function Name: init_irq [x86]
+ *
+ * This function is board specific.  It sets up the interrupt to
+ * be an edge trigger and trigger on the rising edge
+ *
+ * Input: none
+ *
+ * Return value  : none
+ *
+ *****************************************************************/
+static void inline init_irq (void)
+{
+	/* nothing */
+}
+
+/*****************************************************************
+ *
+ * Function Name: release_regions [x86]
+ *
+ * This function is board specific.  It frees all io address.
+ *
+ * Input: hcipriv_t *
+ *
+ * Return value  : none
+ *
+ *****************************************************************/
+static void inline sl811_release_regions (hcipriv_t *hp)
+{
+	DBGFUNC ("Enter release_regions\n");
+	if (hp->hcport > 0) {
+		release_region (hp->hcport, SIZEOF_IO_REGION);
+		hp->hcport = 0;
+	}
+
+	/* hcport2 unused for x86 */
+}
+
+/*****************************************************************
+ *
+ * Function Name: request_regions [x86]
+ *
+ * This function is board specific. It request all io address and
+ * maps into memory (if can).
+ *
+ * Input: hcipriv_t *
+ *
+ * Return value  : 0 = OK
+ *
+ *****************************************************************/
+static int inline sl811_request_regions (hcipriv_t *hp, int base1, int base2)
+{
+	DBGFUNC ("Enter request_regions\n");
+	if (!request_region (base1, SIZEOF_IO_REGION, "SL811")) {
+		DBGERR ("request address 0x%X %d failed\n", base1, SIZEOF_IO_REGION);
+		return -EBUSY;
+	}
+	hp->hcport = base1;
+
+	/* hcport2 unused for x86 */
+	return 0;
+}
+
diff -urN linux-2.4.22-bk41/include/asm-i386/sl811-hw.h linux-2.4.22-bk42/include/asm-i386/sl811-hw.h
--- linux-2.4.22-bk41/include/asm-i386/sl811-hw.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk42/include/asm-i386/sl811-hw.h	2003-10-26 02:49:55.000000000 -0800
@@ -0,0 +1,133 @@
+/*
+File: include/asm-i386/sl811-hw.h
+
+19.09.2003 hne@ist1.de
+Use Kernel 2.4.20 and this source from 2.4.22
+Splitt hardware depens into file sl811-x86.h and sl811-arm.h.
+Functions are inline.
+
+Handle multi instances. For two controller on one board.
+"hc->data_io" not used for x86 arch.
+
+22.09.2003 hne
+Alternate IO-Base for second Controller (CF/USB1).
+
+23.09.2003 hne
+Move Hardware depend header sl811-x86.h into include/asm-i386/sl811-hw.h.
+
+03.10.2003 hne
+Low level only for port io into hardware-include.
+*/
+
+#ifndef __LINUX_SL811_HW_H
+#define __LINUX_SL811_HW_H
+
+#define MAX_CONTROLERS  2       /* Max number of SL811 controllers per module */
+
+static int io[MAX_CONTROLERS] = { 0x220, 0x222 };	/* IO ports for controllers */
+static int irq[MAX_CONTROLERS] = { 12, 12 };		/* Interrupt list */
+
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CONTROLERS) "i");
+MODULE_PARM_DESC(io, "I/O base address(es), 0x220,0x222 default");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CONTROLERS) "i");
+MODULE_PARM_DESC(irq, "IRQ number(s), 12,12 default");
+
+#define OFFSET_DATA_REG		1	/* Offset from ADDR_IO to DATA_IO */
+					/* Do not change this! */
+#define SIZEOF_IO_REGION	2	/* Size for request/release region */
+
+/*
+ * Low level: Read from Data port [x86]
+ */
+static __u8 inline sl811_read_data (struct sl811_hc *hc)
+{
+	return ((__u8) inb (hc->addr_io+OFFSET_DATA_REG));
+}
+
+/*
+ * Low level: Write to index register [x86]
+ */
+static void inline sl811_write_index (struct sl811_hc *hc, __u8 index)
+{
+	outb (index, hc->addr_io);
+}
+
+/*
+ * Low level: Write to Data port [x86]
+ */
+static void inline sl811_write_data (struct sl811_hc *hc, __u8 data)
+{
+	outb (data, hc->addr_io+OFFSET_DATA_REG);
+}
+
+/*
+ * Low level: Write to index register and data port [x86]
+ */
+static void inline sl811_write_index_data (struct sl811_hc *hc, __u8 index, __u8 data)
+{
+	outw (index|(((__u16)data) << 8), hc->addr_io);
+}
+
+/*
+ * This	function is board specific.  It	sets up	the interrupt to
+ * be an edge trigger and trigger on the rising	edge
+ */
+static void inline sl811_init_irq(void)
+{
+	/* nothing for x86 */
+}
+
+
+/*****************************************************************
+ *
+ * Function Name: release_regions [x86]
+ *
+ * This function is board specific. It release all io address
+ * from memory (if can).
+ *
+ * Input: struct sl811_hc * *
+ *
+ * Return value  : 0 = OK
+ *
+ *****************************************************************/
+static void inline sl811_release_regions(struct sl811_hc *hc)
+{
+	if (hc->addr_io)
+		release_region(hc->addr_io, SIZEOF_IO_REGION);
+	hc->addr_io = 0;
+
+	/* data_io unused for x86 */
+	/* ...
+	if (hc->data_io)
+		release_region(hc->data_io, SIZEOF_IO_REGION);
+	hc->data_io = 0;
+	... */
+}
+
+/*****************************************************************
+ *
+ * Function Name: request_regions [x86]
+ *
+ * This function is board specific. It request all io address and
+ * maps into memory (if can).
+ *
+ * Input: struct sl811_hc *
+ *
+ * Return value  : 0 = OK
+ *
+ *****************************************************************/
+static int inline sl811_request_regions (struct sl811_hc *hc, int addr_io, int data_io, const char *name)
+{
+	if (!request_region(addr_io, SIZEOF_IO_REGION, name)) {
+		PDEBUG(3, "request address %d failed", addr_io);
+		return -EBUSY;
+	}
+	hc->addr_io =	addr_io;
+
+	/* data_io unused for x86 */
+	/* hc->data_io = data_io; */
+
+	return 0;
+}
+
+#endif // __LINUX_SL811_HW_H
diff -urN linux-2.4.22-bk41/include/linux/i2c-id.h linux-2.4.22-bk42/include/linux/i2c-id.h
--- linux-2.4.22-bk41/include/linux/i2c-id.h	2003-06-13 07:51:38.000000000 -0700
+++ linux-2.4.22-bk42/include/linux/i2c-id.h	2003-10-26 02:49:55.000000000 -0800
@@ -199,6 +199,7 @@
 #define I2C_HW_SMBUS_AMD756	0x05
 #define I2C_HW_SMBUS_SIS5595	0x06
 #define I2C_HW_SMBUS_ALI1535	0x07
+#define I2C_HW_SMBUS_W9968CF	0x08
 
 /* --- ISA pseudo-adapter						*/
 #define I2C_HW_ISA 0x00
diff -urN linux-2.4.22-bk41/include/linux/usb_ch9.h linux-2.4.22-bk42/include/linux/usb_ch9.h
--- linux-2.4.22-bk41/include/linux/usb_ch9.h	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/include/linux/usb_ch9.h	2003-10-26 02:49:55.000000000 -0800
@@ -116,6 +116,17 @@
 #define USB_DT_DEVICE_QUALIFIER		0x06
 #define USB_DT_OTHER_SPEED_CONFIG	0x07
 #define USB_DT_INTERFACE_POWER		0x08
+/* these are from a minor usb 2.0 revision (ECN) */
+#define USB_DT_OTG			0x09
+#define USB_DT_DEBUG			0x0a
+#define USB_DT_INTERFACE_ASSOCIATION	0x0b
+
+/* conventional codes for class-specific descriptors */
+#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
 
 /* All standard descriptors have these 2 fields at the beginning */
 struct usb_descriptor_header {
@@ -165,6 +176,7 @@
 #define USB_CLASS_CDC_DATA		0x0a
 #define USB_CLASS_CSCID			0x0b	/* chip+ smart card */
 #define USB_CLASS_CONTENT_SEC		0x0d	/* content security */
+#define USB_CLASS_VIDEO			0x0e
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
@@ -283,6 +295,36 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* USB_DT_OTG (from OTG 1.0a supplement) */
+struct usb_otg_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__u8  bmAttributes;	/* support for HNP, SRP, etc */
+} __attribute__ ((packed));
+
+/* from usb_otg_descriptor.bmAttributes */
+#define USB_OTG_SRP		(1 << 0)
+#define USB_OTG_HNP		(1 << 1)	/* swap host/device roles */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
+struct usb_interface_assoc_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+
+	__u8  bFirstInterface;
+	__u8  bInterfaceCount;
+	__u8  bFunctionClass;
+	__u8  bFunctionSubClass;
+	__u8  bFunctionProtocol;
+	__u8  iFunction;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
 /* USB 2.0 defines three speeds, here's how Linux identifies them */
 
 enum usb_device_speed {
diff -urN linux-2.4.22-bk41/include/linux/videodev.h linux-2.4.22-bk42/include/linux/videodev.h
--- linux-2.4.22-bk41/include/linux/videodev.h	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/include/linux/videodev.h	2003-10-26 02:49:55.000000000 -0800
@@ -420,6 +420,7 @@
 #define VID_HARDWARE_CPIA2	33
 #define VID_HARDWARE_VICAM      34
 #define VID_HARDWARE_SF16FMR2	35
+#define VID_HARDWARE_W9968CF	36
 #endif /* __LINUX_VIDEODEV_H */
 
 /*
diff -urN linux-2.4.22-bk41/kernel/sysctl.c linux-2.4.22-bk42/kernel/sysctl.c
--- linux-2.4.22-bk41/kernel/sysctl.c	2003-10-26 02:49:50.000000000 -0800
+++ linux-2.4.22-bk42/kernel/sysctl.c	2003-10-26 02:49:55.000000000 -0800
@@ -180,7 +180,7 @@
 	 0644, NULL, &proc_dointvec},
 	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
 	 0644, NULL, &proc_dointvec},
-	{KERN_CORE_USES_PID, "core_setuid_ok", &core_setuid_ok, sizeof(int),
+	{KERN_CORE_SETUID, "core_setuid_ok", &core_setuid_ok, sizeof(int),
 	0644, NULL, &proc_dointvec},
 	{KERN_CORE_PATTERN, "core_pattern", core_pattern, 64,
 	 0644, NULL, &proc_dostring, &sysctl_string},
