]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.41pre1 2.3.41pre1
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:30:21 +0000 (15:30 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:30:21 +0000 (15:30 -0500)
73 files changed:
CREDITS
Documentation/Configure.help
Documentation/usb/CREDITS
Documentation/usb/ibmcam.txt [new file with mode: 0644]
Documentation/usb/ohci-hcd.txt [deleted file]
Documentation/usb/ohci.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arm/kernel/signal.c
arch/i386/kernel/ls [deleted file]
arch/i386/kernel/signal.c
arch/m68k/kernel/signal.c
drivers/char/pc_keyb.c
drivers/scsi/Makefile
drivers/scsi/aic7xxx/aic7xxx.seq
drivers/scsi/eata_dma.c
drivers/scsi/eata_dma_proc.c
drivers/scsi/gdth.c
drivers/scsi/gdth.h
drivers/scsi/gdth_proc.c
drivers/scsi/gdth_proc.h
drivers/scsi/hosts.c
drivers/scsi/hosts.h
drivers/scsi/pci2220i.h
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_dma.c [new file with mode: 0644]
drivers/scsi/scsi_ioctl.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_obsolete.c
drivers/scsi/scsi_scan.c [new file with mode: 0644]
drivers/scsi/sd.c
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/scsi/sr_vendor.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/dabusb.c
drivers/usb/graphire.c
drivers/usb/hid.c
drivers/usb/hid.h
drivers/usb/hub.c
drivers/usb/ibmcam.c [new file with mode: 0644]
drivers/usb/ibmcam.h [new file with mode: 0644]
drivers/usb/keybdev.c
drivers/usb/mousedev.c
drivers/usb/ohci-hcd.c [deleted file]
drivers/usb/ohci-hcd.h [deleted file]
drivers/usb/uhci-debug.c [deleted file]
drivers/usb/uhci-debug.h
drivers/usb/uhci.c [deleted file]
drivers/usb/uhci.h [deleted file]
drivers/usb/usb-core.c
drivers/usb/usb-debug.c
drivers/usb/usb-ohci.c [new file with mode: 0644]
drivers/usb/usb-ohci.h [new file with mode: 0644]
drivers/usb/usb-serial.c
drivers/usb/usb-uhci.c [new file with mode: 0644]
drivers/usb/usb-uhci.h [new file with mode: 0644]
drivers/usb/usb.c
drivers/usb/usb.h
drivers/usb/usb_scsi.c
drivers/usb/wmforce.c
include/asm-arm/siginfo.h
include/asm-i386/siginfo.h
include/asm-m68k/siginfo.h
include/linux/highuid.h
include/linux/input.h
include/linux/mm.h
include/linux/slab.h
kernel/signal.c
mm/page_alloc.c

diff --git a/CREDITS b/CREDITS
index ea8764167fe8e8b09c1aed8c44d250db7db559f5..a5ab5e9cd689bd8467e59a56e3600eac8f98e316 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1661,7 +1661,7 @@ E: vojtech@suse.cz
 D: Joystick driver
 D: arcnet-hardware readme
 D: Minor ARCnet hacking
-D: USB hacking
+D: USB (HID, ACM, Printer ...)
 S: Ucitelska 1576
 S: Prague 8
 S: 182 00 Czech Republic
index 53838c6cdd538840651aa312e15f9825a73647c2..8ee3e46007668140c9f55b6ce58e2f94834af3be 100644 (file)
@@ -7937,8 +7937,8 @@ CONFIG_USB_UHCI
   The module will be called usb-uhci.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
   
-OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, ...) support?
-CONFIG_USB_OHCI_HCD
+OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support?
+CONFIG_USB_OHCI
   The Open Host Controller Interface is a standard by
   Compaq/Microsoft/National for accessing the USB PC hardware (also
   called USB host controller). If your USB host controller conforms
@@ -7947,11 +7947,11 @@ CONFIG_USB_OHCI_HCD
   chipsets - like SiS (actual 610, 610 and so on) or ALi (ALi IV, ALi V,
   Aladdin Pro..) - conform to this standard.
 
-  You may want to read the file Documentation/usb/ohci-hcd.txt.
+  You may want to read the file Documentation/usb/ohci.txt.
 
   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 usb-ohci-hcd.o. If you want to compile it
+  The module will be called usb-ohci.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
 USB Human Interface Device (HID) support
@@ -8103,6 +8103,18 @@ CONFIG_USB_CPIA
   The module will be called cpia.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+USB IBM (Xirlink) C-It Camera support
+CONFIG_USB_IBMCAM
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port.
+
+  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 ibmcam.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. This camera
+  has several configuration options which can be specified when you
+  load the module. Read Documentation/usb/ibmcam.txt to learn more.
+
 USB OV511 Camera support
 CONFIG_USB_OV511
   Say Y here if you want to connect this type of camera to your
index 738b55efcdd6b277b7ff887655cded3ebf08c894..b1230f70a16a04c3cc27bdbeedf4448c5190073b 100644 (file)
@@ -12,6 +12,7 @@ difficult to maintain, add yourself with a patch if desired.
   ham <ham@unsuave.com>
   Bradley M Keryan <keryan@andrew.cmu.edu>
   Greg Kroah-Hartman <greg@kroah.com>
+  Pavel Machek <pavel@suse.cz>
   Paul Mackerras <paulus@cs.anu.edu.au>
   David E. Nelson <dnelson@jump.net>
   Vojtech Pavlik <vojtech@suse.cz>
diff --git a/Documentation/usb/ibmcam.txt b/Documentation/usb/ibmcam.txt
new file mode 100644 (file)
index 0000000..e668dfc
--- /dev/null
@@ -0,0 +1,167 @@
+README for Linux device driver for the IBM "C-It" USB video camera
+
+INTRODUCTION:
+
+This driver does not use all features known to exist in
+the IBM camera. However most of needed features work well.
+
+This driver was developed using logs of observed USB traffic
+which was produced by standard Windows driver (c-it98.sys).
+I did not have any input from Xirlink. Some people asked about
+data sheets, but nothing came out of that. I didn't try.
+
+Video formats: 128x96, 176x144, 352x288
+Frame rate: 3 - 30 frames per second (FPS)
+External interface: USB
+Internal interface: Video For Linux (V4L)
+Supported controls:
+- by V4L: Contrast,  Brightness, Color, Hue
+- by driver options: frame rate, lighting conditions, video format,
+                     default picture settings, sharpness.
+
+SUPPORTED CAMERAS:
+
+IBM "C-It" camera, also known as "Xirlink PC Camera"
+The device uses proprietary ASIC (and compression method);
+it is manufactured by Xirlink. See http://www.xirlink.com
+
+WHAT YOU NEED:
+
+- A camera
+
+- A Linux box with USB support (2.3/2.4 or 2.2 w/backport)
+
+- A Video4Linux compatible frame grabber program such as xawtv.
+  
+HOW TO COMPILE THE DRIVER:
+
+You need to compile the driver only if you are a developer
+or if you want to make changes to the code. Most distributions
+precompile all modules, so you can go directly to the next
+section "HOW TO USE THE DRIVER".
+
+The driver consists of two files in usb/ directory:
+ibmcam.c and ibmcam.h These files are included into the
+Linux kernel build process if you configure the kernel
+for CONFIG_USB_IBMCAM. Run "make xconfig" and in USB section
+you will find the IBM camera driver. Select it, save the
+configuration and recompile.
+
+HOW TO USE THE DRIVER:
+
+I recommend to compile driver as a module. This gives you an
+easier access to its configuration. The camera has many more
+settings than V4L can operate, so some settings are done using
+module options.
+
+Typically module is installed with command 'modprobe', like this:
+
+# modprobe ibmcam framerate=1
+
+Alternatively you can use 'insmod' in similar fashion:
+
+# insmod /lib/modules/2.x.y/usb/ibmcam.o framerate=1
+
+Module can be inserted with camera connected or disconnected.
+
+The driver can have options, though some defaults are provided.
+
+Driver options:
+
+Name            Type            Range [default] Example
+--------------  --------------  --------------  ------------------
+debug           Integer         0-9 [0]         debug=1
+flags           Integer         0-0xFF [0]      flags=0x0d
+framerate       Integer         0-6 [2]         framerate=1
+init_brightness Integer         0-255 [128]     init_brightness=100
+init_contrast   Integer         0-255 [192]     init_contrast=200
+init_color      Integer         0-255 [128]     init_color=130
+init_hue        Integer         0-255 [128]     init_hue=115
+lighting        Integer         0-2 [1]         lighting=2
+sharpness       Integer         0-6 [4]         sharpness=3
+videosize       Integer         0-2 [2]         videosize=1
+
+debug           You don't need this option unless you are a developer.
+                If you are a developer then you will see in the code
+                what values do what. 0=off.
+
+flags           This is a bit mask, and you can combine any number of
+                bits to produce what you want. Usually you don't want
+                any of extra features this option provides:
+
+                FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
+                                           VIDIOCSYNC ioctls without failing.
+                                           Will work with xawtv, will not
+                                           with xrealproducer. Default is
+                                           not set.
+                FLAGS_MONOCHROME       2  Forces monochrome (b/w) mode.
+                FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
+                                           magic meaning to developers.
+                FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
+                                           useful only for debugging.
+                FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+
+framerate       This setting controls frame rate of the camera. This is
+                an approximate setting (in terms of "worst" ... "best")
+                because camera changes frame rate depending on amount
+                of light available. Setting 0 is slowest, 6 is fastest.
+                Beware - fast settings are very demanding and may not
+                work well with all video sizes. Be conservative.
+
+init_brightness These settings specify _initial_ values which will be
+init_contrast   used to set up the camera. If your V4L application has
+init_color      its own controls to adjust the picture then these
+init_hue        controls will be used too. These options allow you to
+                preconfigure the camera when it gets connected, before
+                any V4L application connects to it. Good for webcams.
+
+lighting        This option selects one of three hardware-defined
+                photosensitivity settings of the camera. 0=bright light,
+                1=Medium (default), 2=Low light. This setting affects
+                frame rate: the dimmer the lighting the lower the frame
+                rate (because longer exposition time is needed).
+
+sharpness       This option controls smoothing (noise reduction)
+                made by camera. Setting 0 is most smooth, setting 6
+                is most sharp. Be aware that CMOS sensor used in the
+                camera is pretty noisy, so if you choose 6 you will
+                be greeted with "snowy" image. Default is 4.
+
+videosize       This setting chooses one if three image sizes that are
+                supported by this driver. Camera supports more, but
+                it's difficult to reverse-engineer all formats.
+                Following video sizes are supported:
+
+                videosize=0     128x96
+                videosize=1     176x144
+                videosize=2     352x288
+
+                The last one (352x288) is the native size of the sensor
+                array, so it's the best resolution camera can yield.
+                Choose the image size you need. The smaller image can
+                support faster frame rate. Default is 352x288.
+
+WHAT NEEDS TO BE DONE:
+
+- The box freezes if working camera (with xawtv) is unplugged (OHCI).
+  Workaround: don't do that :) End the V4L application first.
+- Some USB frames are lost on high frame rates, though they shouldn't
+- ViCE compression (Xirlink proprietary) may improve frame rate
+- On occasion camera does not start properly; xawtv reports errors.
+  Workaround: reload the driver module. Reason: [1].
+- On occasion camera produces negative image (funny colors.)
+  Workaround: reload the driver module. Reason: [1].
+- The button on the camera is not used. I don't know how to get to it.
+- The LED on the camera goes off after video init.
+
+[1]
+- I2O interface does not read what camera reports back. Actually, it
+  reads it, but I don't know what returned data means. If camera fails
+  at some initialization stage then something should be done, and I don't
+  do that because I don't even know that some command failed.
+
+CREDITS:
+
+The code is based in no small part on the CPiA driver by Johannes Erdfelt,
+Randy Dunlap, and others. Big thanks to them for their pioneering work on that
+and the USB stack.
diff --git a/Documentation/usb/ohci-hcd.txt b/Documentation/usb/ohci-hcd.txt
deleted file mode 100644 (file)
index 37a6372..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-
-The OHCI HCD layer is a simple but nearly complete implementation of what the
-USB people would call a HCD  for the OHCI. 
- (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
-It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
-The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
-
-- Roman Weissgaerber <weissg@vienna.at>
-
- * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers 
- * v2.1 1999/05/09 ep_addr correction, code cleanup
- * v0.2.0 1999/05/04 
- * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
- * virtual root hub is now an option, 
- * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
- * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
- * 
- * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
- * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
- * 
- * v0.1.0 1999/04/27 initial release
-to remove the module try:
-rmmod usb-ohci-hcd
-
-Features:
-- virtual root hub, all basic hub descriptors and commands (state: complete) 
-  this is an option now (v0.2.0)
-  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
-  default is with. 
-  (at the moment: the Virtual Root Hub is included automatically)
-  
-  files: ohci-root-hub.c, ohci-root-hub.h 
-
-- Endpoint Descriptor (ED) handling more static approach 
- (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
- as long as the function (device) is alive or another configuration is choosen.
- In the HCD layer the EDs has to be allocated manually either by calling a subroutine
- or by sending a USB root hub vendor specific command to the virtual root hub.
- At the alternate linux usb stack EDs will be added (allocated) at their first use.
- ED will be unlinked from the HC chains if they are not bussy.
- files: ohci-hcd.c ohci-hcd.h
- routines:   (do not use for drivers, use the top layer alternate usb commands instead)
- int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
-            int interval, int load, f_handler handler, int ep_size, int speed)
-       adds an endpoint, (if the endpoint already exists some parameters will be updated)
-       
- int usb_ohci_rm_ep( ) 
-       removes an endpoint and all pending TDs of that EP
-       
-  usb_ohci_rm_function( )
-       removes all Endpoints of a function (device)
-
-- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
-  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
-  to take care of buffer allocation.
-  files: ohci-hcd.c ohci-hcd.h 
-
-  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
-  
-  int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
-  
-  CTRL: ctrl, ctrl_len ... cmd buffer 
-        data, data_len ... data buffer (in or out)
-  INT, BULK:  ctrl = NULL, ctrl_len=0,
-               data, data_len ... data buffer (in or out)
-  ISO: tbd
-
-  There is no buffer reinsertion done by the internal HCD function. 
-  (The interface layer does this for a INT-pipe on request.)
-  If you want a transfer then you have to 
-  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
-  you can send as many as you like. They should come back by the callback f_handler in
-  the same order (for each endpoint, not globally) If an error occurs all
-  queued transfers of an endpoint will return unsent. They will be marked with an error status.
-  
-  e.g double-buffering for int transfers:
-
-       ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
-       ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-       
-  and when a data0 packet returns by the callback f_handler requeue it:
-       ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
-  and when a data1 packet returns by the callback f_handler requeue it:
-       ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-       
-  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
-  The alternate usb uses them for dev_id and usb_device_irq handler.
-
-
-- Done list handling: returns the requests (callback f_handler in ED) and does 
-  some error handling, root-hub request dequeuing
-  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
-
-  
diff --git a/Documentation/usb/ohci.txt b/Documentation/usb/ohci.txt
new file mode 100644 (file)
index 0000000..39a5ce4
--- /dev/null
@@ -0,0 +1,98 @@
+
+The OHCI HCD layer is a simple but nearly complete implementation of what the
+USB people would call a HCD  for the OHCI. 
+ (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
+It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
+The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
+
+- Roman Weissgaerber <weissg@vienna.at>
+
+ * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers 
+ * v2.1 1999/05/09 ep_addr correction, code cleanup
+ * v0.2.0 1999/05/04 
+ * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
+ * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
+ * 
+ * v0.1.0 1999/04/27 initial release
+to remove the module try:
+rmmod usb-ohci
+
+Features:
+- virtual root hub, all basic hub descriptors and commands (state: complete) 
+  this is an option now (v0.2.0)
+  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
+  default is with. 
+  (at the moment: the Virtual Root Hub is included automatically)
+  
+  files: ohci-root-hub.c, ohci-root-hub.h 
+
+- Endpoint Descriptor (ED) handling more static approach 
+ (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
+ as long as the function (device) is alive or another configuration is choosen.
+ In the HCD layer the EDs has to be allocated manually either by calling a subroutine
+ or by sending a USB root hub vendor specific command to the virtual root hub.
+ At the alternate linux usb stack EDs will be added (allocated) at their first use.
+ ED will be unlinked from the HC chains if they are not bussy.
+ files: ohci-hcd.c ohci-hcd.h
+ routines:   (do not use for drivers, use the top layer alternate usb commands instead)
+ int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
+            int interval, int load, f_handler handler, int ep_size, int speed)
+       adds an endpoint, (if the endpoint already exists some parameters will be updated)
+       
+ int usb_ohci_rm_ep( ) 
+       removes an endpoint and all pending TDs of that EP
+       
+  usb_ohci_rm_function( )
+       removes all Endpoints of a function (device)
+
+- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
+  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
+  to take care of buffer allocation.
+  files: ohci-hcd.c ohci-hcd.h 
+
+  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
+  
+  int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
+  
+  CTRL: ctrl, ctrl_len ... cmd buffer 
+        data, data_len ... data buffer (in or out)
+  INT, BULK:  ctrl = NULL, ctrl_len=0,
+               data, data_len ... data buffer (in or out)
+  ISO: tbd
+
+  There is no buffer reinsertion done by the internal HCD function. 
+  (The interface layer does this for a INT-pipe on request.)
+  If you want a transfer then you have to 
+  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
+  you can send as many as you like. They should come back by the callback f_handler in
+  the same order (for each endpoint, not globally) If an error occurs all
+  queued transfers of an endpoint will return unsent. They will be marked with an error status.
+  
+  e.g double-buffering for int transfers:
+
+       ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+       ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+       
+  and when a data0 packet returns by the callback f_handler requeue it:
+       ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  and when a data1 packet returns by the callback f_handler requeue it:
+       ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+       
+  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
+  The alternate usb uses them for dev_id and usb_device_irq handler.
+
+
+- Done list handling: returns the requests (callback f_handler in ED) and does 
+  some error handling, root-hub request dequeuing
+  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
+
+  
index 302705aec01c319d8ad97e824e9d857be551fea0..6135fc893e3c768588c332c6b06a54f35976ff50 100644 (file)
@@ -503,7 +503,7 @@ P:  Vojtech Pavlik
 M:     vojtech@suse.cz
 L:     linux-joystick@atrey.karlin.mff.cuni.cz
 W:     http://www.suse.cz/development/joystick/
-S:     Maintained
+S:     Supported
 
 KERNEL AUTOMOUNTER (AUTOFS)
 P:     H. Peter Anvin
@@ -979,6 +979,19 @@ L: linux-usb@suse.com
 W:     http://www.linux-usb.org
 S:     Supported
 
+USB ACM DRIVER
+P:     Vojtech Pavlik
+M:     vojtech@suse.cz
+L:     linux-usb@suse.com
+S:     Supported
+
+USB HID/HIDBP/INPUT DRIVERS
+P:     Vojtech Pavlik
+M:     vojtech@suse.cz
+L:     linux-usb@suse.com
+W:     http://www.suse.cz/development/input/
+S:     Supported
+
 USB HUB
 P:     Johannes Erdfelt
 M:     jerdfelt@sventech.com
@@ -986,12 +999,16 @@ L:        linux-usb@suse.com
 S:     Maintained
 
 USB OHCI DRIVER
-P:     Gregory P. Smith
-M:     greg@electricrain.com
-M:     greg@suitenine.com
+P:     Roman Weissgaerber
+M:     weissg@vienna.at
 L:     linux-usb@suse.com
-S:     Maintained (not yet usable)
-W:     http://suitenine.com/usb/
+S:     Maintained
+
+USB PRINTER DRIVER
+P:     Vojtech Pavlik
+M:     vojtech@suse.cz
+L:     linux-usb@suse.com
+S:     Supported
 
 USB SERIAL DRIVER
 P:     Greg Kroah-Hartman
index a09e6233403397907467d7b6a884afb79a9ad519..356e9bf01ffc3a1e633ebea8b86babd8a13034e7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 40
+SUBLEVEL = 41
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
index f9fbd25368b668874e17a4e50242498e1fb7f389..54d962790de3b0dfea8175c4b84ae1482a56ea28 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/stddef.h>
 #include <linux/binfmts.h>
 #include <linux/tty.h>
-#include <linux/highuid.h>
 
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -502,7 +501,6 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
                                info.si_code = SI_USER;
                                info.si_pid = current->p_pptr->pid;
                                info.si_uid = current->p_pptr->uid;
-                               info.si_uid16 = high2lowuid(current->p_pptr->uid);
                        }
 
                        /* If the (new) signal is now blocked, requeue it.  */
diff --git a/arch/i386/kernel/ls b/arch/i386/kernel/ls
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
index 18de47dd49b8bc576326bea7262d50d378e4e9db..a973746b9582adea07fb44625b0066faa2451574 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
-#include <linux/highuid.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
@@ -643,7 +642,6 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                                info.si_code = SI_USER;
                                info.si_pid = current->p_pptr->pid;
                                info.si_uid = current->p_pptr->uid;
-                               info.si_uid16 = high2lowuid(current->p_pptr->uid);
                        }
 
                        /* If the (new) signal is now blocked, requeue it.  */
index bbff5d59065f2088c30119dda8124e5ff5d05b50..81014d9c8ce714e0bf53296ca17965aee40c923c 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
-#include <linux/highuid.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -1049,7 +1048,6 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
                                info.si_code = SI_USER;
                                info.si_pid = current->p_pptr->pid;
                                info.si_uid = current->p_pptr->uid;
-                               info.si_uid16 = high2lowuid(current->p_pptr->uid);
                        }
 
                        /* If the (new) signal is now blocked, requeue it.  */
index 6836b26a2aa7872a9a8ccee5ded4c87718bb311d..5236519ad7fb5a5a31c4ef6f6dbb9a45b2563edf 100644 (file)
@@ -412,8 +412,11 @@ static inline void handle_mouse_event(unsigned char scancode)
 #endif
 }
 
+static unsigned char kbd_exists = 1;
+
 static inline void handle_keyboard_event(unsigned char scancode)
 {
+       kbd_exists = 1;
 #ifdef CONFIG_VT
        if (do_acknowledge(scancode))
                handle_scancode(scancode, !(scancode & 0x80));
@@ -482,6 +485,8 @@ static int send_data(unsigned char data)
 {
        int retries = 3;
 
+       if (!kbd_exists) return 0;
+
        do {
                unsigned long timeout = KBD_TIMEOUT;
 
@@ -497,8 +502,9 @@ static int send_data(unsigned char data)
                        mdelay(1);
                        if (!--timeout) {
 #ifdef KBD_REPORT_TIMEOUTS
-                               printk(KERN_WARNING "Keyboard timeout[2]\n");
+                               printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?\n");
 #endif
+                               kbd_exists = 0;
                                return 0;
                        }
                }
@@ -506,6 +512,7 @@ static int send_data(unsigned char data)
 #ifdef KBD_REPORT_TIMEOUTS
        printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
 #endif
+       kbd_exists = 0;
        return 0;
 }
 
index 92a2ddfaf80b897ed0ea1278501628f40fadd8a4..9d8c7ac2b9c6a84401504f8c187dbb5cf5a98b14 100644 (file)
@@ -41,7 +41,7 @@ ifeq ($(CONFIG_SCSI),y)
   endif
   L_OBJS += scsi_n_syms.o hosts.o scsi_ioctl.o constants.o scsicam.o
   L_OBJS += scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o 
-  L_OBJS += scsi_merge.o scsi_proc.o
+  L_OBJS += scsi_merge.o scsi_proc.o scsi_dma.o scsi_scan.o
 else
   ifeq ($(CONFIG_SCSI),m)
     MIX_OBJS += scsi_syms.o
@@ -722,10 +722,11 @@ megaraid.o: megaraid.c
 
 scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
                scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o \
-               scsi_queue.o scsi_lib.o scsi_merge.o
+               scsi_queue.o scsi_lib.o scsi_merge.o scsi_dma.o scsi_scan.o
        $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o \
                constants.o scsicam.o scsi_proc.o scsi_merge.o     \
-               scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o
+               scsi_error.o scsi_obsolete.o scsi_queue.o scsi_lib.o \
+               scsi_dma.o scsi_scan.o
 
 sr_mod.o: sr.o sr_ioctl.o sr_vendor.o
        $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o
index 07729599f5fc6d67b2cee77b3ad7b05f9ee8bd15..8e8dc98ee8826d976438b8ba9c53fa4636319fe0 100644 (file)
@@ -48,7 +48,7 @@
  * a later time.  This problem cannot be resolved by holding a single entry
  * in scratch ram since a reconnecting target can request sense and this will
  * create yet another SCB waiting for selection.  The solution used here is to 
- * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
+ * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
  * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
  * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
  * this list everytime a request sense occurs or after completing a non-tagged
index 4e45fc849d9d84334d400ab20612e141ba8fb33f..97f94f442c6893b56d7fae9d62f5162d281fe1e5 100644 (file)
@@ -113,16 +113,6 @@ static int fake_int_happened;
 static ulong int_counter = 0;
 static ulong queue_counter = 0;
 
-void eata_scsi_done (Scsi_Cmnd * scmd)
-{
-    scmd->request.rq_status = RQ_SCSI_DONE;
-
-    if (scmd->request.sem != NULL)
-       up(scmd->request.sem);
-    
-    return;
-}   
-
 void eata_fake_int_handler(s32 irq, void *dev_id, struct pt_regs * regs)
 {
     fake_int_result = inb((ulong)fake_int_base + HA_RSTATUS);
index c32b9480aafbec86cbaf025b1c6fb6c151e92d29..dd603456178e2cecfe8800c0fbeb08f63a2bbae1 100644 (file)
@@ -67,10 +67,10 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
                   int hostno, int inout)
 {
 
-    Scsi_Device *scd, SDev;
+    Scsi_Device *scd, *SDev;
     struct Scsi_Host *HBA_ptr;
-    Scsi_Cmnd scmd;
-    char cmnd[10];
+    Scsi_Cmnd  * scmd;
+    char cmnd[MAX_COMMAND_SIZE];
     static u8 buff[512];
     static u8 buff2[512];
     hst_cmd_stat *rhcs, *whcs;
@@ -152,13 +152,8 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
        pos = begin + len;
 
     } else {
-       memset(&SDev, 0, sizeof(Scsi_Device));
-       memset(&scmd, 0, sizeof(Scsi_Cmnd));
-
-       SDev.host = HBA_ptr;
-       SDev.id = HBA_ptr->this_id;
-       SDev.lun = 0;
-       SDev.channel = 0;
+        SDev = scsi_get_host_dev(HBA_ptr);
+       scmd  = scsi_allocate_device(SDev, 1, FALSE);
 
        cmnd[0] = LOG_SENSE;
        cmnd[1] = 0;
@@ -171,26 +166,13 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
        cmnd[8] = 0x66;
        cmnd[9] = 0;
 
-       scmd.cmd_len = 10;
+       scmd->cmd_len = 10;
        
-       scmd.host = HBA_ptr; 
-       scmd.device = &SDev;
-       scmd.target = HBA_ptr->this_id; 
-       scmd.lun = 0; 
-       scmd.channel = 0;
-       scmd.use_sg = 0;
-
        /*
         * Do the command and wait for it to finish.
         */     
-       {
-           DECLARE_MUTEX_LOCKED(sem);
-           scmd.request.rq_status = RQ_SCSI_BUSY;
-           scmd.request.sem = &sem;
-           scsi_do_cmd (&scmd, cmnd, buff + 0x144, 0x66,  
-                        eata_scsi_done, 1 * HZ, 1);
-           down(&sem);
-       }
+       scsi_wait_cmd (scmd, cmnd, buff + 0x144, 0x66,  
+                      1 * HZ, 1);
 
        size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
                       (cc->intt == TRUE)?"level":"edge");
@@ -308,19 +290,13 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
            cmnd[8] = 0x44;
            cmnd[9] = 0;
            
-           scmd.cmd_len = 10;
+           scmd->cmd_len = 10;
 
            /*
             * Do the command and wait for it to finish.
             */ 
-           {
-               DECLARE_MUTEX_LOCKED(sem);
-               scmd.request.rq_status = RQ_SCSI_BUSY;
-               scmd.request.sem = &sem;
-               scsi_do_cmd (&scmd, cmnd, buff2, 0x144,
-                            eata_scsi_done, 1 * HZ, 1);
-               down(&sem);
-           }
+           scsi_wait_cmd (scmd, cmnd, buff2, 0x144,
+                          1 * HZ, 1);
 
            swap_statistics(buff2);
            rhcs = (hst_cmd_stat *)(buff2 + 0x2c); 
@@ -354,6 +330,9 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
            len += size; 
            pos = begin + len;
        }
+
+       scsi_release_command(scmd);
+       scsi_free_host_dev(SDev);
     }
     
     if (pos < offset) {
index e318395b24f785876ceb468fa56fb269fd61b43d..cb42f6b7a855b84f57c692b48babcfcabbf53119 100644 (file)
@@ -3157,7 +3157,7 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
             NUMDATA(shp)->busnum= 0;
 
             ha->pccb = CMDDATA(shp);
-            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD);
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = MAX_HDRIVES;
@@ -3172,7 +3172,7 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
-                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
                 free_irq(ha->irq,NULL);
                 scsi_unregister(shp);
                 continue;
@@ -3223,7 +3223,7 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
                     NUMDATA(shp)->hanum));
 
             ha->pccb = CMDDATA(shp);
-            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD);
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = MAX_HDRIVES;
@@ -3238,7 +3238,7 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
-                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
                 free_irq(ha->irq,NULL);
                 scsi_unregister(shp);
                 continue;
@@ -3293,7 +3293,7 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
             NUMDATA(shp)->busnum= 0;
 
             ha->pccb = CMDDATA(shp);
-            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, GDTH_SCRATCH_ORD);
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
@@ -3308,7 +3308,7 @@ int __init gdth_detect(Scsi_Host_Template *shtp)
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
-                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
                 free_irq(ha->irq,NULL);
                 scsi_unregister(shp);
                 continue;
@@ -3359,7 +3359,7 @@ int gdth_release(struct Scsi_Host *shp)
         if (shp->dma_channel != 0xff) {
             free_dma(shp->dma_channel);
         }
-        scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+        free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
         gdth_ctr_released++;
         TRACE2(("gdth_release(): HA %d of %d\n", 
                 gdth_ctr_released, gdth_ctr_count));
@@ -3561,21 +3561,18 @@ static void gdth_flush(int hanum)
 {
     int             i;
     gdth_ha_str     *ha;
-    Scsi_Cmnd       scp;
-    Scsi_Device     sdev;
+    Scsi_Cmnd     * scp;
+    Scsi_Device   * sdev;
     gdth_cmd_str    gdtcmd;
 
     TRACE2(("gdth_flush() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
-    memset(&sdev,0,sizeof(Scsi_Device));
-    memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_tab[hanum];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_tab[hanum];
-    scp.target = sdev.host->this_id;
-    scp.device = &sdev;
-    scp.use_sg = 0;
+
+    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
 
     for (i = 0; i < MAX_HDRIVES; ++i) {
         if (ha->hdr[i].present) {
@@ -3586,9 +3583,11 @@ static void gdth_flush(int hanum)
             gdtcmd.u.cache.BlockNo = 1;
             gdtcmd.u.cache.sg_canz = 0;
             TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
-            gdth_do_cmd(&scp, &gdtcmd, 30);
+            gdth_do_cmd(scp, &gdtcmd, 30);
         }
     }
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
 }
 
 /* shutdown routine */
@@ -3596,8 +3595,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
 {
     int             hanum;
 #ifndef __alpha__
-    Scsi_Cmnd       scp;
-    Scsi_Device     sdev;
+    Scsi_Cmnd     * scp;
+    Scsi_Device   * sdev;
     gdth_cmd_str    gdtcmd;
 #endif
 
@@ -3610,23 +3609,21 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
 
 #ifndef __alpha__
         /* controller reset */
-        memset(&sdev,0,sizeof(Scsi_Device));
-        memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = gdth_ctr_tab[hanum];
-        sdev.id = sdev.host->this_id;
-        scp.cmd_len = 12;
-        scp.host = gdth_ctr_tab[hanum];
-        scp.target = sdev.host->this_id;
-        scp.device = &sdev;
-        scp.use_sg = 0;
+       sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+       scp  = scsi_allocate_device(sdev, 1, FALSE);
+        scp->cmd_len = 12;
+        scp->use_sg = 0;
 
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
         TRACE2(("gdth_halt(): reset controller %d\n", hanum));
-        gdth_do_cmd(&scp, &gdtcmd, 10);
+        gdth_do_cmd(scp, &gdtcmd, 10);
+       scsi_release_command(scp);
+       scsi_free_host_dev(sdev);
 #endif
     }
+
     printk("Done.\n");
 
 #ifdef GDTH_STATISTICS
index 2fa420b25fd9a0b93f58970e42b13af7ebf45eca..946c782543a9ddf3965736c5cdabd04d669d060c 100644 (file)
 #endif
 
 /* limits */
-#define GDTH_SCRATCH    4096                    /* 4KB scratch buffer */
+#define GDTH_SCRATCH    PAGE_SIZE                    /* 4KB scratch buffer */
+#define GDTH_SCRATCH_ORD 0                      /* order 0 means 1 page */
 #define GDTH_MAXCMDS    124
 #define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
 #define GDTH_MAX_RAW    2                       /* max. cmds per raw device */
index 6d0112abab73030830130795e81512471677874e..24861d034d81b87bd6916a70fd14ea2b20368d52 100644 (file)
@@ -31,22 +31,17 @@ int gdth_proc_info(char *buffer,char **start,off_t offset,int length,
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
 {
     int             ret_val;
-    Scsi_Cmnd       scp;
-    Scsi_Device     sdev;
+    Scsi_Cmnd     * scp;
+    Scsi_Device   * sdev;
     gdth_iowr_str   *piowr;
 
     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
     piowr = (gdth_iowr_str *)buffer;
 
-    memset(&sdev,0,sizeof(Scsi_Device));
-    memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_vtab[vh];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_vtab[vh];
-    scp.target = sdev.host->this_id;
-    scp.device = &sdev;
-    scp.use_sg = 0;
+    sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
 
     if (length >= 4) {
         if (strncmp(buffer,"gdth",4) == 0) {
@@ -62,10 +57,14 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
     } else {
         ret_val = -EINVAL;
     }
+
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+
     return ret_val;
 }
          
-static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
 {
     int             orig_length, drive, wb_mode;
     int             i, found;
@@ -105,7 +104,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
                 gdtcmd.u.cache.DeviceNo = i;
                 gdtcmd.u.cache.BlockNo = 1;
                 gdtcmd.u.cache.sg_canz = 0;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
+                gdth_do_cmd(scp, &gdtcmd, 30);
             }
         }
         if (!found)
@@ -158,7 +157,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
-        gdth_do_cmd(&scp, &gdtcmd, 30);
+        gdth_do_cmd(scp, &gdtcmd, 30);
         gdth_ioctl_free(hanum);
         printk("Done.\n");
         return(orig_length);
@@ -168,7 +167,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
     return(-EINVAL);
 }
 
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
 {
     unchar          i, j;
     gdth_ha_str     *ha;
@@ -241,8 +240,8 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
             *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
         }
         /* do IOCTL */
-        gdth_do_cmd(&scp, pcmd, piowr->timeout);
-        piord->status = (ulong32)scp.SCp.Message;
+        gdth_do_cmd(scp, pcmd, piowr->timeout);
+        piord->status = (ulong32)scp->SCp.Message;
         break;
 
       case GDTIOCTL_DRVERS:
@@ -401,8 +400,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
 
     gdth_cmd_str gdtcmd;
     gdth_evt_str estr;
-    Scsi_Cmnd scp;
-    Scsi_Device sdev;
+    Scsi_Cmnd  * scp;
+    Scsi_Device *sdev;
     char hrec[161];
     struct timeval tv;
 
@@ -417,15 +416,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
     ha = HADATA(gdth_ctr_tab[hanum]);
     id = length;
 
-    memset(&sdev,0,sizeof(Scsi_Device));
-    memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_vtab[vh];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_vtab[vh];
-    scp.target = sdev.host->this_id;
-    scp.device = &sdev;
-    scp.use_sg = 0;
+    sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
 
     /* look for buffer ID in length */
     if (id > 1) {
@@ -531,11 +525,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                     sizeof(pds->list[0]);
                 if (pds->entries > cnt)
                     pds->entries = cnt;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message != S_OK) 
+                gdth_do_cmd(scp, &gdtcmd, 30);
+                if (scp->SCp.Message != S_OK) 
                     pds->count = 0;
                 TRACE2(("pdr_statistics() entries %d status %d\n",
-                        pds->count, scp.SCp.Message));
+                        pds->count, scp->SCp.Message));
 
                 /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
                 for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
@@ -551,8 +545,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                     gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
                     gdtcmd.u.ioctl.channel = 
                         ha->raw[i].address | ha->raw[i].id_list[j];
-                    gdth_do_cmd(&scp, &gdtcmd, 30);
-                    if (scp.SCp.Message == S_OK) {
+                    gdth_do_cmd(scp, &gdtcmd, 30);
+                    if (scp->SCp.Message == S_OK) {
                         strncpy(hrec,pdi->vendor,8);
                         strncpy(hrec+8,pdi->product,16);
                         strncpy(hrec+24,pdi->revision,4);
@@ -602,8 +596,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                         gdtcmd.u.ioctl.channel = 
                             ha->raw[i].address | ha->raw[i].id_list[j];
                         pdef->sddc_type = 0x08;
-                        gdth_do_cmd(&scp, &gdtcmd, 30);
-                        if (scp.SCp.Message == S_OK) {
+                        gdth_do_cmd(scp, &gdtcmd, 30);
+                        if (scp->SCp.Message == S_OK) {
                             size = sprintf(buffer+len,
                                            " Grown Defects:\t%d\n",
                                            pdef->sddc_cnt);
@@ -649,8 +643,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                     gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
                     gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
                     gdtcmd.u.ioctl.channel = drv_no;
-                    gdth_do_cmd(&scp, &gdtcmd, 30);
-                    if (scp.SCp.Message != S_OK)
+                    gdth_do_cmd(scp, &gdtcmd, 30);
+                    if (scp->SCp.Message != S_OK)
                         break;
                     pcdi->ld_dtype >>= 16;
                     j++;
@@ -746,8 +740,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
                 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
                 gdtcmd.u.ioctl.channel = i;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message == S_OK) {
+                gdth_do_cmd(scp, &gdtcmd, 30);
+                if (scp->SCp.Message == S_OK) {
                     if (pai->ai_state == 0)
                         strcpy(hrec, "idle");
                     else if (pai->ai_state == 2)
@@ -821,8 +815,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                 gdtcmd.u.ioctl.channel = i;
                 phg->entries = MAX_HDRIVES;
                 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message != S_OK) {
+                gdth_do_cmd(scp, &gdtcmd, 30);
+                if (scp->SCp.Message != S_OK) {
                     ha->hdr[i].ldr_no = i;
                     ha->hdr[i].rw_attribs = 0;
                     ha->hdr[i].start_sec = 0;
@@ -837,7 +831,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                     }
                 }
                 TRACE2(("host_get entries %d status %d\n",
-                        phg->entries, scp.SCp.Message));
+                        phg->entries, scp->SCp.Message));
             }
             gdth_ioctl_free(hanum);
 
@@ -915,6 +909,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
     }
 
 stop_output:
+
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+
     *start = buffer +(offset-begin);
     len -= (offset-begin);
     if (len > length)
@@ -926,11 +924,11 @@ stop_output:
 
 static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout)
 {
-    char cmnd[12];
+    char cmnd[MAX_COMMAND_SIZE];
     DECLARE_MUTEX_LOCKED(sem);
 
     TRACE2(("gdth_do_cmd()\n"));
-    memset(cmnd, 0, 12);
+    memset(cmnd, 0, MAX_COMMAND_SIZE);
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.sem = &sem;
     scp->SCp.this_residual = IOCTL_PRI;
index 1a6f2d164b78195eca7264cc34d3080527e6e13b..8af8e71e67b865c5c7ed8ce3b6375572317566a2 100644 (file)
@@ -6,8 +6,8 @@
  */
 
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
-static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
 static int gdth_get_info(char *buffer,char **start,off_t offset,
                          int length,int vh,int hanum,int busnum);
 
index 5c9fdd941473b8ef2d5ccce29a85721ab693a1b7..95a132498cc4db7c95d564d3d16a1dcc73d1f95e 100644 (file)
@@ -869,7 +869,6 @@ unsigned int __init scsi_init(void)
     printk ("scsi : %d host%s.\n", next_scsi_host,
            (next_scsi_host == 1) ? "" : "s");
     
-    
     /* Now attach the high level drivers */
 #ifdef CONFIG_BLK_DEV_SD
     scsi_register_device(&sd_template);
index a2c810f9753f59be06faac7387595c41af8948ec..1ce17904a04ed6b5257445aa85a8aa22a2b30a0c 100644 (file)
@@ -334,7 +334,6 @@ struct Scsi_Host
     unsigned int max_lun;
     unsigned int max_channel;
 
-
     /* These parameters should be set by the detect routine */
     unsigned long base;
     unsigned long io_port;
@@ -435,6 +434,17 @@ unsigned int scsi_init(void);
 extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
 extern void scsi_unregister(struct Scsi_Host * i);
 
+extern request_fn_proc * scsi_get_request_handler(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
+
+/*
+ * Prototypes for functions/data in scsi_scan.c
+ */
+extern void scan_scsis(struct Scsi_Host *shpnt,
+                      unchar hardcoded,
+                      unchar hchannel,
+                      unchar hid,
+                       unchar hlun);
+
 extern void scsi_mark_host_reset(struct Scsi_Host *Host);
 
 #define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
index c3b80dd9ca7ebcfa6513e29ed459c2da25d44e31..1c75c8c3b2a77dacc60ca1aabab3449cb79a743e 100644 (file)
@@ -248,7 +248,7 @@ typedef struct _IDENTIFY_DATA
        USHORT  SupportLBA                      :1;             // 49 LBA supported
        USHORT  SupportIORDYDisable     :1;             // 49 IORDY can be disabled
        USHORT  SupportIORDY            :1;             // 49 IORDY supported
-       USHORT  ReservedPsuedoDMA       :1;             // 49 reserved for pseudo DMA mode support
+       USHORT  ReservedPseudoDMA       :1;             // 49 reserved for pseudo DMA mode support
        USHORT  Reserved3                       :3;             // 49
        USHORT  Reserved4;                                      // 50
        USHORT  Reserved5                       :8;             // 51 Transfer Cycle Timing - PIO
index eeff3d5fd3ba829b018f6d9a86d987b594813a3f..0ad9bc6e5a7945818af0a73aa0f413e3634cc663 100644 (file)
@@ -86,44 +86,11 @@ static void scsi_dump_status(int level);
  * Definitions and constants.
  */
 
-/*
- * PAGE_SIZE must be a multiple of the sector size (512).  True
- * for all reasonably recent architectures (even the VAX...).
- */
-#define SECTOR_SIZE            512
-#define SECTORS_PER_PAGE       (PAGE_SIZE/SECTOR_SIZE)
-
-#if SECTORS_PER_PAGE <= 8
-typedef unsigned char FreeSectorBitmap;
-#elif SECTORS_PER_PAGE <= 32
-typedef unsigned int FreeSectorBitmap;
-#else
-#error You lose.
-#endif
-
 #define MIN_RESET_DELAY (2*HZ)
 
 /* Do not call reset on error if we just did a reset within 15 sec. */
 #define MIN_RESET_PERIOD (15*HZ)
 
-/* The following devices are known not to tolerate a lun != 0 scan for
- * one reason or another.  Some will respond to all luns, others will
- * lock up.
- */
-
-#define BLIST_NOLUN            0x001
-#define BLIST_FORCELUN         0x002
-#define BLIST_BORKEN           0x004
-#define BLIST_KEY              0x008
-#define BLIST_SINGLELUN        0x010
-#define BLIST_NOTQ             0x020
-#define BLIST_SPARSELUN        0x040
-#define BLIST_MAX5LUN          0x080
-#define BLIST_ISDISK           0x100
-#define BLIST_ISROM            0x200
-#define BLIST_GHOST            0x400   
-
-
 
 /*
  * Data declarations.
@@ -139,12 +106,6 @@ const unsigned char scsi_command_size[8] =
 static unsigned long serial_number = 0;
 static Scsi_Cmnd *scsi_bh_queue_head = NULL;
 static Scsi_Cmnd *scsi_bh_queue_tail = NULL;
-static FreeSectorBitmap *dma_malloc_freelist = NULL;
-static int need_isa_bounce_buffers;
-static unsigned int dma_sectors = 0;
-unsigned int scsi_dma_free_sectors = 0;
-unsigned int scsi_need_isa_buffer = 0;
-static unsigned char **dma_malloc_pages = NULL;
 
 /*
  * Note - the initial logging level can be set here to log events at boot time.
@@ -173,12 +134,7 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
 /* 
  * Function prototypes.
  */
-static void resize_dma_pool(void);
-static void print_inquiry(unsigned char *data);
 extern void scsi_times_out(Scsi_Cmnd * SCpnt);
-static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
-               int *sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
-                            struct Scsi_Host *shpnt, char *scsi_result);
 void scsi_build_commandblocks(Scsi_Device * SDpnt);
 static int scsi_unregister_device(struct Scsi_Device_Template *tpnt);
 
@@ -189,140 +145,40 @@ static int scsi_unregister_device(struct Scsi_Device_Template *tpnt);
 extern void scsi_old_done(Scsi_Cmnd * SCpnt);
 extern void scsi_old_times_out(Scsi_Cmnd * SCpnt);
 
-struct dev_info {
-       const char *vendor;
-       const char *model;
-       const char *revision;   /* Latest revision known to be bad.  Not used yet */
-       unsigned flags;
-};
-
-/*
- * This is what was previously known as the blacklist.  The concept
- * has been expanded so that we can specify other types of things we
- * need to be aware of.
- */
-static struct dev_info device_list[] =
-{
-       {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
-       {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
-       {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
-       {"DENON", "DRD-25X", "V", BLIST_NOLUN},                 /* Locks up if probed for lun != 0 */
-       {"HITACHI", "DK312C", "CM81", BLIST_NOLUN},             /* Responds to all lun - dtg */
-       {"HITACHI", "DK314C", "CR21", BLIST_NOLUN},             /* responds to all lun */
-       {"IMS", "CDD521/10", "2.06", BLIST_NOLUN},              /* Locks-up when LUN>0 polled. */
-       {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},             /* Locks-up when LUN>0 polled. */
-       {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},             /* Locks-up when LUN>0 polled. */
-       {"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},           /* Locks up when LUN>0 polled */
-       {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},             /* Locks-up sometimes when LUN>0 polled. */
-       {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},             /* guess what? */
-       {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},    /*Responds to all lun */
-       {"MICROP", "4110", "*", BLIST_NOTQ},                    /* Buggy Tagged Queuing */
-       {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},        /* Locks-up when LUN>0 polled. */
-       {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},            /* Responds to all lun */
-       {"RODIME", "RO3000S", "2.33", BLIST_NOLUN},             /* Locks up if polled for lun != 0 */
-       {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},             /* causes failed REQUEST SENSE on lun 1
-                                                                * for aha152x controller, which causes
-                                                                * SCSI code to reset bus.*/
-       {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},           /* causes failed REQUEST SENSE on lun 1
-                                                                * for aha152x controller, which causes
-                                                                * SCSI code to reset bus.*/
-       {"SEAGATE", "ST296", "921", BLIST_NOLUN},               /* Responds to all lun */
-       {"SEAGATE", "ST1581", "6538", BLIST_NOLUN},             /* Responds to all lun */
-       {"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},        
-       {"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
-       {"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
-       {"SONY", "CD-ROM CDU-8012", "*", BLIST_NOLUN},
-       {"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},           /* Locks up if polled for lun != 0 */
-       {"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},               /* Locks up if polled for lun != 0 */
-       {"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},                /* causes failed REQUEST SENSE on lun 1
-                                                                * for seagate controller, which causes
-                                                                * SCSI code to reset bus.*/
-       {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},        /* Responds to all lun */
-       {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},               /* causes failed REQUEST SENSE on lun 1
-                                                                * for seagate controller, which causes
-                                                                * SCSI code to reset bus.*/
-       {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},            /* Locks sometimes if polled for lun != 0 */
-       {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},            /* Locks sometimes if polled for lun != 0 */
-       {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},    /* Locks up when polled for lun != 0 */
-       {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},         /* Locks up if polled for lun != 0 */
-       {"SANKYO", "CP525", "6.64", BLIST_NOLUN},               /* causes failed REQ SENSE, extra reset */
-       {"HP", "C1750A", "3226", BLIST_NOLUN},                  /* scanjet iic */
-       {"HP", "C1790A", "", BLIST_NOLUN},                      /* scanjet iip */
-       {"HP", "C2500A", "", BLIST_NOLUN},                      /* scanjet iicx */
-       {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},              /* Locks up if polled for lun != 0 */
-       {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},              /* Locks up if polled for lun != 0  
-                                                                * extra reset */
-       {"RELISYS", "Scorpio", "*", BLIST_NOLUN},               /* responds to all LUN */
-       {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},      /* responds to all LUN */
 
 /*
- * Other types of devices that have special flags.
+ * Function:    scsi_get_request_handler()
+ *
+ * Purpose:     Selects queue handler function for a device.
+ *
+ * Arguments:   SDpnt   - device for which we need a handler function.
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locking assumed or required.
+ *
+ * Notes:       Most devices will end up using scsi_request_fn for the
+ *              handler function (at least as things are done now).
+ *              The "block" feature basically ensures that only one of
+ *              the blocked hosts is active at one time, mainly to work around
+ *              buggy DMA chipsets where the memory gets starved.
+ *              For this case, we have a special handler function, which
+ *              does some checks and ultimately calls scsi_request_fn.
+ *
+ *              As a future enhancement, it might be worthwhile to add support
+ *              for stacked handlers - there might get to be too many permutations
+ *              otherwise.  Then again, we might just have one handler that does
+ *              all of the special cases (a little bit slower), and those devices
+ *              that don't need the special case code would directly call 
+ *              scsi_request_fn.
+ *
+ *              As it stands, I can think of a number of special cases that
+ *              we might need to handle.  This would not only include the blocked
+ *              case, but single_lun (for changers), and any special handling
+ *              we might need for a spun-down disk to spin it back up again.
  */
-       {"SONY", "CD-ROM CDU-8001", "*", BLIST_BORKEN},
-       {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
-       {"IOMEGA", "Io20S         *F", "*", BLIST_KEY},
-       {"INSITE", "Floptical   F*8I", "*", BLIST_KEY},
-       {"INSITE", "I325VM", "*", BLIST_KEY},
-       {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-       {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-       {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN},
-       {"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-       {"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-    {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-   {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-   {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-       {"EMULEX", "MD21/S2     ESDI", "*", BLIST_SINGLELUN},
-       {"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
-       {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
-       {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-       {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
-       {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
-       {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
-       {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
-       {"HITACHI", "GF-1050","*", BLIST_GHOST},  /* Hitachi SCSI DVD-RAM */
-       {"TOSHIBA","CDROM","*", BLIST_ISROM},
-       {"TOSHIBA","DVD-RAM SD-W1101","*", BLIST_GHOST},
-       {"TOSHIBA","DVD-RAM SD-W1111","*", BLIST_GHOST},
-
-       /*
-        * Must be at end of list...
-        */
-       {NULL, NULL, NULL}
-};
-
-static int get_device_flags(unsigned char *response_data)
-{
-       int i = 0;
-       unsigned char *pnt;
-       for (i = 0; 1; i++) {
-               if (device_list[i].vendor == NULL)
-                       return 0;
-               pnt = &response_data[8];
-               while (*pnt && *pnt == ' ')
-                       pnt++;
-               if (memcmp(device_list[i].vendor, pnt,
-                          strlen(device_list[i].vendor)))
-                       continue;
-               pnt = &response_data[16];
-               while (*pnt && *pnt == ' ')
-                       pnt++;
-               if (memcmp(device_list[i].model, pnt,
-                          strlen(device_list[i].model)))
-                       continue;
-               return device_list[i].flags;
-       }
-       return 0;
-}
-
-
-static void scan_scsis_done(Scsi_Cmnd * SCpnt)
-{
-
-       SCSI_LOG_MLCOMPLETE(1, printk("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result));
-       SCpnt->request.rq_status = RQ_SCSI_DONE;
-
-       if (SCpnt->request.sem != NULL)
-               up(SCpnt->request.sem);
+request_fn_proc * scsi_get_request_handler(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt) {
+        return scsi_request_fn;
 }
 
 #ifdef MODULE
@@ -349,43 +205,24 @@ __setup("scsi_logging=", scsi_logging_setup);
 
 #endif
 
-#ifdef CONFIG_SCSI_MULTI_LUN
-static int max_scsi_luns = 8;
-#else
-static int max_scsi_luns = 1;
-#endif
-
-#ifdef MODULE
-
-MODULE_PARM(max_scsi_luns, "i");
-MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)");
-
-#else
-
-static int __init scsi_luns_setup(char *str)
+/*
+ *     Issue a command and wait for it to complete
+ */
+static void scsi_wait_done(Scsi_Cmnd * SCpnt)
 {
-       int tmp;
+       struct request *req;
 
-       if (get_option(&str, &tmp) == 1) {
-               max_scsi_luns = tmp;
-               return 1;
-       } else {
-               printk("scsi_luns_setup : usage max_scsi_luns=n "
-                      "(n should be between 1 and 8)\n");
-               return 0;
+       req = &SCpnt->request;
+       req->rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
+
+       if (req->sem != NULL) {
+               up(req->sem);
        }
 }
 
-__setup("max_scsi_luns=", scsi_luns_setup);
-
-#endif
-
-/*
- *     Issue a command and wait for it to complete
- */
 void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
-                 void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
+                 void *buffer, unsigned bufflen, 
                  int timeout, int retries)
 {
        DECLARE_MUTEX_LOCKED(sem);
@@ -393,594 +230,12 @@ void scsi_wait_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
        SCpnt->request.sem = &sem;
        SCpnt->request.rq_status = RQ_SCSI_BUSY;
        scsi_do_cmd (SCpnt, (void *) cmnd,
-               buffer, bufflen, done, timeout, retries);
+               buffer, bufflen, scsi_wait_done, timeout, retries);
        down (&sem);
        SCpnt->request.sem = NULL;
 }
 
 
-/*
- *  Detecting SCSI devices :
- *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
- *  We use the INQUIRY command, determine device type, and pass the ID /
- *  lun address of all sequential devices to the tape driver, all random
- *  devices to the disk driver.
- */
-static void scan_scsis(struct Scsi_Host *shpnt,
-                      unchar hardcoded,
-                      unchar hchannel,
-                      unchar hid,
-                      unchar hlun)
-{
-       int channel;
-       int dev;
-       int lun;
-       int max_dev_lun;
-       Scsi_Cmnd *SCpnt;
-       unsigned char *scsi_result;
-       unsigned char scsi_result0[256];
-       Scsi_Device *SDpnt;
-       Scsi_Device *SDtail;
-       int sparse_lun;
-
-       scsi_result = NULL;
-       SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd),
-                                              GFP_ATOMIC | GFP_DMA);
-       if (SCpnt) {
-               SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof(Scsi_Device),
-                                                        GFP_ATOMIC);
-               if (SDpnt) {
-                       /*
-                        * Register the queue for the device.  All I/O requests will come
-                        * in through here.  We also need to register a pointer to
-                        * ourselves, since the queue handler won't know what device
-                        * the queue actually represents.   We could look it up, but it
-                        * is pointless work.
-                        */
-                       blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
-                       blk_queue_headactive(&SDpnt->request_queue, 0);
-                       SDpnt->request_queue.queuedata = (void *) SDpnt;
-                       /* Make sure we have something that is valid for DMA purposes */
-                       scsi_result = ((!shpnt->unchecked_isa_dma)
-                                      ? &scsi_result0[0] : scsi_init_malloc(512, GFP_DMA));
-               }
-       }
-       if (scsi_result == NULL) {
-               printk("Unable to obtain scsi_result buffer\n");
-               goto leave;
-       }
-       /*
-        * We must chain ourself in the host_queue, so commands can time out 
-        */
-       SCpnt->next = NULL;
-       SDpnt->device_queue = SCpnt;
-       SDpnt->host = shpnt;
-       SDpnt->online = TRUE;
-
-       initialize_merge_fn(SDpnt);
-
-        /*
-         * Initialize the object that we will use to wait for command blocks.
-         */
-       init_waitqueue_head(&SDpnt->scpnt_wait);
-
-       /*
-        * Next, hook the device to the host in question.
-        */
-       SDpnt->prev = NULL;
-       SDpnt->next = NULL;
-       if (shpnt->host_queue != NULL) {
-               SDtail = shpnt->host_queue;
-               while (SDtail->next != NULL)
-                       SDtail = SDtail->next;
-
-               SDtail->next = SDpnt;
-               SDpnt->prev = SDtail;
-       } else {
-               shpnt->host_queue = SDpnt;
-       }
-
-       /*
-        * We need to increment the counter for this one device so we can track when
-        * things are quiet.
-        */
-       atomic_inc(&shpnt->host_active);
-       atomic_inc(&SDpnt->device_active);
-
-       if (hardcoded == 1) {
-               Scsi_Device *oldSDpnt = SDpnt;
-               struct Scsi_Device_Template *sdtpnt;
-               channel = hchannel;
-               if (channel > shpnt->max_channel)
-                       goto leave;
-               dev = hid;
-               if (dev >= shpnt->max_id)
-                       goto leave;
-               lun = hlun;
-               if (lun >= shpnt->max_lun)
-                       goto leave;
-               scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun,
-                                 &SDpnt, SCpnt, shpnt, scsi_result);
-               if (SDpnt != oldSDpnt) {
-
-                       /* it could happen the blockdevice hasn't yet been inited */
-                       for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-                               if (sdtpnt->init && sdtpnt->dev_noticed)
-                                       (*sdtpnt->init) ();
-
-                       for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
-                               if (sdtpnt->attach) {
-                                       (*sdtpnt->attach) (oldSDpnt);
-                                       if (oldSDpnt->attached) {
-                                               scsi_build_commandblocks(oldSDpnt);
-                                               if (0 == oldSDpnt->has_cmdblocks) {
-                                                       printk("scan_scsis: DANGER, no command blocks\n");
-                                                       /* What to do now ?? */
-                                               }
-                                       }
-                               }
-                       }
-                       resize_dma_pool();
-
-                       for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
-                               if (sdtpnt->finish && sdtpnt->nr_dev) {
-                                       (*sdtpnt->finish) ();
-                               }
-                       }
-               }
-       } else {
-               /* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */
-               int order_dev;
-
-               for (channel = 0; channel <= shpnt->max_channel; channel++) {
-                       for (dev = 0; dev < shpnt->max_id; ++dev) {
-                               if (shpnt->reverse_ordering)
-                                       /* Shift to scanning 15,14,13... or 7,6,5,4, */
-                                       order_dev = shpnt->max_id - dev - 1;
-                               else
-                                       order_dev = dev;
-
-                               if (shpnt->this_id != order_dev) {
-
-                                       /*
-                                        * We need the for so our continue, etc. work fine. We put this in
-                                        * a variable so that we can override it during the scan if we
-                                        * detect a device *KNOWN* to have multiple logical units.
-                                        */
-                                       max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
-                                        max_scsi_luns : shpnt->max_lun);
-                                       sparse_lun = 0;
-                                       for (lun = 0; lun < max_dev_lun; ++lun) {
-                                               if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,
-                                                                      &sparse_lun, &SDpnt, SCpnt, shpnt,
-                                                            scsi_result)
-                                                   && !sparse_lun)
-                                                       break;  /* break means don't probe further for luns!=0 */
-                                       }       /* for lun ends */
-                               }       /* if this_id != id ends */
-                       }       /* for dev ends */
-               }               /* for channel ends */
-       }                       /* if/else hardcoded */
-
-       /*
-        * We need to decrement the counter for this one device
-        * so we know when everything is quiet.
-        */
-       atomic_dec(&shpnt->host_active);
-       atomic_dec(&SDpnt->device_active);
-
-      leave:
-
-       {                       /* Unchain SCpnt from host_queue */
-               Scsi_Device *prev, *next;
-               Scsi_Device *dqptr;
-
-               for (dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next)
-                       continue;
-               if (dqptr) {
-                       prev = dqptr->prev;
-                       next = dqptr->next;
-                       if (prev)
-                               prev->next = next;
-                       else
-                               shpnt->host_queue = next;
-                       if (next)
-                               next->prev = prev;
-               }
-       }
-
-       /* Last device block does not exist.  Free memory. */
-       if (SDpnt != NULL)
-               scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
-
-       if (SCpnt != NULL)
-               scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd));
-
-       /* If we allocated a buffer so we could do DMA, free it now */
-       if (scsi_result != &scsi_result0[0] && scsi_result != NULL) {
-               scsi_init_free(scsi_result, 512);
-       } {
-               Scsi_Device *sdev;
-               Scsi_Cmnd *scmd;
-
-               SCSI_LOG_SCAN_BUS(4, printk("Host status for host %p:\n", shpnt));
-               for (sdev = shpnt->host_queue; sdev; sdev = sdev->next) {
-                       SCSI_LOG_SCAN_BUS(4, printk("Device %d %p: ", sdev->id, sdev));
-                       for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
-                               SCSI_LOG_SCAN_BUS(4, printk("%p ", scmd));
-                       }
-                       SCSI_LOG_SCAN_BUS(4, printk("\n"));
-               }
-       }
-}
-
-/*
- * The worker for scan_scsis.
- * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
- * Global variables used : scsi_devices(linked list)
- */
-int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
-              int *sparse_lun, Scsi_Device ** SDpnt2, Scsi_Cmnd * SCpnt,
-                     struct Scsi_Host *shpnt, char *scsi_result)
-{
-       unsigned char scsi_cmd[12];
-       struct Scsi_Device_Template *sdtpnt;
-       Scsi_Device *SDtail, *SDpnt = *SDpnt2;
-       int bflags, type = -1;
-       static int ghost_channel=-1, ghost_dev=-1;
-       int org_lun = lun;
-
-       SDpnt->host = shpnt;
-       SDpnt->id = dev;
-       SDpnt->lun = lun;
-       SDpnt->channel = channel;
-       SDpnt->online = TRUE;
-
-       if ((channel == ghost_channel) && (dev == ghost_dev) && (lun == 1)) {
-               SDpnt->lun = 0;
-       } else {
-               ghost_channel = ghost_dev = -1;
-       }
-            
-
-       /* Some low level driver could use device->type (DB) */
-       SDpnt->type = -1;
-
-       /*
-        * Assume that the device will have handshaking problems, and then fix this
-        * field later if it turns out it doesn't
-        */
-       SDpnt->borken = 1;
-       SDpnt->was_reset = 0;
-       SDpnt->expecting_cc_ua = 0;
-       SDpnt->starved = 0;
-
-       scsi_cmd[0] = TEST_UNIT_READY;
-       scsi_cmd[1] = lun << 5;
-       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
-
-       SCpnt->host = SDpnt->host;
-       SCpnt->device = SDpnt;
-       SCpnt->target = SDpnt->id;
-       SCpnt->lun = SDpnt->lun;
-       SCpnt->channel = SDpnt->channel;
-
-       scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
-                 (void *) NULL,
-                 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
-
-       SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
-                                   dev, lun, SCpnt->result));
-       SCSI_LOG_SCAN_BUS(3, print_driverbyte(SCpnt->result));
-       SCSI_LOG_SCAN_BUS(3, print_hostbyte(SCpnt->result));
-       SCSI_LOG_SCAN_BUS(3, printk("\n"));
-
-       if (SCpnt->result) {
-               if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
-                    (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
-                   ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
-                       if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
-                           ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
-                           ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0))
-                               return 1;
-               } else
-                       return 0;
-       }
-       SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n"));
-       /*
-        * Build an INQUIRY command block.
-        */
-       scsi_cmd[0] = INQUIRY;
-       scsi_cmd[1] = (lun << 5) & 0xe0;
-       scsi_cmd[2] = 0;
-       scsi_cmd[3] = 0;
-       scsi_cmd[4] = 255;
-       scsi_cmd[5] = 0;
-       SCpnt->cmd_len = 0;
-
-       scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
-                 (void *) scsi_result,
-                 256, scan_scsis_done, SCSI_TIMEOUT, 3);
-
-       SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
-               SCpnt->result ? "failed" : "successful", SCpnt->result));
-
-       if (SCpnt->result)
-               return 0;       /* assume no peripheral if any sort of error */
-
-       /*
-        * Check the peripheral qualifier field - this tells us whether LUNS
-        * are supported here or not.
-        */
-       if ((scsi_result[0] >> 5) == 3) {
-               return 0;       /* assume no peripheral if any sort of error */
-       }
-
-       /*
-        * Get any flags for this device.  
-        */
-       bflags = get_device_flags (scsi_result);
-
-
-        /*   The Toshiba ROM was "gender-changed" here as an inline hack.
-             This is now much more generic.
-             This is a mess: What we really want is to leave the scsi_result
-             alone, and just change the SDpnt structure. And the SDpnt is what
-             we want print_inquiry to print.  -- REW
-        */
-       if (bflags & BLIST_ISDISK) {
-               scsi_result[0] = TYPE_DISK;                                                
-               scsi_result[1] |= 0x80;     /* removable */
-       }
-
-       if (bflags & BLIST_ISROM) {
-               scsi_result[0] = TYPE_ROM;
-               scsi_result[1] |= 0x80;     /* removable */
-       }
-    
-       if (bflags & BLIST_GHOST) {
-               if ((ghost_channel == channel) && (ghost_dev == dev) && (org_lun == 1)) {
-                       lun=1;
-               } else {
-                       ghost_channel = channel;
-                       ghost_dev = dev;
-                       scsi_result[0] = TYPE_MOD;
-                       scsi_result[1] |= 0x80;     /* removable */
-               }
-       }
-       
-
-       memcpy(SDpnt->vendor, scsi_result + 8, 8);
-       memcpy(SDpnt->model, scsi_result + 16, 16);
-       memcpy(SDpnt->rev, scsi_result + 32, 4);
-
-       SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
-       SDpnt->online = TRUE;
-       SDpnt->lockable = SDpnt->removable;
-       SDpnt->changed = 0;
-       SDpnt->access_count = 0;
-       SDpnt->busy = 0;
-       SDpnt->has_cmdblocks = 0;
-       /*
-        * Currently, all sequential devices are assumed to be tapes, all random
-        * devices disk, with the appropriate read only flags set for ROM / WORM
-        * treated as RO.
-        */
-       switch (type = (scsi_result[0] & 0x1f)) {
-       case TYPE_TAPE:
-       case TYPE_DISK:
-       case TYPE_MOD:
-       case TYPE_PROCESSOR:
-       case TYPE_SCANNER:
-       case TYPE_MEDIUM_CHANGER:
-       case TYPE_ENCLOSURE:
-               SDpnt->writeable = 1;
-               break;
-       case TYPE_WORM:
-       case TYPE_ROM:
-               SDpnt->writeable = 0;
-               break;
-       default:
-               printk("scsi: unknown type %d\n", type);
-       }
-
-       SDpnt->device_blocked = FALSE;
-       SDpnt->device_busy = 0;
-       SDpnt->single_lun = 0;
-       SDpnt->soft_reset =
-           (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
-       SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
-       SDpnt->type = (type & 0x1f);
-
-       print_inquiry(scsi_result);
-
-       for (sdtpnt = scsi_devicelist; sdtpnt;
-            sdtpnt = sdtpnt->next)
-               if (sdtpnt->detect)
-                       SDpnt->attached +=
-                           (*sdtpnt->detect) (SDpnt);
-
-       SDpnt->scsi_level = scsi_result[2] & 0x07;
-       if (SDpnt->scsi_level >= 2 ||
-           (SDpnt->scsi_level == 1 &&
-            (scsi_result[3] & 0x0f) == 1))
-               SDpnt->scsi_level++;
-
-       /*
-        * Accommodate drivers that want to sleep when they should be in a polling
-        * loop.
-        */
-       SDpnt->disconnect = 0;
-
-
-       /*
-        * Set the tagged_queue flag for SCSI-II devices that purport to support
-        * tagged queuing in the INQUIRY data.
-        */
-       SDpnt->tagged_queue = 0;
-       if ((SDpnt->scsi_level >= SCSI_2) &&
-           (scsi_result[7] & 2) &&
-           !(bflags & BLIST_NOTQ)) {
-               SDpnt->tagged_supported = 1;
-               SDpnt->current_tag = 0;
-       }
-       /*
-        * Some revisions of the Texel CD ROM drives have handshaking problems when
-        * used with the Seagate controllers.  Before we know what type of device
-        * we're talking to, we assume it's borken and then change it here if it
-        * turns out that it isn't a TEXEL drive.
-        */
-       if ((bflags & BLIST_BORKEN) == 0)
-               SDpnt->borken = 0;
-
-       /*
-        * If we want to only allow I/O to one of the luns attached to this device
-        * at a time, then we set this flag.
-        */
-       if (bflags & BLIST_SINGLELUN)
-               SDpnt->single_lun = 1;
-
-       /*
-        * These devices need this "key" to unlock the devices so we can use it
-        */
-       if ((bflags & BLIST_KEY) != 0) {
-               printk("Unlocked floptical drive.\n");
-               SDpnt->lockable = 0;
-               scsi_cmd[0] = MODE_SENSE;
-               scsi_cmd[1] = (lun << 5) & 0xe0;
-               scsi_cmd[2] = 0x2e;
-               scsi_cmd[3] = 0;
-               scsi_cmd[4] = 0x2a;
-               scsi_cmd[5] = 0;
-               SCpnt->cmd_len = 0;
-               scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
-                       (void *) scsi_result, 0x2a,
-                       scan_scsis_done, SCSI_TIMEOUT, 3);
-       }
-       /*
-        * Detach the command from the device. It was just a temporary to be used while
-        * scanning the bus - the real ones will be allocated later.
-        */
-       SDpnt->device_queue = NULL;
-
-       /*
-        * This device was already hooked up to the host in question,
-        * so at this point we just let go of it and it should be fine.  We do need to
-        * allocate a new one and attach it to the host so that we can further scan the bus.
-        */
-       SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof(Scsi_Device), GFP_ATOMIC);
-       *SDpnt2 = SDpnt;
-       if (!SDpnt) {
-               printk("scsi: scan_scsis_single: Cannot malloc\n");
-               return 0;
-       }
-       /*
-        * Register the queue for the device.  All I/O requests will come
-        * in through here.  We also need to register a pointer to
-        * ourselves, since the queue handler won't know what device
-        * the queue actually represents.   We could look it up, but it
-        * is pointless work.
-        */
-       blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
-       blk_queue_headactive(&SDpnt->request_queue, 0);
-       SDpnt->request_queue.queuedata = (void *) SDpnt;
-       SDpnt->host = shpnt;
-       initialize_merge_fn(SDpnt);
-
-       /*
-        * And hook up our command block to the new device we will be testing
-        * for.
-        */
-       SDpnt->device_queue = SCpnt;
-       SDpnt->online = TRUE;
-
-        /*
-         * Initialize the object that we will use to wait for command blocks.
-         */
-       init_waitqueue_head(&SDpnt->scpnt_wait);
-
-       /*
-        * Since we just found one device, there had damn well better be one in the list
-        * already.
-        */
-       if (shpnt->host_queue == NULL)
-               panic("scan_scsis_single: Host queue == NULL\n");
-
-       SDtail = shpnt->host_queue;
-       while (SDtail->next) {
-               SDtail = SDtail->next;
-       }
-
-       /* Add this device to the linked list at the end */
-       SDtail->next = SDpnt;
-       SDpnt->prev = SDtail;
-       SDpnt->next = NULL;
-
-       /*
-        * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
-        */
-       if (bflags & BLIST_NOLUN)
-               return 0;       /* break; */
-
-       /*
-        * If this device is known to support sparse multiple units, override the
-        * other settings, and scan all of them.
-        */
-       if (bflags & BLIST_SPARSELUN) {
-               *max_dev_lun = 8;
-               *sparse_lun = 1;
-               return 1;
-       }
-       /*
-        * If this device is known to support multiple units, override the other
-        * settings, and scan all of them.
-        */
-       if (bflags & BLIST_FORCELUN) {
-               *max_dev_lun = 8;
-               return 1;
-       }
-       /*
-        * REGAL CDC-4X: avoid hang after LUN 4
-        */
-       if (bflags & BLIST_MAX5LUN) {
-               *max_dev_lun = 5;
-               return 1;
-       }
-
-       /*
-        * If this device is Ghosted, scan upto two luns. (It physically only
-        * has one). -- REW
-        */
-       if (bflags & BLIST_GHOST) {
-               *max_dev_lun = 2;
-               return 1;
-       }  
-
-
-       /*
-        * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI
-        * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1
-        * (ANSI SCSI Revision 1) and Response Data Format 0
-        */
-       if (((scsi_result[2] & 0x07) == 0)
-           ||
-           ((scsi_result[2] & 0x07) == 1 &&
-            (scsi_result[3] & 0x0f) == 0))
-               return 0;
-       return 1;
-}
-
-/*
- *  Flag bits for the internal_timeout array
- */
-#define NORMAL_TIMEOUT 0
-#define IN_ABORT  1
-#define IN_RESET  2
-#define IN_RESET2 4
-#define IN_RESET3 8
-
-
 /*
  * This lock protects the freelist for all devices on the system.
  * We could make this finer grained by having a single lock per
@@ -989,11 +244,6 @@ int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
  */
 static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED;
 
-/*
- * Used for access to internal allocator used for DMA safe buffers.
- */
-static spinlock_t allocator_request_lock = SPIN_LOCK_UNLOCKED;
-
 /*
  * Used to protect insertion into and removal from the queue of
  * commands to be processed by the bottom half handler.
@@ -1465,7 +715,8 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
         * the completion function for the high level driver.
         */
 
-       memcpy((void *) SCpnt->data_cmnd, (const void *) cmnd, 12);
+       memcpy((void *) SCpnt->data_cmnd, (const void *) cmnd, 
+               sizeof(SCpnt->data_cmnd));
        SCpnt->reset_chain = NULL;
        SCpnt->serial_number = 0;
        SCpnt->serial_number_at_timeout = 0;
@@ -1477,7 +728,8 @@ void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
        SCpnt->done = done;
        SCpnt->timeout_per_command = timeout;
 
-       memcpy((void *) SCpnt->cmnd, (const void *) cmnd, 12);
+       memcpy((void *) SCpnt->cmnd, (const void *) cmnd, 
+               sizeof(SCpnt->cmnd));
        /* Zero the sense buffer.  Some host adapters automatically request
         * sense on error.  0 is not a valid sense code.
         */
@@ -1820,127 +1072,6 @@ static int scsi_register_host(Scsi_Host_Template *);
 static void scsi_unregister_host(Scsi_Host_Template *);
 #endif
 
-/*
- * Function:    scsi_malloc
- *
- * Purpose:     Allocate memory from the DMA-safe pool.
- *
- * Arguments:   len       - amount of memory we need.
- *
- * Lock status: No locks assumed to be held.  This function is SMP-safe.
- *
- * Returns:     Pointer to memory block.
- *
- * Notes:       Prior to the new queue code, this function was not SMP-safe.
- *              This function can only allocate in units of sectors
- *              (i.e. 512 bytes).
- *
- *              We cannot use the normal system allocator becuase we need
- *              to be able to guarantee that we can process a complete disk
- *              I/O request without touching the system allocator.  Think
- *              about it - if the system were heavily swapping, and tried to
- *              write out a block of memory to disk, and the SCSI code needed
- *              to allocate more memory in order to be able to write the
- *              data to disk, you would wedge the system.
- */
-void *scsi_malloc(unsigned int len)
-{
-       unsigned int nbits, mask;
-       unsigned long flags;
-
-       int i, j;
-       if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
-               return NULL;
-
-       nbits = len >> 9;
-       mask = (1 << nbits) - 1;
-
-       spin_lock_irqsave(&allocator_request_lock, flags);
-
-       for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
-               for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) {
-                       if ((dma_malloc_freelist[i] & (mask << j)) == 0) {
-                               dma_malloc_freelist[i] |= (mask << j);
-                               scsi_dma_free_sectors -= nbits;
-#ifdef DEBUG
-                               SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9)));
-                               printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9));
-#endif
-                               spin_unlock_irqrestore(&allocator_request_lock, flags);
-                               return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
-                       }
-               }
-       spin_unlock_irqrestore(&allocator_request_lock, flags);
-       return NULL;            /* Nope.  No more */
-}
-
-/*
- * Function:    scsi_free
- *
- * Purpose:     Free memory into the DMA-safe pool.
- *
- * Arguments:   ptr       - data block we are freeing.
- *              len       - size of block we are freeing.
- *
- * Lock status: No locks assumed to be held.  This function is SMP-safe.
- *
- * Returns:     Nothing
- *
- * Notes:       This function *must* only be used to free memory
- *              allocated from scsi_malloc().
- *
- *              Prior to the new queue code, this function was not SMP-safe.
- *              This function can only allocate in units of sectors
- *              (i.e. 512 bytes).
- */
-int scsi_free(void *obj, unsigned int len)
-{
-       unsigned int page, sector, nbits, mask;
-       unsigned long flags;
-
-#ifdef DEBUG
-       unsigned long ret = 0;
-
-#ifdef __mips__
-       __asm__ __volatile__("move\t%0,$31":"=r"(ret));
-#else
-       ret = __builtin_return_address(0);
-#endif
-       printk("scsi_free %p %d\n", obj, len);
-       SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len));
-#endif
-
-       spin_lock_irqsave(&allocator_request_lock, flags);
-
-       for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
-               unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
-               if ((unsigned long) obj >= page_addr &&
-                   (unsigned long) obj < page_addr + PAGE_SIZE) {
-                       sector = (((unsigned long) obj) - page_addr) >> 9;
-
-                       nbits = len >> 9;
-                       mask = (1 << nbits) - 1;
-
-                       if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
-                               panic("scsi_free:Bad memory alignment");
-
-                       if ((dma_malloc_freelist[page] &
-                            (mask << sector)) != (mask << sector)) {
-#ifdef DEBUG
-                               printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
-                                      obj, len, ret);
-#endif
-                               panic("scsi_free:Trying to free unused memory");
-                       }
-                       scsi_dma_free_sectors += nbits;
-                       dma_malloc_freelist[page] &= ~(mask << sector);
-                       spin_unlock_irqrestore(&allocator_request_lock, flags);
-                       return 0;
-               }
-       }
-       panic("scsi_free:Bad offset");
-}
-
 
 int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
 
@@ -2124,7 +1255,7 @@ int __init scsi_dev_init(void)
        /*
         * This should build the DMA pool.
         */
-       resize_dma_pool();
+       scsi_resize_dma_pool();
 
        /*
         * OK, now we finish the initialization by doing spin-up, read
@@ -2140,47 +1271,6 @@ int __init scsi_dev_init(void)
 }
 #endif /* MODULE */            /* } */
 
-static void print_inquiry(unsigned char *data)
-{
-       int i;
-
-       printk("  Vendor: ");
-       for (i = 8; i < 16; i++) {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-       }
-
-       printk("  Model: ");
-       for (i = 16; i < 32; i++) {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-       }
-
-       printk("  Rev: ");
-       for (i = 32; i < 36; i++) {
-               if (data[i] >= 0x20 && i < data[4] + 5)
-                       printk("%c", data[i]);
-               else
-                       printk(" ");
-       }
-
-       printk("\n");
-
-       i = data[0] & 0x1f;
-
-       printk("  Type:   %s ",
-              i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          ");
-       printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
-       if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
-               printk(" CCS\n");
-       else
-               printk("\n");
-}
-
 #ifdef CONFIG_PROC_FS
 static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
 {
@@ -2475,217 +1565,6 @@ out:
 }
 #endif
 
-/*
- * Function:    resize_dma_pool
- *
- * Purpose:     Ensure that the DMA pool is sufficiently large to be
- *              able to guarantee that we can always process I/O requests
- *              without calling the system allocator.
- *
- * Arguments:   None.
- *
- * Lock status: No locks assumed to be held.  This function is SMP-safe.
- *
- * Returns:     Nothing
- *
- * Notes:       Prior to the new queue code, this function was not SMP-safe.
- *              Go through the device list and recompute the most appropriate
- *              size for the dma pool.  Then grab more memory (as required).
- */
-static void resize_dma_pool(void)
-{
-       int i, k;
-       unsigned long size;
-       unsigned long flags;
-       struct Scsi_Host *shpnt;
-       struct Scsi_Host *host = NULL;
-       Scsi_Device *SDpnt;
-       FreeSectorBitmap *new_dma_malloc_freelist = NULL;
-       unsigned int new_dma_sectors = 0;
-       unsigned int new_need_isa_buffer = 0;
-       unsigned char **new_dma_malloc_pages = NULL;
-       int out_of_space = 0;
-
-       spin_lock_irqsave(&allocator_request_lock, flags);
-
-       if (!scsi_hostlist) {
-               /*
-                * Free up the DMA pool.
-                */
-               if (scsi_dma_free_sectors != dma_sectors)
-                       panic("SCSI DMA pool memory leak %d %d\n", scsi_dma_free_sectors, dma_sectors);
-
-               for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
-                       scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
-               if (dma_malloc_pages)
-                       scsi_init_free((char *) dma_malloc_pages,
-                                      (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages));
-               dma_malloc_pages = NULL;
-               if (dma_malloc_freelist)
-                       scsi_init_free((char *) dma_malloc_freelist,
-                                      (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_freelist));
-               dma_malloc_freelist = NULL;
-               dma_sectors = 0;
-               scsi_dma_free_sectors = 0;
-               spin_unlock_irqrestore(&allocator_request_lock, flags);
-               return;
-       }
-       /* Next, check to see if we need to extend the DMA buffer pool */
-
-       new_dma_sectors = 2 * SECTORS_PER_PAGE;         /* Base value we use */
-
-       if (__pa(high_memory) - 1 > ISA_DMA_THRESHOLD)
-               need_isa_bounce_buffers = 1;
-       else
-               need_isa_bounce_buffers = 0;
-
-       if (scsi_devicelist)
-               for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-                       new_dma_sectors += SECTORS_PER_PAGE;    /* Increment for each host */
-
-       for (host = scsi_hostlist; host; host = host->next) {
-               for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-                       /*
-                        * sd and sr drivers allocate scatterlists.
-                        * sr drivers may allocate for each command 1x2048 or 2x1024 extra
-                        * buffers for 2k sector size and 1k fs.
-                        * sg driver allocates buffers < 4k.
-                        * st driver does not need buffers from the dma pool.
-                        * estimate 4k buffer/command for devices of unknown type (should panic).
-                        */
-                       if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
-                           SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
-                               new_dma_sectors += ((host->sg_tablesize *
-                               sizeof(struct scatterlist) + 511) >> 9) *
-                                SDpnt->queue_depth;
-                               if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
-                                       new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
-                       } else if (SDpnt->type == TYPE_SCANNER ||
-                                  SDpnt->type == TYPE_PROCESSOR ||
-                                  SDpnt->type == TYPE_MEDIUM_CHANGER ||
-                                  SDpnt->type == TYPE_ENCLOSURE) {
-                               new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
-                       } else {
-                               if (SDpnt->type != TYPE_TAPE) {
-                                       printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
-                                       new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
-                               }
-                       }
-
-                       if (host->unchecked_isa_dma &&
-                           need_isa_bounce_buffers &&
-                           SDpnt->type != TYPE_TAPE) {
-                               new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-                                   SDpnt->queue_depth;
-                               new_need_isa_buffer++;
-                       }
-               }
-       }
-
-#ifdef DEBUG_INIT
-       printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors);
-#endif
-
-       /* limit DMA memory to 32MB: */
-       new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
-
-       /*
-        * We never shrink the buffers - this leads to
-        * race conditions that I would rather not even think
-        * about right now.
-        */
-#if 0                          /* Why do this? No gain and risks out_of_space */
-       if (new_dma_sectors < dma_sectors)
-               new_dma_sectors = dma_sectors;
-#endif
-       if (new_dma_sectors <= dma_sectors) {
-               spin_unlock_irqrestore(&allocator_request_lock, flags);
-               return;         /* best to quit while we are in front */
-        }
-
-       for (k = 0; k < 20; ++k) {      /* just in case */
-               out_of_space = 0;
-               size = (new_dma_sectors / SECTORS_PER_PAGE) *
-                   sizeof(FreeSectorBitmap);
-               new_dma_malloc_freelist = (FreeSectorBitmap *)
-                   scsi_init_malloc(size, GFP_ATOMIC);
-               if (new_dma_malloc_freelist) {
-                       size = (new_dma_sectors / SECTORS_PER_PAGE) *
-                           sizeof(*new_dma_malloc_pages);
-                       new_dma_malloc_pages = (unsigned char **)
-                           scsi_init_malloc(size, GFP_ATOMIC);
-                       if (!new_dma_malloc_pages) {
-                               size = (new_dma_sectors / SECTORS_PER_PAGE) *
-                                   sizeof(FreeSectorBitmap);
-                               scsi_init_free((char *) new_dma_malloc_freelist, size);
-                               out_of_space = 1;
-                       }
-               } else
-                       out_of_space = 1;
-
-               if ((!out_of_space) && (new_dma_sectors > dma_sectors)) {
-                       for (i = dma_sectors / SECTORS_PER_PAGE;
-                          i < new_dma_sectors / SECTORS_PER_PAGE; i++) {
-                               new_dma_malloc_pages[i] = (unsigned char *)
-                                   scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-                               if (!new_dma_malloc_pages[i])
-                                       break;
-                       }
-                       if (i != new_dma_sectors / SECTORS_PER_PAGE) {  /* clean up */
-                               int k = i;
-
-                               out_of_space = 1;
-                               for (i = 0; i < k; ++i)
-                                       scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE);
-                       }
-               }
-               if (out_of_space) {     /* try scaling down new_dma_sectors request */
-                       printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, "
-                              "wanted=%u, scaling\n", dma_sectors, new_dma_sectors);
-                       if (new_dma_sectors < (8 * SECTORS_PER_PAGE))
-                               break;  /* pretty well hopeless ... */
-                       new_dma_sectors = (new_dma_sectors * 3) / 4;
-                       new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
-                       if (new_dma_sectors <= dma_sectors)
-                               break;  /* stick with what we have got */
-               } else
-                       break;  /* found space ... */
-       }                       /* end of for loop */
-       if (out_of_space) {
-               spin_unlock_irqrestore(&allocator_request_lock, flags);
-               scsi_need_isa_buffer = new_need_isa_buffer;     /* some useful info */
-               printk("      WARNING, not enough memory, pool not expanded\n");
-               return;
-       }
-       /* When we dick with the actual DMA list, we need to
-        * protect things
-        */
-       if (dma_malloc_freelist) {
-               size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
-               memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size);
-               scsi_init_free((char *) dma_malloc_freelist, size);
-       }
-       dma_malloc_freelist = new_dma_malloc_freelist;
-
-       if (dma_malloc_pages) {
-               size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages);
-               memcpy(new_dma_malloc_pages, dma_malloc_pages, size);
-               scsi_init_free((char *) dma_malloc_pages, size);
-       }
-       scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
-       dma_malloc_pages = new_dma_malloc_pages;
-       dma_sectors = new_dma_sectors;
-       scsi_need_isa_buffer = new_need_isa_buffer;
-
-       spin_unlock_irqrestore(&allocator_request_lock, flags);
-
-#ifdef DEBUG_INIT
-       printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
-       printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
-       printk("resize_dma_pool: need isa buffers   = %d\n", scsi_need_isa_buffer);
-#endif
-}
-
 #ifdef CONFIG_MODULES          /* a big #ifdef block... */
 
 /*
@@ -2819,7 +1698,7 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
                 * Now that we have all of the devices, resize the DMA pool,
                 * as required.  */
                if (!out_of_space)
-                       resize_dma_pool();
+                       scsi_resize_dma_pool();
 
 
                /* This does any final handling that is required. */
@@ -3037,7 +1916,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
         * do the right thing and free everything.
         */
        if (!scsi_hosts)
-               resize_dma_pool();
+               scsi_resize_dma_pool();
 
        printk("scsi : %d host%s.\n", next_scsi_host,
               (next_scsi_host == 1) ? "" : "s");
@@ -3049,7 +1928,6 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
               (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
 
-
        /* There were some hosts that were loaded at boot time, so we cannot
           do any more than this */
        if (tpnt->present)
@@ -3132,7 +2010,7 @@ static int scsi_register_device_module(struct Scsi_Device_Template *tpnt)
        if (tpnt->finish && tpnt->nr_dev)
                (*tpnt->finish) ();
        if (!out_of_space)
-               resize_dma_pool();
+               scsi_resize_dma_pool();
        MOD_INC_USE_COUNT;
 
        if (out_of_space) {
@@ -3382,39 +2260,11 @@ int init_module(void)
 
        scsi_loadable_module_flag = 1;
 
-       dma_sectors = PAGE_SIZE / SECTOR_SIZE;
-       scsi_dma_free_sectors = dma_sectors;
-       /*
-        * Set up a minimal DMA buffer list - this will be used during scan_scsis
-        * in some cases.
-        */
+        if( scsi_init_minimal_dma_pool() == 0 )
+        {
+                return 1;
+        }
 
-       /* One bit per sector to indicate free/busy */
-       size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
-       dma_malloc_freelist = (FreeSectorBitmap *)
-           scsi_init_malloc(size, GFP_ATOMIC);
-       if (dma_malloc_freelist) {
-               /* One pointer per page for the page list */
-               dma_malloc_pages = (unsigned char **) scsi_init_malloc(
-                                                                             (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages),
-                                                            GFP_ATOMIC);
-               if (dma_malloc_pages) {
-                       dma_malloc_pages[0] = (unsigned char *)
-                           scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-                       if (dma_malloc_pages[0])
-                               has_space = 1;
-               }
-       }
-       if (!has_space) {
-               if (dma_malloc_freelist) {
-                       scsi_init_free((char *) dma_malloc_freelist, size);
-                       if (dma_malloc_pages)
-                               scsi_init_free((char *) dma_malloc_pages,
-                                              (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages));
-               }
-               printk("scsi::init_module: failed, out of memory\n");
-               return 1;
-       }
        /*
         * This is where the processing takes place for most everything
         * when commands are completed.
@@ -3437,7 +2287,7 @@ void cleanup_module(void)
        /*
         * Free up the DMA pool.
         */
-       resize_dma_pool();
+       scsi_resize_dma_pool();
 
 }
 
@@ -3491,7 +2341,7 @@ Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt)
 
         SDpnt->device_queue = SCpnt;
 
-        blk_init_queue(&SDpnt->request_queue, scsi_request_fn);
+        blk_init_queue(&SDpnt->request_queue, scsi_get_request_handler(SDpnt, SDpnt->host));
         blk_queue_headactive(&SDpnt->request_queue, 0);
         SDpnt->request_queue.queuedata = (void *) SDpnt;
 
@@ -3519,7 +2369,7 @@ Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt)
  */
 void scsi_free_host_dev(Scsi_Device * SDpnt)
 {
-        if( SDpnt->id != SDpnt->host->this_id )
+        if( (unsigned char) SDpnt->id != (unsigned char) SDpnt->host->this_id )
         {
                 panic("Attempt to delete wrong device\n");
         }
index b15575eac78d0b68e218dd6fd35d44e36c52ced9..f8f615c97a6d98ea0745c9bad4f7a606a0626301 100644 (file)
@@ -365,90 +365,120 @@ typedef struct scsi_cmnd Scsi_Cmnd;
  *  Initializes all SCSI devices.  This scans all scsi busses.
  */
 
-extern int scsi_dev_init(void);
-
-
-
-void *scsi_malloc(unsigned int);
-int scsi_free(void *, unsigned int);
 extern unsigned int scsi_logging_level;                /* What do we log? */
 extern unsigned int scsi_dma_free_sectors;     /* How much room do we have left */
 extern unsigned int scsi_need_isa_buffer;      /* True if some devices need indirection
                                                   * buffers */
-extern void scsi_make_blocked_list(void);
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
 
+
 /*
  * These are the error handling functions defined in scsi_error.c
  */
+extern void scsi_times_out(Scsi_Cmnd * SCpnt);
 extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout,
                           void (*complete) (Scsi_Cmnd *));
-extern void scsi_done(Scsi_Cmnd * SCpnt);
 extern int scsi_delete_timer(Scsi_Cmnd * SCset);
 extern void scsi_error_handler(void *host);
-extern int scsi_retry_command(Scsi_Cmnd *);
-extern void scsi_finish_command(Scsi_Cmnd *);
 extern int scsi_sense_valid(Scsi_Cmnd *);
 extern int scsi_decide_disposition(Scsi_Cmnd * SCpnt);
 extern int scsi_block_when_processing_errors(Scsi_Device *);
 extern void scsi_sleep(int);
+
+/*
+ * Prototypes for functions in scsicam.c
+ */
 extern int  scsi_partsize(struct buffer_head *bh, unsigned long capacity,
                     unsigned int *cyls, unsigned int *hds,
                     unsigned int *secs);
 
+/*
+ * Prototypes for functions in scsi_dma.c
+ */
+void scsi_resize_dma_pool(void);
+int scsi_init_minimal_dma_pool(void);
+void *scsi_malloc(unsigned int);
+int scsi_free(void *, unsigned int);
+
 /*
  * Prototypes for functions in scsi_merge.c
  */
 extern void recount_segments(Scsi_Cmnd * SCpnt);
+extern void initialize_merge_fn(Scsi_Device * SDpnt);
+
+/*
+ * Prototypes for functions in scsi_queue.c
+ */
+extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason);
 
 /*
  * Prototypes for functions in scsi_lib.c
  */
-extern void initialize_merge_fn(Scsi_Device * SDpnt);
-extern void scsi_request_fn(request_queue_t * q);
+extern void scsi_maybe_unblock_host(Scsi_Device * SDpnt);
+extern void scsi_blocked_request_fn(request_queue_t * q);
+extern Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate,
+                                  int sectors);
+extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
+extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt);
+extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
+extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
+                              int block_sectors);
 extern void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt);
+extern void scsi_request_fn(request_queue_t * q);
 
-extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
-extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);
 
 /*
  * Prototypes for functions in scsi.c
  */
-
-/*
- *  scsi_abort aborts the current command that is executing on host host.
- *  The error code, if non zero is returned in the host byte, otherwise 
- *  DID_ABORT is returned in the hostbyte.
- */
-
+extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);
+extern void scsi_bottom_half_handler(void);
+extern void scsi_build_commandblocks(Scsi_Device * SDpnt);
+extern void scsi_done(Scsi_Cmnd * SCpnt);
+extern void scsi_finish_command(Scsi_Cmnd *);
+extern int scsi_retry_command(Scsi_Cmnd *);
+extern Scsi_Cmnd *scsi_allocate_device(Scsi_Device *, int, int);
+extern void scsi_release_command(Scsi_Cmnd *);
 extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
                        void *buffer, unsigned bufflen,
                        void (*done) (struct scsi_cmnd *),
                        int timeout, int retries);
-
 extern void scsi_wait_cmd(Scsi_Cmnd *, const void *cmnd,
                          void *buffer, unsigned bufflen,
-                         void (*done) (struct scsi_cmnd *),
                          int timeout, int retries);
+extern int scsi_dev_init(void);
 
-extern Scsi_Cmnd *scsi_allocate_device(Scsi_Device *, int, int);
-
-extern void scsi_release_command(Scsi_Cmnd *);
 
+/*
+ * Prototypes for functions/data in hosts.c
+ */
 extern int max_scsi_hosts;
 
+/*
+ * Prototypes for functions in scsi_proc.c
+ */
 extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
 extern struct proc_dir_entry *proc_scsi;
 
+/*
+ * Prototypes for functions in constants.c
+ */
 extern void print_command(unsigned char *);
 extern void print_sense(const char *, Scsi_Cmnd *);
 extern void print_driverbyte(int scsiresult);
 extern void print_hostbyte(int scsiresult);
+extern void print_status (int status);
 
 /*
  *  The scsi_device struct contains what we know about each given scsi
  *  device.
+ *
+ * FIXME(eric) - one of the great regrets that I have is that I failed to define
+ * these structure elements as something like sdev_foo instead of foo.  This would
+ * make it so much easier to grep through sources and so forth.  I propose that
+ * all new elements that get added to these structures follow this convention.
+ * As time goes on and as people have the stomach for it, it should be possible to 
+ * go back and retrofit at least some of the elements here with with the prefix.
  */
 
 struct scsi_device {
@@ -538,6 +568,14 @@ typedef struct scsi_pointer {
 } Scsi_Pointer;
 
 
+/*
+ * FIXME(eric) - one of the great regrets that I have is that I failed to define
+ * these structure elements as something like sc_foo instead of foo.  This would
+ * make it so much easier to grep through sources and so forth.  I propose that
+ * all new elements that get added to these structures follow this convention.
+ * As time goes on and as people have the stomach for it, it should be possible to 
+ * go back and retrofit at least some of the elements here with with the prefix.
+ */
 struct scsi_cmnd {
 /* private: */
        /*
@@ -593,14 +631,14 @@ struct scsi_cmnd {
        unsigned char old_cmd_len;
 
        /* These elements define the operation we are about to perform */
-       unsigned char cmnd[12];
+       unsigned char cmnd[MAX_COMMAND_SIZE];
        unsigned request_bufflen;       /* Actual request size */
 
        struct timer_list eh_timeout;   /* Used to time out the command. */
        void *request_buffer;   /* Actual requested buffer */
 
        /* These elements define the operation we ultimately want to perform */
-       unsigned char data_cmnd[12];
+       unsigned char data_cmnd[MAX_COMMAND_SIZE];
        unsigned short old_use_sg;      /* We save  use_sg here when requesting
                                         * sense info */
        unsigned short use_sg;  /* Number of pieces of scatter-gather */
@@ -667,13 +705,9 @@ struct scsi_cmnd {
 };
 
 /*
- *  Flag bits for the internal_timeout array
+ *  Flag bit for the internal_timeout array
  */
 #define NORMAL_TIMEOUT 0
-#define IN_ABORT  1
-#define IN_RESET  2
-#define IN_RESET2 4
-#define IN_RESET3 8
 
 /*
  * Definitions and prototypes used for scsi mid-level queue.
@@ -681,16 +715,6 @@ struct scsi_cmnd {
 #define SCSI_MLQUEUE_HOST_BUSY   0x1055
 #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
 
-extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason);
-
-extern Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate,
-                                  int sectors);
-
-extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
-                              int block_sectors);
-
-extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
-
 #define SCSI_SLEEP(QUEUE, CONDITION) {             \
     if (CONDITION) {                               \
        DECLARE_WAITQUEUE(wait, current);           \
index 925c0f8f790a2655efd96a10643a9fd120fdf27a..9f36d08c536d89918cb49fa0a4dde68a058b85c1 100644 (file)
@@ -544,18 +544,6 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
        return 0;
 }
 
-static void sd_test_done(Scsi_Cmnd * SCpnt)
-{
-       struct request *req;
-
-       req = &SCpnt->request;
-       req->rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
-
-       if (req->sem != NULL) {
-               up(req->sem);
-       }
-}
-
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
 {
        static unsigned char cmd[6] =
@@ -575,7 +563,7 @@ static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
         
         printk("Sending command\n");
         scsi_wait_cmd (scp, (void *) cmd, (void *) NULL,
-                       0, sd_test_done,  100, 3);
+                       0, 100, 3);
         
         printk("Releasing command\n");
         scsi_release_command(scp);
diff --git a/drivers/scsi/scsi_dma.c b/drivers/scsi/scsi_dma.c
new file mode 100644 (file)
index 0000000..efb6279
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ *  scsi_dma.c Copyright (C) 2000 Eric Youngdale
+ *
+ *  mid-level SCSI DMA bounce buffer allocator
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/blk.h>
+
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+/*
+ * PAGE_SIZE must be a multiple of the sector size (512).  True
+ * for all reasonably recent architectures (even the VAX...).
+ */
+#define SECTOR_SIZE            512
+#define SECTORS_PER_PAGE       (PAGE_SIZE/SECTOR_SIZE)
+
+#if SECTORS_PER_PAGE <= 8
+typedef unsigned char FreeSectorBitmap;
+#elif SECTORS_PER_PAGE <= 32
+typedef unsigned int FreeSectorBitmap;
+#else
+#error You lose.
+#endif
+
+/*
+ * Used for access to internal allocator used for DMA safe buffers.
+ */
+static spinlock_t allocator_request_lock = SPIN_LOCK_UNLOCKED;
+
+static FreeSectorBitmap *dma_malloc_freelist = NULL;
+static int need_isa_bounce_buffers;
+static unsigned int dma_sectors = 0;
+unsigned int scsi_dma_free_sectors = 0;
+unsigned int scsi_need_isa_buffer = 0;
+static unsigned char **dma_malloc_pages = NULL;
+
+/*
+ * Function:    scsi_malloc
+ *
+ * Purpose:     Allocate memory from the DMA-safe pool.
+ *
+ * Arguments:   len       - amount of memory we need.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Pointer to memory block.
+ *
+ * Notes:       Prior to the new queue code, this function was not SMP-safe.
+ *              This function can only allocate in units of sectors
+ *              (i.e. 512 bytes).
+ *
+ *              We cannot use the normal system allocator becuase we need
+ *              to be able to guarantee that we can process a complete disk
+ *              I/O request without touching the system allocator.  Think
+ *              about it - if the system were heavily swapping, and tried to
+ *              write out a block of memory to disk, and the SCSI code needed
+ *              to allocate more memory in order to be able to write the
+ *              data to disk, you would wedge the system.
+ */
+void *scsi_malloc(unsigned int len)
+{
+       unsigned int nbits, mask;
+       unsigned long flags;
+
+       int i, j;
+       if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
+               return NULL;
+
+       nbits = len >> 9;
+       mask = (1 << nbits) - 1;
+
+       spin_lock_irqsave(&allocator_request_lock, flags);
+
+       for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
+               for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) {
+                       if ((dma_malloc_freelist[i] & (mask << j)) == 0) {
+                               dma_malloc_freelist[i] |= (mask << j);
+                               scsi_dma_free_sectors -= nbits;
+#ifdef DEBUG
+                               SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9)));
+                               printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9));
+#endif
+                               spin_unlock_irqrestore(&allocator_request_lock, flags);
+                               return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
+                       }
+               }
+       spin_unlock_irqrestore(&allocator_request_lock, flags);
+       return NULL;            /* Nope.  No more */
+}
+
+/*
+ * Function:    scsi_free
+ *
+ * Purpose:     Free memory into the DMA-safe pool.
+ *
+ * Arguments:   ptr       - data block we are freeing.
+ *              len       - size of block we are freeing.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       This function *must* only be used to free memory
+ *              allocated from scsi_malloc().
+ *
+ *              Prior to the new queue code, this function was not SMP-safe.
+ *              This function can only allocate in units of sectors
+ *              (i.e. 512 bytes).
+ */
+int scsi_free(void *obj, unsigned int len)
+{
+       unsigned int page, sector, nbits, mask;
+       unsigned long flags;
+
+#ifdef DEBUG
+       unsigned long ret = 0;
+
+#ifdef __mips__
+       __asm__ __volatile__("move\t%0,$31":"=r"(ret));
+#else
+       ret = __builtin_return_address(0);
+#endif
+       printk("scsi_free %p %d\n", obj, len);
+       SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len));
+#endif
+
+       spin_lock_irqsave(&allocator_request_lock, flags);
+
+       for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
+               unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
+               if ((unsigned long) obj >= page_addr &&
+                   (unsigned long) obj < page_addr + PAGE_SIZE) {
+                       sector = (((unsigned long) obj) - page_addr) >> 9;
+
+                       nbits = len >> 9;
+                       mask = (1 << nbits) - 1;
+
+                       if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
+                               panic("scsi_free:Bad memory alignment");
+
+                       if ((dma_malloc_freelist[page] &
+                            (mask << sector)) != (mask << sector)) {
+#ifdef DEBUG
+                               printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
+                                      obj, len, ret);
+#endif
+                               panic("scsi_free:Trying to free unused memory");
+                       }
+                       scsi_dma_free_sectors += nbits;
+                       dma_malloc_freelist[page] &= ~(mask << sector);
+                       spin_unlock_irqrestore(&allocator_request_lock, flags);
+                       return 0;
+               }
+       }
+       panic("scsi_free:Bad offset");
+}
+
+
+/*
+ * Function:    scsi_resize_dma_pool
+ *
+ * Purpose:     Ensure that the DMA pool is sufficiently large to be
+ *              able to guarantee that we can always process I/O requests
+ *              without calling the system allocator.
+ *
+ * Arguments:   None.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       Prior to the new queue code, this function was not SMP-safe.
+ *              Go through the device list and recompute the most appropriate
+ *              size for the dma pool.  Then grab more memory (as required).
+ */
+void scsi_resize_dma_pool(void)
+{
+       int i, k;
+       unsigned long size;
+       unsigned long flags;
+       struct Scsi_Host *shpnt;
+       struct Scsi_Host *host = NULL;
+       Scsi_Device *SDpnt;
+       FreeSectorBitmap *new_dma_malloc_freelist = NULL;
+       unsigned int new_dma_sectors = 0;
+       unsigned int new_need_isa_buffer = 0;
+       unsigned char **new_dma_malloc_pages = NULL;
+       int out_of_space = 0;
+
+       spin_lock_irqsave(&allocator_request_lock, flags);
+
+       if (!scsi_hostlist) {
+               /*
+                * Free up the DMA pool.
+                */
+               if (scsi_dma_free_sectors != dma_sectors)
+                       panic("SCSI DMA pool memory leak %d %d\n", scsi_dma_free_sectors, dma_sectors);
+
+               for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
+                       free_pages((unsigned long) dma_malloc_pages[i], 0);
+               if (dma_malloc_pages)
+                       kfree((char *) dma_malloc_pages);
+               dma_malloc_pages = NULL;
+               if (dma_malloc_freelist)
+                       kfree((char *) dma_malloc_freelist);
+               dma_malloc_freelist = NULL;
+               dma_sectors = 0;
+               scsi_dma_free_sectors = 0;
+               spin_unlock_irqrestore(&allocator_request_lock, flags);
+               return;
+       }
+       /* Next, check to see if we need to extend the DMA buffer pool */
+
+       new_dma_sectors = 2 * SECTORS_PER_PAGE;         /* Base value we use */
+
+       if (__pa(high_memory) - 1 > ISA_DMA_THRESHOLD)
+               need_isa_bounce_buffers = 1;
+       else
+               need_isa_bounce_buffers = 0;
+
+       if (scsi_devicelist)
+               for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+                       new_dma_sectors += SECTORS_PER_PAGE;    /* Increment for each host */
+
+       for (host = scsi_hostlist; host; host = host->next) {
+               for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+                       /*
+                        * sd and sr drivers allocate scatterlists.
+                        * sr drivers may allocate for each command 1x2048 or 2x1024 extra
+                        * buffers for 2k sector size and 1k fs.
+                        * sg driver allocates buffers < 4k.
+                        * st driver does not need buffers from the dma pool.
+                        * estimate 4k buffer/command for devices of unknown type (should panic).
+                        */
+                       if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
+                           SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
+                               new_dma_sectors += ((host->sg_tablesize *
+                               sizeof(struct scatterlist) + 511) >> 9) *
+                                SDpnt->queue_depth;
+                               if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
+                                       new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
+                       } else if (SDpnt->type == TYPE_SCANNER ||
+                                  SDpnt->type == TYPE_PROCESSOR ||
+                                  SDpnt->type == TYPE_MEDIUM_CHANGER ||
+                                  SDpnt->type == TYPE_ENCLOSURE) {
+                               new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+                       } else {
+                               if (SDpnt->type != TYPE_TAPE) {
+                                       printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
+                                       new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+                               }
+                       }
+
+                       if (host->unchecked_isa_dma &&
+                           need_isa_bounce_buffers &&
+                           SDpnt->type != TYPE_TAPE) {
+                               new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+                                   SDpnt->queue_depth;
+                               new_need_isa_buffer++;
+                       }
+               }
+       }
+
+#ifdef DEBUG_INIT
+       printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors);
+#endif
+
+       /* limit DMA memory to 32MB: */
+       new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+
+       /*
+        * We never shrink the buffers - this leads to
+        * race conditions that I would rather not even think
+        * about right now.
+        */
+#if 0                          /* Why do this? No gain and risks out_of_space */
+       if (new_dma_sectors < dma_sectors)
+               new_dma_sectors = dma_sectors;
+#endif
+       if (new_dma_sectors <= dma_sectors) {
+               spin_unlock_irqrestore(&allocator_request_lock, flags);
+               return;         /* best to quit while we are in front */
+        }
+
+       for (k = 0; k < 20; ++k) {      /* just in case */
+               out_of_space = 0;
+               size = (new_dma_sectors / SECTORS_PER_PAGE) *
+                   sizeof(FreeSectorBitmap);
+               new_dma_malloc_freelist = (FreeSectorBitmap *)
+                   kmalloc(size, GFP_ATOMIC);
+               if (new_dma_malloc_freelist) {
+                        memset(new_dma_malloc_freelist, 0, size);
+                       size = (new_dma_sectors / SECTORS_PER_PAGE) *
+                           sizeof(*new_dma_malloc_pages);
+                       new_dma_malloc_pages = (unsigned char **)
+                           kmalloc(size, GFP_ATOMIC);
+                       if (!new_dma_malloc_pages) {
+                               size = (new_dma_sectors / SECTORS_PER_PAGE) *
+                                   sizeof(FreeSectorBitmap);
+                               kfree((char *) new_dma_malloc_freelist);
+                               out_of_space = 1;
+                       } else {
+                                memset(new_dma_malloc_pages, 0, size);
+                        }
+               } else
+                       out_of_space = 1;
+
+               if ((!out_of_space) && (new_dma_sectors > dma_sectors)) {
+                       for (i = dma_sectors / SECTORS_PER_PAGE;
+                          i < new_dma_sectors / SECTORS_PER_PAGE; i++) {
+                               new_dma_malloc_pages[i] = (unsigned char *)
+                                   __get_free_pages(GFP_ATOMIC | GFP_DMA, 0);
+                               if (!new_dma_malloc_pages[i])
+                                       break;
+                       }
+                       if (i != new_dma_sectors / SECTORS_PER_PAGE) {  /* clean up */
+                               int k = i;
+
+                               out_of_space = 1;
+                               for (i = 0; i < k; ++i)
+                                       free_pages((unsigned long) new_dma_malloc_pages[i], 0);
+                       }
+               }
+               if (out_of_space) {     /* try scaling down new_dma_sectors request */
+                       printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, "
+                              "wanted=%u, scaling\n", dma_sectors, new_dma_sectors);
+                       if (new_dma_sectors < (8 * SECTORS_PER_PAGE))
+                               break;  /* pretty well hopeless ... */
+                       new_dma_sectors = (new_dma_sectors * 3) / 4;
+                       new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+                       if (new_dma_sectors <= dma_sectors)
+                               break;  /* stick with what we have got */
+               } else
+                       break;  /* found space ... */
+       }                       /* end of for loop */
+       if (out_of_space) {
+               spin_unlock_irqrestore(&allocator_request_lock, flags);
+               scsi_need_isa_buffer = new_need_isa_buffer;     /* some useful info */
+               printk("      WARNING, not enough memory, pool not expanded\n");
+               return;
+       }
+       /* When we dick with the actual DMA list, we need to
+        * protect things
+        */
+       if (dma_malloc_freelist) {
+               size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
+               memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size);
+               kfree((char *) dma_malloc_freelist);
+       }
+       dma_malloc_freelist = new_dma_malloc_freelist;
+
+       if (dma_malloc_pages) {
+               size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages);
+               memcpy(new_dma_malloc_pages, dma_malloc_pages, size);
+               kfree((char *) dma_malloc_pages);
+       }
+       scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
+       dma_malloc_pages = new_dma_malloc_pages;
+       dma_sectors = new_dma_sectors;
+       scsi_need_isa_buffer = new_need_isa_buffer;
+
+       spin_unlock_irqrestore(&allocator_request_lock, flags);
+
+#ifdef DEBUG_INIT
+       printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
+       printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
+       printk("resize_dma_pool: need isa buffers   = %d\n", scsi_need_isa_buffer);
+#endif
+}
+
+/*
+ * Function:    scsi_init_minimal_dma_pool
+ *
+ * Purpose:     Allocate a minimal (1-page) DMA pool.
+ *
+ * Arguments:   None.
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       
+ */
+int scsi_init_minimal_dma_pool(void)
+{
+       unsigned long size;
+       unsigned long flags;
+       int has_space = 0;
+
+       spin_lock_irqsave(&allocator_request_lock, flags);
+
+       dma_sectors = PAGE_SIZE / SECTOR_SIZE;
+       scsi_dma_free_sectors = dma_sectors;
+       /*
+        * Set up a minimal DMA buffer list - this will be used during scan_scsis
+        * in some cases.
+        */
+
+       /* One bit per sector to indicate free/busy */
+       size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
+       dma_malloc_freelist = (FreeSectorBitmap *)
+           kmalloc(size, GFP_ATOMIC);
+       if (dma_malloc_freelist) {
+                memset(dma_malloc_freelist, 0, size);
+               /* One pointer per page for the page list */
+               dma_malloc_pages = (unsigned char **) kmalloc(
+                        (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages),
+                                                            GFP_ATOMIC);
+               if (dma_malloc_pages) {
+                        memset(dma_malloc_pages, 0, size);
+                       dma_malloc_pages[0] = (unsigned char *)
+                           __get_free_pages(GFP_ATOMIC | GFP_DMA, 0);
+                       if (dma_malloc_pages[0])
+                               has_space = 1;
+               }
+       }
+       if (!has_space) {
+               if (dma_malloc_freelist) {
+                       kfree((char *) dma_malloc_freelist);
+                       if (dma_malloc_pages)
+                               kfree((char *) dma_malloc_pages);
+               }
+               spin_unlock_irqrestore(&allocator_request_lock, flags);
+               printk("scsi::init_module: failed, out of memory\n");
+               return 1;
+       }
+
+       spin_unlock_irqrestore(&allocator_request_lock, flags);
+       return 0;
+}
index 1a45b5880445ade4c2532fcd1bc2dee0556bf81d..f62c1f0153477329cdca48d5b4cfa5349ce23a3a 100644 (file)
@@ -90,18 +90,6 @@ static int ioctl_probe(struct Scsi_Host *host, void *buffer)
  * The output area is then filled in starting from the command byte. 
  */
 
-static void scsi_ioctl_done(Scsi_Cmnd * SCpnt)
-{
-       struct request *req;
-
-       req = &SCpnt->request;
-       req->rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
-
-       if (req->sem != NULL) {
-               up(req->sem);
-       }
-}
-
 static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
                                  int timeout, int retries)
 {
@@ -117,7 +105,7 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
                 return -EINTR;
         }
 
-        scsi_wait_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries);
+        scsi_wait_cmd(SCpnt, cmd, NULL, 0, timeout, retries);
 
        SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
 
@@ -201,7 +189,7 @@ static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
 int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
 {
        char *buf;
-       unsigned char cmd[12];
+       unsigned char cmd[MAX_COMMAND_SIZE];
        char *cmd_in;
        Scsi_Cmnd *SCpnt;
        Scsi_Device *SDpnt;
@@ -300,8 +288,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
                 return -EINTR;
         }
 
-        scsi_wait_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done,
-                      timeout, retries);
+        scsi_wait_cmd(SCpnt, cmd, buf, needed, timeout, retries);
 
        /* 
         * If there was an error condition, pass the info back to the user. 
@@ -358,7 +345,7 @@ int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
 int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
 {
        int result;
-       char scsi_cmd[12];
+       char scsi_cmd[MAX_COMMAND_SIZE];
 
        /* No idea how this happens.... */
        if (!dev)
index 48b1c977d2390470394473cc7110123838842aa4..7d2c021e92bc2c0fc098bff1b8d2ec08622aaa0f 100644 (file)
  * This entire source file deals with the new queueing code.
  */
 
+/*
+ * For hosts that request single-file access to the ISA bus, this is a pointer to
+ * the currently active host.
+ */
+volatile struct Scsi_Host *host_active = NULL;
+
+
 /*
  * Function:    scsi_insert_special_cmd()
  *
@@ -184,6 +191,7 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
        return 1;
 }
 
+
 /*
  * Function:    scsi_queue_next_request()
  *
@@ -202,6 +210,23 @@ int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt)
  *              If SCpnt is NULL, it means that the previous command
  *              was completely finished, and we should simply start
  *              a new command, if possible.
+ *
+ *             This is where a lot of special case code has begun to
+ *             accumulate.  It doesn't really affect readability or
+ *             anything, but it might be considered architecturally
+ *             inelegant.  If more of these special cases start to
+ *             accumulate, I am thinking along the lines of implementing
+ *             an atexit() like technology that gets run when commands
+ *             complete.  I am not convinced that it is worth the
+ *             added overhead, however.  Right now as things stand,
+ *             there are simple conditional checks, and most hosts
+ *             would skip past.
+ *
+ *             Another possible solution would be to tailor different
+ *             handler functions, sort of like what we did in scsi_merge.c.
+ *             This is probably a better solution, but the number of different
+ *             permutations grows as 2**N, and if too many more special cases
+ *             get added, we start to get screwed.
  */
 void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
 {
index eb3eb0cebcb855db2c452c3209e47ceff347ec36..ee1041d88fdcc7dcb6ecfd0de07d8f4fa2a15825 100644 (file)
@@ -132,7 +132,6 @@ static void scsi_dump_status(void);
 /*
  *  Flag bits for the internal_timeout array
  */
-#define NORMAL_TIMEOUT 0
 #define IN_ABORT  1
 #define IN_RESET  2
 #define IN_RESET2 4
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
new file mode 100644 (file)
index 0000000..ed30ae0
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ *  scsi_scan.c Copyright (C) 2000 Eric Youngdale
+ *
+ *  Bus scan logic.
+ *
+ *  This used to live in scsi.c, but that file was just a laundry basket
+ *  full of misc stuff.  This got separated out in order to make things
+ *  clearer.
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/blk.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+/* The following devices are known not to tolerate a lun != 0 scan for
+ * one reason or another.  Some will respond to all luns, others will
+ * lock up.
+ */
+
+#define BLIST_NOLUN            0x001
+#define BLIST_FORCELUN         0x002
+#define BLIST_BORKEN           0x004
+#define BLIST_KEY              0x008
+#define BLIST_SINGLELUN        0x010
+#define BLIST_NOTQ             0x020
+#define BLIST_SPARSELUN        0x040
+#define BLIST_MAX5LUN          0x080
+#define BLIST_ISDISK           0x100
+#define BLIST_ISROM            0x200
+#define BLIST_GHOST            0x400   
+
+static void print_inquiry(unsigned char *data);
+static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
+               int *sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
+                            struct Scsi_Host *shpnt, char *scsi_result);
+
+struct dev_info {
+       const char *vendor;
+       const char *model;
+       const char *revision;   /* Latest revision known to be bad.  Not used yet */
+       unsigned flags;
+};
+
+/*
+ * This is what was previously known as the blacklist.  The concept
+ * has been expanded so that we can specify other types of things we
+ * need to be aware of.
+ */
+static struct dev_info device_list[] =
+{
+       {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
+       {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
+       {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
+       {"DENON", "DRD-25X", "V", BLIST_NOLUN},                 /* Locks up if probed for lun != 0 */
+       {"HITACHI", "DK312C", "CM81", BLIST_NOLUN},             /* Responds to all lun - dtg */
+       {"HITACHI", "DK314C", "CR21", BLIST_NOLUN},             /* responds to all lun */
+       {"IMS", "CDD521/10", "2.06", BLIST_NOLUN},              /* Locks-up when LUN>0 polled. */
+       {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},             /* Locks-up when LUN>0 polled. */
+       {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},             /* Locks-up when LUN>0 polled. */
+       {"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},           /* Locks up when LUN>0 polled */
+       {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},             /* Locks-up sometimes when LUN>0 polled. */
+       {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},             /* guess what? */
+       {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},    /*Responds to all lun */
+       {"MICROP", "4110", "*", BLIST_NOTQ},                    /* Buggy Tagged Queuing */
+       {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},        /* Locks-up when LUN>0 polled. */
+       {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},            /* Responds to all lun */
+       {"RODIME", "RO3000S", "2.33", BLIST_NOLUN},             /* Locks up if polled for lun != 0 */
+       {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},             /* causes failed REQUEST SENSE on lun 1
+                                                                * for aha152x controller, which causes
+                                                                * SCSI code to reset bus.*/
+       {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},           /* causes failed REQUEST SENSE on lun 1
+                                                                * for aha152x controller, which causes
+                                                                * SCSI code to reset bus.*/
+       {"SEAGATE", "ST296", "921", BLIST_NOLUN},               /* Responds to all lun */
+       {"SEAGATE", "ST1581", "6538", BLIST_NOLUN},             /* Responds to all lun */
+       {"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},        
+       {"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
+       {"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
+       {"SONY", "CD-ROM CDU-8012", "*", BLIST_NOLUN},
+       {"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},           /* Locks up if polled for lun != 0 */
+       {"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},               /* Locks up if polled for lun != 0 */
+       {"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},                /* causes failed REQUEST SENSE on lun 1
+                                                                * for seagate controller, which causes
+                                                                * SCSI code to reset bus.*/
+       {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},        /* Responds to all lun */
+       {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},               /* causes failed REQUEST SENSE on lun 1
+                                                                * for seagate controller, which causes
+                                                                * SCSI code to reset bus.*/
+       {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},            /* Locks sometimes if polled for lun != 0 */
+       {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},            /* Locks sometimes if polled for lun != 0 */
+       {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},    /* Locks up when polled for lun != 0 */
+       {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},         /* Locks up if polled for lun != 0 */
+       {"SANKYO", "CP525", "6.64", BLIST_NOLUN},               /* causes failed REQ SENSE, extra reset */
+       {"HP", "C1750A", "3226", BLIST_NOLUN},                  /* scanjet iic */
+       {"HP", "C1790A", "", BLIST_NOLUN},                      /* scanjet iip */
+       {"HP", "C2500A", "", BLIST_NOLUN},                      /* scanjet iicx */
+       {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},              /* Locks up if polled for lun != 0 */
+       {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},              /* Locks up if polled for lun != 0  
+                                                                * extra reset */
+       {"RELISYS", "Scorpio", "*", BLIST_NOLUN},               /* responds to all LUN */
+       {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},      /* responds to all LUN */
+
+/*
+ * Other types of devices that have special flags.
+ */
+       {"SONY", "CD-ROM CDU-8001", "*", BLIST_BORKEN},
+       {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+       {"IOMEGA", "Io20S         *F", "*", BLIST_KEY},
+       {"INSITE", "Floptical   F*8I", "*", BLIST_KEY},
+       {"INSITE", "I325VM", "*", BLIST_KEY},
+       {"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+       {"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+       {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN},
+       {"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+       {"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+    {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+   {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+   {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+       {"EMULEX", "MD21/S2     ESDI", "*", BLIST_SINGLELUN},
+       {"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
+       {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
+       {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+       {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+       {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+       {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
+       {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
+       {"HITACHI", "GF-1050","*", BLIST_GHOST},  /* Hitachi SCSI DVD-RAM */
+       {"TOSHIBA","CDROM","*", BLIST_ISROM},
+       {"TOSHIBA","DVD-RAM SD-W1101","*", BLIST_GHOST},
+       {"TOSHIBA","DVD-RAM SD-W1111","*", BLIST_GHOST},
+
+       /*
+        * Must be at end of list...
+        */
+       {NULL, NULL, NULL}
+};
+
+#ifdef CONFIG_SCSI_MULTI_LUN
+static int max_scsi_luns = 8;
+#else
+static int max_scsi_luns = 1;
+#endif
+
+#ifdef MODULE
+
+MODULE_PARM(max_scsi_luns, "i");
+MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)");
+
+#else
+
+static int __init scsi_luns_setup(char *str)
+{
+       int tmp;
+
+       if (get_option(&str, &tmp) == 1) {
+               max_scsi_luns = tmp;
+               return 1;
+       } else {
+               printk("scsi_luns_setup : usage max_scsi_luns=n "
+                      "(n should be between 1 and 8)\n");
+               return 0;
+       }
+}
+
+__setup("max_scsi_luns=", scsi_luns_setup);
+
+#endif
+
+static void print_inquiry(unsigned char *data)
+{
+       int i;
+
+       printk("  Vendor: ");
+       for (i = 8; i < 16; i++) {
+               if (data[i] >= 0x20 && i < data[4] + 5)
+                       printk("%c", data[i]);
+               else
+                       printk(" ");
+       }
+
+       printk("  Model: ");
+       for (i = 16; i < 32; i++) {
+               if (data[i] >= 0x20 && i < data[4] + 5)
+                       printk("%c", data[i]);
+               else
+                       printk(" ");
+       }
+
+       printk("  Rev: ");
+       for (i = 32; i < 36; i++) {
+               if (data[i] >= 0x20 && i < data[4] + 5)
+                       printk("%c", data[i]);
+               else
+                       printk(" ");
+       }
+
+       printk("\n");
+
+       i = data[0] & 0x1f;
+
+       printk("  Type:   %s ",
+              i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          ");
+       printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
+       if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
+               printk(" CCS\n");
+       else
+               printk("\n");
+}
+
+static int get_device_flags(unsigned char *response_data)
+{
+       int i = 0;
+       unsigned char *pnt;
+       for (i = 0; 1; i++) {
+               if (device_list[i].vendor == NULL)
+                       return 0;
+               pnt = &response_data[8];
+               while (*pnt && *pnt == ' ')
+                       pnt++;
+               if (memcmp(device_list[i].vendor, pnt,
+                          strlen(device_list[i].vendor)))
+                       continue;
+               pnt = &response_data[16];
+               while (*pnt && *pnt == ' ')
+                       pnt++;
+               if (memcmp(device_list[i].model, pnt,
+                          strlen(device_list[i].model)))
+                       continue;
+               return device_list[i].flags;
+       }
+       return 0;
+}
+
+/*
+ *  Detecting SCSI devices :
+ *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
+ *  We use the INQUIRY command, determine device type, and pass the ID /
+ *  lun address of all sequential devices to the tape driver, all random
+ *  devices to the disk driver.
+ */
+void scan_scsis(struct Scsi_Host *shpnt,
+                      unchar hardcoded,
+                      unchar hchannel,
+                      unchar hid,
+                      unchar hlun)
+{
+       int channel;
+       int dev;
+       int lun;
+       int max_dev_lun;
+       Scsi_Cmnd *SCpnt;
+       unsigned char *scsi_result;
+       unsigned char scsi_result0[256];
+       Scsi_Device *SDpnt;
+       Scsi_Device *SDtail;
+       int sparse_lun;
+
+       scsi_result = NULL;
+       SCpnt = (Scsi_Cmnd *) kmalloc(sizeof(Scsi_Cmnd),
+                                              GFP_ATOMIC | GFP_DMA);
+       if (SCpnt) {
+                memset(SCpnt, 0, sizeof(Scsi_Cmnd));
+               SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device),
+                                                        GFP_ATOMIC);
+               if (SDpnt) {
+                        memset(SDpnt, 0, sizeof(Scsi_Device));
+                       /*
+                        * Register the queue for the device.  All I/O requests will come
+                        * in through here.  We also need to register a pointer to
+                        * ourselves, since the queue handler won't know what device
+                        * the queue actually represents.   We could look it up, but it
+                        * is pointless work.
+                        */
+                       blk_init_queue(&SDpnt->request_queue, scsi_get_request_handler(SDpnt, shpnt));
+                       blk_queue_headactive(&SDpnt->request_queue, 0);
+                       SDpnt->request_queue.queuedata = (void *) SDpnt;
+                       /* Make sure we have something that is valid for DMA purposes */
+                       scsi_result = ((!shpnt->unchecked_isa_dma)
+                                      ? &scsi_result0[0] : kmalloc(512, GFP_DMA));
+               }
+       }
+       if (scsi_result == NULL) {
+               printk("Unable to obtain scsi_result buffer\n");
+               goto leave;
+       }
+       /*
+        * We must chain ourself in the host_queue, so commands can time out 
+        */
+       SCpnt->next = NULL;
+       SDpnt->device_queue = SCpnt;
+       SDpnt->host = shpnt;
+       SDpnt->online = TRUE;
+
+       initialize_merge_fn(SDpnt);
+
+        /*
+         * Initialize the object that we will use to wait for command blocks.
+         */
+       init_waitqueue_head(&SDpnt->scpnt_wait);
+
+       /*
+        * Next, hook the device to the host in question.
+        */
+       SDpnt->prev = NULL;
+       SDpnt->next = NULL;
+       if (shpnt->host_queue != NULL) {
+               SDtail = shpnt->host_queue;
+               while (SDtail->next != NULL)
+                       SDtail = SDtail->next;
+
+               SDtail->next = SDpnt;
+               SDpnt->prev = SDtail;
+       } else {
+               shpnt->host_queue = SDpnt;
+       }
+
+       /*
+        * We need to increment the counter for this one device so we can track when
+        * things are quiet.
+        */
+       atomic_inc(&shpnt->host_active);
+       atomic_inc(&SDpnt->device_active);
+
+       if (hardcoded == 1) {
+               Scsi_Device *oldSDpnt = SDpnt;
+               struct Scsi_Device_Template *sdtpnt;
+               channel = hchannel;
+               if (channel > shpnt->max_channel)
+                       goto leave;
+               dev = hid;
+               if (dev >= shpnt->max_id)
+                       goto leave;
+               lun = hlun;
+               if (lun >= shpnt->max_lun)
+                       goto leave;
+               scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun,
+                                 &SDpnt, SCpnt, shpnt, scsi_result);
+               if (SDpnt != oldSDpnt) {
+
+                       /* it could happen the blockdevice hasn't yet been inited */
+                       for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+                               if (sdtpnt->init && sdtpnt->dev_noticed)
+                                       (*sdtpnt->init) ();
+
+                       for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+                               if (sdtpnt->attach) {
+                                       (*sdtpnt->attach) (oldSDpnt);
+                                       if (oldSDpnt->attached) {
+                                               scsi_build_commandblocks(oldSDpnt);
+                                               if (0 == oldSDpnt->has_cmdblocks) {
+                                                       printk("scan_scsis: DANGER, no command blocks\n");
+                                                       /* What to do now ?? */
+                                               }
+                                       }
+                               }
+                       }
+                       scsi_resize_dma_pool();
+
+                       for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+                               if (sdtpnt->finish && sdtpnt->nr_dev) {
+                                       (*sdtpnt->finish) ();
+                               }
+                       }
+               }
+       } else {
+               /* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */
+               int order_dev;
+
+               for (channel = 0; channel <= shpnt->max_channel; channel++) {
+                       for (dev = 0; dev < shpnt->max_id; ++dev) {
+                               if (shpnt->reverse_ordering)
+                                       /* Shift to scanning 15,14,13... or 7,6,5,4, */
+                                       order_dev = shpnt->max_id - dev - 1;
+                               else
+                                       order_dev = dev;
+
+                               if (shpnt->this_id != order_dev) {
+
+                                       /*
+                                        * We need the for so our continue, etc. work fine. We put this in
+                                        * a variable so that we can override it during the scan if we
+                                        * detect a device *KNOWN* to have multiple logical units.
+                                        */
+                                       max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
+                                        max_scsi_luns : shpnt->max_lun);
+                                       sparse_lun = 0;
+                                       for (lun = 0; lun < max_dev_lun; ++lun) {
+                                               if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,
+                                                                      &sparse_lun, &SDpnt, SCpnt, shpnt,
+                                                            scsi_result)
+                                                   && !sparse_lun)
+                                                       break;  /* break means don't probe further for luns!=0 */
+                                       }       /* for lun ends */
+                               }       /* if this_id != id ends */
+                       }       /* for dev ends */
+               }               /* for channel ends */
+       }                       /* if/else hardcoded */
+
+       /*
+        * We need to decrement the counter for this one device
+        * so we know when everything is quiet.
+        */
+       atomic_dec(&shpnt->host_active);
+       atomic_dec(&SDpnt->device_active);
+
+      leave:
+
+       {                       /* Unchain SCpnt from host_queue */
+               Scsi_Device *prev, *next;
+               Scsi_Device *dqptr;
+
+               for (dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next)
+                       continue;
+               if (dqptr) {
+                       prev = dqptr->prev;
+                       next = dqptr->next;
+                       if (prev)
+                               prev->next = next;
+                       else
+                               shpnt->host_queue = next;
+                       if (next)
+                               next->prev = prev;
+               }
+       }
+
+       /* Last device block does not exist.  Free memory. */
+       if (SDpnt != NULL)
+               kfree((char *) SDpnt);
+
+       if (SCpnt != NULL)
+               kfree((char *) SCpnt);
+
+       /* If we allocated a buffer so we could do DMA, free it now */
+       if (scsi_result != &scsi_result0[0] && scsi_result != NULL) {
+               kfree(scsi_result);
+       } {
+               Scsi_Device *sdev;
+               Scsi_Cmnd *scmd;
+
+               SCSI_LOG_SCAN_BUS(4, printk("Host status for host %p:\n", shpnt));
+               for (sdev = shpnt->host_queue; sdev; sdev = sdev->next) {
+                       SCSI_LOG_SCAN_BUS(4, printk("Device %d %p: ", sdev->id, sdev));
+                       for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
+                               SCSI_LOG_SCAN_BUS(4, printk("%p ", scmd));
+                       }
+                       SCSI_LOG_SCAN_BUS(4, printk("\n"));
+               }
+       }
+}
+
+/*
+ * The worker for scan_scsis.
+ * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
+ * Global variables used : scsi_devices(linked list)
+ */
+int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
+              int *sparse_lun, Scsi_Device ** SDpnt2, Scsi_Cmnd * SCpnt,
+                     struct Scsi_Host *shpnt, char *scsi_result)
+{
+       unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+       struct Scsi_Device_Template *sdtpnt;
+       Scsi_Device *SDtail, *SDpnt = *SDpnt2;
+       int bflags, type = -1;
+       static int ghost_channel=-1, ghost_dev=-1;
+       int org_lun = lun;
+
+       SDpnt->host = shpnt;
+       SDpnt->id = dev;
+       SDpnt->lun = lun;
+       SDpnt->channel = channel;
+       SDpnt->online = TRUE;
+
+       if ((channel == ghost_channel) && (dev == ghost_dev) && (lun == 1)) {
+               SDpnt->lun = 0;
+       } else {
+               ghost_channel = ghost_dev = -1;
+       }
+            
+
+       /* Some low level driver could use device->type (DB) */
+       SDpnt->type = -1;
+
+       /*
+        * Assume that the device will have handshaking problems, and then fix this
+        * field later if it turns out it doesn't
+        */
+       SDpnt->borken = 1;
+       SDpnt->was_reset = 0;
+       SDpnt->expecting_cc_ua = 0;
+       SDpnt->starved = 0;
+
+       scsi_cmd[0] = TEST_UNIT_READY;
+       scsi_cmd[1] = lun << 5;
+       scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+
+       SCpnt->host = SDpnt->host;
+       SCpnt->device = SDpnt;
+       SCpnt->target = SDpnt->id;
+       SCpnt->lun = SDpnt->lun;
+       SCpnt->channel = SDpnt->channel;
+
+       scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
+                 (void *) NULL,
+                 0, SCSI_TIMEOUT + 4 * HZ, 5);
+
+       SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
+                                   dev, lun, SCpnt->result));
+       SCSI_LOG_SCAN_BUS(3, print_driverbyte(SCpnt->result));
+       SCSI_LOG_SCAN_BUS(3, print_hostbyte(SCpnt->result));
+       SCSI_LOG_SCAN_BUS(3, printk("\n"));
+
+       if (SCpnt->result) {
+               if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
+                    (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
+                   ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
+                       if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+                           ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+                           ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0))
+                               return 1;
+               } else
+                       return 0;
+       }
+       SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n"));
+       /*
+        * Build an INQUIRY command block.
+        */
+       scsi_cmd[0] = INQUIRY;
+       scsi_cmd[1] = (lun << 5) & 0xe0;
+       scsi_cmd[2] = 0;
+       scsi_cmd[3] = 0;
+       scsi_cmd[4] = 255;
+       scsi_cmd[5] = 0;
+       SCpnt->cmd_len = 0;
+
+       scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
+                 (void *) scsi_result,
+                 256, SCSI_TIMEOUT, 3);
+
+       SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
+               SCpnt->result ? "failed" : "successful", SCpnt->result));
+
+       if (SCpnt->result)
+               return 0;       /* assume no peripheral if any sort of error */
+
+       /*
+        * Check the peripheral qualifier field - this tells us whether LUNS
+        * are supported here or not.
+        */
+       if ((scsi_result[0] >> 5) == 3) {
+               return 0;       /* assume no peripheral if any sort of error */
+       }
+
+       /*
+        * Get any flags for this device.  
+        */
+       bflags = get_device_flags (scsi_result);
+
+
+        /*   The Toshiba ROM was "gender-changed" here as an inline hack.
+             This is now much more generic.
+             This is a mess: What we really want is to leave the scsi_result
+             alone, and just change the SDpnt structure. And the SDpnt is what
+             we want print_inquiry to print.  -- REW
+        */
+       if (bflags & BLIST_ISDISK) {
+               scsi_result[0] = TYPE_DISK;                                                
+               scsi_result[1] |= 0x80;     /* removable */
+       }
+
+       if (bflags & BLIST_ISROM) {
+               scsi_result[0] = TYPE_ROM;
+               scsi_result[1] |= 0x80;     /* removable */
+       }
+    
+       if (bflags & BLIST_GHOST) {
+               if ((ghost_channel == channel) && (ghost_dev == dev) && (org_lun == 1)) {
+                       lun=1;
+               } else {
+                       ghost_channel = channel;
+                       ghost_dev = dev;
+                       scsi_result[0] = TYPE_MOD;
+                       scsi_result[1] |= 0x80;     /* removable */
+               }
+       }
+       
+
+       memcpy(SDpnt->vendor, scsi_result + 8, 8);
+       memcpy(SDpnt->model, scsi_result + 16, 16);
+       memcpy(SDpnt->rev, scsi_result + 32, 4);
+
+       SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+       SDpnt->online = TRUE;
+       SDpnt->lockable = SDpnt->removable;
+       SDpnt->changed = 0;
+       SDpnt->access_count = 0;
+       SDpnt->busy = 0;
+       SDpnt->has_cmdblocks = 0;
+       /*
+        * Currently, all sequential devices are assumed to be tapes, all random
+        * devices disk, with the appropriate read only flags set for ROM / WORM
+        * treated as RO.
+        */
+       switch (type = (scsi_result[0] & 0x1f)) {
+       case TYPE_TAPE:
+       case TYPE_DISK:
+       case TYPE_MOD:
+       case TYPE_PROCESSOR:
+       case TYPE_SCANNER:
+       case TYPE_MEDIUM_CHANGER:
+       case TYPE_ENCLOSURE:
+               SDpnt->writeable = 1;
+               break;
+       case TYPE_WORM:
+       case TYPE_ROM:
+               SDpnt->writeable = 0;
+               break;
+       default:
+               printk("scsi: unknown type %d\n", type);
+       }
+
+       SDpnt->device_blocked = FALSE;
+       SDpnt->device_busy = 0;
+       SDpnt->single_lun = 0;
+       SDpnt->soft_reset =
+           (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
+       SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
+       SDpnt->type = (type & 0x1f);
+
+       print_inquiry(scsi_result);
+
+       for (sdtpnt = scsi_devicelist; sdtpnt;
+            sdtpnt = sdtpnt->next)
+               if (sdtpnt->detect)
+                       SDpnt->attached +=
+                           (*sdtpnt->detect) (SDpnt);
+
+       SDpnt->scsi_level = scsi_result[2] & 0x07;
+       if (SDpnt->scsi_level >= 2 ||
+           (SDpnt->scsi_level == 1 &&
+            (scsi_result[3] & 0x0f) == 1))
+               SDpnt->scsi_level++;
+
+       /*
+        * Accommodate drivers that want to sleep when they should be in a polling
+        * loop.
+        */
+       SDpnt->disconnect = 0;
+
+
+       /*
+        * Set the tagged_queue flag for SCSI-II devices that purport to support
+        * tagged queuing in the INQUIRY data.
+        */
+       SDpnt->tagged_queue = 0;
+       if ((SDpnt->scsi_level >= SCSI_2) &&
+           (scsi_result[7] & 2) &&
+           !(bflags & BLIST_NOTQ)) {
+               SDpnt->tagged_supported = 1;
+               SDpnt->current_tag = 0;
+       }
+       /*
+        * Some revisions of the Texel CD ROM drives have handshaking problems when
+        * used with the Seagate controllers.  Before we know what type of device
+        * we're talking to, we assume it's borken and then change it here if it
+        * turns out that it isn't a TEXEL drive.
+        */
+       if ((bflags & BLIST_BORKEN) == 0)
+               SDpnt->borken = 0;
+
+       /*
+        * If we want to only allow I/O to one of the luns attached to this device
+        * at a time, then we set this flag.
+        */
+       if (bflags & BLIST_SINGLELUN)
+               SDpnt->single_lun = 1;
+
+       /*
+        * These devices need this "key" to unlock the devices so we can use it
+        */
+       if ((bflags & BLIST_KEY) != 0) {
+               printk("Unlocked floptical drive.\n");
+               SDpnt->lockable = 0;
+               scsi_cmd[0] = MODE_SENSE;
+               scsi_cmd[1] = (lun << 5) & 0xe0;
+               scsi_cmd[2] = 0x2e;
+               scsi_cmd[3] = 0;
+               scsi_cmd[4] = 0x2a;
+               scsi_cmd[5] = 0;
+               SCpnt->cmd_len = 0;
+               scsi_wait_cmd (SCpnt, (void *) scsi_cmd,
+                       (void *) scsi_result, 0x2a,
+                       SCSI_TIMEOUT, 3);
+       }
+       /*
+        * Detach the command from the device. It was just a temporary to be used while
+        * scanning the bus - the real ones will be allocated later.
+        */
+       SDpnt->device_queue = NULL;
+
+       /*
+        * This device was already hooked up to the host in question,
+        * so at this point we just let go of it and it should be fine.  We do need to
+        * allocate a new one and attach it to the host so that we can further scan the bus.
+        */
+       SDpnt = (Scsi_Device *) kmalloc(sizeof(Scsi_Device), GFP_ATOMIC);
+       *SDpnt2 = SDpnt;
+       if (!SDpnt) {
+               printk("scsi: scan_scsis_single: Cannot malloc\n");
+               return 0;
+       }
+        memset(SDpnt, 0, sizeof(Scsi_Device));
+
+       /*
+        * Register the queue for the device.  All I/O requests will come
+        * in through here.  We also need to register a pointer to
+        * ourselves, since the queue handler won't know what device
+        * the queue actually represents.   We could look it up, but it
+        * is pointless work.
+        */
+       blk_init_queue(&SDpnt->request_queue, scsi_get_request_handler(SDpnt, shpnt));
+       blk_queue_headactive(&SDpnt->request_queue, 0);
+       SDpnt->request_queue.queuedata = (void *) SDpnt;
+       SDpnt->host = shpnt;
+       initialize_merge_fn(SDpnt);
+
+       /*
+        * And hook up our command block to the new device we will be testing
+        * for.
+        */
+       SDpnt->device_queue = SCpnt;
+       SDpnt->online = TRUE;
+
+        /*
+         * Initialize the object that we will use to wait for command blocks.
+         */
+       init_waitqueue_head(&SDpnt->scpnt_wait);
+
+       /*
+        * Since we just found one device, there had damn well better be one in the list
+        * already.
+        */
+       if (shpnt->host_queue == NULL)
+               panic("scan_scsis_single: Host queue == NULL\n");
+
+       SDtail = shpnt->host_queue;
+       while (SDtail->next) {
+               SDtail = SDtail->next;
+       }
+
+       /* Add this device to the linked list at the end */
+       SDtail->next = SDpnt;
+       SDpnt->prev = SDtail;
+       SDpnt->next = NULL;
+
+       /*
+        * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+        */
+       if (bflags & BLIST_NOLUN)
+               return 0;       /* break; */
+
+       /*
+        * If this device is known to support sparse multiple units, override the
+        * other settings, and scan all of them.
+        */
+       if (bflags & BLIST_SPARSELUN) {
+               *max_dev_lun = 8;
+               *sparse_lun = 1;
+               return 1;
+       }
+       /*
+        * If this device is known to support multiple units, override the other
+        * settings, and scan all of them.
+        */
+       if (bflags & BLIST_FORCELUN) {
+               *max_dev_lun = 8;
+               return 1;
+       }
+       /*
+        * REGAL CDC-4X: avoid hang after LUN 4
+        */
+       if (bflags & BLIST_MAX5LUN) {
+               *max_dev_lun = 5;
+               return 1;
+       }
+
+       /*
+        * If this device is Ghosted, scan upto two luns. (It physically only
+        * has one). -- REW
+        */
+       if (bflags & BLIST_GHOST) {
+               *max_dev_lun = 2;
+               return 1;
+       }  
+
+
+       /*
+        * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI
+        * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1
+        * (ANSI SCSI Revision 1) and Response Data Format 0
+        */
+       if (((scsi_result[2] & 0x07) == 0)
+           ||
+           ((scsi_result[2] & 0x07) == 1 &&
+            (scsi_result[3] & 0x0f) == 0))
+               return 0;
+       return 1;
+}
+
index b615f8a38d6772ee851b1d210e0dd98d5e95a9f8..0790a197804aa969411c4954dc6b3e04ebccfc7c 100644 (file)
@@ -640,17 +640,6 @@ static int check_scsidisk_media_change(kdev_t full_dev)
        return retval;
 }
 
-static void sd_init_done(Scsi_Cmnd * SCpnt)
-{
-       struct request *req;
-
-       req = &SCpnt->request;
-       req->rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
-
-       if (req->sem != NULL) {
-               up(req->sem);
-       }
-}
 static int sd_init_onedisk(int i)
 {
        unsigned char cmd[10];
@@ -698,7 +687,7 @@ static int sd_init_onedisk(int i)
                        SCpnt->sense_buffer[2] = 0;
 
                        scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer,
-                               0/*512*/, sd_init_done,  SD_TIMEOUT, MAX_RETRIES);
+                               0/*512*/, SD_TIMEOUT, MAX_RETRIES);
 
                        the_result = SCpnt->result;
                        retries++;
@@ -724,7 +713,7 @@ static int sd_init_onedisk(int i)
                                SCpnt->sense_buffer[2] = 0;
 
                                scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
-                                           512, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
+                                           512, SD_TIMEOUT, MAX_RETRIES);
                        }
                        spintime = 1;
                        spintime_value = jiffies;
@@ -754,7 +743,7 @@ static int sd_init_onedisk(int i)
                SCpnt->sense_buffer[2] = 0;
 
                scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
-                           8, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
+                           8, SD_TIMEOUT, MAX_RETRIES);
 
                the_result = SCpnt->result;
                retries--;
@@ -905,7 +894,7 @@ static int sd_init_onedisk(int i)
 
                /* same code as READCAPA !! */
                scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
-                           512, sd_init_done, SD_TIMEOUT, MAX_RETRIES);
+                           512, SD_TIMEOUT, MAX_RETRIES);
 
                the_result = SCpnt->result;
 
index 0abc06cf336affc8a0d7f04ca34938d6c7686279..e683405b7fb5917f68baf606a517a1eab5d09659 100644 (file)
@@ -456,18 +456,6 @@ static int sr_attach(Scsi_Device * SDp)
 }
 
 
-static void sr_init_done(Scsi_Cmnd * SCpnt)
-{
-       struct request *req;
-
-       req = &SCpnt->request;
-       req->rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
-
-       if (req->sem != NULL) {
-               up(req->sem);
-       }
-}
-
 void get_sectorsize(int i)
 {
        unsigned char cmd[10];
@@ -494,7 +482,7 @@ void get_sectorsize(int i)
                /* Do the command and wait.. */
 
                scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer,
-                             512, sr_init_done, SR_TIMEOUT, MAX_RETRIES);
+                             512, SR_TIMEOUT, MAX_RETRIES);
 
                the_result = SCpnt->result;
                retries--;
@@ -671,11 +659,11 @@ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command
 
        /* do the locking and issue the command */
        SCpnt->request.rq_dev = cdi->dev;
-       /* scsi_do_cmd sets the command length */
+       /* scsi_wait_cmd sets the command length */
        SCpnt->cmd_len = 0;
 
        scsi_wait_cmd(SCpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen,
-                     sr_init_done, SR_TIMEOUT, MAX_RETRIES);
+                     SR_TIMEOUT, MAX_RETRIES);
 
        if ((cgc->stat = SCpnt->result))
                cgc->sense = (struct request_sense *) SCpnt->sense_buffer;
index 5032d7f8662b392796d30a275d97cd8708727e83..9d08b209b701a0b933786467f104c42153d0c447 100644 (file)
@@ -30,23 +30,6 @@ extern void get_sectorsize(int);
 /* In fact, it is very slow if it has to spin up first */
 #define IOCTL_TIMEOUT 30*HZ
 
-static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
-{
-       struct request *req;
-
-       req = &SCpnt->request;
-       req->rq_status = RQ_SCSI_DONE;  /* Busy, but indicate request done */
-
-       if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) {
-               memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
-               scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511);
-               SCpnt->buffer = req->buffer;
-       }
-       if (req->sem != NULL) {
-               up(req->sem);
-       }
-}
-
 /* We do our own retries because we want to know what the specific
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
@@ -55,6 +38,7 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
 {
        Scsi_Cmnd *SCpnt;
        Scsi_Device *SDev;
+        struct request *req;
        int result, err = 0, retries = 0;
        char *bounce_buffer;
 
@@ -79,7 +63,14 @@ int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflen
 
 
        scsi_wait_cmd(SCpnt, (void *) sr_cmd, (void *) buffer, buflength,
-                     sr_ioctl_done, IOCTL_TIMEOUT, IOCTL_RETRIES);
+                     IOCTL_TIMEOUT, IOCTL_RETRIES);
+
+        req = &SCpnt->request;
+        if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) {
+                memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen);
+                scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511);
+                SCpnt->buffer = req->buffer;
+        }
 
        result = SCpnt->result;
 
@@ -262,14 +253,14 @@ int sr_reset(struct cdrom_device_info *cdi)
 
 int sr_select_speed(struct cdrom_device_info *cdi, int speed)
 {
-       u_char sr_cmd[12];
+       u_char sr_cmd[MAX_COMMAND_SIZE];
 
        if (speed == 0)
                speed = 0xffff; /* set to max */
        else
                speed *= 177;   /* Nx to kbyte/s */
 
-       memset(sr_cmd, 0, 12);
+       memset(sr_cmd, 0, MAX_COMMAND_SIZE);
        sr_cmd[0] = GPCMD_SET_SPEED;    /* SET CD SPEED */
        sr_cmd[1] = (scsi_CDs[MINOR(cdi->dev)].device->lun) << 5;
        sr_cmd[2] = (speed >> 8) & 0xff;        /* MSB for speed (in kbytes/sec) */
@@ -370,14 +361,14 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 
 int sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
 {
-       unsigned char cmd[12];
+       unsigned char cmd[MAX_COMMAND_SIZE];
 
 #ifdef DEBUG
        printk("sr%d: sr_read_cd lba=%d format=%d blksize=%d\n",
               minor, lba, format, blksize);
 #endif
 
-       memset(cmd, 0, 12);
+       memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = GPCMD_READ_CD; /* READ_CD */
        cmd[1] = (scsi_CDs[minor].device->lun << 5) | ((format & 7) << 2);
        cmd[2] = (unsigned char) (lba >> 24) & 0xff;
@@ -408,7 +399,7 @@ int sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
 
 int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
 {
-       unsigned char cmd[12];  /* the scsi-command */
+       unsigned char cmd[MAX_COMMAND_SIZE];    /* the scsi-command */
        int rc;
 
        /* we try the READ CD command first... */
@@ -429,7 +420,7 @@ int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
        printk("sr%d: sr_read_sector lba=%d blksize=%d\n", minor, lba, blksize);
 #endif
 
-       memset(cmd, 0, 12);
+       memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = GPCMD_READ_10;
        cmd[1] = (scsi_CDs[minor].device->lun << 5);
        cmd[2] = (unsigned char) (lba >> 24) & 0xff;
index 56f4f004de187990990159ae6a4c6af80ff43bd2..77be00ea304e0d41d9b43df6ffa219a02b552a9e 100644 (file)
@@ -106,7 +106,7 @@ void sr_vendor_init(int minor)
 int sr_set_blocklength(int minor, int blocklength)
 {
        unsigned char *buffer;  /* the buffer for the ioctl */
-       unsigned char cmd[12];  /* the scsi-command */
+       unsigned char cmd[MAX_COMMAND_SIZE];    /* the scsi-command */
        struct ccs_modesel_head *modesel;
        int rc, density = 0;
 
@@ -122,7 +122,7 @@ int sr_set_blocklength(int minor, int blocklength)
 #ifdef DEBUG
        printk("sr%d: MODE SELECT 0x%x/%d\n", minor, density, blocklength);
 #endif
-       memset(cmd, 0, 12);
+       memset(cmd, 0, MAX_COMMAND_SIZE);
        cmd[0] = MODE_SELECT;
        cmd[1] = (scsi_CDs[minor].device->lun << 5) | (1 << 4);
        cmd[4] = 12;
@@ -153,7 +153,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
 {
        unsigned long sector;
        unsigned char *buffer;  /* the buffer for the ioctl */
-       unsigned char cmd[12];  /* the scsi-command */
+       unsigned char cmd[MAX_COMMAND_SIZE];    /* the scsi-command */
        int rc, no_multi, minor;
 
        minor = MINOR(cdi->dev);
@@ -171,7 +171,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
        switch (VENDOR_ID) {
 
        case VENDOR_SCSI3:
-               memset(cmd, 0, 12);
+               memset(cmd, 0, MAX_COMMAND_SIZE);
                cmd[0] = READ_TOC;
                cmd[1] = (scsi_CDs[minor].device->lun << 5);
                cmd[8] = 12;
@@ -196,7 +196,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
 #ifdef CONFIG_BLK_DEV_SR_VENDOR
        case VENDOR_NEC:{
                        unsigned long min, sec, frame;
-                       memset(cmd, 0, 12);
+                       memset(cmd, 0, MAX_COMMAND_SIZE);
                        cmd[0] = 0xde;
                        cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
                        cmd[2] = 0xb0;
@@ -221,7 +221,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
 
                        /* we request some disc information (is it a XA-CD ?,
                         * where starts the last session ?) */
-                       memset(cmd, 0, 12);
+                       memset(cmd, 0, MAX_COMMAND_SIZE);
                        cmd[0] = 0xc7;
                        cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
                        rc = sr_do_ioctl(minor, cmd, buffer, 4, 1);
@@ -244,7 +244,7 @@ int sr_cd_check(struct cdrom_device_info *cdi)
                }
 
        case VENDOR_WRITER:
-               memset(cmd, 0, 12);
+               memset(cmd, 0, MAX_COMMAND_SIZE);
                cmd[0] = READ_TOC;
                cmd[1] = (scsi_CDs[minor].device->lun << 5);
                cmd[8] = 0x04;
index b0a372455b30b6fff466c23dd043066a668e51d8..215fc53a464c3c6ba79b5526fb2049962ae3a760 100644 (file)
@@ -9,7 +9,7 @@ if [ ! "$CONFIG_USB" = "n" ]; then
 
 comment 'USB Controllers'
    dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-   dep_tristate '  OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI_HCD $CONFIG_USB
+   dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
 
 comment 'Miscellaneous USB options'
    bool '  Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
@@ -28,6 +28,7 @@ comment 'USB Devices'
       bool '    USB Peracom Single Port Serial Driver' CONFIG_USB_SERIAL_PERACOM
    fi
    dep_tristate '  USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
+   dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB
    dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
    dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
    dep_tristate '  USB SCSI (mass storage) support' CONFIG_USB_SCSI $CONFIG_USB
index 9eb62b6a1df8023da1cbd2250c310e0365c4c284..6289e0df57af14eaee758b47f61c30fe20b344c1 100644 (file)
@@ -21,10 +21,8 @@ export-objs          := usb.o input.o
 
 # Multipart objects.
 
-list-multi             := usbcore.o usb-uhci.o usb-ohci-hcd.o
+list-multi             := usbcore.o
 usbcore-objs           := usb.o usb-debug.o usb-core.o hub.o
-usb-uhci-objs          := uhci.o uhci-debug.o
-usb-ohci-hcd-objs      := ohci-hcd.o
 usb-scsi-objs          := usb_scsi.o
 
 # Optional parts of multipart objects.
@@ -47,7 +45,7 @@ obj-  :=
 
 obj-$(CONFIG_USB)              += usbcore.o
 obj-$(CONFIG_USB_UHCI)         += usb-uhci.o
-obj-$(CONFIG_USB_OHCI_HCD)     += usb-ohci-hcd.o
+obj-$(CONFIG_USB_OHCI)         += usb-ohci.o
 
 obj-$(CONFIG_USB_MOUSE)                += usbmouse.o input.o
 obj-$(CONFIG_USB_HID)          += hid.o input.o
@@ -65,6 +63,7 @@ obj-$(CONFIG_USB_PRINTER)     += printer.o
 obj-$(CONFIG_USB_SERIAL)       += usb-serial.o
 obj-$(CONFIG_USB_AUDIO)                += audio.o
 obj-$(CONFIG_USB_CPIA)         += cpia.o
+obj-$(CONFIG_USB_IBMCAM)       += ibmcam.o
 obj-$(CONFIG_USB_DC2XX)                += dc2xx.o
 obj-$(CONFIG_USB_SCSI)         += usb-scsi.o
 obj-$(CONFIG_USB_USS720)       += uss720.o
@@ -106,11 +105,5 @@ include $(TOPDIR)/Rules.make
 usbcore.o: $(usbcore-objs)
        $(LD) -r -o $@ $(usbcore-objs)
 
-usb-uhci.o: $(usb-uhci-objs)
-       $(LD) -r -o $@ $(usb-uhci-objs)
-
-usb-ohci-hcd.o: $(usb-ohci-hcd-objs)
-       $(LD) -r -o $@ $(usb-ohci-hcd-objs)
-
 usb-scsi.o: $(usb-scsi-objs)
        $(LD) -r -o $@ $(usb-scsi-objs)
index a9fb06dbe5cbd4636f2cd1b0c2ec2a28708dc35a..56e7cc400ac229a7b9847c57dfe070f941198714 100644 (file)
@@ -44,8 +44,7 @@
 #include "usb.h"
 
 #include "dabusb.h"
-#include "bitstream.h"
-#include "firmware.h"
+#include "dabfirmware.h"
 /* --------------------------------------------------------------------- */
 
 #define NRDABUSB 4
index cfda14d5c0c2be36ab6e13fdfcb4241422a1cce5..3214c997f72f4c3d2a79c018b7b80f882da18e97 100644 (file)
@@ -1,11 +1,16 @@
 /*
- *  graphire.c  Version 0.1
+ *  graphire.c  Version 0.2
  *
- *  Copyright (c) 1999 Vojtech Pavlik
+ *  Copyright (c) 2000 Vojtech Pavlik          <vojtech@suse.cz>
+ *  Copyright (c) 2000 Andreas Bach Aaen       <abach@stofanet.dk>
  *
  *  USB Wacom Graphire tablet support
  *
  *  Sponsored by SuSE
+ *
+ *  ChangeLog:
+ *      v0.1 (vp)  - Initial release
+ *      v0.2 (aba) - Support for all buttons / combinations
  */
 
 /*
@@ -59,12 +64,11 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
  * There are also two single-byte feature reports (2 and 3).
  */
 
-#define USB_VENDOR_ID_WACOM            0xffff  /* FIXME */
-#define USB_DEVICE_ID_WACOM_GRAPHIRE   0xffff  /* FIXME */
+#define USB_VENDOR_ID_WACOM            0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE   0x0010
 
 struct graphire {
        signed char data[8];
-       int oldx, oldy;
        struct input_dev dev;
        struct urb irq;
 };
@@ -83,41 +87,33 @@ static void graphire_irq(struct urb *urb)
        input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
        input_report_abs(dev, ABS_Y, data[4] | ((__u32)data[5] << 8));
 
-       input_report_key(dev, BTN_NEAR, !!(data[1] & 0x80));
-
        switch ((data[1] >> 5) & 3) {
 
                case 0: /* Pen */
-                       input_report_key(dev, BTN_PEN, !!(data[1] & 0x01));
-                       input_report_key(dev, BTN_PEN_SIDE, !!(data[1] & 0x02));
-                       input_report_key(dev, BTN_PEN_SIDE2, !!(data[1] & 0x04));
+                       input_report_key(dev, BTN_TOOL_PEN, !!(data[1] & 0x80));
+                       input_report_key(dev, BTN_TOUCH, !!(data[1] & 0x01));
+                       input_report_key(dev, BTN_STYLUS, !!(data[1] & 0x02));
+                       input_report_key(dev, BTN_STYLUS2, !!(data[1] & 0x04));
                        input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
                        break;
 
                case 1: /* Rubber */
-                       input_report_key(dev, BTN_RUBBER, !!(data[1] & 0x01));
-                       input_report_key(dev, BTN_PEN_SIDE, !!(data[1] & 0x02));
-                       input_report_key(dev, BTN_PEN_SIDE2, !!(data[1] & 0x04));
+                       input_report_key(dev, BTN_TOOL_RUBBER, !!(data[1] & 0x80));
+                       input_report_key(dev, BTN_TOUCH, !!(data[1] & 0x01));
+                       input_report_key(dev, BTN_STYLUS, !!(data[1] & 0x02));
+                       input_report_key(dev, BTN_STYLUS2, !!(data[1] & 0x04));
                        input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
                        break;
 
                case 2: /* Mouse */
-                       input_report_key(dev, BTN_LEFT, !!(data[0] & 0x01));
-                       input_report_key(dev, BTN_RIGHT, !!(data[0] & 0x02));
-                       input_report_key(dev, BTN_MIDDLE, !!(data[0] & 0x04));
+                       input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 27);
+                       input_report_key(dev, BTN_LEFT, !!(data[1] & 0x01));
+                       input_report_key(dev, BTN_RIGHT, !!(data[1] & 0x02));
+                       input_report_key(dev, BTN_MIDDLE, !!(data[1] & 0x04));
                        input_report_abs(dev, ABS_DISTANCE, data[7]);
-
-                       if (data[1] & 0x80) {
-                               input_report_rel(dev, REL_X, dev->abs[ABS_X] - graphire->oldx);
-                               input_report_rel(dev, REL_Y, dev->abs[ABS_Y] - graphire->oldy);
-                       }
-
                        input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
                        break;
        }
-
-       graphire->oldx = dev->abs[ABS_X];
-       graphire->oldy = dev->abs[ABS_Y];
 }
 
 static void *graphire_probe(struct usb_device *dev, unsigned int ifnum)
@@ -136,11 +132,16 @@ static void *graphire_probe(struct usb_device *dev, unsigned int ifnum)
 
        graphire->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
        graphire->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-       graphire->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_PEN) | BIT(BTN_RUBBER);
-       graphire->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_PEN_SIDE) | BIT(BTN_PEN_SIDE2) | BIT(BTN_NEAR);
-       graphire->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+       graphire->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE);
+       graphire->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+       graphire->dev.relbit[0] |= BIT(REL_WHEEL);
        graphire->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
 
+       graphire->dev.absmax[ABS_X] = 10000;
+       graphire->dev.absmax[ABS_Y] = 7500;
+       graphire->dev.absmax[ABS_PRESSURE] = 500;
+       graphire->dev.absmax[ABS_DISTANCE] = 32;
+
        FILL_INT_URB(&graphire->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
                        graphire->data, 8, graphire_irq, graphire, endpoint->bInterval);
 
@@ -151,7 +152,7 @@ static void *graphire_probe(struct usb_device *dev, unsigned int ifnum)
 
        input_register_device(&graphire->dev);
 
-       printk(KERN_INFO "input%d: Wacom Graphire USB\n", graphire->dev.number);
+       printk(KERN_INFO "input%d: Wacom Graphire\n", graphire->dev.number);
 
        return graphire;
 }
index ec1a4639da1a980bfa6d26178f5ddd5e077afa40..b3937357a49ab2fc55167fc0b44da9206db61a82 100644 (file)
@@ -742,7 +742,11 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
                        switch (device->application) {
                                case HID_GD_GAMEPAD:  usage->code += 0x10;
                                case HID_GD_JOYSTICK: usage->code += 0x10;
-                               case HID_GD_MOUSE:    usage->code += 0x10;
+                               case HID_GD_MOUSE:    usage->code += 0x10; break;
+                               default:
+                                       if (field->physical == HID_GD_POINTER)
+                                               usage->code += 0x10;
+                                       break;
                        }
                        break;
 
@@ -769,7 +773,49 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
                        usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; 
                        break;
 
+               case HID_UP_DIGITIZER:
+
+                       switch (usage->hid & 0xff) {
+
+                               case 0x30: /* TipPressure */
+
+                                       usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; 
+                                       usage->code = ABS_PRESSURE;
+                                       clear_bit(usage->code, bit);
+                                       break;
+
+                               case 0x32: /* InRange */
+
+                                       usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+                                       switch (field->physical & 0xff) {       
+                                               case 0x21: usage->code = BTN_TOOL_MOUSE; break;
+                                               case 0x22: usage->code = BTN_TOOL_FINGER; break;
+                                               default: usage->code = BTN_TOOL_PEN; break;
+                                       }
+                                       break;
+
+                               case 0x33: /* Touch */
+                               case 0x42: /* TipSwitch */
+                               case 0x43: /* TipSwitch2 */
+
+                                       usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+                                       usage->code = BTN_TOUCH;
+                                       clear_bit(usage->code, bit);
+                                       break;
+
+                               case 0x44: /* BarrelSwitch */
+
+                                       usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+                                       usage->code = BTN_STYLUS;
+                                       clear_bit(usage->code, bit);
+                                       break;
+
+                               default:  goto unknown;
+                       }
+                       break;
+
                default:
+               unknown:
 
                        if (field->flags & HID_MAIN_ITEM_RELATIVE) {
                                usage->code = REL_MISC;
@@ -777,7 +823,7 @@ static void hid_configure_usage(struct hid_device *device, struct hid_field *fie
                                break;
                        }
 
-                       if (field->logical_minimum == 0 && field->logical_maximum == 1) {
+                       if (field->report_size == 1) {
                                usage->code = BTN_MISC;
                                usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
                                break;
index ab652442f6cfe315a24424a66728a401ecf7e0a9..528882403de86f9ed35f63c5bb21f1398802f6ec 100644 (file)
@@ -164,6 +164,7 @@ struct hid_item {
 
 #define HID_USAGE              0x0000ffff
 
+#define HID_GD_POINTER         0x00010001
 #define HID_GD_MOUSE           0x00010002
 #define HID_GD_JOYSTICK                0x00010004
 #define HID_GD_GAMEPAD         0x00010005
index c066c3c43291967358cb92d8075694b8cade64bb..3eca7a857605943c874e279c6daa65fa772d720b 100644 (file)
@@ -5,7 +5,7 @@
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Gregory P. Smith
  *
- * $Id: hub.c,v 1.15 1999/12/27 15:17:45 acher Exp $
+ * $Id: hub.c,v 1.21 2000/01/16 21:19:44 acher Exp $
  */
 
 #include <linux/kernel.h>
 #include "usb.h"
 #include "hub.h"
 
-#ifdef __alpha
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-extern long __kernel_thread(unsigned long, int (*)(void *), void *);
-static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       return __kernel_thread(flags | CLONE_VM, fn, arg);
-}
-#endif
-#endif
 /* Wakes up khubd */
 static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
 
@@ -112,6 +103,16 @@ static int hub_irq(int status, void *__buffer, int len, void *dev_id)
        return 1;
 }
 
+static void usb_hub_power_on(struct usb_hub *hub)
+{
+       int i;
+
+       /* Enable power to the ports */
+       dbg("enabling power on all ports");
+       for (i = 0; i < hub->nports; i++)
+               usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER);
+}
+
 static int usb_hub_configure(struct usb_hub *hub)
 {
        struct usb_device *dev = hub->dev;
@@ -191,10 +192,8 @@ static int usb_hub_configure(struct usb_hub *hub)
        dbg("%sover-current condition exists",
                (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 
-       /* Enable power to the ports */
-       dbg("enabling power on all ports");
-       for (i = 0; i < hub->nports; i++)
-               usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+       usb_hub_power_on(hub);
+
        return 0;
 }
 
@@ -322,13 +321,17 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
        portchange = le16_to_cpu(portsts.wPortChange);
        dbg("portstatus %x, change %x, %s", portstatus, portchange,
                portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
-       /* If it's not in CONNECT and ENABLE state, we're done */
-       if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
-           (!(portstatus & USB_PORT_STAT_ENABLE))) {
-               /* Disconnect anything that may have been there */
+
+       /* Clear the connection change status */
+       usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+       /* Disconnect any existing devices under this port */
+       if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+            (!(portstatus & USB_PORT_STAT_ENABLE)))|| (hub->children[port])) {
                usb_disconnect(&hub->children[port]);
-               /* We're done now, we already disconnected the device */
-               return;
+               /* Return now if nothing is connected */
+               if (!(portstatus & USB_PORT_STAT_CONNECTION))
+                       return;
        }
        wait_ms(400);   
 
@@ -350,7 +353,11 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
                dbg("portstatus %x, change %x, %s", portstatus ,portchange,
                        portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "Low Speed" : "High Speed");
 
-               if ((portstatus&(1<<USB_PORT_FEAT_ENABLE))) 
+               if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
+                   !(portstatus & USB_PORT_STAT_CONNECTION))
+                       return;
+
+               if (portstatus & USB_PORT_STAT_ENABLE)
                        break;
 
                wait_ms(200);
@@ -361,6 +368,9 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port)
                err("Maybe the USB cable is bad?");
                return;
        }
+
+       usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
+
        /* Allocate a new device struct for it */
 
        usb = usb_alloc_dev(hub, hub->bus);
@@ -432,8 +442,6 @@ static void usb_hub_events(void)
                        if (portchange & USB_PORT_STAT_C_CONNECTION) {
                                dbg("port %d connection change", i + 1);
 
-                               usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_CONNECTION);
-
                                usb_hub_port_connect_change(dev, i);
                        }
 
@@ -442,12 +450,15 @@ static void usb_hub_events(void)
                                usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
                        }
 
-                       if (portchange & USB_PORT_STAT_C_SUSPEND)
+                       if (portstatus & USB_PORT_STAT_SUSPEND) {
                                dbg("port %d suspend change", i + 1);
-
+                               usb_clear_port_feature(dev, i + 1,  USB_PORT_FEAT_SUSPEND);
+                       }
+                       
                        if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
-                               dbg("port %d over-current change", i + 1);
+                               err("port %d over-current change", i + 1);
                                usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+                               usb_hub_power_on(hub);
                        }
 
                        if (portchange & USB_PORT_STAT_C_RESET) {
@@ -468,7 +479,9 @@ static void usb_hub_events(void)
                        }
                        if (hubchange & HUB_CHANGE_OVERCURRENT) {
                                dbg("hub overcurrent change");
+                               wait_ms(500); //Cool down
                                usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
+                               usb_hub_power_on(hub);
                        }
                }
         } /* end while (1) */
@@ -491,6 +504,7 @@ static int usb_hub_thread(void *__hub)
         * This thread doesn't need any user-level access,
         * so get rid of all our resources
         */
+       exit_files(current);  /* daemonize doesn't do exit_files */
        daemonize();
 
        /* Setup a nice name */
diff --git a/drivers/usb/ibmcam.c b/drivers/usb/ibmcam.c
new file mode 100644 (file)
index 0000000..4e809d0
--- /dev/null
@@ -0,0 +1,2258 @@
+/*
+ * USB IBM C-It Video Camera driver
+ *
+ * Supports IBM C-It Video Camera.
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/videodev.h>
+#include <linux/vmalloc.h>
+#include <linux/wrapper.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+
+#include "usb.h"
+#include "ibmcam.h"
+
+#define        ENABLE_HEXDUMP  0       /* Enable if you need it */
+static int debug = 0;
+
+/* Completion states of the data parser */
+typedef enum {
+       scan_Continue,          /* Just parse next item */
+       scan_NextFrame,         /* Frame done, send it to V4L */
+       scan_Out,               /* Not enough data for frame */
+       scan_EndParse           /* End parsing */
+} scan_state_t;
+
+/* Bit flags (options) */
+#define FLAGS_RETRY_VIDIOCSYNC         (1 << 0)
+#define        FLAGS_MONOCHROME                (1 << 1)
+#define FLAGS_DISPLAY_HINTS            (1 << 2)
+#define FLAGS_OVERLAY_STATS            (1 << 3)
+#define FLAGS_FORCE_TESTPATTERN                (1 << 4)
+
+static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+
+/* This is the size of V4L frame that we provide */
+static const int imgwidth = V4L_FRAME_WIDTH_USED;
+static const int imgheight = V4L_FRAME_HEIGHT;
+static const int min_imgwidth  = 8;
+static const int min_imgheight = 4;
+
+#define        LIGHTING_MIN    0 /* 0=Bright 1=Med 2=Low */
+#define        LIGHTING_MAX    2
+static int lighting = (LIGHTING_MIN + LIGHTING_MAX) / 2; /* Medium */
+
+#define SHARPNESS_MIN  0
+#define SHARPNESS_MAX  6
+static int sharpness = 4; /* Low noise, good details */
+
+#define FRAMERATE_MIN  0
+#define FRAMERATE_MAX  6
+static int framerate = 2; /* Lower, reliable frame rate (8-12 fps) */
+
+enum {
+       VIDEOSIZE_128x96 = 0,
+       VIDEOSIZE_176x144,
+       VIDEOSIZE_352x288
+};
+
+static int videosize = VIDEOSIZE_352x288;
+
+/*
+ * The value of 'scratchbufsize' affects quality of the picture
+ * in many ways. Shorter buffers may cause loss of data when client
+ * is too slow. Larger buffers are memory-consuming and take longer
+ * to work with. This setting can be adjusted, but the default value
+ * should be OK for most desktop users.
+ */
+#define DEFAULT_SCRATCH_BUF_SIZE       (0x10000)       /* 64 KB */
+static const int scratchbufsize = DEFAULT_SCRATCH_BUF_SIZE;
+
+/*
+ * Here we define several initialization variables. They may
+ * be used to automatically set color, hue, brightness and
+ * contrast to desired values. This is particularly useful in
+ * case of webcams (which have no controls and no on-screen
+ * output) and also when a client V4L software is used that
+ * does not have some of those controls. In any case it's
+ * good to have startup values as options.
+ *
+ * These values are all in [0..255] range. This simplifies
+ * operation. Note that actual values of V4L variables may
+ * be scaled up (as much as << 8). User can see that only
+ * on overlay output, however, or through a V4L client.
+ */
+static int init_brightness = 128;
+static int init_contrast = 192;
+static int init_color = 128;
+static int init_hue = 128;
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(flags, "i");
+MODULE_PARM(framerate, "i");
+MODULE_PARM(lighting, "i");
+MODULE_PARM(sharpness, "i");
+MODULE_PARM(videosize, "i");
+MODULE_PARM(init_brightness, "i");
+MODULE_PARM(init_contrast, "i");
+MODULE_PARM(init_color, "i");
+MODULE_PARM(init_hue, "i");
+
+/* Still mysterious i2o commands */
+static const unsigned short unknown_88 = 0x0088;
+static const unsigned short unknown_89 = 0x0089;
+static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
+static const unsigned short contrast_14 = 0x0014;
+static const unsigned short light_27 = 0x0027;
+static const unsigned short sharp_13 = 0x0013;
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+#define MDEBUG(x)      do { } while(0)         /* Debug memory management */
+
+static struct usb_driver ibmcam_driver;
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+       unsigned long ret = 0UL;
+       pmd_t *pmd;
+       pte_t *ptep, pte;
+
+       if (!pgd_none(*pgd)) {
+               pmd = pmd_offset(pgd, adr);
+               if (!pmd_none(*pmd)) {
+                       ptep = pte_offset(pmd, adr);
+                       pte = *ptep;
+                       if (pte_present(pte))
+                               ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
+               }
+       }
+       MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
+       return ret;
+}
+
+static inline unsigned long uvirt_to_bus(unsigned long adr)
+{
+       unsigned long kva, ret;
+
+       kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+       ret = virt_to_bus((void *)kva);
+       MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
+       return ret;
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr)
+{
+       unsigned long va, kva, ret;
+
+       va = VMALLOC_VMADDR(adr);
+       kva = uvirt_to_kva(pgd_offset_k(va), va);
+       ret = virt_to_bus((void *)kva);
+       MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
+       return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+       unsigned long va, kva, ret;
+
+       va = VMALLOC_VMADDR(adr);
+       kva = uvirt_to_kva(pgd_offset_k(va), va);
+       ret = __pa(kva);
+       MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+       return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr, page;
+
+       /* Round it off to PAGE_SIZE */
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       mem = vmalloc(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) {
+               page = kvirt_to_pa(adr);
+               mem_map_reserve(MAP_NR(__va(page)));
+               adr += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr, page;
+
+       if (!mem)
+               return;
+
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       adr=(unsigned long) mem;
+       while (size > 0) {
+               page = kvirt_to_pa(adr);
+               mem_map_unreserve(MAP_NR(__va(page)));
+               adr += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       vfree(mem);
+}
+
+/*
+ * usb_ibmcam_overlaychar()
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_overlaychar(
+       struct usb_ibmcam *ibmcam,
+       struct ibmcam_frame *frame,
+       int x, int y, int ch)
+{
+       static const unsigned short digits[16] = {
+               0xF6DE, /* 0 */
+               0x2492, /* 1 */
+               0xE7CE, /* 2 */
+               0xE79E, /* 3 */
+               0xB792, /* 4 */
+               0xF39E, /* 5 */
+               0xF3DE, /* 6 */
+               0xF492, /* 7 */
+               0xF7DE, /* 8 */
+               0xF79E, /* 9 */
+               0x77DA, /* a */
+               0xD75C, /* b */
+               0xF24E, /* c */
+               0xD6DC, /* d */
+               0xF34E, /* e */
+               0xF348  /* f */
+       };
+       unsigned short digit;
+       int ix, iy;
+
+       if ((ibmcam == NULL) || (frame == NULL))
+               return;
+
+       if (ch >= '0' && ch <= '9')
+               ch -= '0';
+       else if (ch >= 'A' && ch <= 'F')
+               ch = 10 + (ch - 'A');
+       else if (ch >= 'a' && ch <= 'f')
+               ch = 10 + (ch - 'a');
+       else
+               return;
+       digit = digits[ch];
+
+       for (iy=0; iy < 5; iy++) {
+               for (ix=0; ix < 3; ix++) {
+                       if (digit & 0x8000) {
+                               IBMCAM_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
+                       }
+                       digit = digit << 1;
+               }
+       }
+}
+
+/*
+ * usb_ibmcam_overlaystring()
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_overlaystring(
+       struct usb_ibmcam *ibmcam,
+       struct ibmcam_frame *frame,
+       int x, int y, const char *str)
+{
+       while (*str) {
+               usb_ibmcam_overlaychar(ibmcam, frame, x, y, *str);
+               str++;
+               x += 4; /* 3 pixels character + 1 space */
+       }
+}
+
+/*
+ * usb_ibmcam_overlaystats()
+ *
+ * Overlays important debugging information.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_overlaystats(struct usb_ibmcam *ibmcam, struct ibmcam_frame *frame)
+{
+       const int y_diff = 8;
+       char tmp[16];
+       int x = 10;
+       int y = 10;
+
+       sprintf(tmp, "%8x", ibmcam->frame_num);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", ibmcam->urb_count);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", ibmcam->urb_length);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", ibmcam->data_count);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", ibmcam->header_count);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", ibmcam->scratch_ovf_count);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", ibmcam->iso_skip_count);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", ibmcam->iso_err_count);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", ibmcam->vpic.colour);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", ibmcam->vpic.hue);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", ibmcam->vpic.brightness >> 8);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", ibmcam->vpic.contrast >> 12);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8d", ibmcam->vpic.whiteness >> 8);
+       usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+       y += y_diff;
+}
+
+/*
+ * usb_ibmcam_testpattern()
+ *
+ * Procedure forms a test pattern (yellow grid on blue background).
+ *
+ * Parameters:
+ * fullframe:   if TRUE then entire frame is filled, otherwise the procedure
+ *           continues from the current scanline.
+ * pmode       0: fill the frame with solid blue color (like on VCR or TV)
+ *           1: Draw a colored grid
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_testpattern(struct usb_ibmcam *ibmcam, int fullframe, int pmode)
+{
+       static const char proc[] = "usb_ibmcam_testpattern";
+       struct ibmcam_frame *frame;
+       unsigned char *f;
+       int num_cell = 0;
+       int scan_length = 0;
+       static int num_pass = 0;
+
+       if (ibmcam == NULL) {
+               printk(KERN_ERR "%s: ibmcam == NULL\n", proc);
+               return;
+       }
+       if ((ibmcam->curframe < 0) || (ibmcam->curframe >= IBMCAM_NUMFRAMES)) {
+               printk(KERN_ERR "%s: ibmcam->curframe=%d.\n", proc, ibmcam->curframe);
+               return;
+       }
+
+       /* Grab the current frame */
+       frame = &ibmcam->frame[ibmcam->curframe];
+
+       /* Optionally start at the beginning */
+       if (fullframe) {
+               frame->curline = 0;
+               frame->scanlength = 0;
+       }
+
+       /* Form every scan line */
+       for (; frame->curline < imgheight; frame->curline++) {
+               int i;
+
+               f = frame->data + (imgwidth * 3 * frame->curline);
+               for (i=0; i < imgwidth; i++) {
+                       unsigned char cb=0x80;
+                       unsigned char cg = 0;
+                       unsigned char cr = 0;
+
+                       if (pmode == 1) {
+                               if (frame->curline % 32 == 0)
+                                       cb = 0, cg = cr = 0xFF;
+                               else if (i % 32 == 0) {
+                                       if (frame->curline % 32 == 1)
+                                               num_cell++;
+                                       cb = 0, cg = cr = 0xFF;
+                               } else {
+                                       cb = ((num_cell*7) + num_pass) & 0xFF;
+                                       cg = ((num_cell*5) + num_pass*2) & 0xFF;
+                                       cr = ((num_cell*3) + num_pass*3) & 0xFF;
+                               }
+                       } else {
+                               /* Just the blue screen */
+                       }
+                               
+                       *f++ = cb;
+                       *f++ = cg;
+                       *f++ = cr;
+                       scan_length += 3;
+               }
+       }
+
+       frame->grabstate = FRAME_DONE;
+       frame->scanlength += scan_length;
+       ++num_pass;
+
+       /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
+       usb_ibmcam_overlaystats(ibmcam, frame);
+}
+
+static unsigned char *ibmcam_find_header(const unsigned char hdr_sig, unsigned char *data, int len)
+{
+       while (len >= 4)
+       {
+               if ((data[0] == 0x00) && (data[1] == 0xFF) && (data[2] == 0x00))
+               {
+#if 0
+                       /* This code helps to detect new frame markers */
+                       printk(KERN_DEBUG "Header sig: 00 FF 00 %02X\n", data[3]);
+#endif
+                       if (data[3] == hdr_sig) {
+                               if (debug > 2)
+                                       printk(KERN_DEBUG "Header found.\n");
+                               return data;
+                       }
+               }
+               ++data;
+               --len;
+       }
+       return NULL;
+}
+
+/* How much data is left in the scratch buf? */
+#define scratch_left(x)        (ibmcam->scratchlen - (int)((char *)x - (char *)ibmcam->scratch))
+
+/* Grab the remaining */
+static void usb_ibmcam_align_scratch(struct usb_ibmcam *ibmcam, unsigned char *data)
+{
+       unsigned long left;
+
+       left = scratch_left(data);
+       memmove(ibmcam->scratch, data, left);
+       ibmcam->scratchlen = left;
+}
+
+/*
+ * usb_ibmcam_find_header()
+ *
+ * Locate one of supported header markers in the scratch buffer.
+ * Once found, remove all preceding bytes AND the marker (4 bytes)
+ * from the scratch buffer. Whatever follows must be video lines.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static scan_state_t usb_ibmcam_find_header(struct usb_ibmcam *ibmcam)
+{
+       struct ibmcam_frame *frame;
+       unsigned char *data, *tmp;
+
+       data = ibmcam->scratch;
+       frame = &ibmcam->frame[ibmcam->curframe];
+       tmp = ibmcam_find_header(frame->hdr_sig, data, scratch_left(data));
+
+       if (tmp == NULL) {
+               /* No header - entire scratch buffer is useless! */
+               if (debug > 2)
+                       printk(KERN_DEBUG "Skipping frame, no header\n");
+               ibmcam->scratchlen = 0;
+               return scan_EndParse;
+       }
+       /* Header found */
+       data = tmp+4;
+
+       ibmcam->has_hdr = 1;
+       ibmcam->header_count++;
+       frame->scanstate = STATE_LINES;
+       frame->curline = 0;
+
+       if (flags & FLAGS_FORCE_TESTPATTERN) {
+               usb_ibmcam_testpattern(ibmcam, 1, 1);
+               return scan_NextFrame;
+       }
+       usb_ibmcam_align_scratch(ibmcam, data);
+       return scan_Continue;
+}
+
+/*
+ * usb_ibmcam_parse_lines()
+ *
+ * Parse one line (TODO: more than one!) from the scratch buffer, put
+ * decoded RGB value into the current frame buffer and add the written
+ * number of bytes (RGB) to the *pcopylen.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen)
+{
+       struct ibmcam_frame *frame;
+       unsigned char *data, *f, *chromaLine;
+       unsigned int len;
+       const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL; /* V4L line offset */
+       int y, u, v, i, frame_done=0, mono_plane, hue_corr, color_corr;
+
+       hue_corr = (ibmcam->vpic.hue - 0x8000) >> 10;      /* -32..+31 */
+       color_corr = (ibmcam->vpic.colour - 0x8000) >> 10; /* -32..+31 */
+
+       data = ibmcam->scratch;
+       frame = &ibmcam->frame[ibmcam->curframe];
+
+       len = frame->frmwidth * 3; /* 1 line of mono + 1 line of color */
+       /*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/
+
+       mono_plane = ((frame->curline & 1) == 0);
+
+       /*
+        * Lines are organized this way (or are they?)
+        *
+        * I420:
+        * ~~~~
+        * ___________________________________
+        * |-----Y-----|---UVUVUV...UVUV-----| \
+        * |-----------+---------------------|  \
+        * |<-- 176 -->|<------ 176*2 ------>|  Total 72. pairs of lines
+        * |...    ...       ...|  /
+        * |___________|_____________________| /
+        *  - odd line- ------- even line ---
+        *
+        * another format:
+        * ~~~~~~~~~~~~~~
+        * ___________________________________
+        * |-----Y-----|---UVUVUV...UVUV-----| \
+        * |-----------+---------------------|  \
+        * |<-- 352 -->|<------ 352*2 ------>|  Total 144. pairs of lines
+        * |...    ...       ...|  /
+        * |___________|_____________________| /
+        *  - odd line- ------- even line ---
+        */
+
+       /* Make sure there's enough data for the entire line */
+       if (scratch_left(data) < (len+1024)) {
+               /*printk(KERN_DEBUG "out of data, need %u.\n", len);*/
+               return scan_Out;
+       }
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Mind that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 1) >= V4L_FRAME_HEIGHT)
+               return scan_NextFrame;
+
+       /*
+        * Now we are sure that entire line (representing all 'frame->frmwidth'
+        * pixels from the camera) is available in the scratch buffer. We
+        * start copying the line left-aligned to the V4L buffer (which
+        * might be larger - not smaller, hopefully). If the camera
+        * line is shorter then we should pad the V4L buffer with something
+        * (black in this case) to complete the line.
+        */
+       f = frame->data + (v4l_linesize * frame->curline);
+
+       /*
+        * chromaLine points to 1st pixel of the line with chrominance.
+        * If current line is monochrome then chromaLine points to next
+        * line after monochrome one. If current line has chrominance
+        * then chromaLine points to this very line. Such method allows
+        * to access chrominance data uniformly.
+        *
+        * To obtain chrominance data from the 'chromaLine' use this:
+        *   v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
+        *   u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
+        *
+        * Indices must be calculated this way:
+        * v_index = (i >> 1) << 2;
+        * u_index = (i >> 1) << 2 + 2;
+        *
+        * where 'i' is the column number [0..frame->frmwidth-1]
+        */
+       chromaLine = data;
+       if (mono_plane)
+               chromaLine += frame->frmwidth;
+
+       for (i = 0; i < frame->frmwidth; i++, data += (mono_plane ? 1 : 2))
+       {
+               unsigned char rv, gv, bv;       /* RGB components */
+
+               /*
+                * Search for potential Start-Of-Frame marker. It should
+                * not be here, of course, but if your formats don't match
+                * you might exceed the frame. We must match the marker to
+                * each byte of multi-byte data element if it is multi-byte.
+                */
+#if 1
+               if (scratch_left(data) >= (4+2)) {
+                       unsigned char *dp;
+                       int j;
+
+                       for (j=0, dp=data; j < 2; j++, dp++) {
+                               if ((dp[0] == 0x00) && (dp[1] == 0xFF) &&
+                                   (dp[2] == 0x00) && (dp[3] == frame->hdr_sig)) {
+                                       ibmcam->has_hdr = 2;
+                                       frame_done++;
+                                       break;
+                               }
+                       }
+               }
+#endif
+
+               /* Check for various visual debugging hints (colorized pixels) */
+               if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) {
+                       /*
+                        * This is bad and should not happen. This means that
+                        * we somehow overshoot the line and encountered new
+                        * frame! Obviously our camera/V4L frame size is out
+                        * of whack. This cyan dot will help you to figure
+                        * out where exactly the new frame arrived.
+                        */
+                       if (ibmcam->has_hdr == 1) {
+                               bv = 0; /* Yellow marker */
+                               gv = 0xFF;
+                               rv = 0xFF;
+                       } else {
+                               bv = 0xFF; /* Cyan marker */
+                               gv = 0xFF;
+                               rv = 0;
+                       }
+                       ibmcam->has_hdr = 0;
+                       goto make_pixel;
+               }
+
+               y = mono_plane ? data[0] : data[1];
+
+               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
+                       rv = gv = bv = y;
+               else {
+                       if (frame->order_uv) {
+                               u = chromaLine[(i >> 1) << 2] + hue_corr;
+                               v = chromaLine[((i >> 1) << 2) + 2] + color_corr;
+                       } else {
+                               v = chromaLine[(i >> 1) << 2] + color_corr;
+                               u = chromaLine[((i >> 1) << 2) + 2] + hue_corr;
+                       }
+                       YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+               }
+
+       make_pixel:
+               /*
+                * The purpose of creating the pixel here, in one,
+                * dedicated place is that we may need to make the
+                * pixel wider and taller than it actually is. This
+                * may be used if camera generates small frames for
+                * sake of frame rate (or any other reason.)
+                *
+                * The output data consists of B, G, R bytes
+                * (in this order).
+                */
+#if USES_IBMCAM_PUTPIXEL
+               IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+#else
+               *f++ = bv;
+               *f++ = gv;
+               *f++ = rv;
+#endif
+               /*
+                * Typically we do not decide within a legitimate frame
+                * that we want to end the frame. However debugging code
+                * may detect marker of new frame within the data. Then
+                * this condition activates. The 'data' pointer is already
+                * pointing at the new marker, so we'd better leave it as is.
+                */
+               if (frame_done)
+                       break;  /* End scanning of lines */
+       }
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline++;
+       *pcopylen += v4l_linesize;
+       usb_ibmcam_align_scratch(ibmcam, data);
+
+       if (frame_done || (frame->curline >= frame->frmheight))
+               return scan_NextFrame;
+       else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_parse_data()
+ *
+ * Generic routine to parse the scratch buffer. It employs either
+ * usb_ibmcam_find_header() or usb_ibmcam_parse_lines() to do most
+ * of work.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static void ibmcam_parse_data(struct usb_ibmcam *ibmcam)
+{
+       struct ibmcam_frame *frame;
+       unsigned char *data = ibmcam->scratch;
+       scan_state_t newstate;
+       long copylen = 0;
+
+       /* Grab the current frame and the previous frame */
+       frame = &ibmcam->frame[ibmcam->curframe];
+
+       /* printk(KERN_DEBUG "parsing %u.\n", ibmcam->scratchlen); */
+
+       while (1) {
+
+               newstate = scan_Out;
+               if (scratch_left(data)) {
+                       if (frame->scanstate == STATE_SCANNING)
+                               newstate = usb_ibmcam_find_header(ibmcam);
+                       else if (frame->scanstate == STATE_LINES)
+                               newstate = usb_ibmcam_parse_lines(ibmcam, &copylen);
+               }
+               if (newstate == scan_Continue)
+                       continue;
+               else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
+                       break;
+               else
+                       return; /* scan_EndParse */
+       }
+
+       if (newstate == scan_NextFrame) {
+               frame->grabstate = FRAME_DONE;
+               ibmcam->curframe = -1;
+               ibmcam->frame_num++;
+
+               /* Optionally display statistics on the screen */
+               if (flags & FLAGS_OVERLAY_STATS)
+                       usb_ibmcam_overlaystats(ibmcam, frame);
+
+               /* This will cause the process to request another frame. */
+               if (waitqueue_active(&frame->wq))
+                       wake_up_interruptible(&frame->wq);
+       }
+
+       /* Update the frame's uncompressed length. */
+       frame->scanlength += copylen;
+}
+
+#if ENABLE_HEXDUMP
+static void ibmcam_hexdump(const unsigned char *data, int len)
+{
+       char tmp[80];
+       int i, k;
+
+       for (i=k=0; len > 0; i++, len--) {
+               if (i > 0 && (i%16 == 0)) {
+                       printk("%s\n", tmp);
+                       k=0;
+               }
+               k += sprintf(&tmp[k], "%02x ", data[i]);
+       }
+       if (k > 0)
+               printk("%s\n", tmp);
+}
+#endif
+
+/*
+ * Make all of the blocks of data contiguous
+ */
+static int ibmcam_compress_isochronous(struct usb_ibmcam *ibmcam, urb_t *urb)
+{
+       unsigned char *cdata, *data, *data0;
+       int i, totlen = 0;
+
+       data = data0 = ibmcam->scratch + ibmcam->scratchlen;
+       for (i = 0; i < urb->number_of_packets; i++) {
+               int n = urb->iso_frame_desc[i].actual_length;
+               int st = urb->iso_frame_desc[i].status;
+               
+               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+               /* Detect and ignore errored packets */
+               if (st < 0) {
+                       if (debug >= 1) {
+                               printk(KERN_ERR "ibmcam data error: [%d] len=%d, status=%X\n",
+                                      i, n, st);
+                       }
+                       ibmcam->iso_err_count++;
+                       continue;
+               }
+
+               /* Detect and ignore empty packets */
+               if (n <= 0) {
+                       ibmcam->iso_skip_count++;
+                       continue;
+               }
+
+               /*
+                * If camera continues to feed us with data but there is no
+                * consumption (if, for example, V4L client fell asleep) we
+                * may overflow the buffer. We have to move old data over to
+                * free room for new data. This is bad for old data. If we
+                * just drop new data then it's bad for new data... choose
+                * your favorite evil here.
+                */
+               if ((ibmcam->scratchlen + n) > scratchbufsize) {
+#if 0
+                       ibmcam->scratch_ovf_count++;
+                       if (debug >= 3)
+                               printk(KERN_ERR "ibmcam: scratch buf overflow! "
+                                      "scr_len: %d, n: %d\n", ibmcam->scratchlen, n );
+                       return totlen;
+#else
+                       int mv;
+
+                       ibmcam->scratch_ovf_count++;
+                       if (debug >= 3) {
+                               printk(KERN_ERR "ibmcam: scratch buf overflow! "
+                                      "scr_len: %d, n: %d\n", ibmcam->scratchlen, n );
+                       }
+                       mv  = (ibmcam->scratchlen + n) - scratchbufsize;
+                       if (ibmcam->scratchlen >= mv) {
+                               int newslen = ibmcam->scratchlen - mv;
+                               memmove(ibmcam->scratch, ibmcam->scratch + mv, newslen);
+                               ibmcam->scratchlen = newslen;
+                               data = data0 = ibmcam->scratch + ibmcam->scratchlen;
+                       } else {
+                               printk(KERN_ERR "ibmcam: scratch buf too small\n");
+                               return totlen;
+                       }
+#endif
+               }
+
+               /* Now we know that there is enough room in scratch buffer */
+               memmove(data, cdata, n);
+               data += n;
+               totlen += n;
+               ibmcam->scratchlen += n;
+       }
+#if 0
+       if (totlen > 0) {
+               static int foo=0;
+               if (foo < 1) {
+                       printk(KERN_DEBUG "+%d.\n", totlen);
+                       ibmcam_hexdump(data0, (totlen > 64) ? 64:totlen);
+                       ++foo;
+               }
+       }
+#endif
+       return totlen;
+}
+
+static void ibmcam_isoc_irq(struct urb *urb)
+{
+       int len;
+       struct usb_ibmcam *ibmcam = urb->context;
+       struct ibmcam_sbuf *sbuf;
+       int i;
+
+       /* We don't want to do anything if we are about to be removed! */
+       if (ibmcam->remove_pending)
+               return;
+
+#if 0
+       if (urb->actual_length > 0) {
+               printk(KERN_DEBUG "ibmcam_isoc_irq: %p status %d, "
+                      " errcount = %d, length = %d\n", urb, urb->status,
+                      urb->error_count, urb->actual_length);
+       } else {
+               static int c = 0;
+               if (c++ % 100 == 0)
+                       printk(KERN_DEBUG "ibmcam_isoc_irq: no data\n");
+       }
+#endif
+
+       if (!ibmcam->streaming) {
+               if (debug >= 1)
+                       printk(KERN_DEBUG "ibmcam: oops, not streaming, but interrupt\n");
+               return;
+       }
+       
+       sbuf = &ibmcam->sbuf[ibmcam->cursbuf];
+
+       /* Copy the data received into our scratch buffer */
+       len = ibmcam_compress_isochronous(ibmcam, urb);
+
+       ibmcam->urb_count++;
+       ibmcam->urb_length = len;
+       ibmcam->data_count += len;
+
+#if 0   /* This code prints few initial bytes of ISO data: used to decode markers */
+       if (ibmcam->urb_count % 64 == 1) {
+               if (ibmcam->urb_count == 1) {
+                       ibmcam_hexdump(ibmcam->scratch,
+                                      (ibmcam->scratchlen > 32) ? 32 : ibmcam->scratchlen);
+               }
+       }
+#endif
+
+       /* If we collected enough data let's parse! */
+       if (ibmcam->scratchlen) {
+               /* If we don't have a frame we're current working on, complain */
+               if (ibmcam->curframe >= 0)
+                       ibmcam_parse_data(ibmcam);
+               else {
+                       if (debug >= 1)
+                               printk(KERN_DEBUG "ibmcam: received data, but no frame available\n");
+               }
+       }
+
+       for (i = 0; i < FRAMES_PER_DESC; i++) {
+               sbuf->urb->iso_frame_desc[i].status = 0;
+               sbuf->urb->iso_frame_desc[i].actual_length = 0;
+       }
+
+       /* Move to the next sbuf */
+       ibmcam->cursbuf = (ibmcam->cursbuf + 1) % IBMCAM_NUMSBUF;
+
+       return;
+}
+
+static int usb_ibmcam_veio(
+       struct usb_device *dev,
+       unsigned char req,
+       unsigned short value,
+       unsigned short index)
+{
+       static const char proc[] = "usb_ibmcam_veio";
+       unsigned char cp[8] = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef };
+       const unsigned short len = sizeof(cp);
+       int i;
+
+       if (req == 1) {
+               i = usb_control_msg(
+                       dev,
+                       usb_rcvctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value,
+                       index,
+                       cp,
+                       len,
+                       HZ);
+#if 0
+               printk(KERN_DEBUG "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                      "(req=$%02x val=$%04x ind=$%04x len=%d.)\n",
+                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                      req, value, index, len);
+#endif
+       } else {
+               i = usb_control_msg(
+                       dev,
+                       usb_sndctrlpipe(dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       HZ);
+       }
+       if (i < 0)
+               printk(KERN_ERR "%s: ERROR=%d.\n", proc, i);
+       return i;
+}
+
+/*
+ * usb_ibmcam_calculate_fps()
+ *
+ * This procedure roughly calculates the real frame rate based
+ * on FPS code (framerate=NNN option). Actual FPS differs
+ * slightly depending on lighting conditions, so that actual frame
+ * rate is determined by the camera. Since I don't know how to ask
+ * the camera what FPS is now I have to use the FPS code instead.
+ *
+ * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
+ * Corresponding real FPS should be in range [3..30] frames per second.
+ * The conversion formula is obvious:
+ *
+ * real_fps = 3 + (fps_code * 4.5)
+ *
+ * History:
+ * 1/18/99  Created.
+ */
+static int usb_ibmcam_calculate_fps(void)
+{
+       return 3 + framerate*4 + framerate/2;
+}
+
+/*
+ * usb_ibmcam_send_FF_04_02()
+ *
+ * This procedure sends magic 3-command prefix to the camera.
+ * The purpose of this prefix is not known.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void usb_ibmcam_send_FF_04_02(struct usb_device *dev)
+{
+       usb_ibmcam_veio(dev, 0, 0x00FF, 0x0127);
+       usb_ibmcam_veio(dev, 0, 0x0004, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0002, 0x0124);
+}
+
+static void usb_ibmcam_send_00_04_06(struct usb_device *dev)
+{
+       usb_ibmcam_veio(dev, 0, 0x0000, 0x0127);
+       usb_ibmcam_veio(dev, 0, 0x0004, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0006, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00(struct usb_device *dev, unsigned short x)
+{
+       usb_ibmcam_veio(dev, 0, x,      0x0127);
+       usb_ibmcam_veio(dev, 0, 0x0000, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05(struct usb_device *dev, unsigned short x)
+{
+       usb_ibmcam_send_x_00(dev, x);
+       usb_ibmcam_veio(dev, 0, 0x0005, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05_02(struct usb_device *dev, unsigned short x)
+{
+       usb_ibmcam_veio(dev, 0, x,      0x0127);
+       usb_ibmcam_veio(dev, 0, 0x0000, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0005, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0002, 0x0124);
+}
+
+static void usb_ibmcam_send_x_01_00_05(struct usb_device *dev, unsigned short x)
+{
+       usb_ibmcam_veio(dev, 0, x,      0x0127);
+       usb_ibmcam_veio(dev, 0, 0x0001, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0000, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0005, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05_02_01(struct usb_device *dev, unsigned short x)
+{
+       usb_ibmcam_veio(dev, 0, x,      0x0127);
+       usb_ibmcam_veio(dev, 0, 0x0000, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0005, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0002, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0001, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05_02_08_01(struct usb_device *dev, unsigned short x)
+{
+       usb_ibmcam_veio(dev, 0, x,      0x0127);
+       usb_ibmcam_veio(dev, 0, 0x0000, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0005, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0002, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0008, 0x0124);
+       usb_ibmcam_veio(dev, 0, 0x0001, 0x0124);
+}
+
+static void usb_ibmcam_Packet_Format1(struct usb_device *dev, unsigned char fkey, unsigned char val)
+{
+       usb_ibmcam_send_x_01_00_05      (dev, unknown_88);
+       usb_ibmcam_send_x_00_05         (dev, fkey);
+       usb_ibmcam_send_x_00_05_02_08_01(dev, val);
+       usb_ibmcam_send_x_00_05         (dev, unknown_88);
+       usb_ibmcam_send_x_00_05_02_01   (dev, fkey);
+       usb_ibmcam_send_x_00_05         (dev, unknown_89);
+       usb_ibmcam_send_x_00            (dev, fkey);
+       usb_ibmcam_send_00_04_06        (dev);
+       usb_ibmcam_veio                 (dev, 1, 0x0000, 0x0126);
+       usb_ibmcam_send_FF_04_02        (dev);
+}
+
+static void usb_ibmcam_PacketFormat2(struct usb_device *dev, unsigned char fkey, unsigned char val)
+{
+       usb_ibmcam_send_x_01_00_05      (dev, unknown_88);
+       usb_ibmcam_send_x_00_05         (dev, fkey);
+       usb_ibmcam_send_x_00_05_02      (dev, val);
+}
+
+/*
+ * usb_ibmcam_adjust_contrast()
+ *
+ * The contrast value changes from 0 (high contrast) to 15 (low contrast).
+ * This is in reverse to usual order of things (such as TV controls), so
+ * we reverse it again here.
+ *
+ * TODO: we probably don't need to send the setup 5 times...
+ *
+ * History:
+ * 1/2/99   Created.
+ */
+static void usb_ibmcam_adjust_contrast(struct usb_ibmcam *ibmcam)
+{
+       struct usb_device *dev = ibmcam->dev;
+       unsigned char new_contrast = ibmcam->vpic.contrast >> 12;
+       const int ntries = 5;
+
+       if (new_contrast >= 16)
+               new_contrast = 15;
+       new_contrast = 15 - new_contrast;
+       if (new_contrast != ibmcam->vpic_old.contrast) {
+               int i;
+               ibmcam->vpic_old.contrast = new_contrast;
+               for (i=0; i < ntries; i++) {
+                       usb_ibmcam_Packet_Format1(dev, contrast_14, new_contrast);
+                       usb_ibmcam_send_FF_04_02(dev);
+               }
+               /*usb_ibmcam_veio(dev, 0, 0x00FF, 0x0127);*/
+       }
+}
+
+/*
+ * usb_ibmcam_change_lighting_conditions()
+ *
+ * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
+ * Low lighting forces slower FPS. Lighting is set as a module parameter.
+ *
+ * History:
+ * 1/5/99   Created.
+ */
+static void usb_ibmcam_change_lighting_conditions(struct usb_ibmcam *ibmcam)
+{
+       static const char proc[] = "usb_ibmcam_change_lighting_conditions";
+       struct usb_device *dev = ibmcam->dev;
+       const int ntries = 5;
+       int i;
+
+       RESTRICT_TO_RANGE(lighting, LIGHTING_MIN, LIGHTING_MAX);
+       if (debug > 0)
+               printk(KERN_INFO "%s: Set lighting to %hu.\n", proc, lighting);
+
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, light_27, (unsigned short) lighting);
+}
+
+static void usb_ibmcam_set_sharpness(struct usb_ibmcam *ibmcam)
+{
+       static const char proc[] = "usb_ibmcam_set_sharpness";
+       struct usb_device *dev = ibmcam->dev;
+       static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
+       unsigned short i, sv;
+
+       RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+       if (debug > 0)
+               printk(KERN_INFO "%s: Set sharpness to %hu.\n", proc, sharpness);
+
+       sv = sa[sharpness - SHARPNESS_MIN];
+       for (i=0; i < 2; i++) {
+               usb_ibmcam_send_x_01_00_05      (dev, unknown_88);
+               usb_ibmcam_send_x_00_05         (dev, sharp_13);
+               usb_ibmcam_send_x_00_05_02      (dev, sv);
+       }
+}
+
+static void usb_ibmcam_set_brightness(struct usb_ibmcam *ibmcam)
+{
+       static const char proc[] = "usb_ibmcam_set_brightness";
+       struct usb_device *dev = ibmcam->dev;
+       static const unsigned short n = 1;
+       unsigned short i, j, bv[3];
+
+       bv[0] = bv[1] = bv[2] = ibmcam->vpic.brightness >> 10;
+       if (bv[0] == (ibmcam->vpic_old.brightness >> 10))
+               return;
+       ibmcam->vpic_old.brightness = ibmcam->vpic.brightness;
+
+       if (debug > 0)
+               printk(KERN_INFO "%s: Set brightness to (%hu,%hu,%hu)\n",
+                      proc, bv[0], bv[1], bv[2]);
+
+       for (j=0; j < 3; j++)
+               for (i=0; i < n; i++)
+                       usb_ibmcam_Packet_Format1(dev, bright_3x[j], bv[j]);
+}
+
+static void usb_ibmcam_adjust_picture(struct usb_ibmcam *ibmcam)
+{
+       usb_ibmcam_adjust_contrast(ibmcam);
+       usb_ibmcam_set_brightness(ibmcam);
+}
+
+static void usb_ibmcam_setup_before_if1(struct usb_device *dev)
+{
+       switch (videosize) {
+       case VIDEOSIZE_128x96:
+       case VIDEOSIZE_176x144:
+               usb_ibmcam_veio(dev, 1, 0x00, 0x0100);
+               usb_ibmcam_veio(dev, 0, 0x01, 0x0100);
+               usb_ibmcam_veio(dev, 0, 0x01, 0x0108);
+               break;
+       case VIDEOSIZE_352x288:
+               usb_ibmcam_veio(dev, 1, 0x00, 0x0100);
+               usb_ibmcam_veio(dev, 0, 0x01, 0x0100);
+               usb_ibmcam_veio(dev, 1, 0x00, 0x0100);
+               usb_ibmcam_veio(dev, 0, 0x81, 0x0100);
+               usb_ibmcam_veio(dev, 1, 0x00, 0x0100);
+               usb_ibmcam_veio(dev, 0, 0x01, 0x0100);
+               usb_ibmcam_veio(dev, 0, 0x01, 0x0108);
+               break;
+       }
+}
+
+static void usb_ibmcam_setup_before_if2(struct usb_device *dev)
+{
+       const int ntries = 5;
+       int i;
+
+       usb_ibmcam_veio(dev, 0, 0x03, 0x0112);
+       usb_ibmcam_veio(dev, 1, 0x00, 0x0115);
+       usb_ibmcam_veio(dev, 0, 0x06, 0x0115);
+       usb_ibmcam_veio(dev, 1, 0x00, 0x0116);
+       usb_ibmcam_veio(dev, 0, 0x44, 0x0116);
+       usb_ibmcam_veio(dev, 1, 0x00, 0x0116);
+       usb_ibmcam_veio(dev, 0, 0x40, 0x0116);
+       usb_ibmcam_veio(dev, 1, 0x00, 0x0115);
+       usb_ibmcam_veio(dev, 0, 0x0e, 0x0115);
+       usb_ibmcam_veio(dev, 0, 0x19, 0x012c);
+
+       usb_ibmcam_Packet_Format1(dev, 0x00, 0x1e);
+       usb_ibmcam_Packet_Format1(dev, 0x39, 0x0d);
+       usb_ibmcam_Packet_Format1(dev, 0x39, 0x09);
+       usb_ibmcam_Packet_Format1(dev, 0x3b, 0x00);
+       usb_ibmcam_Packet_Format1(dev, 0x28, 0x22);
+       usb_ibmcam_Packet_Format1(dev, light_27, 0);
+       usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1f);
+       usb_ibmcam_Packet_Format1(dev, 0x39, 0x08);
+
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x2c, 0x00);
+
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x30, 0x14);
+
+       usb_ibmcam_PacketFormat2(dev, 0x39, 0x02);
+       usb_ibmcam_PacketFormat2(dev, 0x01, 0xe1);
+       usb_ibmcam_PacketFormat2(dev, 0x02, 0xcd);
+       usb_ibmcam_PacketFormat2(dev, 0x03, 0xcd);
+       usb_ibmcam_PacketFormat2(dev, 0x04, 0xfa);
+       usb_ibmcam_PacketFormat2(dev, 0x3f, 0xff);
+       usb_ibmcam_PacketFormat2(dev, 0x39, 0x00);
+
+       usb_ibmcam_PacketFormat2(dev, 0x39, 0x02);
+       usb_ibmcam_PacketFormat2(dev, 0x0a, 0x37);
+       usb_ibmcam_PacketFormat2(dev, 0x0b, 0xb8);
+       usb_ibmcam_PacketFormat2(dev, 0x0c, 0xf3);
+       usb_ibmcam_PacketFormat2(dev, 0x0d, 0xe3);
+       usb_ibmcam_PacketFormat2(dev, 0x0e, 0x0d);
+       usb_ibmcam_PacketFormat2(dev, 0x0f, 0xf2);
+       usb_ibmcam_PacketFormat2(dev, 0x10, 0xd5);
+       usb_ibmcam_PacketFormat2(dev, 0x11, 0xba);
+       usb_ibmcam_PacketFormat2(dev, 0x12, 0x53);
+       usb_ibmcam_PacketFormat2(dev, 0x3f, 0xff);
+       usb_ibmcam_PacketFormat2(dev, 0x39, 0x00);
+
+       usb_ibmcam_PacketFormat2(dev, 0x39, 0x02);
+       usb_ibmcam_PacketFormat2(dev, 0x16, 0x00);
+       usb_ibmcam_PacketFormat2(dev, 0x17, 0x28);
+       usb_ibmcam_PacketFormat2(dev, 0x18, 0x7d);
+       usb_ibmcam_PacketFormat2(dev, 0x19, 0xbe);
+       usb_ibmcam_PacketFormat2(dev, 0x3f, 0xff);
+       usb_ibmcam_PacketFormat2(dev, 0x39, 0x00);
+
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x00, 0x18);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x13, 0x18);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x14, 0x06);
+
+       /* This is default brightness */
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x31, 0x37);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x32, 0x46);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x33, 0x55);
+
+       usb_ibmcam_Packet_Format1(dev, 0x2e, 0x04);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x2d, 0x04);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x29, 0x80);
+       usb_ibmcam_Packet_Format1(dev, 0x2c, 0x01);
+       usb_ibmcam_Packet_Format1(dev, 0x30, 0x17);
+       usb_ibmcam_Packet_Format1(dev, 0x39, 0x08);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x34, 0x00);
+
+       usb_ibmcam_veio(dev, 0, 0x00, 0x0101);
+       usb_ibmcam_veio(dev, 0, 0x00, 0x010a);
+
+       switch (videosize) {
+       case VIDEOSIZE_128x96:
+               usb_ibmcam_veio(dev, 0, 0x80, 0x0103);
+               usb_ibmcam_veio(dev, 0, 0x60, 0x0105);
+               usb_ibmcam_veio(dev, 0, 0x0c, 0x010b);
+               usb_ibmcam_veio(dev, 0, 0x04, 0x011b);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x0b, 0x011d);
+               usb_ibmcam_veio(dev, 0, 0x00, 0x011e);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x00, 0x0129);
+               break;
+       case VIDEOSIZE_176x144:
+               usb_ibmcam_veio(dev, 0, 0xb0, 0x0103);
+               usb_ibmcam_veio(dev, 0, 0x8f, 0x0105);
+               usb_ibmcam_veio(dev, 0, 0x06, 0x010b);
+               usb_ibmcam_veio(dev, 0, 0x04, 0x011b);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x0d, 0x011d);
+               usb_ibmcam_veio(dev, 0, 0x00, 0x011e);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x03, 0x0129);
+               break;
+       case VIDEOSIZE_352x288:
+               usb_ibmcam_veio(dev, 0, 0xb0, 0x0103);
+               usb_ibmcam_veio(dev, 0, 0x90, 0x0105);
+               usb_ibmcam_veio(dev, 0, 0x02, 0x010b);
+               usb_ibmcam_veio(dev, 0, 0x04, 0x011b);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x05, 0x011d);
+               usb_ibmcam_veio(dev, 0, 0x00, 0x011e);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x00, 0x0129);
+               break;
+       }
+
+       usb_ibmcam_veio(dev, 0, 0xff, 0x012b);
+
+       /* This is another brightness - don't know why */
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x31, 0xc3);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x32, 0xd2);
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, 0x33, 0xe1);
+
+       /* Default contrast */
+       for (i=0; i < ntries; i++)
+               usb_ibmcam_Packet_Format1(dev, contrast_14, 0x0a);
+
+       /* Default sharpness */
+       for (i=0; i < 2; i++)
+               usb_ibmcam_PacketFormat2(dev, sharp_13, 0x1a);  /* Level 4 FIXME */
+
+       /* Default lighting conditions */
+       usb_ibmcam_Packet_Format1(dev, light_27, lighting); /* 0=Bright 2=Low */
+
+       /* Assorted init */
+
+       switch (videosize) {
+       case VIDEOSIZE_128x96:
+               usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1e);
+               usb_ibmcam_veio(dev, 0, 0xc9, 0x0119);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x80, 0x0109);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x36, 0x0102);
+               usb_ibmcam_veio(dev, 0, 0x1a, 0x0104);
+               usb_ibmcam_veio(dev, 0, 0x04, 0x011a);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x2b, 0x011c);
+               usb_ibmcam_veio(dev, 0, 0x23, 0x012a);  /* Same everywhere */
+#if 0
+               usb_ibmcam_veio(dev, 0, 0x00, 0x0106);
+               usb_ibmcam_veio(dev, 0, 0x38, 0x0107);
+#else
+               usb_ibmcam_veio(dev, 0, 0x02, 0x0106);
+               usb_ibmcam_veio(dev, 0, 0x2a, 0x0107);
+#endif
+               break;
+       case VIDEOSIZE_176x144:
+               usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1e);
+               usb_ibmcam_veio(dev, 0, 0xc9, 0x0119);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x80, 0x0109);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x04, 0x0102);
+               usb_ibmcam_veio(dev, 0, 0x02, 0x0104);
+               usb_ibmcam_veio(dev, 0, 0x04, 0x011a);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x2b, 0x011c);
+               usb_ibmcam_veio(dev, 0, 0x23, 0x012a);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x01, 0x0106);
+               usb_ibmcam_veio(dev, 0, 0xca, 0x0107);
+               break;
+       case VIDEOSIZE_352x288:
+               usb_ibmcam_Packet_Format1(dev, 0x2b, 0x1f);
+               usb_ibmcam_veio(dev, 0, 0xc9, 0x0119);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x80, 0x0109);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x08, 0x0102);
+               usb_ibmcam_veio(dev, 0, 0x01, 0x0104);
+               usb_ibmcam_veio(dev, 0, 0x04, 0x011a);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x2f, 0x011c);
+               usb_ibmcam_veio(dev, 0, 0x23, 0x012a);  /* Same everywhere */
+               usb_ibmcam_veio(dev, 0, 0x03, 0x0106);
+               usb_ibmcam_veio(dev, 0, 0xf6, 0x0107);
+               break;
+       }
+}
+
+static void usb_ibmcam_setup_after_video_if(struct usb_device *dev)
+{
+       unsigned short internal_frame_rate;
+
+       RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
+       internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
+       usb_ibmcam_veio(dev, 0, internal_frame_rate, 0x0111);
+       usb_ibmcam_veio(dev, 0, 0x01, 0x0114);
+       usb_ibmcam_veio(dev, 0, 0xc0, 0x010c);
+}
+
+static void usb_ibmcam_setup_video_stop(struct usb_device *dev)
+{
+       usb_ibmcam_veio(dev, 0, 0x00, 0x010c);
+       usb_ibmcam_veio(dev, 0, 0x00, 0x010c);
+       usb_ibmcam_veio(dev, 0, 0x01, 0x0114);
+       usb_ibmcam_veio(dev, 0, 0xc0, 0x010c);
+       usb_ibmcam_veio(dev, 0, 0x00, 0x010c);
+       usb_ibmcam_send_FF_04_02(dev);
+       usb_ibmcam_veio(dev, 1, 0x00, 0x0100);
+       usb_ibmcam_veio(dev, 0, 0x81, 0x0100);
+}
+
+/*
+ * usb_ibmcam_reinit_iso()
+ *
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void usb_ibmcam_reinit_iso(struct usb_ibmcam *ibmcam, int do_stop)
+{
+       if (do_stop)
+               usb_ibmcam_setup_video_stop(ibmcam->dev);
+
+       usb_ibmcam_veio(ibmcam->dev, 0, 0x0001, 0x0114);
+       usb_ibmcam_veio(ibmcam->dev, 0, 0x00c0, 0x010c);
+       usb_clear_halt(ibmcam->dev, ibmcam->video_endp);
+       usb_ibmcam_setup_after_video_if(ibmcam->dev);
+}
+
+static int ibmcam_init_isoc(struct usb_ibmcam *ibmcam)
+{
+       struct usb_device *dev = ibmcam->dev;
+       urb_t *urb;
+       int fx, err;
+
+       ibmcam->compress = 0;
+       ibmcam->curframe = -1;
+       ibmcam->cursbuf = 0;
+       ibmcam->scratchlen = 0;
+
+       /* Alternate interface 1 is is the biggest frame size */
+       if (usb_set_interface(ibmcam->dev, 2, 1) < 0) {
+               printk(KERN_ERR "usb_set_interface error\n");
+               return -EBUSY;
+       }
+       usb_ibmcam_change_lighting_conditions(ibmcam);
+       usb_ibmcam_set_sharpness(ibmcam);
+       usb_ibmcam_reinit_iso(ibmcam, 0);
+
+       /* We double buffer the Iso lists */
+       urb = usb_alloc_urb(FRAMES_PER_DESC);
+       
+       if (!urb) {
+               printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc ret %d\n",
+                       0);
+               return -ENOMEM;
+       }
+       ibmcam->sbuf[0].urb = urb;
+       urb->dev = dev;
+       urb->context = ibmcam;
+       urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp);
+       urb->transfer_flags = USB_ISO_ASAP;
+       urb->transfer_buffer = ibmcam->sbuf[0].data;
+       urb->complete = ibmcam_isoc_irq;
+       urb->number_of_packets = FRAMES_PER_DESC;
+       urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC;
+       for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+               urb->iso_frame_desc[fx].offset = ibmcam->iso_packet_len * fx;
+               urb->iso_frame_desc[fx].length = ibmcam->iso_packet_len;
+       }
+       urb = usb_alloc_urb(FRAMES_PER_DESC);
+       if (!urb) {
+               printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc ret %d\n",
+                       0);
+               return -ENOMEM;
+       }
+       ibmcam->sbuf[1].urb = urb;
+       urb->dev = dev;
+       urb->context = ibmcam;
+       urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp);
+       urb->transfer_flags = USB_ISO_ASAP;
+       urb->transfer_buffer = ibmcam->sbuf[1].data;
+       urb->complete = ibmcam_isoc_irq;
+       urb->number_of_packets = FRAMES_PER_DESC;
+       urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC;
+       for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+               urb->iso_frame_desc[fx].offset = ibmcam->iso_packet_len * fx;
+               urb->iso_frame_desc[fx].length = ibmcam->iso_packet_len;
+       }
+
+       ibmcam->sbuf[1].urb->next = ibmcam->sbuf[0].urb;
+       ibmcam->sbuf[0].urb->next = ibmcam->sbuf[1].urb;
+       
+       err = usb_submit_urb(ibmcam->sbuf[0].urb);
+       if (err)
+               printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(0) ret %d\n",
+                       err);
+       err = usb_submit_urb(ibmcam->sbuf[1].urb);
+       if (err)
+               printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(1) ret %d\n",
+                       err);
+
+       ibmcam->streaming = 1;
+       // printk(KERN_DEBUG "streaming=1 ibmcam->video_endp=$%02x\n", ibmcam->video_endp);
+       return 0;
+}
+
+static void ibmcam_stop_isoc(struct usb_ibmcam *ibmcam)
+{
+       if (!ibmcam->streaming)
+               return;
+
+       usb_ibmcam_setup_video_stop(ibmcam->dev);
+
+       /* Set packet size to 0 */
+       if (usb_set_interface(ibmcam->dev, 2, 0) < 0) {
+               printk(KERN_ERR "usb_set_interface error\n");
+               return /* -EINVAL */;
+       }
+
+       /* Unschedule all of the iso td's */
+       usb_unlink_urb(ibmcam->sbuf[1].urb);
+       usb_unlink_urb(ibmcam->sbuf[0].urb);
+
+       // printk(KERN_DEBUG "streaming=0\n");
+       ibmcam->streaming = 0;
+
+       /* Delete them all */
+       usb_free_urb(ibmcam->sbuf[1].urb);
+       usb_free_urb(ibmcam->sbuf[0].urb);
+}
+
+static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
+{
+       struct ibmcam_frame *frame;
+       int n, width, height;
+
+       /* If we're not grabbing a frame right now and the other frame is */
+       /*  ready to be grabbed into, then use it instead */
+       if (ibmcam->curframe != -1)
+               return 0;
+
+       n = (framenum - 1 + IBMCAM_NUMFRAMES) % IBMCAM_NUMFRAMES;
+       if (ibmcam->frame[n].grabstate == FRAME_READY)
+               framenum = n;
+
+       frame = &ibmcam->frame[framenum];
+
+       frame->grabstate = FRAME_GRABBING;
+       frame->scanstate = STATE_SCANNING;
+       frame->scanlength = 0;          /* Accumulated in ibmcam_parse_data() */
+       ibmcam->curframe = framenum;
+#if 0
+       /* This provides a "clean" frame but slows things down */
+       memset(frame->data, 0, MAX_FRAME_SIZE);
+#endif
+       switch (videosize) {
+       case VIDEOSIZE_128x96:
+               frame->frmwidth = 128;
+               frame->frmheight = 96;
+               frame->order_uv = 1;    /* U Y V Y ... */
+               frame->hdr_sig = 0x06;  /* 00 FF 00 06 */
+               break;
+       case VIDEOSIZE_176x144:
+               frame->frmwidth = 176;
+               frame->frmheight = 144;
+               frame->order_uv = 1;    /* U Y V Y ... */
+               frame->hdr_sig = 0x0E;  /* 00 FF 00 0E */
+               break;
+       case VIDEOSIZE_352x288:
+               frame->frmwidth = 352;
+               frame->frmheight = 288;
+               frame->order_uv = 0;    /* V Y U Y ... */
+               frame->hdr_sig = 0x00;  /* 00 FF 00 00 */
+               break;
+       }
+
+       width = frame->width;
+       RESTRICT_TO_RANGE(width, min_imgwidth, imgwidth);
+       width &= ~7;            /* Multiple of 8 */
+
+       height = frame->height;
+       RESTRICT_TO_RANGE(height, min_imgheight, imgheight);
+       height &= ~3;           /* Multiple of 4 */
+
+       return 0;
+}
+
+/* Video 4 Linux API */
+static int ibmcam_open(struct video_device *dev, int flags)
+{
+       int err = -EBUSY;
+       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+
+       if (ibmcam->remove_pending)
+               return -EFAULT;
+
+       down(&ibmcam->lock);
+       if (ibmcam->user)
+               goto out_unlock;
+
+       ibmcam->frame[0].grabstate = FRAME_UNUSED;
+       ibmcam->frame[1].grabstate = FRAME_UNUSED;
+
+       err = -ENOMEM;
+
+       /* Allocate memory for the frame buffers */
+       ibmcam->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
+       if (!ibmcam->fbuf)
+               goto open_err_ret;
+
+       ibmcam->frame[0].data = ibmcam->fbuf;
+       ibmcam->frame[1].data = ibmcam->fbuf + MAX_FRAME_SIZE;
+
+       ibmcam->sbuf[0].data = kmalloc (FRAMES_PER_DESC * ibmcam->iso_packet_len, GFP_KERNEL);
+       if (!ibmcam->sbuf[0].data)
+               goto open_err_on0;
+
+       ibmcam->sbuf[1].data = kmalloc (FRAMES_PER_DESC * ibmcam->iso_packet_len, GFP_KERNEL);
+       if (!ibmcam->sbuf[1].data)
+               goto open_err_on1;
+
+       /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
+        * (using read() instead). */
+       ibmcam->frame[0].width = imgwidth;
+       ibmcam->frame[0].height = imgheight;
+       ibmcam->frame[0].bytes_read = 0;
+       ibmcam->frame[1].width = imgwidth;
+       ibmcam->frame[1].height = imgheight;
+       ibmcam->frame[1].bytes_read = 0;
+
+       err = ibmcam_init_isoc(ibmcam);
+       if (err)
+               goto open_err_on2;
+
+       ibmcam->user++;
+       up(&ibmcam->lock);
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+
+open_err_on2:
+       kfree (ibmcam->sbuf[1].data);
+open_err_on1:
+       kfree (ibmcam->sbuf[0].data);
+open_err_on0:
+       rvfree(ibmcam->fbuf, 2 * MAX_FRAME_SIZE);
+open_err_ret:
+       return err;
+
+out_unlock:
+       up(&ibmcam->lock);
+       return err;
+}
+
+static void ibmcam_close(struct video_device *dev)
+{
+       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+
+       down(&ibmcam->lock);    
+       ibmcam->user--;
+
+       MOD_DEC_USE_COUNT;
+
+       ibmcam_stop_isoc(ibmcam);
+
+       rvfree(ibmcam->fbuf, 2 * MAX_FRAME_SIZE);
+
+       kfree(ibmcam->sbuf[1].data);
+       kfree(ibmcam->sbuf[0].data);
+
+       up(&ibmcam->lock);
+}
+
+static int ibmcam_init_done(struct video_device *dev)
+{
+       return 0;
+}
+
+static long ibmcam_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+       return -EINVAL;
+}
+
+static int ibmcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+
+       if (ibmcam->remove_pending)
+               return -EFAULT;
+
+       switch (cmd) {
+               case VIDIOCGCAP:
+               {
+                       if (copy_to_user(arg, &ibmcam->vcap, sizeof(ibmcam->vcap)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCGCHAN:
+               {
+                       if (copy_to_user(arg, &ibmcam->vchan, sizeof(ibmcam->vchan)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCSCHAN:
+               {
+                       int v;
+
+                       if (copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       if ((v < 0) || (v >= 3)) /* 3 grades of lighting conditions */
+                               return -EINVAL;
+                       if (v != ibmcam->vchan.channel) {
+                               ibmcam->vchan.channel = v;
+                               usb_ibmcam_change_lighting_conditions(ibmcam);
+                       }
+                       return 0;
+               }
+               case VIDIOCGPICT:
+               {
+                       if (copy_to_user(arg, &ibmcam->vpic, sizeof(ibmcam->vpic)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCSPICT:
+               {
+                       if (copy_from_user(&ibmcam->vpic, arg, sizeof(ibmcam->vpic)))
+                               return -EFAULT;
+                       usb_ibmcam_adjust_picture(ibmcam);
+                       return 0;
+               }
+               case VIDIOCSWIN:
+               {
+                       struct video_window vw;
+
+                       if (copy_from_user(&vw, arg, sizeof(vw)))
+                               return -EFAULT;
+                       if (vw.flags)
+                               return -EINVAL;
+                       if (vw.clipcount)
+                               return -EINVAL;
+                       if (vw.height != imgheight)
+                               return -EINVAL;
+                       if (vw.width != imgwidth)
+                               return -EINVAL;
+
+                       ibmcam->compress = 0;
+
+                       return 0;
+               }
+               case VIDIOCGWIN:
+               {
+                       struct video_window vw;
+
+                       vw.x = 0;
+                       vw.y = 0;
+                       vw.width = imgwidth;
+                       vw.height = imgheight;
+                       vw.chromakey = 0;
+                       vw.flags = usb_ibmcam_calculate_fps();
+
+                       if (copy_to_user(arg, &vw, sizeof(vw)))
+                               return -EFAULT;
+
+                       return 0;
+               }
+               case VIDIOCGMBUF:
+               {
+                       struct video_mbuf vm;
+
+                       memset(&vm, 0, sizeof(vm));
+                       vm.size = MAX_FRAME_SIZE * 2;
+                       vm.frames = 2;
+                       vm.offsets[0] = 0;
+                       vm.offsets[1] = MAX_FRAME_SIZE;
+
+                       if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+                               return -EFAULT;
+
+                       return 0;
+               }
+               case VIDIOCMCAPTURE:
+               {
+                       struct video_mmap vm;
+
+                       if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
+                               return -EFAULT;
+
+                       if (debug >= 1)
+                               printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n",
+                                       vm.frame, vm.width, vm.height, vm.format);
+
+                       if (vm.format != VIDEO_PALETTE_RGB24)
+                               return -EINVAL;
+
+                       if ((vm.frame != 0) && (vm.frame != 1))
+                               return -EINVAL;
+
+                       if (ibmcam->frame[vm.frame].grabstate == FRAME_GRABBING)
+                               return -EBUSY;
+
+                       /* Don't compress if the size changed */
+                       if ((ibmcam->frame[vm.frame].width != vm.width) ||
+                           (ibmcam->frame[vm.frame].height != vm.height))
+                               ibmcam->compress = 0;
+
+                       ibmcam->frame[vm.frame].width = vm.width;
+                       ibmcam->frame[vm.frame].height = vm.height;
+
+                       /* Mark it as ready */
+                       ibmcam->frame[vm.frame].grabstate = FRAME_READY;
+
+                       return ibmcam_new_frame(ibmcam, vm.frame);
+               }
+               case VIDIOCSYNC:
+               {
+                       int frame;
+
+                       if (copy_from_user((void *)&frame, arg, sizeof(int)))
+                               return -EFAULT;
+
+                       if (debug >= 1)
+                               printk(KERN_DEBUG "ibmcam: syncing to frame %d\n", frame);
+
+                       switch (ibmcam->frame[frame].grabstate) {
+                       case FRAME_UNUSED:
+                               return -EINVAL;
+                       case FRAME_READY:
+                       case FRAME_GRABBING:
+                       case FRAME_ERROR:
+                       {
+                               int ntries;
+               redo:
+                               ntries = 0; 
+                               do {
+                                       interruptible_sleep_on(&ibmcam->frame[frame].wq);
+                                       if (signal_pending(current)) {
+                                               if (flags & FLAGS_RETRY_VIDIOCSYNC) {
+                                                       /* Polling apps will destroy frames with that! */
+                                                       ibmcam_new_frame(ibmcam, frame);
+                                                       usb_ibmcam_testpattern(ibmcam, 1, 0);
+                                                       ibmcam->curframe = -1;
+                                                       ibmcam->frame_num++;
+
+                                                       /* This will request another frame. */
+                                                       if (waitqueue_active(&ibmcam->frame[frame].wq))
+                                                               wake_up_interruptible(&ibmcam->frame[frame].wq);
+                                                       return 0;
+                                               } else {
+                                                       /* Standard answer: not ready yet! */
+                                                       return -EINTR;
+                                               }
+                                       }
+                               } while (ibmcam->frame[frame].grabstate == FRAME_GRABBING);
+
+                               if (ibmcam->frame[frame].grabstate == FRAME_ERROR) {
+                                       int ret = ibmcam_new_frame(ibmcam, frame);
+                                       if (ret < 0)
+                                               return ret;
+                                       goto redo;
+                               }
+                       }
+                       case FRAME_DONE:
+                               ibmcam->frame[frame].grabstate = FRAME_UNUSED;
+                               break;
+                       }
+
+                       ibmcam->frame[frame].grabstate = FRAME_UNUSED;
+
+                       return 0;
+               }
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer vb;
+
+                       memset(&vb, 0, sizeof(vb));
+                       vb.base = NULL; /* frame buffer not supported, not used */
+
+                       if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+                               return -EFAULT;
+
+                       return 0;
+               }
+               case VIDIOCKEY:
+                       return 0;
+
+               case VIDIOCCAPTURE:
+                       return -EINVAL;
+
+               case VIDIOCSFBUF:
+
+               case VIDIOCGTUNER:
+               case VIDIOCSTUNER:
+
+               case VIDIOCGFREQ:
+               case VIDIOCSFREQ:
+
+               case VIDIOCGAUDIO:
+               case VIDIOCSAUDIO:
+                       return -EINVAL;
+
+               default:
+                       return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static long ibmcam_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
+{
+       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+       int frmx = -1;
+       volatile struct ibmcam_frame *frame;
+
+       if (debug >= 1)
+               printk(KERN_DEBUG "ibmcam_read: %ld bytes, noblock=%d\n", count, noblock);
+
+       if (ibmcam->remove_pending)
+               return -EFAULT;
+
+       if (!dev || !buf)
+               return -EFAULT;
+
+       /* See if a frame is completed, then use it. */
+       if (ibmcam->frame[0].grabstate >= FRAME_DONE)   /* _DONE or _ERROR */
+               frmx = 0;
+       else if (ibmcam->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
+               frmx = 1;
+
+       if (noblock && (frmx == -1))
+               return -EAGAIN;
+
+       /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
+       /* See if a frame is in process (grabbing), then use it. */
+       if (frmx == -1) {
+               if (ibmcam->frame[0].grabstate == FRAME_GRABBING)
+                       frmx = 0;
+               else if (ibmcam->frame[1].grabstate == FRAME_GRABBING)
+                       frmx = 1;
+       }
+
+       /* If no frame is active, start one. */
+       if (frmx == -1)
+               ibmcam_new_frame(ibmcam, frmx = 0);
+
+       frame = &ibmcam->frame[frmx];
+
+restart:
+       while (frame->grabstate == FRAME_GRABBING) {
+               interruptible_sleep_on((void *)&frame->wq);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       if (frame->grabstate == FRAME_ERROR) {
+               frame->bytes_read = 0;
+               if (ibmcam_new_frame(ibmcam, frmx))
+                       printk(KERN_ERR "ibmcam_read: ibmcam_new_frame error\n");
+               goto restart;
+       }
+
+       if (debug >= 1)
+               printk(KERN_DEBUG "ibmcam_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n",
+                       frmx, frame->bytes_read, frame->scanlength);
+
+       /* copy bytes to user space; we allow for partials reads */
+       if ((count + frame->bytes_read) > frame->scanlength)
+               count = frame->scanlength - frame->bytes_read;
+
+       if (copy_to_user(buf, frame->data + frame->bytes_read, count))
+               return -EFAULT;
+
+       frame->bytes_read += count;
+       if (debug >= 1)
+               printk(KERN_DEBUG "ibmcam_read: {copy} count used=%ld, new bytes_read=%ld\n",
+                       count, frame->bytes_read);
+
+       if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
+               frame->bytes_read = 0;
+
+               /* Mark it as available to be used again. */
+               ibmcam->frame[frmx].grabstate = FRAME_UNUSED;
+               if (ibmcam_new_frame(ibmcam, frmx ? 0 : 1))
+                       printk(KERN_ERR "ibmcam_read: ibmcam_new_frame returned error\n");
+       }
+
+       return count;
+}
+
+static int ibmcam_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+       unsigned long start = (unsigned long)adr;
+       unsigned long page, pos;
+
+       if (ibmcam->remove_pending)
+               return -EFAULT;
+
+       if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+               return -EINVAL;
+
+       pos = (unsigned long)ibmcam->fbuf;
+       while (size > 0) {
+               page = kvirt_to_pa(pos);
+               if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return 0;
+}
+
+static struct video_device ibmcam_template = {
+       "CPiA USB Camera",
+       VID_TYPE_CAPTURE,
+       VID_HARDWARE_CPIA,
+       ibmcam_open,
+       ibmcam_close,
+       ibmcam_read,
+       ibmcam_write,
+       NULL,
+       ibmcam_ioctl,
+       ibmcam_mmap,
+       ibmcam_init_done,
+       NULL,
+       0,
+       0
+};
+
+static void usb_ibmcam_configure_video(struct usb_ibmcam *ibmcam)
+{
+       if (ibmcam == NULL)
+               return;
+
+       RESTRICT_TO_RANGE(init_brightness, 0, 255);
+       RESTRICT_TO_RANGE(init_contrast, 0, 255);
+       RESTRICT_TO_RANGE(init_color, 0, 255);
+       RESTRICT_TO_RANGE(init_hue, 0, 255);
+
+       memset(&ibmcam->vpic, 0, sizeof(ibmcam->vpic));
+       memset(&ibmcam->vpic_old, 0x55, sizeof(ibmcam->vpic_old));
+
+       ibmcam->vpic.colour = init_color << 8;
+       ibmcam->vpic.hue = init_hue << 8;
+       ibmcam->vpic.brightness = init_brightness << 8;
+       ibmcam->vpic.contrast = init_contrast << 8;
+       ibmcam->vpic.whiteness = 105 << 8; /* This one isn't used */
+       ibmcam->vpic.depth = 24;
+       ibmcam->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&ibmcam->vcap, 0, sizeof(ibmcam->vcap));
+       strcpy(ibmcam->vcap.name, "IBM USB Camera");
+       ibmcam->vcap.type = VID_TYPE_CAPTURE /*| VID_TYPE_SUBCAPTURE*/;
+       ibmcam->vcap.channels = 1;
+       ibmcam->vcap.audios = 0;
+       ibmcam->vcap.maxwidth = imgwidth;
+       ibmcam->vcap.maxheight = imgheight;
+       ibmcam->vcap.minwidth = min_imgwidth;
+       ibmcam->vcap.minheight = min_imgheight;
+
+       memset(&ibmcam->vchan, 0, sizeof(ibmcam->vchan));
+       ibmcam->vchan.flags = 0;
+       ibmcam->vchan.tuners = 0;
+       ibmcam->vchan.channel = 0;
+       ibmcam->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(ibmcam->vchan.name, "Camera");
+}
+
+static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
+{
+       struct usb_ibmcam *ibmcam = NULL;
+       struct usb_interface_descriptor *interface;
+
+       if (debug >= 1)
+               printk(KERN_DEBUG "ibmcam_probe(%p,%u.)\n", dev, ifnum);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return NULL;
+
+       /* Is it an IBM camera? */
+       if ((dev->descriptor.idVendor != 0x0545) ||
+           (dev->descriptor.idProduct != 0x8080))
+               return NULL;
+
+       /* Camera confirmed. We claim only interface 2 (video data) */
+       if (ifnum != 2)
+               return NULL;
+
+       /* We found an IBM camera */
+       printk(KERN_INFO "IBM USB camera found (interface %u.)\n", ifnum);
+
+       if (debug >= 1)
+               printk(KERN_DEBUG "ibmcam_probe: new ibmcam alloc\n");
+       ibmcam = kmalloc(sizeof(*ibmcam), GFP_KERNEL);
+       if (ibmcam == NULL) {
+               printk(KERN_ERR "couldn't kmalloc ibmcam struct\n");
+               return NULL;
+       }
+       memset(ibmcam, 0, sizeof(struct usb_ibmcam));
+       ibmcam->dev = dev;
+       interface = &dev->actconfig->interface[ifnum].altsetting[0];
+       ibmcam->iface = interface->bInterfaceNumber;
+       ibmcam->video_endp = 0x82;
+       ibmcam->scratch = kmalloc(scratchbufsize, GFP_KERNEL);
+       if (ibmcam->scratch == NULL) {
+               printk(KERN_ERR "couldn't kmalloc ibmcam->scratch\n");
+               kfree(ibmcam);
+               return NULL;
+       }
+       init_waitqueue_head (&ibmcam->remove_ok);
+       ibmcam->iso_packet_len = 1014;
+
+       /* Camera setup */
+       usb_ibmcam_veio(dev, 1, 0, 0x128);
+       usb_ibmcam_setup_before_if1(dev);
+       usb_ibmcam_setup_before_if2(dev);
+
+       memcpy(&ibmcam->vdev, &ibmcam_template, sizeof(ibmcam_template));
+       usb_ibmcam_configure_video(ibmcam);
+
+       init_waitqueue_head(&ibmcam->frame[0].wq);
+       init_waitqueue_head(&ibmcam->frame[1].wq);
+
+       if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER) == -1) {
+               printk(KERN_ERR "video_register_device failed\n");
+               return NULL;
+       }
+       if (debug > 1)
+               printk(KERN_DEBUG "video_register_device() successful\n");
+
+       ibmcam->compress = 0;
+       ibmcam->user=0; 
+       init_MUTEX(&ibmcam->lock);      /* to 1 == available */
+
+       return ibmcam;
+}
+
+static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr)
+{
+       static const char proc[] = "usb_ibmcam_disconnect";
+       struct usb_ibmcam *ibmcam = (struct usb_ibmcam *) ptr;
+
+       if (debug > 0)
+               printk(KERN_DEBUG "%s(%p,%p.)\n", proc, dev, ptr);
+
+       ibmcam->remove_pending = 1;
+       /* Now all ISO data will be ignored */
+
+       /* At this time we ask to cancel outstanding URBs */
+       ibmcam_stop_isoc(ibmcam);
+
+       /* sleep_on(&s->remove_ok); */
+       /* Now it should be safe to remove */
+
+       video_unregister_device(&ibmcam->vdev);
+
+       /* Free the memory */
+       if (debug > 0)
+               printk(KERN_DEBUG "%s: freeing ibmcam=%p\n", proc, ibmcam);
+       if (ibmcam->scratch != NULL)
+               kfree(ibmcam->scratch);
+       kfree(ibmcam);
+}
+
+static struct usb_driver ibmcam_driver = {
+       "ibmcam",
+       usb_ibmcam_probe,
+       usb_ibmcam_disconnect,
+       { NULL, NULL }
+};
+
+int usb_ibmcam_init(void)
+{
+       return usb_register(&ibmcam_driver);
+}
+
+void usb_ibmcam_cleanup(void)
+{
+       usb_deregister(&ibmcam_driver);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return usb_ibmcam_init();
+}
+
+void cleanup_module(void)
+{
+       usb_ibmcam_cleanup();
+}
+#endif
diff --git a/drivers/usb/ibmcam.h b/drivers/usb/ibmcam.h
new file mode 100644 (file)
index 0000000..8dd6eda
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Header file for USB IBM C-It Video Camera driver.
+ *
+ * Supports IBM C-It Video Camera.
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ */
+
+#ifndef __LINUX_IBMCAM_H
+#define __LINUX_IBMCAM_H
+
+#include <linux/list.h>
+
+#define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
+
+/* Video Size 384 x 288 x 3 bytes for RGB */
+/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */
+#define V4L_FRAME_WIDTH         384
+#define V4L_FRAME_WIDTH_USED   352
+#define V4L_FRAME_HEIGHT        288
+#define V4L_BYTES_PER_PIXEL     3
+#define MAX_FRAME_SIZE          (V4L_FRAME_WIDTH * V4L_FRAME_HEIGHT * V4L_BYTES_PER_PIXEL)
+
+/* Camera capabilities (maximum) */
+#define CAMERA_IMAGE_WIDTH      352
+#define CAMERA_IMAGE_HEIGHT     288
+#define CAMERA_IMAGE_LINE_SZ    ((CAMERA_IMAGE_WIDTH * 3) / 2) /* Bytes */
+#define CAMERA_URB_FRAMES       32
+#define CAMERA_MAX_ISO_PACKET   1023 /* 1022 actually sent by camera */
+
+#define IBMCAM_NUMFRAMES       2
+#define IBMCAM_NUMSBUF         2
+
+#define FRAMES_PER_DESC                (CAMERA_URB_FRAMES)
+#define FRAME_SIZE_PER_DESC    (CAMERA_MAX_ISO_PACKET)
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+
+/*
+ * This macro performs bounds checking - use it when working with
+ * new formats, or else you may get oopses all over the place.
+ * If pixel falls out of bounds then it gets shoved back (as close
+ * to place of offence as possible) and is painted bright red.
+ */
+#define IBMCAM_PUTPIXEL(fr, ix, iy, vr, vg, vb) { \
+       register unsigned char *pf; \
+       int limiter = 0, mx, my; \
+       mx = ix; \
+       my = iy; \
+       if (mx < 0) { \
+               mx=0; \
+               limiter++; \
+       } else if (mx >= 352) { \
+               mx=351; \
+               limiter++; \
+       } \
+       if (my < 0) { \
+               my = 0; \
+               limiter++; \
+       } else if (my >= V4L_FRAME_HEIGHT) { \
+               my = V4L_FRAME_HEIGHT - 1; \
+               limiter++; \
+       } \
+       pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*352 + (ix)); \
+       if (limiter) { \
+               *pf++ = 0; \
+               *pf++ = 0; \
+               *pf++ = 0xFF; \
+       } else { \
+               *pf++ = (vb); \
+               *pf++ = (vg); \
+               *pf++ = (vr); \
+       } \
+}
+
+/*
+ * We use macros to do YUV -> RGB conversion because this is
+ * very important for speed and totally unimportant for size.
+ *
+ * YUV -> RGB Conversion
+ * ---------------------
+ *
+ * B = 1.164*(Y-16)                + 2.018*(V-128)
+ * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
+ * R = 1.164*(Y-16) + 1.596*(U-128)
+ *
+ * If you fancy integer arithmetics (as you should), hear this:
+ *
+ * 65536*B = 76284*(Y-16)                + 132252*(V-128)
+ * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
+ * 65536*R = 76284*(Y-16) + 104595*(U-128)
+ *
+ * Make sure the output values are within [0..255] range.
+ */
+#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
+#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
+    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+    mm_y = (my) - 16;  \
+    mm_u = (mu) - 128; \
+    mm_v = (mv) - 128; \
+    mm_yc= mm_y * 76284; \
+    mm_b = (mm_yc              + 132252*mm_v   ) >> 16; \
+    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v  ) >> 16; \
+    mm_r = (mm_yc + 104595*mm_u                        ) >> 16; \
+    mb = LIMIT_RGB(mm_b); \
+    mg = LIMIT_RGB(mm_g); \
+    mr = LIMIT_RGB(mm_r); \
+}
+
+enum {
+       STATE_SCANNING,         /* Scanning for header */
+       STATE_LINES,            /* Parsing lines */
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+struct usb_device;
+
+struct ibmcam_sbuf {
+       char *data;
+       urb_t *urb;
+};
+
+struct ibmcam_frame {
+       char *data;             /* Frame buffer */
+       int order_uv;           /* True=UV False=VU */
+       unsigned char hdr_sig;  /* "00 FF 00 ??" where 'hdr_sig' is '??' */
+
+       int width;              /* Width application is expecting */
+       int height;             /* Height */
+
+       int frmwidth;           /* Width the frame actually is */
+       int frmheight;          /* Height */
+
+       volatile int grabstate; /* State of grabbing */
+       int scanstate;          /* State of scanning */
+
+       int curline;            /* Line of frame we're working on */
+
+       long scanlength;        /* uncompressed, raw data length of frame */
+       long bytes_read;        /* amount of scanlength that has been read from *data */
+
+       wait_queue_head_t wq;   /* Processes waiting */
+};
+
+struct usb_ibmcam {
+       struct video_device vdev;
+
+       /* Device structure */
+       struct usb_device *dev;
+
+       unsigned char iface;
+
+       struct semaphore lock;
+       int user;               /* user count for exclusive use */
+
+       int streaming;          /* Are we streaming Isochronous? */
+       int grabbing;           /* Are we grabbing? */
+
+       int compress;           /* Should the next frame be compressed? */
+
+       char *fbuf;             /* Videodev buffer area */
+
+       int curframe;
+       struct ibmcam_frame frame[IBMCAM_NUMFRAMES];    /* Double buffering */
+
+       int cursbuf;            /* Current receiving sbuf */
+       struct ibmcam_sbuf sbuf[IBMCAM_NUMSBUF];        /* Double buffering */
+       volatile int remove_pending;    /* If set then about to exit */
+       wait_queue_head_t remove_ok;    /* Wait here until removal is safe */
+
+        /*
+        * Scratch space from the Isochronous pipe.
+        * Scratch buffer should contain at least one pair of lines
+        * (CAMERA_IMAGE_LINE_SZ). We set it to two pairs here.
+        * This will be approximately 2 KB. HOWEVER in reality this
+        * buffer must be as large as hundred of KB because otherwise
+        * you'll get lots of overflows because V4L client may request
+        * frames not as uniformly as USB sources them.
+        */
+       unsigned char *scratch;
+       int scratchlen;
+
+       struct video_picture vpic, vpic_old;    /* Picture settings */
+       struct video_capability vcap;           /* Video capabilities */
+       struct video_channel vchan;     /* May be used for tuner support */
+       unsigned char video_endp;       /* 0x82 for IBM camera */
+        int has_hdr;
+        int frame_num;
+       int iso_packet_len;             /* Videomode-dependent, saves bus bandwidth */
+
+       /* Statistics that can be overlayed on screen */
+        unsigned long urb_count;        /* How many URBs we received so far */
+        unsigned long urb_length;       /* Length of last URB */
+        unsigned long data_count;       /* How many bytes we received */
+        unsigned long header_count;     /* How many frame headers we found */
+       unsigned long scratch_ovf_count;/* How many times we overflowed scratch */
+       unsigned long iso_skip_count;   /* How many empty ISO packets received */
+       unsigned long iso_err_count;    /* How many bad ISO packets received */
+};
+
+#endif /* __LINUX_IBMCAM_H */
index 34da929414e01a8c1a5384a4787afd4909b347dd..f45f7032fe2914a20eba7f7f9e6cc83a0ee005f6 100644 (file)
@@ -50,11 +50,11 @@ static unsigned char keybdev_mac_codes[256] =
        { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
         12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128,  1,
          2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
-        11, 45, 46, 43, 47, 44,123, 67, 55, 49, 57,122,120, 99,118, 96,
+        11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
         97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
-        84, 85, 82, 65, 42,  0, 10,103,111,  0,  0,  0,  0,  0,  0,  0,
+        84, 85, 82, 65, 42,105, 10,103,111,  0,  0,  0,  0,  0,  0,  0,
         76,125, 75,  0,124,  0,115, 62,116, 59, 60,119, 61,121,114,117,
-         0,  0,  0,  0,127, 81,  0,113 };
+         0,  0,  0,  0,127, 24,  0,113,  0,  0,  0,  0,  0, 55, 55,  0 };
 
 #endif
 
index c10b76557b91c2750c125d3d487df2ce6993c40e..8bcecdb8359986ec6e3e366852a433ccdbf64605 100644 (file)
@@ -51,10 +51,10 @@ struct mousedev_list {
        struct fasync_struct *fasync;
        struct mousedev *mousedev;
        struct mousedev_list *next;
-       int dx, dy, dz;
+       int dx, dy, dz, oldx, oldy;
        unsigned char ps2[6];
        unsigned long buttons;
-       unsigned char ready, buffer, bufsiz;
+       unsigned char ready, inrange, buffer, bufsiz;
        unsigned char mode, genseq, impseq;
 };
 
@@ -79,6 +79,23 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
 
        while (list) {
                switch (type) {
+                       case EV_ABS:
+                               if (test_bit(EV_REL, handle->dev->evbit) && test_bit(REL_X, handle->dev->relbit))
+                                       return;
+                               switch (code) {
+                                       case ABS_X:     
+                                               if (list->inrange) list->dx += (value - list->oldx) * 2000 /
+                                                       (handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]);
+                                               list->oldx = value;
+                                               break;
+                                       case ABS_Y:
+                                               if (list->inrange) list->dy += (value - list->oldy) * 2000 /
+                                                       (handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]);
+                                               list->oldy = value;
+                                               break;
+                               }
+                               break;
+
                        case EV_REL:
                                switch (code) {
                                        case REL_X:     list->dx += value; break;
@@ -89,12 +106,20 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
 
                        case EV_KEY:
                                switch (code) {
+                                       case BTN_TOUCH:
                                        case BTN_LEFT:   index = 0; break;
                                        case BTN_EXTRA:  if (list->mode > 1) { index = 4; break; }
+                                       case BTN_STYLUS:
                                        case BTN_RIGHT:  index = 1; break;
                                        case BTN_SIDE:   if (list->mode > 1) { index = 3; break; }
+                                       case BTN_STYLUS2:
                                        case BTN_MIDDLE: index = 2; break;      
-                                       default: index = 0;
+                                       default: 
+                                               if (code >= BTN_TOOL_PEN && code <= BTN_TOOL_MOUSE) {
+                                                       list->inrange = value;  
+                                                       return;
+                                               }
+                                               index = 0;
                                }
                                switch (value) {
                                        case 0: clear_bit(index, &list->buttons); break;
@@ -330,15 +355,14 @@ struct file_operations mousedev_fops = {
 static int mousedev_connect(struct input_handler *handler, struct input_dev *dev)
 {
 
-       if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_REL, dev->evbit)))    /* The device must have both rels and keys */
+       if (!test_bit(EV_KEY, dev->evbit) ||
+          (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
                return -1;
 
-       if (!(test_bit(REL_X, dev->relbit) && test_bit(REL_Y, dev->relbit)))    /* It must be a pointer device */
+       if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
+           (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
                return -1;
        
-       if (!test_bit(BTN_LEFT, dev->keybit))                           /* And have at least one mousebutton */
-               return -1;
-
 #ifdef CONFIG_INPUT_MOUSEDEV_MIX
        {
                struct input_handle *handle;
diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c
deleted file mode 100644 (file)
index 30274cb..0000000
+++ /dev/null
@@ -1,1823 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * 
- * [ Initialisation is based on Linus'  ]
- * [ uhci code and gregs ohci fragments ]
- * [ (C) Copyright 1999 Linus Torvalds  ]
- * [ (C) Copyright 1999 Gregory P. Smith]
- * 
- * 
- * History:
- * 
- * v5.2 1999/12/07 URB 3rd preview, 
- * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
- * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
- *     i386: HUB, Keyboard, Mouse, Printer 
- *
- * v4.3 1999/10/27 multiple HCs, bulk_request
- * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
- * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
- * v4.0 1999/08/18 
- * v3.0 1999/06/25 
- * v2.1 1999/05/09  code clean up
- * v2.0 1999/05/04 
- * v1.0 1999/04/27 initial release
- * 
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>  /* for in_interrupt() */
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#undef DEBUG
-#define OHCI_USE_NPS
-
-#include "usb.h"
-#include "ohci-hcd.h"
-
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-static int handle_apm_event (apm_event_t event);
-#endif
-
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-
-static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); 
-static LIST_HEAD (ohci_hcd_list);
-spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
-
-/*-------------------------------------------------------------------------*
- * URB support functions 
- *-------------------------------------------------------------------------*/ 
-/* free the private part of an URB */
-static void urb_rm_priv (urb_t * urb) 
-{
-       urb_priv_t * urb_priv = urb->hcpriv;
-       int i;
-       void * wait;
-       
-       if (!urb_priv) return;
-       
-       wait = urb_priv->wait;
-       
-       for (i = 0; i < urb_priv->length; i++) {
-               if (urb_priv->td [i]) {
-                       OHCI_FREE (urb_priv->td [i]);
-               }
-       }
-       kfree (urb->hcpriv);
-       urb->hcpriv = NULL;
-       
-       if (wait) {
-               add_wait_queue (&op_wakeup, wait); 
-               wake_up (&op_wakeup);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-#ifdef DEBUG
-static int sohci_get_current_frame_number (struct usb_device * dev);
-
-/* debug| print the main components of an URB     
- * small: 0) header + data packets 1) just header */
-static void urb_print (urb_t * 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;
-       }
-       
-       dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)", 
-                       str,
-                       sohci_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 (KERN_DEBUG __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 (KERN_DEBUG __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 < 16 && i < len; i++) 
-                               printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-                       printk ("%s stat:%d\n", i < len? "...": "", urb->status);
-               }
-       } 
-       
-}
-/* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/
-void ep_print_int_eds (ohci_t * ohci, char * str) {
-       int i, j;
-        __u32 * ed_p;
-       for (i= 0; i < 32; i++) {
-               j = 5;
-               printk (KERN_DEBUG __FILE__ " %s branch int %2d(%2x):", str, i, i);
-               ed_p = &(ohci->hcca.int_table [i]);
-               while (*ed_p != 0 && j--) {
-                       ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
-                       printk (" ed: %4x;", ed->hwINFO);
-                       ed_p = &ed->hwNextED;
-               }
-               printk ("\n");
-       }
-}
-               
-
-#endif
-
-/*-------------------------------------------------------------------------*
- * Interface functions (URB)
- *-------------------------------------------------------------------------*/
-
-/* return a request to the completion handler */
-static int sohci_return_urb (urb_t * urb)
-{
-       urb_priv_t * urb_priv = urb->hcpriv;
-       urb_t * urbt;
-       unsigned long flags;
-       int i;
-       
-       /* just to be sure */
-       if (!urb->complete) {
-               urb_rm_priv (urb);
-               usb_dec_dev_use (urb->dev);
-               return -1;
-       }
-       
-       if (!urb_priv) return -1; /* urb already unlinked */
-       
-#ifdef DEBUG
-       urb_print (urb, "RET", usb_pipeout (urb->pipe));
-#endif
-
-       switch (usb_pipetype (urb->pipe)) {
-               case PIPE_INTERRUPT:
-                       urb->complete (urb); /* call complete and requeue URB */        
-                       urb->actual_length = 0;
-                       urb->status = USB_ST_URB_PENDING;
-                       if (urb_priv->state != URB_DEL)
-                               td_submit_urb (urb);
-                       break;
-                       
-               case PIPE_ISOCHRONOUS:
-                       for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
-                       if (urbt) { /* send the reply and requeue URB */        
-                               urb->complete (urb);
-                               
-                               spin_lock_irqsave (&usb_ed_lock, flags);
-                               urb->actual_length = 0;
-                               urb->status = USB_ST_URB_PENDING;
-                               urb->start_frame = urb_priv->ed->last_iso + 1;
-                               if (urb_priv->state != URB_DEL) {
-                                       for (i = 0; i < urb->number_of_packets; i++) {
-                                               urb->iso_frame_desc[i].actual_length = 0;
-                                               urb->iso_frame_desc[i].status = -EXDEV;
-                                       }
-                                       td_submit_urb (urb);
-                               }
-                               spin_unlock_irqrestore (&usb_ed_lock, flags);
-                               
-                       } else { /* unlink URB, call complete */
-                               urb_rm_priv (urb);
-                               usb_dec_dev_use (urb->dev);
-                               urb->complete (urb);    
-                       }               
-                       break;
-                               
-               case PIPE_BULK:
-               case PIPE_CONTROL: /* unlink URB, call complete */
-                       urb_rm_priv (urb);
-                       usb_dec_dev_use (urb->dev);
-                       urb->complete (urb);    
-                       break;
-       }
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* get a transfer request */
-static int sohci_submit_urb (urb_t * urb)
-{
-       ohci_t * ohci;
-       ed_t * ed;
-       urb_priv_t * urb_priv;
-       unsigned int pipe = urb->pipe;
-       int i, size = 0;
-       unsigned long flags;
-       
-       if (!urb->dev || !urb->dev->bus) return -EINVAL;
-       
-       if (urb->hcpriv) return -EINVAL; /* urb already in use */
-
-       usb_inc_dev_use (urb->dev);
-       ohci = (ohci_t *) urb->dev->bus->hcpriv;
-       
-#ifdef DEBUG
-       urb_print (urb, "SUB", usb_pipein (pipe));
-#endif
-       
-       if (usb_pipedevice (pipe) == ohci->rh.devnum) 
-               return rh_submit_urb (urb); /* a request to the virtual root hub */
-
-       /* every endpoint has a ed, locate and fill it */
-       if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
-               usb_dec_dev_use (urb->dev);     
-               return -ENOMEM;
-       }
-
-       /* for the private part of the URB we need the number of TDs (size) */
-       switch (usb_pipetype (pipe)) {
-               case PIPE_BULK: /* one TD for every 4096 Byte */
-                       size = (urb->transfer_buffer_length - 1) / 4096 + 1;
-                       break;
-               case PIPE_ISOCHRONOUS: /* number of packets from URB */
-                       size = urb->number_of_packets;
-                       for (i = 0; i < urb->number_of_packets; i++) {
-                               urb->iso_frame_desc[i].actual_length = 0;
-                               urb->iso_frame_desc[i].status = -EXDEV;
-                       }
-                       break;
-               case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
-                       size = (urb->transfer_buffer_length == 0)? 2: 
-                                               (urb->transfer_buffer_length - 1) / 4096 + 3;
-                       break;
-               case PIPE_INTERRUPT: /* one TD */
-                       size = 1;
-                       
-                       break;
-       }
-
-       /* allocate the private part or the URB */
-       urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
-                                                       in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-       if (!urb_priv) {
-               usb_dec_dev_use (urb->dev);     
-               return -ENOMEM;
-       }
-       memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
-       
-       /* fill the private part of the URB */
-       urb->hcpriv = urb_priv;
-       urb_priv->length = size;
-       urb_priv->td_cnt = 0;
-       urb_priv->state = 0;
-       urb_priv->ed = ed;      
-       urb_priv->wait = NULL;
-       
-       /* allocate the TDs */
-       for (i = 0; i < size; i++) { 
-               OHCI_ALLOC (urb_priv->td[i], sizeof (td_t));
-               if (!urb_priv->td[i]) {
-                       usb_dec_dev_use (urb->dev);     
-                       urb_rm_priv (urb);
-                       return -ENOMEM;
-               }
-       }       
-       spin_lock_irqsave (&usb_ed_lock, flags);        
-       if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
-               urb_rm_priv(urb);
-               usb_dec_dev_use (urb->dev);     
-               return -EINVAL;
-       }
-       
-       /* for ISOC transfers calculate start frame index */
-       if (urb->transfer_flags & USB_ISO_ASAP) { 
-               urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): 
-                                                               (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
-       }       
-       
-       td_submit_urb (urb); /* fill the TDs and link it to the ed */
-                                               
-       if (ed->state != ED_OPER)  /* link the ed into a chain if is not already */
-               ep_link (ohci, ed);
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
-       
-       urb->status = USB_ST_URB_PENDING; 
-       // queue_urb(s, &urb->urb_list);
-
-       return 0;       
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* deactivate all TDs and remove the private part of the URB */
-static int sohci_unlink_urb (urb_t * urb)
-{
-       unsigned long flags;
-       ohci_t * ohci;
-       DECLARE_WAITQUEUE (wait, current);
-       
-       if (!urb) /* just to be sure */ 
-               return -EINVAL;
-               
-#ifdef DEBUG
-       urb_print (urb, "UNLINK", 1);
-#endif           
-
-       ohci = (ohci_t *) urb->dev->bus->hcpriv; 
-
-       if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) 
-               return rh_unlink_urb (urb); /* a request to the virtual root hub */
-       
-       if (urb->hcpriv) { 
-               if (urb->status == USB_ST_URB_PENDING) { /* URB active? */
-                       urb_priv_t  * urb_priv = urb->hcpriv;
-                       urb_priv->state = URB_DEL; 
-                       /* we want to delete the TDs of an URB from an ed 
-                        * request the deletion, it will be handled at the next USB-frame */
-                       urb_priv->wait = &wait;
-                       
-                       spin_lock_irqsave (&usb_ed_lock, flags);
-                       ep_rm_ed (urb->dev, urb_priv->ed);
-                       urb_priv->ed->state |= ED_URB_DEL;
-                       spin_unlock_irqrestore (&usb_ed_lock, flags);
-
-                       current->state = TASK_UNINTERRUPTIBLE;
-                       if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
-                               remove_wait_queue (&op_wakeup, &wait); 
-                       else
-                               err("unlink URB timeout!");
-               } else 
-                       urb_rm_priv (urb);
-               usb_dec_dev_use (urb->dev);             
-       }       
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* allocate private data space for a usb device */
-
-static int sohci_alloc_dev (struct usb_device *usb_dev)
-{
-       struct ohci_device * dev;
-
-       dev = kmalloc (sizeof (*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-               
-       memset (dev, 0, sizeof (*dev));
-
-       usb_dev->hcpriv = dev;
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* free private data space of usb device */
-  
-static int sohci_free_dev (struct usb_device * usb_dev)
-{
-       unsigned long flags;
-       int i, cnt = 0;
-       ed_t * ed;
-       DECLARE_WAITQUEUE (wait, current);
-       struct ohci_device * dev = usb_to_ohci (usb_dev);
-       ohci_t * ohci = usb_dev->bus->hcpriv;
-       
-       if (!dev) return 0;
-       
-       if (usb_dev->devnum >= 0) {
-       
-               /* delete all TDs of all EDs */
-               spin_lock_irqsave (&usb_ed_lock, flags);        
-               for(i = 0; i < NUM_EDS; i++) {
-                       ed = &(dev->ed[i]);
-                       if (ed->state != ED_NEW) {
-                               if (ed->state == ED_OPER) ep_unlink (ohci, ed);
-                               ep_rm_ed (usb_dev, ed);
-                               ed->state = ED_DEL;
-                               cnt++;
-                       }
-               }
-               spin_unlock_irqrestore (&usb_ed_lock, flags);
-               
-       if (cnt > 0) { 
-               dev->wait = &wait;
-                       current->state = TASK_UNINTERRUPTIBLE;
-                       schedule_timeout (HZ / 10);
-                       remove_wait_queue (&op_wakeup, &wait);
-               }
-       }
-       kfree (dev);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* tell us the current USB frame number */
-
-static int sohci_get_current_frame_number (struct usb_device *usb_dev) 
-{
-       ohci_t * ohci = usb_dev->bus->hcpriv;
-       
-       return le16_to_cpu (ohci->hcca.frame_no);
-}
-
-/*-------------------------------------------------------------------------*/
-
-struct usb_operations sohci_device_operations = {
-       sohci_alloc_dev,
-       sohci_free_dev,
-       sohci_get_current_frame_number,
-       sohci_submit_urb,
-       sohci_unlink_urb
-};
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/  
-               
-/* search for the right branch to insert an interrupt ed into the int tree 
- * do some load ballancing;
- * returns the branch and 
- * sets the interval to interval = 2^integer (ld (interval)) */
-
-static int ep_int_ballance (ohci_t * ohci, int interval, int load)
-{
-       int i, branch = 0;
-   
-       /* search for the least loaded interrupt endpoint branch of all 32 branches */
-       for (i = 0; i < 32; i++) 
-               if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i; 
-  
-       branch = branch % interval;
-       for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;
-
-       return branch;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*  2^int( ld (inter)) */
-
-static int ep_2_n_interval (int inter)
-{      
-       int i;
-       for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); 
-       return 1 << i;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* the int tree is a binary tree 
- * in order to process it sequentially the indexes of the branches have to be mapped 
- * the mapping reverses the bits of a word of num_bits length */
-static int ep_rev (int num_bits, int word)
-{
-       int i, wout = 0;
-
-       for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
-       return wout;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* link an ed into one of the HC chains */
-
-static int ep_link (ohci_t * ohci, ed_t * edi)
-{       
-       int int_branch;
-       int i;
-       int inter;
-       int interval;
-       int load;
-       __u32 * ed_p;
-       volatile ed_t * ed = edi;
-       
-       ed->state = ED_OPER;
-       
-       switch (ed->type) {
-       case CTRL:
-               ed->hwNextED = 0;
-               if (ohci->ed_controltail == NULL) {
-                       writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
-               } else {
-                       ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
-               }
-               ed->ed_prev = ohci->ed_controltail;
-               ohci->ed_controltail = ed;        
-               break;
-               
-       case BULK:  
-               ed->hwNextED = 0;
-               if (ohci->ed_bulktail == NULL) {
-                       writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
-               } else {
-                       ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
-               }
-               ed->ed_prev = ohci->ed_bulktail;
-               ohci->ed_bulktail = ed;   
-               break;
-               
-       case INT:
-               load = ed->int_load;
-               interval = ep_2_n_interval (ed->int_period);
-               ed->int_interval = interval;
-               int_branch = ep_int_ballance (ohci, interval, load);
-               ed->int_branch = int_branch;
-               
-               for (i = 0; i < ep_rev (6, interval); i += inter) {
-                       inter = 1;
-                       for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]); 
-                               (*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval >= interval); 
-                               ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
-                                       inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
-                       ed->hwNextED = *ed_p; 
-                       *ed_p = cpu_to_le32 (virt_to_bus (ed));
-               }
-#ifdef DEBUG
-               ep_print_int_eds (ohci, "LINK_INT");
-#endif
-               break;
-               
-       case ISO:
-               ed->hwNextED = 0;
-               ed->int_interval = 1;
-               if (ohci->ed_isotail != NULL) {
-                       ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
-                       ed->ed_prev = ohci->ed_isotail;
-               } else {
-                       for ( i = 0; i < 32; i += inter) {
-                               inter = 1;
-                               for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
-                                       *ed_p != 0; 
-                                       ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
-                                               inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
-                               *ed_p = cpu_to_le32 (virt_to_bus (ed)); 
-                       }       
-                       ed->ed_prev = NULL;
-               }       
-               ohci->ed_isotail = ed;  
-#ifdef DEBUG
-               ep_print_int_eds (ohci, "LINK_ISO");
-#endif
-               break;
-       }               
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* unlink an ed from one of the HC chains. 
- * just the link to the ed is unlinked.
- * the link from the ed still points to another operational ed or 0
- * so the HC can eventually finish the processing of the unlinked ed */
-
-static int ep_unlink (ohci_t * ohci, ed_t * ed) 
-{
-       int int_branch;
-       int i;
-       int inter;
-       int interval;
-       __u32 * ed_p;
-        
-    
-       switch (ed->type) {
-       case CTRL: 
-               if (ed->ed_prev == NULL) {
-                       writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
-               } else {
-                       ed->ed_prev->hwNextED = ed->hwNextED;
-               }
-               if(ohci->ed_controltail == ed) {
-                       ohci->ed_controltail = ed->ed_prev;
-               } else {
-                       ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-               }
-               break;
-      
-       case BULK: 
-               if (ed->ed_prev == NULL) {
-                       writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
-               } else {
-                       ed->ed_prev->hwNextED = ed->hwNextED;
-               }
-               if (ohci->ed_bulktail == ed) {
-                       ohci->ed_bulktail = ed->ed_prev;
-               } else {
-                       ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-               }
-               break;
-      
-    case INT: 
-       int_branch = ed->int_branch;
-               interval = ed->int_interval;
-
-               for (i = 0; i < ep_rev (6, interval); i += inter) {
-                       for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]), inter = 1; 
-                               (*ed_p != 0) && (*ed_p != ed->hwNextED); 
-                               ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED), 
-                               inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval)) {                               
-                                       if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
-                                               *ed_p = ed->hwNextED;           
-                                               break;
-                                       }
-                         }
-               }
-               for (i = int_branch; i < 32; i += interval) ohci->ohci_int_load[i] -= ed->int_load;
-#ifdef DEBUG
-               ep_print_int_eds (ohci, "UNLINK_INT");
-#endif         break;
-               
-    case ISO:
-       if (ohci->ed_isotail == ed)
-                               ohci->ed_isotail = ed->ed_prev;
-               if (ed->hwNextED != 0) 
-                               ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-                               
-               if (ed->ed_prev != NULL) {
-                       ed->ed_prev->hwNextED = ed->hwNextED;
-               } else {
-                       for (i = 0; i < 32; i += inter) {
-                               inter = 1;
-                               for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
-                                       *ed_p != 0; 
-                                       ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
-                                               inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
-                                               if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
-                                                       *ed_p = ed->hwNextED;           
-                                                       break;
-                                               }
-                               }
-                       }       
-               }       
-#ifdef DEBUG
-               ep_print_int_eds (ohci, "UNLINK_ISO");
-#endif
-               break;
-    }
-    ed->state = ED_UNLINK;
-    return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
- * but the USB stack is a little bit stateless  so we do it at every transaction
- * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
- * in all other cases the state is left unchanged
- * the ed info fields are setted anyway even though most of them should not change */
-static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load)
-{
-       ohci_t * ohci = usb_dev->bus->hcpriv;
-       td_t * td;  
-       volatile ed_t * ed; 
-       
-       
-       spin_lock (&usb_ed_lock);
-
-       ed = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
-                       (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
-
-       if((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) 
-               return NULL; /* pending delete request */
-       
-       if (ed->state == ED_NEW) {
-               ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
-               OHCI_ALLOC (td, sizeof (*td)); /* dummy td; end of td list for ed */
-               if(!td) return NULL; /* out of memory */
-               ed->hwTailP = cpu_to_le32 (virt_to_bus (td));
-               ed->hwHeadP = ed->hwTailP;      
-               ed->state = ED_UNLINK;
-               ed->type = usb_pipetype (pipe);
-               usb_to_ohci (usb_dev)->ed_cnt++;
-       }
-
-       ohci->dev[usb_pipedevice (pipe)] = usb_dev;
-       
-       ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
-                       | usb_pipeendpoint (pipe) << 7
-                       | (usb_pipeisoc (pipe)? 0x8000: 0)
-                       | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
-                       | usb_pipeslow (pipe) << 13
-                       | usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
-  
-       if (ed->type == INT && ed->state == ED_UNLINK) {
-               ed->int_period = interval;
-               ed->int_load = load;
-       }
-       
-       spin_unlock(&usb_ed_lock);
-       return ed; 
-}
-
-/*-------------------------------------------------------------------------*/
-/* request the removal of an endpoint
- * put the ep on the rm_list and request a stop of the bulk or ctrl list 
- * real removal is done at the next start of frame (SOF) hardware interrupt */
-static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
-{    
-       unsigned int frame;
-       ohci_t * ohci = usb_dev->bus->hcpriv;
-
-       if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) return;
-       
-       ed->hwINFO  |=  cpu_to_le32 (OHCI_ED_SKIP);
-       
-       writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-       writel (OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
-
-       frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1;
-       ed->ed_rm_list = ohci->ed_rm_list[frame];
-       ohci->ed_rm_list[frame] = ed;
-
-       switch (ed->type) {
-               case CTRL: /* stop CTRL list */
-                       writel (ohci->hc_control &= ~(0x01 << 4), &ohci->regs->control); 
-                       break;
-               case BULK: /* stop BULK list */
-                       writel (ohci->hc_control &= ~(0x01 << 5), &ohci->regs->control); 
-                       break;
-       }
-}
-
-/*-------------------------------------------------------------------------*
- * TD handling functions
- *-------------------------------------------------------------------------*/
-
-/* prepare a TD */
-
-static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int type, int index)
-{
-       volatile td_t  * td, * td_pt;
-       urb_priv_t * urb_priv = urb->hcpriv;
-
-       if (index >= urb_priv->length) {
-               err("internal OHCI error: TD index > length");
-               return;
-       }
-       
-       td_pt = urb_priv->td [index];
-       /* fill the old dummy TD */
-       td = (td_t *) bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0);
-       td->ed = urb_priv->ed;
-       td->index = index;
-       td->urb = urb; 
-       td->hwINFO = cpu_to_le32 (info);
-       td->type = type;
-       if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
-               td->hwCBP = cpu_to_le32 (((!data || !len)? 
-                                                               0 : virt_to_bus (data)) & 0xFFFFF000);
-               td->ed->last_iso = info & 0xffff;
-       } else {
-               td->hwCBP = cpu_to_le32 (((!data || !len)? 0 : virt_to_bus (data))); 
-       }                       
-       td->hwBE = cpu_to_le32 ((!data || !len )? 0: virt_to_bus (data + len - 1));
-       td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt));
-       td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000);
-       td_pt->hwNextTD = 0;
-       td->ed->hwTailP = td->hwNextTD;
-       urb_priv->td [index] = td;
-   
-       td->next_dl_td = NULL; //td_pt;
-}
-
-/*-------------------------------------------------------------------------*/
-/* prepare all TDs of a transfer */
-
-static void td_submit_urb (urb_t * urb)
-{ 
-       urb_priv_t * urb_priv = urb->hcpriv;
-       ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
-       void * ctrl = urb->setup_packet;
-       void * data = urb->transfer_buffer;
-       int data_len = urb->transfer_buffer_length;
-       int cnt = 0; 
-       __u32 info = 0;
-  
-
-       urb_priv->td_cnt = 0;
-       
-       switch (usb_pipetype (urb->pipe)) {
-               case PIPE_BULK:
-                       info = usb_pipeout (urb->pipe)? 
-                               TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_DP_IN | TD_T_TOGGLE;
-                       while(data_len > 4096) {                
-                               td_fill (info, data, 4096, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
-                               data += 4096; data_len -= 4096; cnt++;
-                       }
-                       info = usb_pipeout (urb->pipe)?
-                               TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE;
-                       td_fill (info, data, data_len, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
-                       cnt++;
-                       writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-                       break;
-
-               case PIPE_INTERRUPT:
-                       info = usb_pipeout (urb->pipe)? 
-                               TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE;
-                       td_fill (info, data, data_len, urb, ST_ADDR | ADD_LEN, cnt++);
-                       break;
-
-               case PIPE_CONTROL:
-                       info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-                       td_fill (info, ctrl, 8, urb, ST_ADDR, cnt++); 
-                       if (data_len > 0) {  
-                               info = usb_pipeout (urb->pipe)? 
-                                       TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
-                               td_fill (info, data, data_len, urb, ADD_LEN, cnt++);  
-                       } 
-                       info = usb_pipeout (urb->pipe)? 
-                               TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
-                       td_fill (info, NULL, 0, urb, 0, cnt++);
-                       writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-                       break;
-
-               case PIPE_ISOCHRONOUS:
-                       for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
-                               td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
-                                       (__u8 *) data + urb->iso_frame_desc[cnt].offset, 
-                                       urb->iso_frame_desc[cnt].length, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt); 
-                       }
-                       break;
-       } 
-       if (urb_priv->length != cnt) 
-               dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
-}
-
-/*-------------------------------------------------------------------------*
- * Done List handling functions
- *-------------------------------------------------------------------------*/
-/* replies to the request have to be on a FIFO basis so
- * we reverse the reversed done-list */
-static td_t * dl_reverse_done_list (ohci_t * ohci)
-{
-       __u32 td_list_hc;
-       td_t * td_rev = NULL;
-       td_t * td_list = NULL;
-       urb_priv_t * urb_priv = NULL;
-       unsigned long flags;
-       
-       spin_lock_irqsave (&usb_ed_lock, flags);
-       
-       td_list_hc = le32_to_cpup (&ohci->hcca.done_head) & 0xfffffff0;
-       ohci->hcca.done_head = 0;
-       
-       while (td_list_hc) {            
-               td_list = (td_t *) bus_to_virt (td_list_hc);
-
-               if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
-                       urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
-                       dbg(" USB-error/status: %x : %p", 
-                                       TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
-                       if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
-                               if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
-                                       td_list->ed->hwHeadP = 
-                                               (urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
-                                                                       (td_list->ed->hwHeadP & cpu_to_le32 (0x2));
-                                       urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
-                               } else 
-                                       td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
-                       }
-               }
-
-               td_list->next_dl_td = td_rev;   
-               td_rev = td_list;
-               td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;    
-       }       
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
-       return td_list;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* there are some pending requests to remove 
- * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
- * - some URBs/TDs if urb_priv->state == URB_DEL */
-static void dl_del_list (ohci_t  * ohci, unsigned int frame)
-{
-       unsigned long flags;
-       ed_t * ed;
-       __u32 edINFO;
-       td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
-       __u32 * td_p;
-       int ctrl = 0, bulk = 0;
-
-       spin_lock_irqsave (&usb_ed_lock, flags);
-       for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
-
-               tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-               tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
-               edINFO = le32_to_cpup (&ed->hwINFO);
-               td_p = &ed->hwHeadP;
-                       
-               for (td = tdHeadP; td != tdTailP; td = td_next) { 
-                       urb_t * urb = td->urb;
-                       urb_priv_t * urb_priv = td->urb->hcpriv;
-                       
-                       td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
-                       if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
-                               *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
-                               if(++ (urb_priv->td_cnt) == urb_priv->length) 
-                                       urb_rm_priv (urb);
-                       } else {
-                               td_p = &td->hwNextTD;
-                       }
-                       
-               }
-               if (ed->state & ED_DEL) { /* set by sohci_free_dev */
-                       struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
-                       OHCI_FREE (tdTailP); /* free dummy td */
-                       ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
-                       ed->state = ED_NEW; 
-                       /* if all eds are removed wake up sohci_free_dev */
-                       if ((! --dev->ed_cnt) && dev->wait) {
-                               add_wait_queue (&op_wakeup, dev->wait); 
-                               wake_up (&op_wakeup);
-                       }
-               }
-               else {
-                       ed->state &= ~ED_URB_DEL;
-                       ed->hwINFO  &=  ~cpu_to_le32 (OHCI_ED_SKIP);
-               }
-               
-               if ((ed->type & 3) == CTRL) ctrl |= 1;
-               if ((ed->type & 3) == BULK) bulk |= 1;  
-       }
-       
-       if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
-       if (bulk) writel (0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
-       if (!ohci->ed_rm_list[!frame])          /* start CTRL u. BULK list */ 
-               writel (ohci->hc_control |= (0x03<<4), &ohci->regs->control);   
-       ohci->ed_rm_list[frame] = NULL;
-
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* td done list */
-
-static void dl_done_list (ohci_t * ohci, td_t * td_list)
-{
-       td_t * td_list_next = NULL;
-       ed_t * ed;
-       int dlen = 0;
-       int cc = 0;
-       urb_t * urb;
-       urb_priv_t * urb_priv;
-       __u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP;
-       __u16 tdPSW;
-       unsigned long flags;
-       
-       while (td_list) {
-               td_list_next = td_list->next_dl_td;
-               
-               urb = td_list->urb;
-               urb_priv = urb->hcpriv;
-               tdINFO = le32_to_cpup (&td_list->hwINFO);
-               tdBE   = le32_to_cpup (&td_list->hwBE);
-               tdCBP  = le32_to_cpup (&td_list->hwCBP);
-               
-               ed = td_list->ed;
-               
-               if (td_list->type & ST_ADDR) 
-                       urb->actual_length = 0;
-                       
-               if (td_list->type & ADD_LEN) { /* accumulate length of multi td transfers */
-                       if (tdINFO & TD_ISO) {
-                               tdPSW = le16_to_cpu (td_list->hwPSW[0]);
-                               cc = (tdPSW >> 12) & 0xF;
-                               if (cc < 0xE)  {
-                                       if (usb_pipeout(urb->pipe)) {
-                                               dlen = urb->iso_frame_desc[td_list->index].length;
-                                       } else {
-                                               dlen = tdPSW & 0x3ff;
-                                       }
-                                       urb->actual_length += dlen;
-                                       urb->iso_frame_desc[td_list->index].actual_length = dlen;
-                                       if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
-                                               cc = TD_CC_NOERROR;
-                                        
-                                       urb->iso_frame_desc[td_list->index].status = cc_to_error[cc];
-                               }
-                       } else {
-                               if (tdBE != 0) {
-                                       dlen = (bus_to_virt (tdBE) - urb->transfer_buffer + 1);
-                                       if (td_list->hwCBP == 0)
-                                       urb->actual_length += dlen;
-                                       else
-                                       urb->actual_length += (bus_to_virt(tdCBP) - urb->transfer_buffer);
-                           }
-                       }
-               }
-               /* error code of transfer */
-               cc = TD_CC_GET (tdINFO);
-               if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
-                                               cc = TD_CC_NOERROR;
-               if (++(urb_priv->td_cnt) == urb_priv->length) {
-                       if (urb_priv->state != URB_DEL && !(ed->state & ED_DEL) && ed->state != ED_NEW) { 
-                               urb->status = cc_to_error[cc];
-                               sohci_return_urb (urb);
-                       } else {
-                               urb_rm_priv (urb);
-                       }
-               }
-               
-               spin_lock_irqsave (&usb_ed_lock, flags);
-               if (ed->state != ED_NEW) { 
-                       edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
-                       edTailP = le32_to_cpup (&ed->hwTailP);
-
-               if((edHeadP == edTailP) && (ed->state == ED_OPER)) 
-                       ep_unlink (ohci, ed); /* unlink eds if they are not busy */
-               
-       }       
-       spin_unlock_irqrestore (&usb_ed_lock, flags);
-       
-       td_list = td_list_next;
-       }  
-}
-
-
-
-
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub 
- *-------------------------------------------------------------------------*/
-static __u8 root_hub_dev_des[] =
-{
-       0x12,       /*  __u8  bLength; */
-       0x01,       /*  __u8  bDescriptorType; Device */
-       0x00,       /*  __u16 bcdUSB; v1.0 */
-       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; */
-       0x00,       /*  __u8  iProduct; */
-       0x00,       /*  __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 */
-       0x08,       /*  __u16 ep_wMaxPacketSize; 8 Bytes */
-       0x00,
-       0xff        /*  __u8  ep_bInterval; 255 ms */
-};
-
-/* 
-For OHCI we need just the  2nd Byte, so we 
-don't need this constant byte-array 
-
-static __u8 root_hub_hub_des[] =
-{ 
-       0x00,       *  __u8  bLength; *
-       0x29,       *  __u8  bDescriptorType; Hub-descriptor *
-       0x02,       *  __u8  bNbrPorts; *
-       0x00,       * __u16  wHubCharacteristics; *
-       0x00,
-       0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
-       0x00,       *  __u8  bHubContrCurrent; 0 mA *
-       0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
-       0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
-};
-*/
-
-/*-------------------------------------------------------------------------*/
-
-/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */ 
-static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
-{
-       int num_ports;
-       int i;
-       int ret;
-       int len;
-
-       __u8 data[8];
-
-       num_ports = readl (&ohci->regs->roothub.a) & 0xff; 
-       *(__u8 *) data = (readl (&ohci->regs->roothub.status) & 0x00030000) > 0? 1: 0;
-       ret = *(__u8 *) data;
-
-       for ( i = 0; i < num_ports; i++) {
-               *(__u8 *) (data + (i + 1) / 8) |= 
-                       ((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);
-               ret += *(__u8 *) (data + (i + 1) / 8);
-       }
-       len = i/8 + 1;
-  
-       if (ret > 0) { 
-               memcpy (rh_data, data, min (len, min (rh_len, sizeof(data))));
-               return len;
-       }
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-static void rh_int_timer_do (unsigned long ptr)
-{
-       int len; 
-
-       urb_t * urb = (urb_t *) ptr;
-       ohci_t * ohci = urb->dev->bus->hcpriv;
-       
-       if(ohci->rh.send) { 
-               len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
-               if (len > 0) {
-                       urb->actual_length = len;
-#ifdef DEBUG
-                       urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
-#endif
-                       if (urb->complete) urb->complete (urb);
-               }
-       }       
-       rh_init_int_timer (urb);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Root Hub INTs are polled by this timer */
-
-static int rh_init_int_timer (urb_t * urb) 
-{
-       ohci_t * ohci = urb->dev->bus->hcpriv;
-
-       ohci->rh.interval = urb->interval;
-       init_timer (&ohci->rh.rh_int_timer);
-       ohci->rh.rh_int_timer.function = rh_int_timer_do;
-       ohci->rh.rh_int_timer.data = (unsigned long) urb;
-       ohci->rh.rh_int_timer.expires = 
-                       jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
-       add_timer (&ohci->rh.rh_int_timer);
-       
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#define OK(x)                          len = (x); break
-#define WR_RH_STAT(x)          writel((x), &ohci->regs->roothub.status)
-#define WR_RH_PORTSTAT(x)      writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT                     readl(&ohci->regs->roothub.status)
-#define RD_RH_PORTSTAT         readl(&ohci->regs->roothub.portstatus[wIndex-1])
-
-/* request to virtual root hub */
-
-static int rh_submit_urb (urb_t * urb)
-{
-       struct usb_device * usb_dev = urb->dev;
-       ohci_t * ohci = usb_dev->bus->hcpriv;
-       unsigned int pipe = urb->pipe;
-       devrequest * cmd = (devrequest *) urb->setup_packet;
-       void * data = urb->transfer_buffer;
-       int leni = urb->transfer_buffer_length;
-       int len = 0;
-       int status = TD_CC_NOERROR;
-       
-       __u8 datab[16];
-       __u8  * data_buf = datab;
-       
-       __u16 bmRType_bReq;
-       __u16 wValue; 
-       __u16 wIndex;
-       __u16 wLength;
-
-       if (usb_pipeint(pipe)) {
-       
-               ohci->rh.urb =  urb;
-               ohci->rh.send = 1;
-               ohci->rh.interval = urb->interval;
-               rh_init_int_timer(urb);
-               urb->status = cc_to_error [TD_CC_NOERROR];
-               
-               return 0;
-       }
-
-       bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
-       wValue        = le16_to_cpu (cmd->value);
-       wIndex        = le16_to_cpu (cmd->index);
-       wLength       = le16_to_cpu (cmd->length);
-       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 (RD_RH_STAT & 0x7fff7fff); OK (4);
-               case RH_GET_STATUS | RH_OTHER | RH_CLASS:       
-                               *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); 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): 
-                                               WR_RH_STAT(RH_HS_OCIC); OK (0);
-                       }
-                       break;
-               
-               case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-                       switch (wValue) {
-                               case (RH_PORT_ENABLE):                  
-                                               WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
-                               case (RH_PORT_SUSPEND):                 
-                                               WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
-                               case (RH_PORT_POWER):                   
-                                               WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
-                               case (RH_C_PORT_CONNECTION):    
-                                               WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
-                               case (RH_C_PORT_ENABLE):                
-                                               WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
-                               case (RH_C_PORT_SUSPEND):               
-                                               WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
-                               case (RH_C_PORT_OVER_CURRENT):  
-                                               WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
-                               case (RH_C_PORT_RESET):                 
-                                               WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); 
-                       }
-                       break;
-               case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-                       switch (wValue) {
-                               case (RH_PORT_SUSPEND):                 
-                                               WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 
-                               case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
-                                               if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PRS ); OK (0);
-                               case (RH_PORT_POWER):                   
-                                               WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 
-                               case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
-                                               if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PES ); OK (0);
-                       }
-                       break;
-
-               case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
-
-               case RH_GET_DESCRIPTOR:
-                       switch ((wValue & 0xff00) >> 8) {
-                               case (0x01): /* device descriptor */
-                                       len = min (leni, min (sizeof (root_hub_dev_des), wLength));
-                                       data_buf = root_hub_dev_des; OK(len);
-                               case (0x02): /* configuration descriptor */
-                                       len = min (leni, min (sizeof (root_hub_config_des), wLength));
-                                       data_buf = root_hub_config_des; OK(len);
-                               case (0x03): /* string descriptors */
-                               default: 
-                                       status = TD_CC_STALL;
-                       }
-                       break;
-               
-               case RH_GET_DESCRIPTOR | RH_CLASS:
-                       *(__u8 *)  (data_buf+1) = 0x29;
-                       *(__u32 *) (data_buf+2) = cpu_to_le32 (readl (&ohci->regs->roothub.a));  
-                       *(__u8 *)  data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */
-                                
-                       len = min (leni, min(*(__u8 *) data_buf, wLength));
-                       *(__u8 *) (data_buf+6) = 0; /* Root Hub needs no current from bus */
-                       if (*(__u8 *) (data_buf+2) < 8) { /* less than 8 Ports */
-                               *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff; 
-                               *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16; 
-                       } else {
-                               *(__u32 *) (data_buf+7) = cpu_to_le32 (readl(&ohci->regs->roothub.b)); 
-                       }
-                       OK (len); 
-               case RH_GET_CONFIGURATION:      *(__u8 *) data_buf = 0x01; OK (1);
-
-               case RH_SET_CONFIGURATION:      WR_RH_STAT (0x10000); OK (0);
-
-               default: 
-                       status = TD_CC_STALL;
-       }
-       
-       dbg("USB HC roothubstat1: %x", readl ( &(ohci->regs->roothub.portstatus[0]) ));
-       dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
-
-       len = min(len, leni);
-       memcpy (data, data_buf, len);
-       urb->actual_length = len;
-       urb->status = cc_to_error [status];
-       
-#ifdef DEBUG
-       urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
-#endif
-
-       if (urb->complete) urb->complete (urb);
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int rh_unlink_urb (urb_t * urb)
-{
-       ohci_t * ohci = urb->dev->bus->hcpriv;
-       ohci->rh.send = 0;
-       del_timer (&ohci->rh.rh_int_timer);
-       return 0;
-}
-/*-------------------------------------------------------------------------*
- * HC functions
- *-------------------------------------------------------------------------*/
-
-/* reset the HC not the BUS */
-
-static void hc_reset (ohci_t * ohci)
-{
-       int timeout = 30;
-       int smm_timeout = 50; /* 0,5 sec */
-               
-       if (readl (&ohci->regs->control) & 0x100) { /* SMM owns the HC */
-               writel (0x08, &ohci->regs->cmdstatus); /* request ownership */
-               dbg("USB HC TakeOver from SMM");
-               while (readl (&ohci->regs->control) & 0x100) {
-                       wait_ms (10);
-                       if (--smm_timeout == 0) {
-                               err("USB HC TakeOver failed!");
-                               break;
-                       }
-               }
-       }       
-               
-       writel ((1 << 31), &ohci->regs->intrdisable); /* Disable HC interrupts */
-       dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
-       /* this seems to be needed for the lucent controller on powerbooks.. */
-       writel (0, &ohci->regs->control);           /* Move USB to reset state */
-       
-       writel (1,  &ohci->regs->cmdstatus);       /* HC Reset */
-       while ((readl (&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
-               if (--timeout == 0) {
-                       err("USB HC reset timed out!");
-                       return;
-               }       
-               udelay (1);
-       }        
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Start an OHCI controller, set the BUS operational
- * enable interrupts 
- * connect the virtual root hub */
-
-static int hc_start (ohci_t * ohci)
-{
-       unsigned int mask;
-       unsigned int fminterval;
-       struct usb_device  * usb_dev;
-       struct ohci_device * dev;
-       
-       /* Tell the controller where the control and bulk lists are
-        * The lists are empty now. */
-        
-       writel (0, &ohci->regs->ed_controlhead);
-       writel (0, &ohci->regs->ed_bulkhead);
-       
-       writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
-   
-       fminterval = 0x2edf;
-       writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
-       fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 
-       writel (fminterval, &ohci->regs->fminterval);   
-       writel (0x628, &ohci->regs->lsthresh);
-
-       /* Choose the interrupts we care about now, others later on demand */
-       mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO;
-       
-       writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
-       writel (mask, &ohci->regs->intrenable);
-       writel (mask, &ohci->regs->intrstatus);
-
-#ifdef OHCI_USE_NPS
-       writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
-               &ohci->regs->roothub.a);
-       writel (0x10000, &ohci->regs->roothub.status);
-       mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
-#endif /* OHCI_USE_NPS */
-       /* connect the virtual root hub */
-       
-       usb_dev = usb_alloc_dev (NULL, ohci->bus);
-       if (!usb_dev) return -1;
-
-       dev = usb_to_ohci (usb_dev);
-       ohci->bus->root_hub = usb_dev;
-       usb_connect (usb_dev);
-       if (usb_new_device (usb_dev) != 0) {
-               usb_free_dev (usb_dev); 
-               return -1;
-       }
-       
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* an interrupt happens */
-
-static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
-{
-       ohci_t * ohci = __ohci;
-       struct ohci_regs * regs = ohci->regs;
-       int ints; 
-
-       if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) {
-               ints =  OHCI_INTR_WDH;
-       } else { 
-               if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0)
-                       return;
-       } 
-
-       dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
-       
-       if (ints & OHCI_INTR_WDH) {
-               writel (OHCI_INTR_WDH, &regs->intrdisable);     
-               dl_done_list (ohci, dl_reverse_done_list (ohci));
-               writel (OHCI_INTR_WDH, &regs->intrenable); 
-       }
-  
-       if (ints & OHCI_INTR_SO) {
-               dbg("USB Schedule overrun");
-               writel (OHCI_INTR_SO, &regs->intrenable);        
-       }
-
-       if (ints & OHCI_INTR_SF) { 
-               unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
-               writel (OHCI_INTR_SF, &regs->intrdisable);      
-               if (ohci->ed_rm_list[!frame] != NULL) {
-                       dl_del_list (ohci, !frame);
-               }
-               if (ohci->ed_rm_list[frame] != NULL) writel (OHCI_INTR_SF, &regs->intrenable);  
-       }
-       writel (ints, &regs->intrstatus);
-       writel (OHCI_INTR_MIE, &regs->intrenable);      
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* allocate OHCI */
-
-static ohci_t * hc_alloc_ohci (void * mem_base)
-{
-       int i;
-       ohci_t * ohci;
-       struct usb_bus * bus;
-
-       ohci = (ohci_t *) __get_free_pages (GFP_KERNEL, 1);
-       if (!ohci)
-               return NULL;
-               
-       memset (ohci, 0, sizeof (ohci_t));
-       
-       ohci->irq = -1;
-       ohci->regs = mem_base;   
-
-       /* for load ballancing of the interrupt branches */
-       for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-       for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
-       
-       /* end of control and bulk lists */      
-       ohci->ed_isotail     = NULL;
-       ohci->ed_controltail = NULL;
-       ohci->ed_bulktail    = NULL;
-
-       bus = usb_alloc_bus (&sohci_device_operations);
-       if (!bus) {
-               free_pages ((unsigned long) ohci, 1);
-               return NULL;
-       }
-
-       ohci->bus = bus;
-       bus->hcpriv = (void *) ohci;
-       return ohci;
-} 
-
-/*-------------------------------------------------------------------------*/
-
-/* De-allocate all resources.. */
-
-static void hc_release_ohci (ohci_t * ohci)
-{      
-       dbg("USB HC release ohci");
-
-       /* disconnect all devices */    
-       if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub);
-       
-       hc_reset (ohci);
-       writel (OHCI_USB_RESET, &ohci->regs->control);
-       wait_ms (10);
-       
-       if (ohci->irq >= 0) {
-               free_irq (ohci->irq, ohci);
-               ohci->irq = -1;
-       }
-
-       usb_deregister_bus (ohci->bus);
-       usb_free_bus (ohci->bus);
-    
-       /* unmap the IO address space */
-       iounmap (ohci->regs);
-       
-       free_pages ((unsigned long) ohci, 1);   
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Increment the module usage count, start the control thread and
- * return success. */
-static int hc_found_ohci (int irq, void * mem_base)
-{
-       ohci_t * ohci;
-       dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base);
-    
-       ohci = hc_alloc_ohci (mem_base);
-       if (!ohci) {
-               return -ENOMEM;
-       }
-       
-       INIT_LIST_HEAD (&ohci->ohci_hcd_list);
-       list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
-       
-       hc_reset (ohci);
-       writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
-       wait_ms (10);
-       usb_register_bus (ohci->bus);
-       
-       if (request_irq (irq, hc_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
-               ohci->irq = irq;     
-               hc_start (ohci);
-               return 0;
-       }       
-       err("request interrupt %d failed", irq);
-       hc_release_ohci (ohci);
-       return -EBUSY;
-}
-
-/*-------------------------------------------------------------------------*/
-static int hc_start_ohci (struct pci_dev * dev)
-{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-       unsigned long mem_base = dev->resource[0].start;
-#else
-       unsigned long mem_base = dev->base_address[0];
-       if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
-       mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
-#endif
-       
-       pci_set_master (dev);
-       mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
-
-       if (!mem_base) {
-               err("Error mapping OHCI memory");
-               return -EFAULT;
-       }
-       return hc_found_ohci (dev->irq, (void *) mem_base);
-} 
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef CONFIG_PMAC_PBOOK
-
-/* On Powerbooks, put the controller into suspend mode when going
- * to sleep, and do a resume when waking up. */
-
-static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
-{
-       struct list_head * ohci_l;
-       ohci_t * ohci;
-       
-       for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
-       ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-
-               switch (when) {
-               case PBOOK_SLEEP_NOW:
-                       disable_irq (ohci->irq);
-                       writel (ohci->hc_control = OHCI_USB_SUSPEND, &ohci->regs->control);
-                       wait_ms (10);
-                       break;
-               case PBOOK_WAKE:
-                       writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
-                       wait_ms (20);
-                       writel (ohci->hc_control = 0xBF, &ohci->regs->control);
-                       enable_irq (ohci->irq);
-                       break;
-               }
-       }
-       return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier ohci_sleep_notifier = {
-       ohci_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_APM
-static int handle_apm_event (apm_event_t event) 
-{
-       static int down = 0;
-       ohci_t * ohci;
-       struct list_head * ohci_l;
-       
-       switch (event) {
-       case APM_SYS_SUSPEND:
-       case APM_USER_SUSPEND:
-               if (down) {
-                       dbg("received extra suspend event");
-                       break;
-               }
-               for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
-                       ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-                       dbg("USB-Bus suspend: %p", ohci);
-                       writel (ohci->hc_control = 0xFF, &ohci->regs->control);
-               }
-               wait_ms (10);
-               down = 1;
-               break;
-       case APM_NORMAL_RESUME:
-       case APM_CRITICAL_RESUME:
-               if (!down) {
-                       dbg("received bogus resume event");
-                       break;
-               }
-               for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
-                       ohci = list_entry(ohci_l, ohci_t, ohci_hcd_list);
-                       dbg("USB-Bus resume: %p", ohci);
-                       writel (ohci->hc_control = 0x7F, &ohci->regs->control);
-               }               
-               wait_ms (20);
-               for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
-                       ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-                       writel (ohci->hc_control = 0xBF, &ohci->regs->control);
-               }
-               down = 0;
-               break;
-       }
-       return 0;
-}
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
-int ohci_hcd_init (void) 
-{
-       int ret = -ENODEV;
-       struct pci_dev * dev = NULL;
-       while ((dev = pci_find_class (PCI_CLASS_SERIAL_USB_OHCI, dev))) { 
-               if (hc_start_ohci(dev) >= 0) ret = 0;
-       }
-    
-#ifdef CONFIG_APM
-       apm_register_callback (&handle_apm_event);
-#endif
-
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_register_sleep_notifier (&ohci_sleep_notifier);
-#endif  
-    return ret;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef MODULE
-int init_module (void) 
-{
-       return ohci_hcd_init ();
-}
-
-/*-------------------------------------------------------------------------*/
-
-void cleanup_module (void) 
-{      
-       ohci_t * ohci;
-       
-#ifdef CONFIG_APM
-       apm_unregister_callback (&handle_apm_event);
-#endif
-
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
-#endif  
-
-       while (!list_empty (&ohci_hcd_list)) {
-               ohci = list_entry (ohci_hcd_list.next, ohci_t, ohci_hcd_list);
-               list_del (&ohci->ohci_hcd_list);
-               INIT_LIST_HEAD (&ohci->ohci_hcd_list);
-               hc_release_ohci (ohci);
-       }               
-}
-#endif //MODULE
-
diff --git a/drivers/usb/ohci-hcd.h b/drivers/usb/ohci-hcd.h
deleted file mode 100644 (file)
index f3d7115..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
- /*
- * URB OHCI HCD (Host Controller Driver) for USB.
- * 
- *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * 
- * ohci-hcd.h
- * 
- */
-
-#define MODSTR "ohci: "
-
-
-static int cc_to_error[16] = { 
-
-/* mapping of the OHCI CC status to error codes */ 
-#ifdef USB_ST_CRC /* status codes */
-       /* No  Error  */               USB_ST_NOERROR,
-       /* CRC Error  */               USB_ST_CRC,
-       /* Bit Stuff  */               USB_ST_BITSTUFF,
-       /* Data Togg  */               USB_ST_CRC,
-       /* Stall      */               USB_ST_STALL,
-       /* DevNotResp */               USB_ST_NORESPONSE,
-       /* PIDCheck   */               USB_ST_BITSTUFF,
-       /* UnExpPID   */               USB_ST_BITSTUFF,
-       /* DataOver   */               USB_ST_DATAOVERRUN,
-       /* DataUnder  */               USB_ST_DATAUNDERRUN,
-       /* reservd    */               USB_ST_NORESPONSE,
-       /* reservd    */               USB_ST_NORESPONSE,
-       /* BufferOver */               USB_ST_BUFFEROVERRUN,
-       /* BuffUnder  */               USB_ST_BUFFERUNDERRUN,
-       /* Not Access */               USB_ST_NORESPONSE,
-       /* Not Access */               USB_ST_NORESPONSE 
-};
-
-#else  /* error codes */
-       /* No  Error  */               0,
-       /* CRC Error  */               -EILSEQ,
-       /* Bit Stuff  */               -EPROTO,
-       /* Data Togg  */               -EILSEQ,
-       /* Stall      */               -EPIPE,
-       /* DevNotResp */               -ETIMEDOUT,
-       /* PIDCheck   */               -EPROTO,
-       /* UnExpPID   */               -EPROTO,
-       /* DataOver   */               -EOVERFLOW,
-       /* DataUnder  */               -EREMOTEIO,
-       /* reservd    */               -ETIMEDOUT,
-       /* reservd    */               -ETIMEDOUT,
-       /* BufferOver */               -ECOMM,
-       /* BuffUnder  */               -ECOMM,
-       /* Not Access */               -ETIMEDOUT,
-       /* Not Access */               -ETIMEDOUT  
-};
-#define USB_ST_URB_PENDING             -EINPROGRESS
-#endif
-
-
-struct ed;
-struct td;
-/* for ED and TD structures */
-
-/* ED States */
-
-#define ED_NEW                 0x00
-#define ED_UNLINK      0x01
-#define ED_OPER                0x02
-#define ED_DEL         0x04
-#define ED_URB_DEL  0x08
-
-/* usb_ohci_ed */
-typedef struct ed {
-       __u32 hwINFO;       
-       __u32 hwTailP;
-       __u32 hwHeadP;
-       __u32 hwNextED;
-
-       struct ed * ed_prev;  
-       __u8 int_period;
-       __u8 int_branch;
-       __u8 int_load; 
-       __u8 int_interval;
-       __u8 state;
-       __u8 type; 
-       __u16 last_iso;
-    struct ed * ed_rm_list;
-   
-} ed_t;
-
-/* TD info field */
-#define TD_CC       0xf0000000
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC       0x0C000000
-#define TD_T        0x03000000
-#define TD_T_DATA0  0x02000000
-#define TD_T_DATA1  0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R        0x00040000
-#define TD_DI       0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP       0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN    0x00100000
-#define TD_DP_OUT   0x00080000
-
-#define TD_ISO         0x00010000
-#define TD_DEL      0x00020000
-
-/* CC Codes */
-#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
-
-
-#define MAXPSW 1
-
-typedef struct td { 
-       __u32 hwINFO;
-       __u32 hwCBP;            /* Current Buffer Pointer */
-       __u32 hwNextTD;         /* Next TD Pointer */
-       __u32 hwBE;             /* Memory Buffer End Pointer */
-       __u16 hwPSW[MAXPSW];
-
-       __u8 type;
-       __u8 index;
-       struct ed * ed;
-       struct td * next_dl_td;
-       urb_t * urb;
-} td_t;
-
-
-/* TD types */
-#define BULK           0x03
-#define INT                    0x01
-#define CTRL           0x02
-#define ISO                    0x00
-#define SEND            0x01
-#define ST_ADDR         0x02
-#define ADD_LEN         0x04
-#define DEL             0x08
-
-
-#define OHCI_ED_SKIP   (1 << 14)
-
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of.  It must be 256-byte aligned.
- */
-#define NUM_INTS 32    /* part of the OHCI standard */
-struct ohci_hcca {
-    __u32      int_table[NUM_INTS];    /* Interrupt ED table */
-       __u16   frame_no;               /* current frame number */
-       __u16   pad1;                   /* set to 0 on each frame_no change */
-       __u32   done_head;              /* info returned for an interrupt */
-       u8              reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-  
-/*
- * Maximum number of root hub ports.  
- */
-#define MAX_ROOT_PORTS 15      /* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region.  This is Memory Mapped I/O.  You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
-       /* control and status registers */
-       __u32   revision;
-       __u32   control;
-       __u32   cmdstatus;
-       __u32   intrstatus;
-       __u32   intrenable;
-       __u32   intrdisable;
-       /* memory pointers */
-       __u32   hcca;
-       __u32   ed_periodcurrent;
-       __u32   ed_controlhead;
-       __u32   ed_controlcurrent;
-       __u32   ed_bulkhead;
-       __u32   ed_bulkcurrent;
-       __u32   donehead;
-       /* frame counters */
-       __u32   fminterval;
-       __u32   fmremaining;
-       __u32   fmnumber;
-       __u32   periodicstart;
-       __u32   lsthresh;
-       /* Root hub ports */
-       struct  ohci_roothub_regs {
-               __u32   a;
-               __u32   b;
-               __u32   status;
-               __u32   portstatus[MAX_ROOT_PORTS];
-       } roothub;
-} __attribute((aligned(32)));
-
-/*
- * cmdstatus register */
-#define OHCI_CLF  0x02
-#define OHCI_BLF  0x04
-
-/*
- * Interrupt register masks
- */
-#define OHCI_INTR_SO   (1)
-#define OHCI_INTR_WDH  (1 << 1)
-#define OHCI_INTR_SF   (1 << 2)
-#define OHCI_INTR_RD   (1 << 3)
-#define OHCI_INTR_UE   (1 << 4)
-#define OHCI_INTR_FNO  (1 << 5)
-#define OHCI_INTR_RHSC (1 << 6)
-#define OHCI_INTR_OC   (1 << 30)
-#define OHCI_INTR_MIE  (1 << 31)
-
-/*
- * Control register masks
- */
-#define OHCI_USB_RESET         0
-#define OHCI_USB_RESUME     (1 << 6)
-#define OHCI_USB_OPER          (2 << 6)
-#define OHCI_USB_SUSPEND       (3 << 6)
-
-
-/* Virtual Root HUB */
-struct virt_root_hub {
-       int devnum; /* Address of Root Hub endpoint */ 
-       void * urb;
-       void * int_addr;
-       int send;
-       int interval;
-       struct timer_list rh_int_timer;
-};
-/* 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
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
-/* Root-Hub Register info */
-
-#define RH_PS_CCS            0x00000001   
-#define RH_PS_PES            0x00000002   
-#define RH_PS_PSS            0x00000004   
-#define RH_PS_POCI           0x00000008   
-#define RH_PS_PRS            0x00000010  
-#define RH_PS_PPS            0x00000100   
-#define RH_PS_LSDA           0x00000200    
-#define RH_PS_CSC            0x00010000 
-#define RH_PS_PESC           0x00020000   
-#define RH_PS_PSSC           0x00040000    
-#define RH_PS_OCIC           0x00080000    
-#define RH_PS_PRSC           0x00100000   
-
-/* Root hub status bits */
-#define RH_HS_LPS           0x00000001
-#define RH_HS_OCI           0x00000002
-#define RH_HS_DRWE          0x00008000
-#define RH_HS_LPSC          0x00010000
-#define RH_HS_OCIC          0x00020000
-#define RH_HS_CRWE          0x80000000
-
-#define min(a,b) (((a)<(b))?(a):(b))  
-
-/* urb */
-typedef struct 
-{
-       ed_t * ed;
-       __u16 length;   // number of tds associated with this request
-       __u16 td_cnt;   // number of tds already serviced
-       int   state;
-       void * wait;
-       td_t * td[0];   // list pointer to all corresponding TDs associated with this request
-
-} urb_priv_t;
-#define URB_DEL 1
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-
-
-typedef struct ohci {
-       struct ohci_hcca hcca;                                  /* hcca */                
-
-       int irq;
-       struct ohci_regs * regs;                                        /* OHCI controller's memory */  
-    struct list_head ohci_hcd_list;         /* list of all ohci_hcd */           
-
-       struct ohci * next;             // chain of uhci device contexts
-       struct list_head urb_list;      // list of all pending urbs
-       spinlock_t urb_list_lock;       // lock to keep consistency 
-  
-       int ohci_int_load[32];                  /* load of the 32 Interrupt Chains (for load ballancing)*/     
-       ed_t * ed_rm_list[2];     /* lists of all endpoints to be removed */
-       ed_t * ed_bulktail;       /* last endpoint of bulk list */
-       ed_t * ed_controltail;    /* last endpoint of control list */
-       ed_t * ed_isotail;        /* last endpoint of iso list */
-       int intrstatus;
-       __u32 hc_control;                                               /* copy of the hc control reg */  
-       struct usb_bus * bus;    
-       struct usb_device * dev[128];
-       struct virt_root_hub rh;
-} ohci_t;
-
-
-#define NUM_TDS        0               /* num of preallocated transfer descriptors */
-#define NUM_EDS 32             /* num of preallocated endpoint descriptors */
-
-struct ohci_device {
-       ed_t    ed[NUM_EDS];
-       int ed_cnt;
-       void  * wait;
-};
-
-// #define ohci_to_usb(ohci)   ((ohci)->usb)
-#define usb_to_ohci(usb)       ((struct ohci_device *)(usb)->hcpriv)
-
-/* hcd */
-/* endpoint */
-static int ep_link(ohci_t * ohci, ed_t * ed);
-static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load);
-static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
-/* td */
-static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int type, int index);
-static void td_submit_urb(urb_t * urb);
-/* root hub */
-static int rh_submit_urb(urb_t * urb);
-static int rh_unlink_urb(urb_t * urb);
-static int rh_init_int_timer(urb_t * urb);
-
-#ifdef DEBUG
-#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d: %4x\n", -- __ohci_free_cnt, (unsigned int) x)
-#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); printk("OHCI ALLO: %d: %4x\n", ++ __ohci_free_cnt,(unsigned int) x)
-static int __ohci_free_cnt = 0;
-#else
-#define OHCI_FREE(x) kfree(x) 
-#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) 
-#endif
diff --git a/drivers/usb/uhci-debug.c b/drivers/usb/uhci-debug.c
deleted file mode 100644 (file)
index 2ecd611..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * $Id: uhci-debug.c,v 1.12 1999/12/13 15:24:42 fliegl Exp $
- */
-
-#include <linux/version.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#define DEBUG
-
-#include "usb.h"
-#include "uhci.h"
-
-void dump_urb (purb_t purb)
-{
-       dbg("urb                   :%p", purb);
-       dbg("next                  :%p", purb->next);
-       dbg("dev                   :%p", purb->dev);
-       dbg("pipe                  :%08X", purb->pipe);
-       dbg("status                :%d", purb->status);
-       dbg("transfer_flags        :%08X", purb->transfer_flags);
-       dbg("transfer_buffer       :%p", purb->transfer_buffer);
-       dbg("transfer_buffer_length:%d", purb->transfer_buffer_length);
-       dbg("actual_length         :%d", purb->actual_length);
-       dbg("setup_packet          :%p", purb->setup_packet);
-       dbg("start_frame           :%d", purb->start_frame);
-       dbg("number_of_packets     :%d", purb->number_of_packets);
-       dbg("interval              :%d", purb->interval);
-       dbg("error_count           :%d", purb->error_count);
-       dbg("context               :%p", purb->context);
-       dbg("complete              :%p", purb->complete);
-}
-
-void beep (long freq)
-{
-       long v;
-       char low, high;
-
-       if (!freq)
-               outb (inb (0x61) & 252, 0x61);
-       else {
-               outb (inb (0x61) | 0x3, 0x61);
-
-               v = 1193180L / freq;
-
-               low = (char) (v & 255);
-               high = (char) ((v >> 8) & 255);
-
-               outb (182, 0x43);
-               outb (low, 0x42);
-               outb (high, 0x42);
-       }
-}
-
-void uhci_show_qh (puhci_desc_t qh)
-{
-       if (qh->type != QH_TYPE) {
-               dbg("qh has not QH_TYPE");
-               return;
-       }
-       dbg("uhci_show_qh %p (%08lX):", qh, virt_to_bus (qh));
-
-       if (qh->hw.qh.head & UHCI_PTR_TERM)
-               dbg("Head Terminate");
-       else {
-               if (qh->hw.qh.head & UHCI_PTR_QH)
-                       dbg("Head points to QH");
-               else
-                       dbg("Head points to TD");
-
-               dbg("head: %08X", qh->hw.qh.head & ~UHCI_PTR_BITS);
-       }
-       if (qh->hw.qh.element & UHCI_PTR_TERM)
-               dbg("Element Terminate");
-       else {
-
-               if (qh->hw.qh.element & UHCI_PTR_QH)
-                       dbg("Element points to QH");
-               else
-                       dbg("Element points to TD");
-               dbg("element: %08X", qh->hw.qh.element & ~UHCI_PTR_BITS);
-       }
-}
-
-void uhci_show_td (puhci_desc_t td)
-{
-       char *spid;
-
-       switch (td->hw.td.info & 0xff) {
-       case USB_PID_SETUP:
-               spid = "SETUP";
-               break;
-       case USB_PID_OUT:
-               spid = " OUT ";
-               break;
-       case USB_PID_IN:
-               spid = " IN  ";
-               break;
-       default:
-               spid = "  ?  ";
-               break;
-       }
-
-       dbg("uhci_show_td %p (%08lX) MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)",
-            td,
-            virt_to_bus(td),
-            td->hw.td.info >> 21,
-            ((td->hw.td.info >> 19) & 1),
-            (td->hw.td.info >> 15) & 15,
-            (td->hw.td.info >> 8) & 127,
-            (td->hw.td.info & 0xff),
-            spid,
-            td->hw.td.buffer);
-
-       dbg("Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
-            td->hw.td.status & 0x7ff,
-            ((td->hw.td.status >> 27) & 3),
-            (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
-            (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
-            (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
-            (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
-            (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
-            (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
-            (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
-            (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
-            (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
-            (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
-               );
-
-       if (td->hw.td.link & UHCI_PTR_TERM)
-               dbg("Link Terminate");
-       else {
-               if (td->hw.td.link & UHCI_PTR_QH)
-                       dbg("%s, link points to QH @ %08x",
-                            (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
-                            td->hw.td.link & ~UHCI_PTR_BITS);
-               else
-                       dbg("%s, link points to TD @ %08x",
-                            (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
-                            td->hw.td.link & ~UHCI_PTR_BITS);
-       }
-}
-
-void uhci_show_td_queue (puhci_desc_t td)
-{
-       dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td));
-       while (1) {
-               uhci_show_td (td);
-               if (td->hw.td.link & UHCI_PTR_TERM)
-                       break;
-               //if(!(td->hw.td.link&UHCI_PTR_DEPTH))
-               //      break;
-               if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
-                       td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
-               else {
-                       dbg("td points to itself!");
-                       break;
-               }
-//              schedule();
-       }
-}
-
-void uhci_show_queue (puhci_desc_t qh)
-{
-       dbg("uhci_show_queue %p:", qh);
-       while (1) {
-               uhci_show_qh (qh);
-
-               if (qh->hw.qh.element & UHCI_PTR_QH)
-                       dbg("Warning: qh->element points to qh!");
-               else if (!(qh->hw.qh.element & UHCI_PTR_TERM))
-                       uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
-
-               if (qh->hw.qh.head & UHCI_PTR_TERM)
-                       break;
-
-               if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
-                       qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
-               else {
-                       dbg("qh points to itself!");
-                       break;
-               }
-       }
-}
-
-static void uhci_show_sc (int port, unsigned short status)
-{
-       dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
-            port,
-            status,
-            (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
-            (status & USBPORTSC_PR) ? "PortReset " : "",
-            (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
-            (status & USBPORTSC_RD) ? "ResumeDetect " : "",
-            (status & USBPORTSC_PEC) ? "EnableChange " : "",
-            (status & USBPORTSC_PE) ? "PortEnabled " : "",
-            (status & USBPORTSC_CSC) ? "ConnectChange " : "",
-            (status & USBPORTSC_CCS) ? "PortConnected " : "");
-}
-
-void uhci_show_status (puhci_t s)
-{
-       unsigned int io_addr = s->io_addr;
-       unsigned short usbcmd, usbstat, usbint, usbfrnum;
-       unsigned int flbaseadd;
-       unsigned char sof;
-       unsigned short portsc1, portsc2;
-
-       usbcmd = inw (io_addr + 0);
-       usbstat = inw (io_addr + 2);
-       usbint = inw (io_addr + 4);
-       usbfrnum = inw (io_addr + 6);
-       flbaseadd = inl (io_addr + 8);
-       sof = inb (io_addr + 12);
-       portsc1 = inw (io_addr + 16);
-       portsc2 = inw (io_addr + 18);
-
-       dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
-            usbcmd,
-            (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
-            (usbcmd & USBCMD_CF) ? "CF " : "",
-            (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
-            (usbcmd & USBCMD_FGR) ? "FGR " : "",
-            (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
-            (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
-            (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
-            (usbcmd & USBCMD_RS) ? "RS " : "");
-
-       dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
-            usbstat,
-            (usbstat & USBSTS_HCH) ? "HCHalted " : "",
-            (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
-            (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
-            (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
-            (usbstat & USBSTS_ERROR) ? "USBError " : "",
-            (usbstat & USBSTS_USBINT) ? "USBINT " : "");
-
-       dbg("  usbint    =     %04x", usbint);
-       dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
-            0xfff & (4 * (unsigned int) usbfrnum));
-       dbg("  flbaseadd = %08x", flbaseadd);
-       dbg("  sof       =       %02x", sof);
-       uhci_show_sc (1, portsc1);
-       uhci_show_sc (2, portsc2);
-}
index aebc836aa97bb8cc36682e2e040641f7cb8b5ac5..b4a64413553bad0393e7e39b7b71bb9532d212f8 100644 (file)
@@ -1,7 +1,195 @@
-void uhci_show_qh(puhci_desc_t qh);
-void uhci_show_td(puhci_desc_t td);
-void uhci_show_td_queue(puhci_desc_t td);
-void uhci_show_queue(puhci_desc_t qh);
-void uhci_show_status(puhci_t s);
-void beep(long freq);
-void dump_urb (purb_t purb);
\ No newline at end of file
+#ifdef DEBUG
+
+static void uhci_show_qh (puhci_desc_t qh)
+{
+       if (qh->type != QH_TYPE) {
+               printk (KERN_DEBUG MODSTR "qh has not QH_TYPE\n");
+               return;
+       }
+       printk (KERN_DEBUG MODSTR "uhci_show_qh %p (%08lX):\n", qh, virt_to_bus (qh));
+
+       if (qh->hw.qh.head & UHCI_PTR_TERM)
+               printk (KERN_DEBUG MODSTR "Head Terminate\n");
+       else {
+               if (qh->hw.qh.head & UHCI_PTR_QH)
+                       printk (KERN_DEBUG MODSTR "Head points to QH\n");
+               else
+                       printk (KERN_DEBUG MODSTR "Head points to TD\n");
+
+               printk (KERN_DEBUG MODSTR "head: %08X\n", qh->hw.qh.head & ~UHCI_PTR_BITS);
+       }
+       if (qh->hw.qh.element & UHCI_PTR_TERM)
+               printk (KERN_DEBUG MODSTR "Element Terminate\n");
+       else {
+
+               if (qh->hw.qh.element & UHCI_PTR_QH)
+                       printk (KERN_DEBUG MODSTR "Element points to QH\n");
+               else
+                       printk (KERN_DEBUG MODSTR "Element points to TD\n");
+               printk (KERN_DEBUG MODSTR "element: %08X\n", qh->hw.qh.element & ~UHCI_PTR_BITS);
+       }
+}
+#endif
+
+static void uhci_show_td (puhci_desc_t td)
+{
+       char *spid;
+       printk (KERN_DEBUG MODSTR "uhci_show_td %p (%08lX) ", td, virt_to_bus (td));
+
+       switch (td->hw.td.info & 0xff) {
+       case USB_PID_SETUP:
+               spid = "SETUP";
+               break;
+       case USB_PID_OUT:
+               spid = " OUT ";
+               break;
+       case USB_PID_IN:
+               spid = " IN  ";
+               break;
+       default:
+               spid = "  ?  ";
+               break;
+       }
+
+       printk ("MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)\n",
+            td->hw.td.info >> 21,
+            ((td->hw.td.info >> 19) & 1),
+            (td->hw.td.info >> 15) & 15,
+            (td->hw.td.info >> 8) & 127,
+            (td->hw.td.info & 0xff),
+            spid,
+            td->hw.td.buffer);
+
+       printk (KERN_DEBUG MODSTR "Len=%02x e%d %s%s%s%s%s%s%s%s%s%s\n",
+            td->hw.td.status & 0x7ff,
+            ((td->hw.td.status >> 27) & 3),
+            (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
+            (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
+            (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
+            (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
+            (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
+            (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+            (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
+            (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
+            (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+            (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
+               );
+#if 1
+       if (td->hw.td.link & UHCI_PTR_TERM)
+               printk (KERN_DEBUG MODSTR "Link Terminate\n");
+       else {
+               if (td->hw.td.link & UHCI_PTR_QH)
+                       printk (KERN_DEBUG MODSTR "%s, link points to QH @ %08x\n",
+                            (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
+                            td->hw.td.link & ~UHCI_PTR_BITS);
+               else
+                       printk (KERN_DEBUG MODSTR "%s, link points to TD @ %08x \n",
+                            (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
+                            td->hw.td.link & ~UHCI_PTR_BITS);
+       }
+#endif
+}
+#ifdef DEBUG
+static void uhci_show_td_queue (puhci_desc_t td)
+{
+       printk (KERN_DEBUG MODSTR "uhci_show_td_queue %p (%08lX):\n", td, virt_to_bus (td));
+       while (1) {
+               uhci_show_td (td);
+               if (td->hw.td.link & UHCI_PTR_TERM)
+                       break;
+               //if(!(td->hw.td.link&UHCI_PTR_DEPTH))
+               //      break;
+               if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
+                       td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
+               else {
+                       printk (KERN_DEBUG MODSTR "td points to itself!\n");
+                       break;
+               }
+//              schedule();
+       }
+}
+
+static void uhci_show_queue (puhci_desc_t qh)
+{
+       printk (KERN_DEBUG MODSTR "uhci_show_queue %p:\n", qh);
+       while (1) {
+               uhci_show_qh (qh);
+
+               if (qh->hw.qh.element & UHCI_PTR_QH)
+                       printk (KERN_DEBUG MODSTR "Warning: qh->element points to qh!\n");
+               else if (!(qh->hw.qh.element & UHCI_PTR_TERM))
+                       uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+
+               if (qh->hw.qh.head & UHCI_PTR_TERM)
+                       break;
+
+               if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
+                       qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
+               else {
+                       printk (KERN_DEBUG MODSTR "qh points to itself!\n");
+                       break;
+               }
+       }
+}
+
+static void uhci_show_sc (int port, unsigned short status)
+{
+       printk ("  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+            port,
+            status,
+            (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+            (status & USBPORTSC_PR) ? "PortReset " : "",
+            (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+            (status & USBPORTSC_RD) ? "ResumeDetect " : "",
+            (status & USBPORTSC_PEC) ? "EnableChange " : "",
+            (status & USBPORTSC_PE) ? "PortEnabled " : "",
+            (status & USBPORTSC_CSC) ? "ConnectChange " : "",
+            (status & USBPORTSC_CCS) ? "PortConnected " : "");
+}
+
+void uhci_show_status (puhci_t s)
+{
+       unsigned int io_addr = s->io_addr;
+       unsigned short usbcmd, usbstat, usbint, usbfrnum;
+       unsigned int flbaseadd;
+       unsigned char sof;
+       unsigned short portsc1, portsc2;
+
+       usbcmd = inw (io_addr + 0);
+       usbstat = inw (io_addr + 2);
+       usbint = inw (io_addr + 4);
+       usbfrnum = inw (io_addr + 6);
+       flbaseadd = inl (io_addr + 8);
+       sof = inb (io_addr + 12);
+       portsc1 = inw (io_addr + 16);
+       portsc2 = inw (io_addr + 18);
+
+       printk ("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+            usbcmd,
+            (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
+            (usbcmd & USBCMD_CF) ? "CF " : "",
+            (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
+            (usbcmd & USBCMD_FGR) ? "FGR " : "",
+            (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
+            (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
+            (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+            (usbcmd & USBCMD_RS) ? "RS " : "");
+
+       printk ("  usbstat   =     %04x   %s%s%s%s%s%s\n",
+            usbstat,
+            (usbstat & USBSTS_HCH) ? "HCHalted " : "",
+            (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
+            (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
+            (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
+            (usbstat & USBSTS_ERROR) ? "USBError " : "",
+            (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+       printk ("  usbint    =     %04x\n", usbint);
+       printk ("  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
+            0xfff & (4 * (unsigned int) usbfrnum));
+       printk ("  flbaseadd = %08x\n", flbaseadd);
+       printk ("  sof       =       %02x\n", sof);
+       uhci_show_sc (1, portsc1);
+       uhci_show_sc (2, portsc2);
+}
+#endif
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
deleted file mode 100644 (file)
index 09dc042..0000000
+++ /dev/null
@@ -1,2336 +0,0 @@
-/* 
- * Universal Host Controller Interface driver for USB (take II).
- *
- * (c) 1999 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
- *          Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
- *          Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
- *          Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
- *          
- * HW-initalization based on material of
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- *
- * $Id: uhci.c,v 1.149 1999/12/26 20:57:14 acher Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/interrupt.h>   /* for in_interrupt() */
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-#include "usb.h"
-#include "uhci.h"
-#include "uhci-debug.h"
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#define __init 
-#define __exit
-#endif
-
-#ifdef __alpha
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-extern long __kernel_thread (unsigned long, int (*)(void *), void *);
-static inline long kernel_thread (int (*fn) (void *), void *arg, unsigned long flags)
-{
-       return __kernel_thread (flags | CLONE_VM, fn, arg);
-}
-#undef CONFIG_APM
-#endif
-#endif
-
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-static int handle_apm_event (apm_event_t event);
-#endif
-
-/* We added an UHCI_SLAB slab support just for debugging purposes. In real 
-   life this compile option is NOT recommended, because slab caches are not 
-   suitable for modules.
-*/
-
-// #define _UHCI_SLAB 
-#ifdef _UHCI_SLAB
-static kmem_cache_t *uhci_desc_kmem;
-static kmem_cache_t *urb_priv_kmem;
-#endif
-
-static int rh_submit_urb (purb_t purb);
-static int rh_unlink_urb (purb_t purb);
-static puhci_t devs = NULL;
-
-/*-------------------------------------------------------------------*/
-static void queue_urb (puhci_t s, struct list_head *p, int do_lock)
-{
-       unsigned long flags=0;
-
-       if (do_lock) 
-               spin_lock_irqsave (&s->urb_list_lock, flags);
-               
-       list_add_tail (p, &s->urb_list);
-       
-       if (do_lock) 
-               spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-
-/*-------------------------------------------------------------------*/
-static void dequeue_urb (puhci_t s, struct list_head *p, int do_lock)
-{
-       unsigned long flags=0;
-       
-       if (do_lock) 
-               spin_lock_irqsave (&s->urb_list_lock, flags);
-
-       list_del (p);
-
-       if (do_lock) 
-               spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-
-/*-------------------------------------------------------------------*/
-static int alloc_td (puhci_desc_t * new, int flags)
-{
-#ifdef _UHCI_SLAB
-       *new= kmem_cache_alloc(uhci_desc_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL);
-#else
-       *new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
-#endif
-       if (!*new)
-               return -ENOMEM;
-       
-       memset (*new, 0, sizeof (uhci_desc_t));
-       (*new)->hw.td.link = UHCI_PTR_TERM | (flags & UHCI_PTR_BITS);   // last by default
-
-       (*new)->type = TD_TYPE;
-       INIT_LIST_HEAD (&(*new)->vertical);
-       INIT_LIST_HEAD (&(*new)->horizontal);
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-/* insert td at last position in td-list of qh (vertical) */
-static int insert_td (puhci_t s, puhci_desc_t qh, puhci_desc_t new, int flags)
-{
-       uhci_desc_t *prev;
-       unsigned long xxx;
-       
-       spin_lock_irqsave (&s->td_lock, xxx);
-
-       list_add_tail (&new->vertical, &qh->vertical);
-
-       if (qh->hw.qh.element & UHCI_PTR_TERM) {
-               // virgin qh without any tds
-               qh->hw.qh.element = virt_to_bus (new);  /* QH's cannot have the DEPTH bit set */
-       }
-       else {
-               // already tds inserted 
-               prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
-               // implicitely remove TERM bit of prev
-               prev->hw.td.link = virt_to_bus (new) | (flags & UHCI_PTR_DEPTH);
-       }
-       
-       spin_unlock_irqrestore (&s->td_lock, xxx);
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-/* insert new_td after td (horizontal) */
-static int insert_td_horizontal (puhci_t s, puhci_desc_t td, puhci_desc_t new, int flags)
-{
-       uhci_desc_t *next;
-       unsigned long xxx;
-       
-       spin_lock_irqsave (&s->td_lock, xxx);
-
-       next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
-       new->hw.td.link = td->hw.td.link;
-       list_add (&new->horizontal, &td->horizontal);
-       td->hw.td.link = virt_to_bus (new);
-       
-       spin_unlock_irqrestore (&s->td_lock, xxx);      
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int unlink_td (puhci_t s, puhci_desc_t element)
-{
-       uhci_desc_t *next, *prev;
-       int dir = 0;
-       unsigned long xxx;
-       
-       spin_lock_irqsave (&s->td_lock, xxx);
-       
-       next = list_entry (element->vertical.next, uhci_desc_t, vertical);
-       
-       if (next == element) {
-               dir = 1;
-               next = list_entry (element->horizontal.next, uhci_desc_t, horizontal);
-               prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-       }
-       else {
-               prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
-       }
-       
-       if (prev->type == TD_TYPE)
-               prev->hw.td.link = element->hw.td.link;
-       else
-               prev->hw.qh.element = element->hw.td.link;
-       
-       wmb ();
-       
-       if (dir == 0)
-               list_del (&element->vertical);
-       else
-               list_del (&element->horizontal);
-       
-       spin_unlock_irqrestore (&s->td_lock, xxx);      
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int delete_desc (puhci_desc_t element)
-{
-#ifdef _UHCI_SLAB
-       kmem_cache_free(uhci_desc_kmem, element);
-#else
-       kfree (element);
-#endif
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-// Allocates qh element
-static int alloc_qh (puhci_desc_t * new)
-{
-#ifdef _UHCI_SLAB
-       *new= kmem_cache_alloc(uhci_desc_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL);
-#else
-       *new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
-#endif 
-       if (!*new)
-               return -ENOMEM;
-       
-       memset (*new, 0, sizeof (uhci_desc_t));
-       (*new)->hw.qh.head = UHCI_PTR_TERM;
-       (*new)->hw.qh.element = UHCI_PTR_TERM;
-       (*new)->type = QH_TYPE;
-       INIT_LIST_HEAD (&(*new)->horizontal);
-       INIT_LIST_HEAD (&(*new)->vertical);
-       
-       dbg("Allocated qh @ %p", *new);
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-// inserts new qh before/after the qh at pos
-// flags: 0: insert before pos, 1: insert after pos (for low speed transfers)
-static int insert_qh (puhci_t s, puhci_desc_t pos, puhci_desc_t new, int flags)
-{
-       puhci_desc_t old;
-       unsigned long xxx;
-
-       spin_lock_irqsave (&s->qh_lock, xxx);
-
-       if (!flags) {
-               // (OLD) (POS) -> (OLD) (NEW) (POS)
-               old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
-               list_add_tail (&new->horizontal, &pos->horizontal);
-               new->hw.qh.head = MAKE_QH_ADDR (pos) ;
-               
-               if (!(old->hw.qh.head & UHCI_PTR_TERM))
-                       old->hw.qh.head = MAKE_QH_ADDR (new) ;
-       }
-       else {
-               // (POS) (OLD) -> (POS) (NEW) (OLD)
-               old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
-               list_add (&new->horizontal, &pos->horizontal);
-               pos->hw.qh.head = MAKE_QH_ADDR (new) ;
-               new->hw.qh.head = MAKE_QH_ADDR (old);
-       }
-
-       wmb ();
-       
-       spin_unlock_irqrestore (&s->qh_lock, xxx);
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int unlink_qh (puhci_t s, puhci_desc_t element)
-{
-       puhci_desc_t next, prev;
-       unsigned long xxx;
-
-       spin_lock_irqsave (&s->qh_lock, xxx);
-       
-       next = list_entry (element->horizontal.next, uhci_desc_t, horizontal);
-       prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-       prev->hw.qh.head = element->hw.qh.head;
-       wmb ();
-       list_del (&element->horizontal);
-       
-       spin_unlock_irqrestore (&s->qh_lock, xxx);
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int delete_qh (puhci_t s, puhci_desc_t qh)
-{
-       puhci_desc_t td;
-       struct list_head *p;
-
-       list_del (&qh->horizontal);
-       
-       while ((p = qh->vertical.next) != &qh->vertical) {
-               td = list_entry (p, uhci_desc_t, vertical);
-               unlink_td (s, td);
-               delete_desc (td);
-       }
-       
-       delete_desc (qh);
-       
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-void clean_td_chain (puhci_desc_t td)
-{
-       struct list_head *p;
-       puhci_desc_t td1;
-
-       if (!td)
-               return;
-       
-       while ((p = td->horizontal.next) != &td->horizontal) {
-               td1 = list_entry (p, uhci_desc_t, horizontal);
-               delete_desc (td1);
-       }
-       
-       delete_desc (td);
-}
-/*-------------------------------------------------------------------*/
-// Removes ALL qhs in chain (paranoia!)
-static void cleanup_skel (puhci_t s)
-{
-       unsigned int n;
-       puhci_desc_t td;
-
-       dbg("cleanup_skel");
-       
-       for (n = 0; n < 8; n++) {
-               td = s->int_chain[n];
-               clean_td_chain (td);
-       }
-
-       if (s->iso_td) {
-               for (n = 0; n < 1024; n++) {
-                       td = s->iso_td[n];
-                       clean_td_chain (td);
-               }
-               kfree (s->iso_td);
-       }
-
-       if (s->framelist)
-               free_page ((unsigned long) s->framelist);
-
-       if (s->control_chain) {
-               // completed init_skel?
-               struct list_head *p;
-               puhci_desc_t qh, qh1;
-
-               qh = s->control_chain;
-               while ((p = qh->horizontal.next) != &qh->horizontal) {
-                       qh1 = list_entry (p, uhci_desc_t, horizontal);
-                       delete_qh (s, qh1);
-               }
-               delete_qh (s, qh);
-       }
-       else {
-               if (s->control_chain)
-                       kfree (s->control_chain);
-               if (s->bulk_chain)
-                       kfree (s->bulk_chain);
-               if (s->chain_end)
-                       kfree (s->chain_end);
-       }
-}
-/*-------------------------------------------------------------------*/
-// allocates framelist and qh-skeletons
-// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
-static int init_skel (puhci_t s)
-{
-       int n, ret;
-       puhci_desc_t qh, td;
-       
-       dbg("init_skel");
-       
-       s->framelist = (__u32 *) get_free_page (GFP_KERNEL);
-
-       if (!s->framelist)
-               return -ENOMEM;
-
-       memset (s->framelist, 0, 4096);
-
-       dbg("allocating iso desc pointer list");
-       s->iso_td = (puhci_desc_t *) kmalloc (1024 * sizeof (puhci_desc_t), GFP_KERNEL);
-       
-       if (!s->iso_td)
-               goto init_skel_cleanup;
-
-       s->control_chain = NULL;
-       s->bulk_chain = NULL;
-       s->chain_end = NULL;
-
-       dbg("allocating iso descs");
-       for (n = 0; n < 1024; n++) {
-               // allocate skeleton iso/irq-tds
-               ret = alloc_td (&td, 0);
-               if (ret)
-                       goto init_skel_cleanup;
-               s->iso_td[n] = td;
-               s->framelist[n] = ((__u32) virt_to_bus (td));
-       }
-
-       dbg("allocating qh: chain_end");
-       ret = alloc_qh (&qh);
-       
-       if (ret)
-               goto init_skel_cleanup;
-       
-       s->chain_end = qh;
-
-       dbg("allocating qh: bulk_chain");
-       ret = alloc_qh (&qh);
-       
-       if (ret)
-               goto init_skel_cleanup;
-       
-       insert_qh (s, s->chain_end, qh, 0);
-       s->bulk_chain = qh;
-       dbg("allocating qh: control_chain");
-       ret = alloc_qh (&qh);
-       
-       if (ret)
-               goto init_skel_cleanup;
-       
-       insert_qh (s, s->bulk_chain, qh, 0);
-       s->control_chain = qh;
-       for (n = 0; n < 8; n++)
-               s->int_chain[n] = 0;
-
-       dbg("allocating skeleton INT-TDs");
-       
-       for (n = 0; n < 8; n++) {
-               puhci_desc_t td;
-
-               alloc_td (&td, 0);
-               if (!td)
-                       goto init_skel_cleanup;
-               s->int_chain[n] = td;
-               if (n == 0) {
-                       s->int_chain[0]->hw.td.link = virt_to_bus (s->control_chain);
-               }
-               else {
-                       s->int_chain[n]->hw.td.link = virt_to_bus (s->int_chain[0]);
-               }
-       }
-
-       dbg("linking skeleton INT-TDs");
-       
-       for (n = 0; n < 1024; n++) {
-               // link all iso-tds to the interrupt chains
-               int m, o;
-               //dbg("framelist[%i]=%x",n,s->framelist[n]);
-               for (o = 1, m = 2; m <= 128; o++, m += m) {
-                       // n&(m-1) = n%m
-                       if ((n & (m - 1)) == ((m - 1) / 2)) {
-                               ((puhci_desc_t) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]);
-                       }
-               }
-       }
-
-       //uhci_show_queue(s->control_chain);   
-       dbg("init_skel exit");
-       return 0;               // OK
-
-      init_skel_cleanup:
-       cleanup_skel (s);
-       return -ENOMEM;
-}
-
-/*-------------------------------------------------------------------*/
-static void fill_td (puhci_desc_t td, int status, int info, __u32 buffer)
-{
-       td->hw.td.status = status;
-       td->hw.td.info = info;
-       td->hw.td.buffer = buffer;
-}
-
-/*-------------------------------------------------------------------*/
-//                         LOW LEVEL STUFF
-//          assembles QHs und TDs for control, bulk and iso
-/*-------------------------------------------------------------------*/
-static int uhci_submit_control_urb (purb_t purb)
-{
-       puhci_desc_t qh, td;
-       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-       purb_priv_t purb_priv = purb->hcpriv;
-       unsigned long destination, status;
-       int maxsze = usb_maxpacket (purb->dev, purb->pipe, usb_pipeout (purb->pipe));
-       unsigned long len, bytesrequested;
-       char *data;
-
-       dbg("uhci_submit_control start");
-       alloc_qh (&qh);         // alloc qh for this request
-
-       if (!qh)
-               return -ENOMEM;
-
-       alloc_td (&td, UHCI_PTR_DEPTH);         // get td for setup stage
-
-       if (!td) {
-               delete_qh (s, qh);
-               return -ENOMEM;
-       }
-
-       /* The "pipe" thing contains the destination in bits 8--18 */
-       destination = (purb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-       /* 3 errors */
-       status = (purb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-               (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-       /*  Build the TD for the control request, try forever, 8 bytes of data */
-       fill_td (td, status, destination | (7 << 21), virt_to_bus (purb->setup_packet));
-
-       /* If direction is "send", change the frame from SETUP (0x2D)
-          to OUT (0xE1). Else change it from SETUP to IN (0x69). */
-
-       destination ^= (USB_PID_SETUP ^ USB_PID_IN);    /* SETUP -> IN */
-       
-       if (usb_pipeout (purb->pipe))
-               destination ^= (USB_PID_IN ^ USB_PID_OUT);      /* IN -> OUT */
-
-       insert_td (s, qh, td, 0);       // queue 'setup stage'-td in qh
-#if 0
-       dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", purb->pipe,
-               purb->setup_packet[0], purb->setup_packet[1], purb->setup_packet[2], purb->setup_packet[3],
-               purb->setup_packet[4], purb->setup_packet[5], purb->setup_packet[6], purb->setup_packet[7]);
-       //uhci_show_td(td);
-#endif
-       /*  Build the DATA TD's */
-       len = purb->transfer_buffer_length;
-       bytesrequested = len;
-       data = purb->transfer_buffer;
-       
-       while (len > 0) {
-               int pktsze = len;
-
-               alloc_td (&td, UHCI_PTR_DEPTH);
-               if (!td) {
-                       delete_qh (s, qh);
-                       return -ENOMEM;
-               }
-
-               if (pktsze > maxsze)
-                       pktsze = maxsze;
-
-               destination ^= 1 << TD_TOKEN_TOGGLE;    // toggle DATA0/1
-
-               fill_td (td, status, destination | ((pktsze - 1) << 21),
-                        virt_to_bus (data));   // Status, pktsze bytes of data
-
-               insert_td (s, qh, td, UHCI_PTR_DEPTH);  // queue 'data stage'-td in qh
-
-               data += pktsze;
-               len -= pktsze;
-       }
-
-       /*  Build the final TD for control status */
-       /* It's only IN if the pipe is out AND we aren't expecting data */
-       destination &= ~0xFF;
-       
-       if (usb_pipeout (purb->pipe) | (bytesrequested == 0))
-               destination |= USB_PID_IN;
-       else
-               destination |= USB_PID_OUT;
-
-       destination |= 1 << TD_TOKEN_TOGGLE;    /* End in Data1 */
-
-       alloc_td (&td, UHCI_PTR_DEPTH);
-       
-       if (!td) {
-               delete_qh (s, qh);
-               return -ENOMEM;
-       }
-
-       /* no limit on errors on final packet , 0 bytes of data */
-       fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),
-                0);
-
-       insert_td (s, qh, td, UHCI_PTR_DEPTH);  // queue status td
-
-
-       list_add (&qh->desc_list, &purb_priv->desc_list);
-
-       /* Start it up... put low speed first */
-       if (purb->pipe & TD_CTRL_LS)
-               insert_qh (s, s->control_chain, qh, 1); // insert after control chain
-       else
-               insert_qh (s, s->bulk_chain, qh, 0);    // insert before bulk chain
-       //uhci_show_queue(s->control_chain);
-
-       dbg("uhci_submit_control end");
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int uhci_submit_bulk_urb (purb_t purb)
-{
-       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-       purb_priv_t purb_priv = purb->hcpriv;
-       puhci_desc_t qh, td;
-       unsigned long destination, status;
-       char *data;
-       unsigned int pipe = purb->pipe;
-       int maxsze = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
-       int info, len;
-
-       /* shouldn't the clear_halt be done in the USB core or in the client driver? - Thomas */
-       if (usb_endpoint_halted (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) &&
-           usb_clear_halt (purb->dev, usb_pipeendpoint (pipe) | (pipe & USB_DIR_IN)))
-               return -EPIPE;
-
-       if (!maxsze)
-               return -EMSGSIZE;
-       /* FIXME: should tell the client that the endpoint is invalid, i.e. not in the descriptor */
-
-       alloc_qh (&qh);         // get qh for this request
-
-       if (!qh)
-               return -ENOMEM;
-
-       /* The "pipe" thing contains the destination in bits 8--18. */
-       destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
-
-       /* 3 errors */
-       status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-               ((purb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-       /* Build the TDs for the bulk request */
-       len = purb->transfer_buffer_length;
-       data = purb->transfer_buffer;
-       dbg("uhci_submit_bulk_urb: pipe %x, len %d", pipe, len);
-       
-       while (len > 0) {
-               int pktsze = len;
-
-               alloc_td (&td, UHCI_PTR_DEPTH);
-
-               if (!td) {
-                       delete_qh (s, qh);
-                       return -ENOMEM;
-               }
-
-               if (pktsze > maxsze)
-                       pktsze = maxsze;
-
-               // pktsze bytes of data 
-               info = destination | ((pktsze - 1) << 21) |
-                       (usb_gettoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-               fill_td (td, status, info, virt_to_bus (data));
-
-               data += pktsze;
-               len -= pktsze;
-
-               if (!len)
-                       td->hw.td.status |= TD_CTRL_IOC;        // last one generates INT
-               //dbg("insert td %p, len %i",td,pktsze);
-
-               insert_td (s, qh, td, UHCI_PTR_DEPTH);
-               
-               /* Alternate Data0/1 (start with Data0) */
-               usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-       }
-
-       list_add (&qh->desc_list, &purb_priv->desc_list);
-
-       insert_qh (s, s->chain_end, qh, 0);     // insert before end marker
-       //uhci_show_queue(s->bulk_chain);
-
-       dbg("uhci_submit_bulk_urb: exit");
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-// unlinks an urb by dequeuing its qh, waits some frames and forgets it
-// Problem: unlinking in interrupt requires waiting for one frame (udelay)
-// to allow the whole structures to be safely removed
-static int uhci_unlink_urb (purb_t purb)
-{
-       puhci_t s;
-       puhci_desc_t qh;
-       puhci_desc_t td;
-       purb_priv_t purb_priv;
-       unsigned long flags=0;
-       struct list_head *p;
-
-       if (!purb)              // you never know...
-               return -1;
-
-       s = (puhci_t) purb->dev->bus->hcpriv;   // get pointer to uhci struct
-
-       if (usb_pipedevice (purb->pipe) == s->rh.devnum)
-               return rh_unlink_urb (purb);
-
-       if(!in_interrupt()) {
-               // is the following really necessary? dequeue_urb has its own spinlock (GA)
-               spin_lock_irqsave (&s->unlink_urb_lock, flags);         // do not allow interrupts
-       }
-       
-       //dbg("unlink_urb called %p",purb);
-       if (purb->status == USB_ST_URB_PENDING) {
-               // URB probably still in work
-               purb_priv = purb->hcpriv;
-               dequeue_urb (s, &purb->urb_list,1);
-               purb->status = USB_ST_URB_KILLED;       // mark urb as killed
-               
-               if(!in_interrupt()) {
-                       spin_unlock_irqrestore (&s->unlink_urb_lock, flags);    // allow interrupts from here
-               }
-
-               switch (usb_pipetype (purb->pipe)) {
-               case PIPE_ISOCHRONOUS:
-               case PIPE_INTERRUPT:
-                       for (p = purb_priv->desc_list.next; p != &purb_priv->desc_list; p = p->next) {
-                               td = list_entry (p, uhci_desc_t, desc_list);
-                               unlink_td (s, td);
-                       }
-                       // wait at least 1 Frame
-                       if (in_interrupt ())
-                               udelay (1000);
-                       else
-                               schedule_timeout (1 + 1 * HZ / 1000);
-                       while ((p = purb_priv->desc_list.next) != &purb_priv->desc_list) {
-                               td = list_entry (p, uhci_desc_t, desc_list);
-                               list_del (p);
-                               delete_desc (td);
-                       }
-                       break;
-
-               case PIPE_BULK:
-               case PIPE_CONTROL:
-                       qh = list_entry (purb_priv->desc_list.next, uhci_desc_t, desc_list);
-
-                       unlink_qh (s, qh);      // remove this qh from qh-list
-                       // wait at least 1 Frame
-
-                       if (in_interrupt ())
-                               udelay (1000);
-                       else
-                               schedule_timeout (1 + 1 * HZ / 1000);
-                       delete_qh (s, qh);              // remove it physically
-
-               }
-               
-#ifdef _UHCI_SLAB
-               kmem_cache_free(urb_priv_kmem, purb->hcpriv);
-#else
-               kfree (purb->hcpriv);
-#endif
-               if (purb->complete) {
-                       dbg("unlink_urb: calling completion");
-                       purb->complete ((struct urb *) purb);
-                       usb_dec_dev_use (purb->dev);
-               }
-               return 0;
-       }
-       else {
-               if(!in_interrupt())
-                       spin_unlock_irqrestore (&s->unlink_urb_lock, flags);    // allow interrupts from here
-       }
-
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-// In case of ASAP iso transfer, search the URB-list for already queued URBs
-// for this EP and calculate the earliest start frame for the new
-// URB (easy seamless URB continuation!)
-static int find_iso_limits (purb_t purb, unsigned int *start, unsigned int *end)
-{
-       purb_t u, last_urb = NULL;
-       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-       struct list_head *p = s->urb_list.next;
-       int ret=-1;
-       unsigned long flags;
-       
-       spin_lock_irqsave (&s->urb_list_lock, flags);
-
-       for (; p != &s->urb_list; p = p->next) {
-               u = list_entry (p, urb_t, urb_list);
-               // look for pending URBs with identical pipe handle
-               // works only because iso doesn't toggle the data bit!
-               if ((purb->pipe == u->pipe) && (purb->dev == u->dev) && (u->status == USB_ST_URB_PENDING)) {
-                       if (!last_urb)
-                               *start = u->start_frame;
-                       last_urb = u;
-               }
-       }
-       
-       if (last_urb) {
-               *end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
-               ret=0;
-       }
-       
-       spin_unlock_irqrestore(&s->urb_list_lock, flags);
-       
-       return ret;     // no previous urb found
-
-}
-/*-------------------------------------------------------------------*/
-// adjust start_frame according to scheduling constraints (ASAP etc)
-
-static void jnx_show_desc (puhci_desc_t d)
-{
-       switch (d->type) {
-       case TD_TYPE:
-               dbg("td @ 0x%08lx: link 0x%08x status 0x%08x info 0x%08x buffer 0x%08x",
-                       (unsigned long) d, d->hw.td.link, d->hw.td.status, d->hw.td.info, d->hw.td.buffer);
-               if (!(d->hw.td.link & UHCI_PTR_TERM))
-                       jnx_show_desc ((puhci_desc_t) bus_to_virt (d->hw.td.link & ~UHCI_PTR_BITS));
-               break;
-
-       case QH_TYPE:
-               dbg("qh @ 0x%08lx: head 0x%08x element 0x%08x",
-                       (unsigned long) d, d->hw.qh.head, d->hw.qh.element);
-               if (!(d->hw.qh.element & UHCI_PTR_TERM))
-                       jnx_show_desc ((puhci_desc_t) bus_to_virt (d->hw.qh.element & ~UHCI_PTR_BITS));
-               if (!(d->hw.qh.head & UHCI_PTR_TERM))
-                       jnx_show_desc ((puhci_desc_t) bus_to_virt (d->hw.qh.head & ~UHCI_PTR_BITS));
-               break;
-
-       default:
-               dbg("desc @ 0x%08lx: invalid type %u", (unsigned long) d, d->type);
-       }
-}
-
-/*-------------------------------------------------------------------*/
-static int iso_find_start (purb_t purb)
-{
-       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-       unsigned int now;
-       unsigned int start_limit = 0, stop_limit = 0, queued_size;
-       int limits;
-
-       now = UHCI_GET_CURRENT_FRAME (s) & 1023;
-
-       if ((unsigned) purb->number_of_packets > 900)
-               return -EFBIG;
-       
-       limits = find_iso_limits (purb, &start_limit, &stop_limit);
-       queued_size = (stop_limit - start_limit) & 1023;
-
-       if (purb->transfer_flags & USB_ISO_ASAP) {
-               // first iso
-               if (limits) {
-                       // 10ms setup should be enough //FIXME!
-                       purb->start_frame = (now + 10) & 1023;
-               }
-               else {
-                       purb->start_frame = stop_limit;         //seamless linkage
-
-                       if (((now - purb->start_frame) & 1023) <= (unsigned) purb->number_of_packets) {
-                               dbg("iso_find_start: warning, ASAP gap, should not happen");
-                               dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
-                                       now, purb->start_frame, purb->number_of_packets, purb->pipe);
-                               {
-                                       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-                                       struct list_head *p;
-                                       purb_t u;
-                                       int a = -1, b = -1;
-                                       unsigned long flags;
-
-                                       spin_lock_irqsave (&s->urb_list_lock, flags);
-                                       p=s->urb_list.next;
-
-                                       for (; p != &s->urb_list; p = p->next) {
-                                               u = list_entry (p, urb_t, urb_list);
-                                               if (purb->dev != u->dev)
-                                                       continue;
-                                               dbg("urb: pipe 0x%08x status %d start_frame %u number_of_packets %u",
-                                                       u->pipe, u->status, u->start_frame, u->number_of_packets);
-                                               if (!usb_pipeisoc (u->pipe))
-                                                       continue;
-                                               if (a == -1)
-                                                       a = u->start_frame;
-                                               b = (u->start_frame + u->number_of_packets - 1) & 1023;
-                                       }
-                                       spin_unlock_irqrestore(&s->urb_list_lock, flags);
-#if 0
-                                       if (a != -1 && b != -1) {
-                                               do {
-                                                       jnx_show_desc (s->iso_td[a]);
-                                                       a = (a + 1) & 1023;
-                                               }
-                                               while (a != b);
-                                       }
-#endif
-                               }
-                               purb->start_frame = (now + 5) & 1023;   // 5ms setup should be enough //FIXME!
-                               //return -EAGAIN; //FIXME
-
-                       }
-               }
-       }
-       else {
-               purb->start_frame &= 1023;
-               if (((now - purb->start_frame) & 1023) < (unsigned) purb->number_of_packets) {
-                       dbg("iso_find_start: now between start_frame and end");
-                       return -EAGAIN;
-               }
-       }
-
-       /* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */
-       if (limits)
-               return 0;
-       if (((purb->start_frame - start_limit) & 1023) < queued_size ||
-           ((purb->start_frame + purb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
-               dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
-                       purb->start_frame, purb->number_of_packets, start_limit, stop_limit);
-               return -EAGAIN;
-       }
-
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-// submits USB interrupt (ie. polling ;-) 
-// ASAP-flag set implicitely
-// if period==0, the the transfer is only done once (usb_scsi need this...)
-
-static int uhci_submit_int_urb (purb_t purb)
-{
-       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-       purb_priv_t purb_priv = purb->hcpriv;
-       int nint, n, ret;
-       puhci_desc_t td;
-       int status, destination;
-       int now;
-       int info;
-       unsigned int pipe = purb->pipe;
-
-       //dbg("SUBMIT INT");
-
-       if (purb->interval < 0 || purb->interval >= 256)
-               return -EINVAL;
-
-       if (purb->interval == 0)
-               nint = 0;
-       else {
-               for (nint = 0, n = 1; nint <= 8; nint++, n += n)        // round interval down to 2^n
-                {
-                       if (purb->interval < n) {
-                               purb->interval = n / 2;
-                               break;
-                       }
-               }
-               nint--;
-       }
-       dbg("Rounded interval to %i, chain  %i", purb->interval, nint);
-
-       now = UHCI_GET_CURRENT_FRAME (s) & 1023;
-       purb->start_frame = now;        // remember start frame, just in case...
-
-       purb->number_of_packets = 1;
-
-       // INT allows only one packet
-       if (purb->transfer_buffer_length > usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)))
-               return -EINVAL;
-
-       ret = alloc_td (&td, UHCI_PTR_DEPTH);
-
-       if (ret)
-               return -ENOMEM;
-
-       status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
-               (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (1 << 27);
-
-       destination = (purb->pipe & PIPE_DEVEP_MASK) | usb_packetid (purb->pipe) |
-               (((purb->transfer_buffer_length - 1) & 0x7ff) << 21);
-
-
-       info = destination | (usb_gettoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-       fill_td (td, status, info, virt_to_bus (purb->transfer_buffer));
-       list_add_tail (&td->desc_list, &purb_priv->desc_list);
-       insert_td_horizontal (s, s->int_chain[nint], td, UHCI_PTR_DEPTH);       // store in INT-TDs
-
-       usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-
-#if 0
-       td = tdm[purb->number_of_packets];
-       fill_td (td, TD_CTRL_IOC, 0, 0);
-       insert_td_horizontal (s, s->iso_td[(purb->start_frame + (purb->number_of_packets) * purb->interval + 1) & 1023], td, UHCI_PTR_DEPTH);
-       list_add_tail (&td->desc_list, &purb_priv->desc_list);
-#endif
-
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int uhci_submit_iso_urb (purb_t purb)
-{
-       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
-       purb_priv_t purb_priv = purb->hcpriv;
-       int n, ret;
-       puhci_desc_t td, *tdm;
-       int status, destination;
-       unsigned long flags;
-       spinlock_t lock;
-
-       spin_lock_init (&lock);
-       spin_lock_irqsave (&lock, flags);       // Disable IRQs to schedule all ISO-TDs in time
-
-       ret = iso_find_start (purb);    // adjusts purb->start_frame for later use
-
-       if (ret)
-               goto err;
-
-       tdm = (puhci_desc_t *) kmalloc (purb->number_of_packets * sizeof (puhci_desc_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
-
-       if (!tdm) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       // First try to get all TDs
-       for (n = 0; n < purb->number_of_packets; n++) {
-               dbg("n:%d purb->iso_frame_desc[n].length:%d", n, purb->iso_frame_desc[n].length);
-               if (!purb->iso_frame_desc[n].length) {
-                       // allows ISO striping by setting length to zero in iso_descriptor
-                       tdm[n] = 0;
-                       continue;
-               }
-               ret = alloc_td (&td, UHCI_PTR_DEPTH);
-               if (ret) {
-                       int i;  // Cleanup allocated TDs
-
-                       for (i = 0; i < n; n++)
-                               if (tdm[i])
-                                       kfree (tdm[i]);
-                       kfree (tdm);
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               tdm[n] = td;
-       }
-
-       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;  //| (purb->transfer_flags&USB_DISABLE_SPD?0:TD_CTRL_SPD);
-
-       destination = (purb->pipe & PIPE_DEVEP_MASK) | usb_packetid (purb->pipe);
-
-       // Queue all allocated TDs
-       for (n = 0; n < purb->number_of_packets; n++) {
-               td = tdm[n];
-               if (!td)
-                       continue;
-               if (n + 1 >= purb->number_of_packets)
-                       status |= TD_CTRL_IOC;
-
-               fill_td (td, status, destination | (((purb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
-                        virt_to_bus (purb->transfer_buffer + purb->iso_frame_desc[n].offset));
-               list_add_tail (&td->desc_list, &purb_priv->desc_list);
-               insert_td_horizontal (s, s->iso_td[(purb->start_frame + n) & 1023], td, UHCI_PTR_DEPTH);        // store in iso-tds
-               //uhci_show_td(td);
-
-       }
-
-       kfree (tdm);
-       dbg("ISO-INT# %i, start %i, now %i", purb->number_of_packets, purb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
-       ret = 0;
-
-      err:
-       spin_unlock_irqrestore (&lock, flags);
-       return ret;
-
-}
-/*-------------------------------------------------------------------*/
-static int search_dev_ep (puhci_t s, purb_t purb)
-{
-       unsigned long flags;
-       struct list_head *p = s->urb_list.next;
-       purb_t tmp;
-
-       dbg("search_dev_ep:");
-       spin_lock_irqsave (&s->urb_list_lock, flags);
-
-       for (; p != &s->urb_list; p = p->next) {
-               tmp = list_entry (p, urb_t, urb_list);
-               dbg("urb: %p", tmp);
-               // we can accept this urb if it is not queued at this time 
-               // or if non-iso transfer requests should be scheduled for the same device and pipe
-               if ((usb_pipetype (purb->pipe) != PIPE_ISOCHRONOUS &&
-                    tmp->dev == purb->dev && tmp->pipe == purb->pipe) || (purb == tmp)) {
-                       spin_unlock_irqrestore (&s->urb_list_lock, flags);
-                       return 1;       // found another urb already queued for processing
-               }
-       }
-
-       spin_unlock_irqrestore (&s->urb_list_lock, flags);
-
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int uhci_submit_urb (purb_t purb)
-{
-       puhci_t s;
-       purb_priv_t purb_priv;
-       int ret = 0;
-
-       if (!purb->dev || !purb->dev->bus)
-               return -ENODEV;
-
-       s = (puhci_t) purb->dev->bus->hcpriv;
-       //dbg("submit_urb: %p type %d",purb,usb_pipetype(purb->pipe));
-
-       if (usb_pipedevice (purb->pipe) == s->rh.devnum)
-               return rh_submit_urb (purb);    /* virtual root hub */
-
-       usb_inc_dev_use (purb->dev);
-
-       if (search_dev_ep (s, purb)) {
-               usb_dec_dev_use (purb->dev);
-               return -ENXIO;  // urb already queued
-
-       }
-
-#ifdef _UHCI_SLAB
-       purb_priv = kmem_cache_alloc(urb_priv_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL);
-#else
-       purb_priv = kmalloc (sizeof (urb_priv_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
-#endif
-       if (!purb_priv) {
-               usb_dec_dev_use (purb->dev);
-               return -ENOMEM;
-       }
-
-       purb->hcpriv = purb_priv;
-       INIT_LIST_HEAD (&purb_priv->desc_list);
-       purb_priv->short_control_packet=0;
-       dbg("submit_urb: scheduling %p", purb);
-
-       switch (usb_pipetype (purb->pipe)) {
-       case PIPE_ISOCHRONOUS:
-               ret = uhci_submit_iso_urb (purb);
-               break;
-       case PIPE_INTERRUPT:
-               ret = uhci_submit_int_urb (purb);
-               break;
-       case PIPE_CONTROL:
-               //dump_urb (purb);
-               ret = uhci_submit_control_urb (purb);
-               break;
-       case PIPE_BULK:
-               ret = uhci_submit_bulk_urb (purb);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       dbg("submit_urb: scheduled with ret: %d", ret);
-
-       if (ret != USB_ST_NOERROR) {
-               usb_dec_dev_use (purb->dev);
-#ifdef _UHCI_SLAB
-               kmem_cache_free(urb_priv_kmem, purb_priv);
-#else
-               kfree (purb_priv);
-#endif
-               return ret;
-       }
-
-       purb->status = USB_ST_URB_PENDING;
-       queue_urb (s, &purb->urb_list,1);
-       dbg("submit_urb: exit");
-
-       return 0;
-}
-/*-------------------------------------------------------------------
- Virtual Root Hub
- -------------------------------------------------------------------*/
-
-static __u8 root_hub_dev_des[] =
-{
-       0x12,                   /*  __u8  bLength; */
-       0x01,                   /*  __u8  bDescriptorType; Device */
-       0x00,                   /*  __u16 bcdUSB; v1.0 */
-       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; */
-       0x00,                   /*  __u8  iProduct; */
-       0x00,                   /*  __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 */
-       0x08,                   /*  __u16 ep_wMaxPacketSize; 8 Bytes */
-       0x00,
-       0xff                    /*  __u8  ep_bInterval; 255 ms */
-};
-
-
-static __u8 root_hub_hub_des[] =
-{
-       0x09,                   /*  __u8  bLength; */
-       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
-       0x02,                   /*  __u8  bNbrPorts; */
-       0x00,                   /* __u16  wHubCharacteristics; */
-       0x00,
-       0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */
-       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
-       0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
-       0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-/*-------------------------------------------------------------------------*/
-/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-static int rh_send_irq (purb_t purb)
-{
-
-       int len = 1;
-       int i;
-       puhci_t uhci = purb->dev->bus->hcpriv;
-       unsigned int io_addr = uhci->io_addr;
-       __u16 data = 0;
-
-       for (i = 0; i < uhci->rh.numports; i++) {
-               data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
-               len = (i + 1) / 8 + 1;
-       }
-
-       *(__u16 *) purb->transfer_buffer = cpu_to_le16 (data);
-       purb->actual_length = len;
-       purb->status = USB_ST_NOERROR;
-
-       if ((data > 0) && (uhci->rh.send != 0)) {
-               dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
-                    inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
-               purb->complete (purb);
-
-       }
-       return USB_ST_NOERROR;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-static int rh_init_int_timer (purb_t purb);
-
-static void rh_int_timer_do (unsigned long ptr)
-{
-       int len;
-
-       purb_t purb = (purb_t) ptr;
-       puhci_t uhci = purb->dev->bus->hcpriv;
-
-       if (uhci->rh.send) {
-               len = rh_send_irq (purb);
-               if (len > 0) {
-                       purb->actual_length = len;
-                       if (purb->complete)
-                               purb->complete (purb);
-               }
-       }
-       rh_init_int_timer (purb);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer (purb_t purb)
-{
-       puhci_t uhci = purb->dev->bus->hcpriv;
-
-       uhci->rh.interval = purb->interval;
-       init_timer (&uhci->rh.rh_int_timer);
-       uhci->rh.rh_int_timer.function = rh_int_timer_do;
-       uhci->rh.rh_int_timer.data = (unsigned long) purb;
-       uhci->rh.rh_int_timer.expires = jiffies + (HZ * (purb->interval < 30 ? 30 : purb->interval)) / 1000;
-       add_timer (&uhci->rh.rh_int_timer);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-#define OK(x)                  len = (x); break
-
-#define CLR_RH_PORTSTAT(x) \
-               status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
-               status = (status & 0xfff5) & ~(x); \
-               outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
-
-#define SET_RH_PORTSTAT(x) \
-               status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
-               status = (status & 0xfff5) | (x); \
-               outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
-
-
-/*-------------------------------------------------------------------------*/
-/****
- ** Root Hub Control Pipe
- *************************/
-
-
-static int rh_submit_urb (purb_t purb)
-{
-       struct usb_device *usb_dev = purb->dev;
-       puhci_t uhci = usb_dev->bus->hcpriv;
-       unsigned int pipe = purb->pipe;
-       devrequest *cmd = (devrequest *) purb->setup_packet;
-       void *data = purb->transfer_buffer;
-       int leni = purb->transfer_buffer_length;
-       int len = 0;
-       int status = 0;
-       int stat = USB_ST_NOERROR;
-       int i;
-       unsigned int io_addr = uhci->io_addr;
-       __u16 cstatus;
-
-       __u16 bmRType_bReq;
-       __u16 wValue;
-       __u16 wIndex;
-       __u16 wLength;
-
-       if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
-               dbg("Root-Hub submit IRQ: every %d ms", purb->interval);
-               uhci->rh.urb = purb;
-               uhci->rh.send = 1;
-               uhci->rh.interval = purb->interval;
-               rh_init_int_timer (purb);
-
-               return USB_ST_NOERROR;
-       }
-
-
-       bmRType_bReq = cmd->requesttype | cmd->request << 8;
-       wValue = le16_to_cpu (cmd->value);
-       wIndex = le16_to_cpu (cmd->index);
-       wLength = le16_to_cpu (cmd->length);
-
-       for (i = 0; i < 8; i++)
-               uhci->rh.c_p_r[i] = 0;
-
-       dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",
-            uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, 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 = cpu_to_le16 (1);
-               OK (2);
-       case RH_GET_STATUS | RH_INTERFACE:
-               *(__u16 *) data = cpu_to_le16 (0);
-               OK (2);
-       case RH_GET_STATUS | RH_ENDPOINT:
-               *(__u16 *) data = cpu_to_le16 (0);
-               OK (2);
-       case RH_GET_STATUS | RH_CLASS:
-               *(__u32 *) data = cpu_to_le32 (0);
-               OK (4);         /* hub power ** */
-       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-               status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
-               cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
-                       ((status & USBPORTSC_PEC) >> (3 - 1)) |
-                       (uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
-               status = (status & USBPORTSC_CCS) |
-                       ((status & USBPORTSC_PE) >> (2 - 1)) |
-                       ((status & USBPORTSC_SUSP) >> (12 - 2)) |
-                       ((status & USBPORTSC_PR) >> (9 - 4)) |
-                       (1 << 8) |      /* power on ** */
-                       ((status & USBPORTSC_LSDA) << (-8 + 9));
-
-               *(__u16 *) data = cpu_to_le16 (status);
-               *(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
-               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_OVER_CURRENT):
-                       OK (0); /* hub power over current ** */
-               }
-               break;
-
-       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-               switch (wValue) {
-               case (RH_PORT_ENABLE):
-                       CLR_RH_PORTSTAT (USBPORTSC_PE);
-                       OK (0);
-               case (RH_PORT_SUSPEND):
-                       CLR_RH_PORTSTAT (USBPORTSC_SUSP);
-                       OK (0);
-               case (RH_PORT_POWER):
-                       OK (0); /* port power ** */
-               case (RH_C_PORT_CONNECTION):
-                       SET_RH_PORTSTAT (USBPORTSC_CSC);
-                       OK (0);
-               case (RH_C_PORT_ENABLE):
-                       SET_RH_PORTSTAT (USBPORTSC_PEC);
-                       OK (0);
-               case (RH_C_PORT_SUSPEND):
-/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
-                       OK (0);
-               case (RH_C_PORT_OVER_CURRENT):
-                       OK (0); /* port power over current ** */
-               case (RH_C_PORT_RESET):
-                       uhci->rh.c_p_r[wIndex - 1] = 0;
-                       OK (0);
-               }
-               break;
-
-       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-               switch (wValue) {
-               case (RH_PORT_SUSPEND):
-                       SET_RH_PORTSTAT (USBPORTSC_SUSP);
-                       OK (0);
-               case (RH_PORT_RESET):
-                       SET_RH_PORTSTAT (USBPORTSC_PR);
-                       wait_ms (10);
-                       uhci->rh.c_p_r[wIndex - 1] = 1;
-                       CLR_RH_PORTSTAT (USBPORTSC_PR);
-                       udelay (10);
-                       SET_RH_PORTSTAT (USBPORTSC_PE);
-                       wait_ms (10);
-                       SET_RH_PORTSTAT (0xa);
-                       OK (0);
-               case (RH_PORT_POWER):
-                       OK (0); /* port power ** */
-               case (RH_PORT_ENABLE):
-                       SET_RH_PORTSTAT (USBPORTSC_PE);
-                       OK (0);
-               }
-               break;
-
-       case RH_SET_ADDRESS:
-               uhci->rh.devnum = wValue;
-               OK (0);
-
-       case RH_GET_DESCRIPTOR:
-               switch ((wValue & 0xff00) >> 8) {
-               case (0x01):    /* device descriptor */
-                       len = min (leni, min (sizeof (root_hub_dev_des), wLength));
-                       memcpy (data, root_hub_dev_des, len);
-                       OK (len);
-               case (0x02):    /* configuration descriptor */
-                       len = min (leni, min (sizeof (root_hub_config_des), wLength));
-                       memcpy (data, root_hub_config_des, len);
-                       OK (len);
-               case (0x03):    /*string descriptors */
-                       stat = -EPIPE;
-               }
-               break;
-
-       case RH_GET_DESCRIPTOR | RH_CLASS:
-               root_hub_hub_des[2] = uhci->rh.numports;
-               len = min (leni, min (sizeof (root_hub_hub_des), wLength));
-               memcpy (data, root_hub_hub_des, len);
-               OK (len);
-
-       case RH_GET_CONFIGURATION:
-               *(__u8 *) data = 0x01;
-               OK (1);
-
-       case RH_SET_CONFIGURATION:
-               OK (0);
-       default:
-               stat = -EPIPE;
-       }
-
-
-       dbg("Root-Hub stat port1: %x port2: %x",
-            inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
-
-       purb->actual_length = len;
-       purb->status = stat;
-       if (purb->complete)
-               purb->complete (purb);
-       return USB_ST_NOERROR;
-}
-/*-------------------------------------------------------------------------*/
-
-static int rh_unlink_urb (purb_t purb)
-{
-       puhci_t uhci = purb->dev->bus->hcpriv;
-
-       dbg("Root-Hub unlink IRQ");
-       uhci->rh.send = 0;
-       del_timer (&uhci->rh.rh_int_timer);
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-
-#define UHCI_DEBUG
-
-/*
- * Map status to standard result codes
- *
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
- * <dir_out> is True for output TDs and False for input TDs.
- */
-static int uhci_map_status (int status, int dir_out)
-{
-       if (!status)
-               return USB_ST_NOERROR;
-       if (status & TD_CTRL_BITSTUFF)  /* Bitstuff error */
-               return USB_ST_BITSTUFF;
-       if (status & TD_CTRL_CRCTIMEO) {        /* CRC/Timeout */
-               if (dir_out)
-                       return USB_ST_NORESPONSE;
-               else
-                       return USB_ST_CRC;
-       }
-       if (status & TD_CTRL_NAK)       /* NAK */
-               return USB_ST_TIMEOUT;
-       if (status & TD_CTRL_BABBLE)    /* Babble */
-               return -EPIPE;
-       if (status & TD_CTRL_DBUFERR)   /* Buffer error */
-               return USB_ST_BUFFERUNDERRUN;
-       if (status & TD_CTRL_STALLED)   /* Stalled */
-               return -EPIPE;
-       if (status & TD_CTRL_ACTIVE)    /* Active */
-               return USB_ST_NOERROR;
-
-       return USB_ST_INTERNALERROR;
-}
-
-/*
- * Only the USB core should call uhci_alloc_dev and uhci_free_dev
- */
-static int uhci_alloc_dev (struct usb_device *usb_dev)
-{
-       return 0;
-}
-
-static int uhci_free_dev (struct usb_device *usb_dev)
-{
-       return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-static int uhci_get_current_frame_number (struct usb_device *usb_dev)
-{
-       return UHCI_GET_CURRENT_FRAME ((puhci_t) usb_dev->bus->hcpriv);
-}
-
-struct usb_operations uhci_device_operations =
-{
-       uhci_alloc_dev,
-       uhci_free_dev,
-       uhci_get_current_frame_number,
-       uhci_submit_urb,
-       uhci_unlink_urb
-};
-
-/* 
- * For IN-control transfers, process_transfer gets a bit more complicated,
- * since there are devices that return less data (eg. strings) than they
- * have announced. This leads to a queue abort due to the short packet,
- * the status stage is not executed. If this happens, the status stage
- * is manually re-executed.
- * FIXME: Stall-condition may override 'nearly' successful CTRL-IN-transfer
- * when the transfered length fits exactly in maxsze-packets. A bit
- * more intelligence is needed to detect this and finish without error.
- */
-static int process_transfer (puhci_t s, purb_t purb)
-{
-       int ret = USB_ST_NOERROR;
-       purb_priv_t purb_priv = purb->hcpriv;
-       struct list_head *qhl = purb_priv->desc_list.next;
-       puhci_desc_t qh = list_entry (qhl, uhci_desc_t, desc_list);
-       struct list_head *p = qh->vertical.next;
-       puhci_desc_t desc= list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list);
-       puhci_desc_t last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
-       int data_toggle = usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));   // save initial data_toggle
-
-
-       // extracted and remapped info from TD
-       int maxlength;
-       int actual_length;
-       int status = USB_ST_NOERROR;
-
-       dbg("process_transfer: urb contains bulk/control request");
-
-
-       /* if the status phase has been retriggered and the
-          queue is empty or the last status-TD is inactive, the retriggered
-          status stage is completed
-        */
-#if 1
-       if (purb_priv->short_control_packet && 
-               ((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE)))) 
-               goto transfer_finished;
-#endif
-       purb->actual_length=0;
-
-       for (; p != &qh->vertical; p = p->next) {
-               desc = list_entry (p, uhci_desc_t, vertical);
-
-               if (desc->hw.td.status & TD_CTRL_ACTIVE)        // do not process active TDs
-                       return ret;
-
-               // extract transfer parameters from TD
-               actual_length = (desc->hw.td.status + 1) & 0x7ff;
-               maxlength = (((desc->hw.td.info >> 21) & 0x7ff) + 1) & 0x7ff;
-               status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe));
-
-               // see if EP is stalled
-               if (status == -EPIPE) {
-                       // set up stalled condition
-                       usb_endpoint_halt (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
-               }
-
-               // if any error occured stop processing of further TDs
-               if (status != USB_ST_NOERROR) {
-                       // only set ret if status returned an error
-                       uhci_show_td (desc);
-                       ret = status;
-                       purb->error_count++;
-                       break;
-               }
-               else if ((desc->hw.td.info & 0xff) != USB_PID_SETUP)
-                       purb->actual_length += actual_length;
-
-#if 0
-               if (i++==0)
-                       uhci_show_td (desc);    // show first TD of each transfer
-#endif
-
-               // got less data than requested
-               if ( (actual_length < maxlength)) {
-                       if (purb->transfer_flags & USB_DISABLE_SPD) {
-                               ret = USB_ST_SHORT_PACKET;      // treat as real error
-                               dbg("process_transfer: SPD!!");
-                               break;  // exit after this TD because SP was detected
-                       }
-
-                       // short read during control-IN: re-start status stage
-                       if ((usb_pipetype (purb->pipe) == PIPE_CONTROL)) {
-                               if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) {
-                                       uhci_show_td (last_desc);
-                                       qh->hw.qh.element = virt_to_bus (last_desc);  // re-trigger status stage
-                                       info("short packet during control transfer, retrigger status stage @ %p",last_desc);
-                                       purb_priv->short_control_packet=1;
-                                       return 0;
-                               }
-                       }
-                       // all other cases: short read is OK
-                       data_toggle = uhci_toggle (desc->hw.td.info);
-                       break;
-               }
-
-               data_toggle = uhci_toggle (desc->hw.td.info);
-               //dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, desc->hw.td.status,status, data_toggle);      
-
-       }
-       usb_settoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe), !data_toggle);
-       transfer_finished:
-
-       /* APC BackUPS Pro kludge */     
-       /* It tries to send all of the descriptor instead of */
-       /*  the amount we requested */   
-       if (desc->hw.td.status & TD_CTRL_IOC &&  
-               status & TD_CTRL_ACTIVE &&   
-               status & TD_CTRL_NAK )
-       {
-               ret=0;
-               status=0;
-       }
-
-       unlink_qh (s, qh);
-       delete_qh (s, qh);
-
-       purb->status = status;
-                                                               
-       dbg("process_transfer: urb %p, wanted len %d, len %d status %x err %d",
-               purb,purb->transfer_buffer_length,purb->actual_length, purb->status, purb->error_count);
-       //dbg("process_transfer: exit");
-       return ret;
-}
-
-static int process_interrupt (puhci_t s, purb_t purb)
-{
-       int i, ret = USB_ST_URB_PENDING;
-       purb_priv_t purb_priv = purb->hcpriv;
-       struct list_head *p = purb_priv->desc_list.next;
-       puhci_desc_t desc = list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list);
-       int data_toggle = usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe),
-                                        usb_pipeout (purb->pipe));     // save initial data_toggle
-       // extracted and remapped info from TD
-
-       int actual_length;
-       int status = USB_ST_NOERROR;
-
-       //dbg("urb contains interrupt request");
-
-       for (i = 0; p != &purb_priv->desc_list; p = p->next, i++)       // Maybe we allow more than one TD later ;-)
-       {
-               desc = list_entry (p, uhci_desc_t, desc_list);
-
-               if (desc->hw.td.status & TD_CTRL_ACTIVE) {
-                       // do not process active TDs
-                       //dbg("TD ACT Status @%p %08x",desc,desc->hw.td.status);
-                       break;
-               }
-
-               if (!desc->hw.td.status & TD_CTRL_IOC) {
-                       // do not process one-shot TDs, no recycling
-                       break;
-               }
-               // extract transfer parameters from TD
-
-               actual_length = (desc->hw.td.status + 1) & 0x7ff;
-               status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe));
-
-               // see if EP is stalled
-               if (status == -EPIPE) {
-                       // set up stalled condition
-                       usb_endpoint_halt (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
-               }
-
-               // if any error occured: ignore this td, and continue
-               if (status != USB_ST_NOERROR) {
-                       purb->error_count++;
-                       goto recycle;
-               }
-               else
-                       purb->actual_length = actual_length;
-
-               // FIXME: SPD?
-
-               data_toggle = uhci_toggle (desc->hw.td.info);
-
-               if (purb->complete && status != USB_ST_TIMEOUT) {
-                       // for last td, no user completion is needed
-                       dbg("process_interrupt: calling completion");
-                       purb->status = status;
-                       purb->complete ((struct urb *) purb);
-                       purb->status = USB_ST_URB_PENDING;
-               }
-       recycle:
-               // Recycle INT-TD if interval!=0, else mark TD as one-shot
-               if (purb->interval) {
-                       desc->hw.td.status |= TD_CTRL_ACTIVE;
-                       desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
-                       desc->hw.td.info |= (usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe),
-                             usb_pipeout (purb->pipe)) << TD_TOKEN_TOGGLE);
-                       usb_dotoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
-               }
-               else {
-                       desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
-               }
-       }
-
-       return ret;
-}
-
-
-static int process_iso (puhci_t s, purb_t purb)
-{
-       int i;
-       int ret = USB_ST_NOERROR;
-       purb_priv_t purb_priv = purb->hcpriv;
-       struct list_head *p = purb_priv->desc_list.next;
-       puhci_desc_t desc = list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list);
-
-       dbg("urb contains iso request");
-       if (desc->hw.td.status & TD_CTRL_ACTIVE)
-               return USB_ST_PARTIAL_ERROR;    // last TD not finished
-
-       purb->error_count = 0;
-       purb->actual_length = 0;
-       purb->status = USB_ST_NOERROR;
-
-       for (i = 0; p != &purb_priv->desc_list; p = p->next, i++) {
-               desc = list_entry (p, uhci_desc_t, desc_list);
-
-               //uhci_show_td(desc);
-               if (desc->hw.td.status & TD_CTRL_ACTIVE) {
-                       // means we have completed the last TD, but not the TDs before
-                       dbg("TD still active (%x)- grrr. paranoia!", desc->hw.td.status);
-                       ret = USB_ST_PARTIAL_ERROR;
-                       purb->iso_frame_desc[i].status = ret;
-                       unlink_td (s, desc);
-                       goto err;
-               }
-
-               unlink_td (s, desc);
-
-               if (purb->number_of_packets <= i) {
-                       dbg("purb->number_of_packets (%d)<=(%d)", purb->number_of_packets, i);
-                       ret = USB_ST_URB_INVALID_ERROR;
-                       goto err;
-               }
-
-               if (purb->iso_frame_desc[i].offset + purb->transfer_buffer != bus_to_virt (desc->hw.td.buffer)) {
-                       // Hm, something really weird is going on
-                       dbg("Pointer Paranoia: %p!=%p", purb->iso_frame_desc[i].offset + purb->transfer_buffer, bus_to_virt (desc->hw.td.buffer));
-                       ret = USB_ST_URB_INVALID_ERROR;
-                       purb->iso_frame_desc[i].status = ret;
-                       goto err;
-               }
-               purb->iso_frame_desc[i].actual_length = (desc->hw.td.status + 1) & 0x7ff;
-               purb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe));
-               purb->actual_length += purb->iso_frame_desc[i].actual_length;
-
-             err:
-
-               if (purb->iso_frame_desc[i].status != USB_ST_NOERROR) {
-                       purb->error_count++;
-                       purb->status = purb->iso_frame_desc[i].status;
-               }
-               dbg("process_iso: len:%d status:%x",
-                    purb->iso_frame_desc[i].length, purb->iso_frame_desc[i].status);
-
-               delete_desc (desc);
-               list_del (p);
-       }
-       dbg("process_iso: exit %i (%d)", i, ret);
-       return ret;
-}
-
-
-static int process_urb (puhci_t s, struct list_head *p)
-{
-       int ret = USB_ST_NOERROR;
-       purb_t purb;
-
-       spin_lock(&s->urb_list_lock);
-       purb=list_entry (p, urb_t, urb_list);
-       dbg("found queued urb: %p", purb);
-
-       switch (usb_pipetype (purb->pipe)) {
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-               ret = process_transfer (s, purb);
-               break;
-       case PIPE_ISOCHRONOUS:
-               ret = process_iso (s, purb);
-               break;
-       case PIPE_INTERRUPT:
-               ret = process_interrupt (s, purb);
-               break;
-       }
-
-       spin_unlock(&s->urb_list_lock);
-
-       if (purb->status != USB_ST_URB_PENDING) {
-               int proceed = 0;
-               dbg("dequeued urb: %p", purb);
-               dequeue_urb (s, p, 1);
-
-#ifdef _UHCI_SLAB
-               kmem_cache_free(urb_priv_kmem, purb->hcpriv);
-#else
-               kfree (purb->hcpriv);
-#endif
-
-               if ((usb_pipetype (purb->pipe) != PIPE_INTERRUPT)) {
-                       purb_t tmp = purb->next;        // pointer to first urb
-                       int is_ring = 0;
-                       
-                       if (purb->next) {
-                               do {
-                                       if (tmp->status != USB_ST_URB_PENDING) {
-                                               proceed = 1;
-                                               break;
-                                       }
-                                       tmp = tmp->next;
-                               }
-                               while (tmp != NULL && tmp != purb->next);
-                               if (tmp == purb->next)
-                                       is_ring = 1;
-                       }
-
-                       // In case you need the current URB status for your completion handler
-                       if (purb->complete && (!proceed || (purb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
-                               dbg("process_transfer: calling early completion");
-                               purb->complete ((struct urb *) purb);
-                               if (!proceed && is_ring && (purb->status != USB_ST_URB_KILLED))
-                                       uhci_submit_urb (purb);
-                       }
-
-                       if (proceed && purb->next) {
-                               // if there are linked urbs - handle submitting of them right now.
-                               tmp = purb->next;       // pointer to first urb
-
-                               do {
-                                       if ((tmp->status != USB_ST_URB_PENDING) && (tmp->status != USB_ST_URB_KILLED) && uhci_submit_urb (tmp) != USB_ST_NOERROR)
-                                               break;
-                                       tmp = tmp->next;
-                               }
-                               while (tmp != NULL && tmp != purb->next);       // submit until we reach NULL or our own pointer or submit fails
-
-                               if (purb->complete && !(purb->transfer_flags & USB_URB_EARLY_COMPLETE)) {
-                                       dbg("process_transfer: calling completion");
-                                       purb->complete ((struct urb *) purb);
-                               }
-                       }
-                       usb_dec_dev_use (purb->dev);
-               }
-       }
-
-       return ret;
-}
-
-static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
-{
-       puhci_t s = __uhci;
-       unsigned int io_addr = s->io_addr;
-       unsigned short status;
-       struct list_head *p, *p2;
-
-       /*
-        * Read the interrupt status, and write it back to clear the
-        * interrupt cause
-        */
-       dbg("interrupt");
-       status = inw (io_addr + USBSTS);
-
-       if (!status)            /* shared interrupt, not mine */
-               return;
-
-       if (status != 1) {
-               dbg("interrupt, status %x", status);
-               //uhci_show_status (s);
-       }
-       //beep(1000);           
-       /*
-        * the following is very subtle and was blatantly wrong before
-        * traverse the list in *reverse* direction, because new entries
-        * may be added at the end.
-        * also, because process_urb may unlink the current urb,
-        * we need to advance the list before
-        * - Thomas Sailer
-        */
-
-       spin_lock(&s->unlink_urb_lock);
-       spin_lock (&s->urb_list_lock);
-       p = s->urb_list.prev;
-       spin_unlock (&s->urb_list_lock);
-
-       while (p != &s->urb_list) {
-               p2 = p;
-               p = p->prev;
-               process_urb (s, p2);
-       }
-
-       spin_unlock(&s->unlink_urb_lock);       
-
-       outw (status, io_addr + USBSTS);
-#ifdef __alpha
-       mb ();                  // ?
-#endif
-       dbg("done");
-}
-
-static void reset_hc (puhci_t s)
-{
-       unsigned int io_addr = s->io_addr;
-
-       s->apm_state = 0;
-       /* Global reset for 50ms */
-       outw (USBCMD_GRESET, io_addr + USBCMD);
-       wait_ms (50);
-       outw (0, io_addr + USBCMD);
-       wait_ms (10);
-}
-
-static void start_hc (puhci_t s)
-{
-       unsigned int io_addr = s->io_addr;
-       int timeout = 1000;
-
-       /*
-        * Reset the HC - this will force us to get a
-        * new notification of any already connected
-        * ports due to the virtual disconnect that it
-        * implies.
-        */
-       outw (USBCMD_HCRESET, io_addr + USBCMD);
-
-       while (inw (io_addr + USBCMD) & USBCMD_HCRESET) {
-               if (!--timeout) {
-                       err("USBCMD_HCRESET timed out!");
-                       break;
-               }
-       }
-
-       /* Turn on all interrupts */
-       outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
-
-       /* Start at frame 0 */
-       outw (0, io_addr + USBFRNUM);
-       outl (virt_to_bus (s->framelist), io_addr + USBFLBASEADD);
-
-       /* Run and mark it configured with a 64-byte max packet */
-       outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-       s->apm_state = 1;
-}
-
-static void __exit uhci_cleanup_dev(puhci_t s)
-{
-       struct usb_device *root_hub = s->bus->root_hub;
-       if (root_hub)
-               usb_disconnect (&root_hub);
-
-       usb_deregister_bus (s->bus);
-
-       reset_hc (s);
-       release_region (s->io_addr, s->io_size);
-       free_irq (s->irq, s);
-       usb_free_bus (s->bus);
-       cleanup_skel (s);
-       kfree (s);
-
-}
-
-static int __init uhci_start_usb (puhci_t s)
-{                              /* start it up */
-       /* connect the virtual root hub */
-       struct usb_device *usb_dev;
-
-       usb_dev = usb_alloc_dev (NULL, s->bus);
-       if (!usb_dev)
-               return -1;
-
-       s->bus->root_hub = usb_dev;
-       usb_connect (usb_dev);
-
-       if (usb_new_device (usb_dev) != 0) {
-               usb_free_dev (usb_dev);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int __init alloc_uhci (int irq, unsigned int io_addr, unsigned int io_size)
-{
-       puhci_t s;
-       struct usb_bus *bus;
-
-       s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
-       if (!s)
-               return -1;
-
-       memset (s, 0, sizeof (uhci_t));
-       INIT_LIST_HEAD (&s->urb_list);
-       spin_lock_init (&s->urb_list_lock);
-       spin_lock_init (&s->qh_lock);
-       spin_lock_init (&s->td_lock);
-       spin_lock_init (&s->unlink_urb_lock);
-       s->irq = -1;
-       s->io_addr = io_addr;
-       s->io_size = io_size;
-       s->next = devs; //chain new uhci device into global list        
-
-       bus = usb_alloc_bus (&uhci_device_operations);
-       if (!bus) {
-               kfree (s);
-               return -1;
-       }
-
-       s->bus = bus;
-       bus->hcpriv = s;
-
-       /* UHCI specs says devices must have 2 ports, but goes on to say */
-       /* they may have more but give no way to determine how many they */
-       /* have, so default to 2 */
-       /* According to the UHCI spec, Bit 7 is always set to 1. So we try */
-       /* to use this to our advantage */
-
-       for (s->maxports = 0; s->maxports < (io_size - 0x10) / 2; s->maxports++) {
-               unsigned int portstatus;
-
-               portstatus = inw (io_addr + 0x10 + (s->maxports * 2));
-               dbg("port %i, adr %x status %x", s->maxports,
-                       io_addr + 0x10 + (s->maxports * 2), portstatus);
-               if (!(portstatus & 0x0080))
-                       break;
-       }
-       dbg("Detected %d ports", s->maxports);
-
-       /* This is experimental so anything less than 2 or greater than 8 is */
-       /*  something weird and we'll ignore it */
-       if (s->maxports < 2 || s->maxports > 8) {
-               dbg("Port count misdetected, forcing to 2 ports");
-               s->maxports = 2;
-       }
-
-       s->rh.numports = s->maxports;
-
-       if (init_skel (s)) {
-               usb_free_bus (bus);
-               kfree(s);
-               return -1;
-       }
-
-       request_region (s->io_addr, io_size, MODNAME);
-       reset_hc (s);
-       usb_register_bus (s->bus);
-
-       start_hc (s);
-
-       if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
-               err("request_irq %d failed!",irq);
-               usb_free_bus (bus);
-               reset_hc (s);
-               release_region (s->io_addr, s->io_size);
-               cleanup_skel(s);
-               kfree(s);
-               return -1;
-       }
-
-       s->irq = irq;
-
-       if(uhci_start_usb (s) < 0) {
-               uhci_cleanup_dev(s);
-               return -1;
-       }
-       
-       //chain new uhci device into global list
-       devs = s;
-
-       return 0;
-}
-
-static int __init start_uhci (struct pci_dev *dev)
-{
-       int i;
-
-       /* Search for the IO base address.. */
-       for (i = 0; i < 6; i++) {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
-               unsigned int io_addr = dev->resource[i].start;
-               unsigned int io_size =
-               dev->resource[i].end - dev->resource[i].start + 1;
-               if (!(dev->resource[i].flags & 1))
-                       continue;
-#else
-               unsigned int io_addr = dev->base_address[i];
-               unsigned int io_size = 0x14;
-               if (!(io_addr & 1))
-                       continue;
-               io_addr &= ~1;
-#endif
-
-               /* Is it already in use? */
-               if (check_region (io_addr, io_size))
-                       break;
-               /* disable legacy emulation */
-               pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-               return alloc_uhci(dev->irq, io_addr, io_size);
-       }
-       return -1;
-}
-
-#ifdef CONFIG_APM
-static int handle_apm_event (apm_event_t event)
-{
-       static int down = 0;
-       puhci_t s = devs;
-       dbg("handle_apm_event(%d)", event);
-       switch (event) {
-       case APM_SYS_SUSPEND:
-       case APM_USER_SUSPEND:
-               if (down) {
-                       dbg("received extra suspend event");
-                       break;
-               }
-               while (s) {
-                       reset_hc (s);
-                       s = s->next;
-               }
-               down = 1;
-               break;
-       case APM_NORMAL_RESUME:
-       case APM_CRITICAL_RESUME:
-               if (!down) {
-                       dbg("received bogus resume event");
-                       break;
-               }
-               down = 0;
-               while (s) {
-                       start_hc (s);
-                       s = s->next;
-               }
-               break;
-       }
-       return 0;
-}
-#endif
-
-int __init uhci_init (void)
-{
-       int retval = -ENODEV;
-       struct pci_dev *dev = NULL;
-       u8 type;
-       int i=0;
-
-#ifdef _UHCI_SLAB
-       char *slabname=kmalloc(16, GFP_KERNEL);
-
-       if(!slabname)
-               return -ENOMEM;
-
-       strcpy(slabname, "uhci_desc");
-       uhci_desc_kmem = kmem_cache_create(slabname, sizeof(uhci_desc_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-       
-       if(!uhci_desc_kmem) {
-               err("kmem_cache_create for uhci_desc failed (out of memory)");
-               return -ENOMEM;
-       }
-
-       slabname=kmalloc(16, GFP_KERNEL);
-
-       if(!slabname)
-               return -ENOMEM;
-
-       strcpy(slabname, "urb_priv");   
-       urb_priv_kmem = kmem_cache_create(slabname, sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-       
-       if(!urb_priv_kmem) {
-               err("kmem_cache_create for urb_priv_t failed (out of memory)");
-               return -ENOMEM;
-       }
-#endif 
-       info(VERSTR);
-
-       for (;;) {
-               dev = pci_find_class (PCI_CLASS_SERIAL_USB << 8, dev);
-               if (!dev)
-                       break;
-
-               /* Is it UHCI */
-               pci_read_config_byte (dev, PCI_CLASS_PROG, &type);
-               if (type != 0)
-                       continue;
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
-               pci_enable_device (dev);
-#endif
-               if(!dev->irq)
-               {
-                       err("Found UHCI device with no IRQ assigned. Check BIOS settings!");
-                       continue;
-               }
-
-               /* Ok set it up */
-               retval = start_uhci (dev);
-       
-               if (!retval)
-                       i++;
-
-       }
-
-#ifdef CONFIG_APM
-       if(i)
-               apm_register_callback (&handle_apm_event);
-#endif
-       return retval;
-}
-
-void __exit uhci_cleanup (void)
-{
-       puhci_t s;
-       while ((s = devs)) {
-               devs = devs->next;
-               uhci_cleanup_dev(s);
-       }
-#ifdef _UHCI_SLAB
-       kmem_cache_shrink(uhci_desc_kmem);
-       kmem_cache_shrink(urb_priv_kmem);
-#endif
-}
-
-#ifdef MODULE
-int init_module (void)
-{
-       return uhci_init ();
-}
-
-void cleanup_module (void)
-{
-#ifdef CONFIG_APM
-       apm_unregister_callback (&handle_apm_event);
-#endif
-       uhci_cleanup ();
-}
-
-#endif //MODULE
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
deleted file mode 100644 (file)
index d8ef7f0..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-#ifndef __LINUX_UHCI_H
-#define __LINUX_UHCI_H
-
-/*
-   $Id: uhci.h,v 1.30 1999/12/15 17:57:25 fliegl Exp $
- */
-#define MODNAME "usb-uhci"
-#define VERSTR "version v0.9 time " __TIME__ " " __DATE__
-
-/* Command register */
-#define USBCMD         0
-#define   USBCMD_RS            0x0001  /* Run/Stop */
-#define   USBCMD_HCRESET       0x0002  /* Host reset */
-#define   USBCMD_GRESET                0x0004  /* Global reset */
-#define   USBCMD_EGSM          0x0008  /* Global Suspend Mode */
-#define   USBCMD_FGR           0x0010  /* Force Global Resume */
-#define   USBCMD_SWDBG         0x0020  /* SW Debug mode */
-#define   USBCMD_CF            0x0040  /* Config Flag (sw only) */
-#define   USBCMD_MAXP          0x0080  /* Max Packet (0 = 32, 1 = 64) */
-
-/* Status register */
-#define USBSTS         2
-#define   USBSTS_USBINT                0x0001  /* Interrupt due to IOC */
-#define   USBSTS_ERROR         0x0002  /* Interrupt due to error */
-#define   USBSTS_RD            0x0004  /* Resume Detect */
-#define   USBSTS_HSE           0x0008  /* Host System Error - basically PCI problems */
-#define   USBSTS_HCPE          0x0010  /* Host Controller Process Error - the scripts were buggy */
-#define   USBSTS_HCH           0x0020  /* HC Halted */
-
-/* Interrupt enable register */
-#define USBINTR                4
-#define   USBINTR_TIMEOUT      0x0001  /* Timeout/CRC error enable */
-#define   USBINTR_RESUME       0x0002  /* Resume interrupt enable */
-#define   USBINTR_IOC          0x0004  /* Interrupt On Complete enable */
-#define   USBINTR_SP           0x0008  /* Short packet interrupt enable */
-
-#define USBFRNUM       6
-#define USBFLBASEADD   8
-#define USBSOF         12
-
-/* USB port status and control registers */
-#define USBPORTSC1     16
-#define USBPORTSC2     18
-#define   USBPORTSC_CCS                0x0001  /* Current Connect Status ("device present") */
-#define   USBPORTSC_CSC                0x0002  /* Connect Status Change */
-#define   USBPORTSC_PE         0x0004  /* Port Enable */
-#define   USBPORTSC_PEC                0x0008  /* Port Enable Change */
-#define   USBPORTSC_LS         0x0030  /* Line Status */
-#define   USBPORTSC_RD         0x0040  /* Resume Detect */
-#define   USBPORTSC_LSDA       0x0100  /* Low Speed Device Attached */
-#define   USBPORTSC_PR         0x0200  /* Port Reset */
-#define   USBPORTSC_SUSP       0x1000  /* Suspend */
-
-/* Legacy support register */
-#define USBLEGSUP 0xc0
-#define USBLEGSUP_DEFAULT 0x2000       /* only PIRQ enable set */
-
-#define UHCI_NULL_DATA_SIZE    0x7ff   /* for UHCI controller TD */
-
-#define UHCI_PTR_BITS          0x000F
-#define UHCI_PTR_TERM          0x0001
-#define UHCI_PTR_QH            0x0002
-#define UHCI_PTR_DEPTH         0x0004
-
-#define UHCI_NUMFRAMES         1024    /* in the frame list [array] */
-#define UHCI_MAX_SOF_NUMBER    2047    /* in an SOF packet */
-#define CAN_SCHEDULE_FRAMES    1000    /* how far future frames can be scheduled */
-
-/*
- * for TD <status>:
- */
-#define TD_CTRL_SPD            (1 << 29)       /* Short Packet Detect */
-#define TD_CTRL_C_ERR_MASK     (3 << 27)       /* Error Counter bits */
-#define TD_CTRL_LS             (1 << 26)       /* Low Speed Device */
-#define TD_CTRL_IOS            (1 << 25)       /* Isochronous Select */
-#define TD_CTRL_IOC            (1 << 24)       /* Interrupt on Complete */
-#define TD_CTRL_ACTIVE         (1 << 23)       /* TD Active */
-#define TD_CTRL_STALLED                (1 << 22)       /* TD Stalled */
-#define TD_CTRL_DBUFERR                (1 << 21)       /* Data Buffer Error */
-#define TD_CTRL_BABBLE         (1 << 20)       /* Babble Detected */
-#define TD_CTRL_NAK            (1 << 19)       /* NAK Received */
-#define TD_CTRL_CRCTIMEO       (1 << 18)       /* CRC/Time Out Error */
-#define TD_CTRL_BITSTUFF       (1 << 17)       /* Bit Stuff Error */
-#define TD_CTRL_ACTLEN_MASK    0x7ff   /* actual length, encoded as n - 1 */
-
-#define TD_CTRL_ANY_ERROR      (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
-                                TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
-
-#define uhci_status_bits(ctrl_sts)     (ctrl_sts & 0xFE0000)
-#define uhci_actual_length(ctrl_sts)   ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK)  /* 1-based */
-#define uhci_ptr_to_virt(x)    bus_to_virt(x & ~UHCI_PTR_BITS)
-
-/*
- * for TD <flags>:
- */
-#define UHCI_TD_REMOVE         0x0001  /* Remove when done */
-
-/*
- * for TD <info>: (a.k.a. Token)
- */
-#define TD_TOKEN_TOGGLE                19
-
-#define uhci_maxlen(token)     ((token) >> 21)
-#define uhci_toggle(token)     (((token) >> TD_TOKEN_TOGGLE) & 1)
-#define uhci_endpoint(token)   (((token) >> 15) & 0xf)
-#define uhci_devaddr(token)    (((token) >> 8) & 0x7f)
-#define uhci_devep(token)      (((token) >> 8) & 0x7ff)
-#define uhci_packetid(token)   ((token) & 0xff)
-#define uhci_packetout(token)  (uhci_packetid(token) != USB_PID_IN)
-#define uhci_packetin(token)   (uhci_packetid(token) == USB_PID_IN)
-
-/* ------------------------------------------------------------------------------------
-   New TD/QH-structures
-   ------------------------------------------------------------------------------------ */
-typedef enum {
-       TD_TYPE, QH_TYPE
-} uhci_desc_type_t;
-
-typedef struct {
-       __u32 link;
-       __u32 status;
-       __u32 info;
-       __u32 buffer;
-} uhci_td_t, *puhci_td_t;
-
-typedef struct {
-       __u32 head;
-       __u32 element;          /* Queue element pointer */
-} uhci_qh_t, *puhci_qh_t;
-
-typedef struct {
-       union {
-               uhci_td_t td;
-               uhci_qh_t qh;
-       } hw;
-       uhci_desc_type_t type;
-       struct list_head horizontal;
-       struct list_head vertical;
-       struct list_head desc_list;
-} uhci_desc_t, *puhci_desc_t;
-
-typedef struct {
-       struct list_head desc_list;     // list pointer to all corresponding TDs/QHs associated with this request
-       int short_control_packet;
-} urb_priv_t, *purb_priv_t;
-
-struct virt_root_hub {
-       int devnum;             /* Address of Root Hub endpoint */
-       void *urb;
-       void *int_addr;
-       int send;
-       int interval;
-       int numports;
-       int c_p_r[8];
-       struct timer_list rh_int_timer;
-};
-
-typedef struct uhci {
-       int irq;
-       unsigned int io_addr;
-       unsigned int io_size;
-       unsigned int maxports;
-
-       int apm_state;
-
-       struct uhci *next;      // chain of uhci device contexts
-
-       struct list_head urb_list;      // list of all pending urbs
-
-       spinlock_t urb_list_lock;       // lock to keep consistency 
-
-       struct usb_bus *bus;    // our bus
-
-       spinlock_t unlink_urb_lock;     // lock for unlink_urb
-
-       __u32 *framelist;
-       uhci_desc_t **iso_td;
-       uhci_desc_t *int_chain[8];
-       uhci_desc_t *control_chain;
-       uhci_desc_t *bulk_chain;
-       uhci_desc_t *chain_end;
-       spinlock_t qh_lock;
-       spinlock_t td_lock;
-       struct virt_root_hub rh;        //private data of the virtual root hub
-} uhci_t, *puhci_t;
-
-
-#define MAKE_TD_ADDR(a) (virt_to_bus(a)&~UHCI_PTR_QH)
-#define MAKE_QH_ADDR(a) (virt_to_bus(a)|UHCI_PTR_QH)
-#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
-
-/* ------------------------------------------------------------------------------------ 
-   Virtual Root HUB 
-   ------------------------------------------------------------------------------------ */
-/* 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
-
-/* Our Vendor Specific feature */
-#define RH_REMOVE_EP               0x00
-
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
-
-#define min(a,b) (((a)<(b))?(a):(b))
-
-#endif
index f0b30bf93a02d5e9c10ebe1023b673ac24d38601..fd211b1c445b7153840a43d8cad9be86673466ea 100644 (file)
@@ -32,6 +32,7 @@ void usb_major_cleanup(void);
 int usb_acm_init(void);
 int usb_audio_init(void);
 int usb_cpia_init(void);
+int usb_ibmcam_init(void);
 int usb_ov511_init(void);
 int usb_dc2xx_init(void);
 int usb_scanner_init(void);
@@ -98,6 +99,9 @@ int usb_init(void)
 #ifdef CONFIG_USB_CPIA
        usb_cpia_init();
 #endif
+#ifdef CONFIG_USB_IBMCAM
+       usb_ibmcam_init();
+#endif
 #ifdef CONFIG_USB_OV511
        usb_ov511_init();
 #endif
index 2cca351513eaa12d2e09c90f0404617e6c3227c0..925b3e2440c03160c86325b6464a9770f8f120b5 100644 (file)
@@ -6,8 +6,8 @@
  */
 #include <linux/version.h>
 #include <linux/kernel.h>
-#include <linux/slab.h>
-
+#include <linux/mm.h>
+#include <linux/malloc.h>
 #define DEBUG
 
 #include "usb.h"
@@ -59,6 +59,11 @@ void usb_show_device(struct usb_device *dev)
  */
 void usb_show_device_descriptor(struct usb_device_descriptor *desc)
 {
+       if (!desc)
+       {
+               printk("Invalid USB device descriptor (NULL POINTER)\n");
+               return;
+       }
        printk("  Length              = %2d%s\n", desc->bLength,
                desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)");
        printk("  DescriptorType      = %02x\n", desc->bDescriptorType);
@@ -132,6 +137,24 @@ void usb_show_interface_descriptor(struct usb_interface_descriptor *desc)
        printk("    iInterface          =   %02x\n", desc->iInterface);
 }
 
+void usb_show_hid_descriptor(struct usb_hid_descriptor * desc)
+{
+       int i;
+    
+       printk("    HID:\n");
+       printk("      HID version %x.%02x\n", desc->bcdHID >> 8, desc->bcdHID & 0xff);
+       printk("      bLength             = %4d\n", desc->bLength);
+       printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);
+       printk("      bCountryCode        =   %02x\n", desc->bCountryCode);
+       printk("      bNumDescriptors     =   %02x\n", desc->bNumDescriptors);
+
+       for (i=0; i<desc->bNumDescriptors; i++) {
+               printk("        %d:\n", i);
+               printk("            bDescriptorType      =   %02x\n", desc->desc[i].bDescriptorType);
+               printk("            wDescriptorLength    =   %04x\n", desc->desc[i].wDescriptorLength);
+       }
+}
+
 void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc)
 {
        char *LengthCommentString = (desc->bLength ==
@@ -167,3 +190,23 @@ void usb_show_string(struct usb_device *dev, char *id, int index)
        kfree(buf);
 }
 
+void usb_dump_urb (purb_t purb)
+{
+       printk ("urb                   :%p\n", purb);
+       printk ("next                  :%p\n", purb->next);
+       printk ("dev                   :%p\n", purb->dev);
+       printk ("pipe                  :%08X\n", purb->pipe);
+       printk ("status                :%d\n", purb->status);
+       printk ("transfer_flags        :%08X\n", purb->transfer_flags);
+       printk ("transfer_buffer       :%p\n", purb->transfer_buffer);
+       printk ("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
+       printk ("actual_length         :%d\n", purb->actual_length);
+       printk ("setup_packet          :%p\n", purb->setup_packet);
+       printk ("start_frame           :%d\n", purb->start_frame);
+       printk ("number_of_packets     :%d\n", purb->number_of_packets);
+       printk ("interval              :%d\n", purb->interval);
+       printk ("error_count           :%d\n", purb->error_count);
+       printk ("context               :%p\n", purb->context);
+       printk ("complete              :%p\n", purb->complete);
+}
+
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
new file mode 100644 (file)
index 0000000..2603749
--- /dev/null
@@ -0,0 +1,1823 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * 
+ * History:
+ * 
+ * v5.2 1999/12/07 URB 3rd preview, 
+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
+ *     i386: HUB, Keyboard, Mouse, Printer 
+ *
+ * v4.3 1999/10/27 multiple HCs, bulk_request
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18 
+ * v3.0 1999/06/25 
+ * v2.1 1999/05/09  code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27 initial release
+ * 
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>  /* for in_interrupt() */
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#undef DEBUG
+#define OHCI_USE_NPS
+
+#include "usb.h"
+#include "usb-ohci.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event (apm_event_t event);
+#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); 
+static LIST_HEAD (ohci_hcd_list);
+spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+
+/*-------------------------------------------------------------------------*
+ * URB support functions 
+ *-------------------------------------------------------------------------*/ 
+/* free the private part of an URB */
+static void urb_rm_priv (urb_t * urb) 
+{
+       urb_priv_t * urb_priv = urb->hcpriv;
+       int i;
+       void * wait;
+       
+       if (!urb_priv) return;
+       
+       wait = urb_priv->wait;
+       
+       for (i = 0; i < urb_priv->length; i++) {
+               if (urb_priv->td [i]) {
+                       OHCI_FREE (urb_priv->td [i]);
+               }
+       }
+       kfree (urb->hcpriv);
+       urb->hcpriv = NULL;
+       
+       if (wait) {
+               add_wait_queue (&op_wakeup, wait); 
+               wake_up (&op_wakeup);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header */
+static void urb_print (urb_t * 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;
+       }
+       
+       dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)", 
+                       str,
+                       sohci_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 (KERN_DEBUG __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 (KERN_DEBUG __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 < 16 && i < len; i++) 
+                               printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+                       printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+               }
+       } 
+       
+}
+/* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t * ohci, char * str) {
+       int i, j;
+        __u32 * ed_p;
+       for (i= 0; i < 32; i++) {
+               j = 5;
+               printk (KERN_DEBUG __FILE__ " %s branch int %2d(%2x):", str, i, i);
+               ed_p = &(ohci->hcca.int_table [i]);
+               while (*ed_p != 0 && j--) {
+                       ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
+                       printk (" ed: %4x;", ed->hwINFO);
+                       ed_p = &ed->hwNextED;
+               }
+               printk ("\n");
+       }
+}
+               
+
+#endif
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* return a request to the completion handler */
+static int sohci_return_urb (urb_t * urb)
+{
+       urb_priv_t * urb_priv = urb->hcpriv;
+       urb_t * urbt;
+       unsigned long flags;
+       int i;
+       
+       /* just to be sure */
+       if (!urb->complete) {
+               urb_rm_priv (urb);
+               usb_dec_dev_use (urb->dev);
+               return -1;
+       }
+       
+       if (!urb_priv) return -1; /* urb already unlinked */
+       
+#ifdef DEBUG
+       urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif
+
+       switch (usb_pipetype (urb->pipe)) {
+               case PIPE_INTERRUPT:
+                       urb->complete (urb); /* call complete and requeue URB */        
+                       urb->actual_length = 0;
+                       urb->status = USB_ST_URB_PENDING;
+                       if (urb_priv->state != URB_DEL)
+                               td_submit_urb (urb);
+                       break;
+                       
+               case PIPE_ISOCHRONOUS:
+                       for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
+                       if (urbt) { /* send the reply and requeue URB */        
+                               urb->complete (urb);
+                               
+                               spin_lock_irqsave (&usb_ed_lock, flags);
+                               urb->actual_length = 0;
+                               urb->status = USB_ST_URB_PENDING;
+                               urb->start_frame = urb_priv->ed->last_iso + 1;
+                               if (urb_priv->state != URB_DEL) {
+                                       for (i = 0; i < urb->number_of_packets; i++) {
+                                               urb->iso_frame_desc[i].actual_length = 0;
+                                               urb->iso_frame_desc[i].status = -EXDEV;
+                                       }
+                                       td_submit_urb (urb);
+                               }
+                               spin_unlock_irqrestore (&usb_ed_lock, flags);
+                               
+                       } else { /* unlink URB, call complete */
+                               urb_rm_priv (urb);
+                               usb_dec_dev_use (urb->dev);
+                               urb->complete (urb);    
+                       }               
+                       break;
+                               
+               case PIPE_BULK:
+               case PIPE_CONTROL: /* unlink URB, call complete */
+                       urb_rm_priv (urb);
+                       usb_dec_dev_use (urb->dev);
+                       urb->complete (urb);    
+                       break;
+       }
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+static int sohci_submit_urb (urb_t * urb)
+{
+       ohci_t * ohci;
+       ed_t * ed;
+       urb_priv_t * urb_priv;
+       unsigned int pipe = urb->pipe;
+       int i, size = 0;
+       unsigned long flags;
+       
+       if (!urb->dev || !urb->dev->bus) return -EINVAL;
+       
+       if (urb->hcpriv) return -EINVAL; /* urb already in use */
+
+       usb_inc_dev_use (urb->dev);
+       ohci = (ohci_t *) urb->dev->bus->hcpriv;
+       
+#ifdef DEBUG
+       urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+       
+       if (usb_pipedevice (pipe) == ohci->rh.devnum) 
+               return rh_submit_urb (urb); /* a request to the virtual root hub */
+
+       /* every endpoint has a ed, locate and fill it */
+       if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
+               usb_dec_dev_use (urb->dev);     
+               return -ENOMEM;
+       }
+
+       /* for the private part of the URB we need the number of TDs (size) */
+       switch (usb_pipetype (pipe)) {
+               case PIPE_BULK: /* one TD for every 4096 Byte */
+                       size = (urb->transfer_buffer_length - 1) / 4096 + 1;
+                       break;
+               case PIPE_ISOCHRONOUS: /* number of packets from URB */
+                       size = urb->number_of_packets;
+                       for (i = 0; i < urb->number_of_packets; i++) {
+                               urb->iso_frame_desc[i].actual_length = 0;
+                               urb->iso_frame_desc[i].status = -EXDEV;
+                       }
+                       break;
+               case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+                       size = (urb->transfer_buffer_length == 0)? 2: 
+                                               (urb->transfer_buffer_length - 1) / 4096 + 3;
+                       break;
+               case PIPE_INTERRUPT: /* one TD */
+                       size = 1;
+                       
+                       break;
+       }
+
+       /* allocate the private part or the URB */
+       urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
+                                                       in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+       if (!urb_priv) {
+               usb_dec_dev_use (urb->dev);     
+               return -ENOMEM;
+       }
+       memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
+       
+       /* fill the private part of the URB */
+       urb->hcpriv = urb_priv;
+       urb_priv->length = size;
+       urb_priv->td_cnt = 0;
+       urb_priv->state = 0;
+       urb_priv->ed = ed;      
+       urb_priv->wait = NULL;
+       
+       /* allocate the TDs */
+       for (i = 0; i < size; i++) { 
+               OHCI_ALLOC (urb_priv->td[i], sizeof (td_t));
+               if (!urb_priv->td[i]) {
+                       usb_dec_dev_use (urb->dev);     
+                       urb_rm_priv (urb);
+                       return -ENOMEM;
+               }
+       }       
+       spin_lock_irqsave (&usb_ed_lock, flags);        
+       if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+               urb_rm_priv(urb);
+               usb_dec_dev_use (urb->dev);     
+               return -EINVAL;
+       }
+       
+       /* for ISOC transfers calculate start frame index */
+       if (urb->transfer_flags & USB_ISO_ASAP) { 
+               urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): 
+                                                               (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
+       }       
+       
+       td_submit_urb (urb); /* fill the TDs and link it to the ed */
+                                               
+       if (ed->state != ED_OPER)  /* link the ed into a chain if is not already */
+               ep_link (ohci, ed);
+       spin_unlock_irqrestore (&usb_ed_lock, flags);
+       
+       urb->status = USB_ST_URB_PENDING; 
+       // queue_urb(s, &urb->urb_list);
+
+       return 0;       
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* deactivate all TDs and remove the private part of the URB */
+static int sohci_unlink_urb (urb_t * urb)
+{
+       unsigned long flags;
+       ohci_t * ohci;
+       DECLARE_WAITQUEUE (wait, current);
+       
+       if (!urb) /* just to be sure */ 
+               return -EINVAL;
+               
+#ifdef DEBUG
+       urb_print (urb, "UNLINK", 1);
+#endif           
+
+       ohci = (ohci_t *) urb->dev->bus->hcpriv; 
+
+       if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) 
+               return rh_unlink_urb (urb); /* a request to the virtual root hub */
+       
+       if (urb->hcpriv) { 
+               if (urb->status == USB_ST_URB_PENDING) { /* URB active? */
+                       urb_priv_t  * urb_priv = urb->hcpriv;
+                       urb_priv->state = URB_DEL; 
+                       /* we want to delete the TDs of an URB from an ed 
+                        * request the deletion, it will be handled at the next USB-frame */
+                       urb_priv->wait = &wait;
+                       
+                       spin_lock_irqsave (&usb_ed_lock, flags);
+                       ep_rm_ed (urb->dev, urb_priv->ed);
+                       urb_priv->ed->state |= ED_URB_DEL;
+                       spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+                       current->state = TASK_UNINTERRUPTIBLE;
+                       if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
+                               remove_wait_queue (&op_wakeup, &wait); 
+                       else
+                               err("unlink URB timeout!");
+               } else 
+                       urb_rm_priv (urb);
+               usb_dec_dev_use (urb->dev);             
+       }       
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* allocate private data space for a usb device */
+
+static int sohci_alloc_dev (struct usb_device *usb_dev)
+{
+       struct ohci_device * dev;
+
+       dev = kmalloc (sizeof (*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+               
+       memset (dev, 0, sizeof (*dev));
+
+       usb_dev->hcpriv = dev;
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* free private data space of usb device */
+  
+static int sohci_free_dev (struct usb_device * usb_dev)
+{
+       unsigned long flags;
+       int i, cnt = 0;
+       ed_t * ed;
+       DECLARE_WAITQUEUE (wait, current);
+       struct ohci_device * dev = usb_to_ohci (usb_dev);
+       ohci_t * ohci = usb_dev->bus->hcpriv;
+       
+       if (!dev) return 0;
+       
+       if (usb_dev->devnum >= 0) {
+       
+               /* delete all TDs of all EDs */
+               spin_lock_irqsave (&usb_ed_lock, flags);        
+               for(i = 0; i < NUM_EDS; i++) {
+                       ed = &(dev->ed[i]);
+                       if (ed->state != ED_NEW) {
+                               if (ed->state == ED_OPER) ep_unlink (ohci, ed);
+                               ep_rm_ed (usb_dev, ed);
+                               ed->state = ED_DEL;
+                               cnt++;
+                       }
+               }
+               spin_unlock_irqrestore (&usb_ed_lock, flags);
+               
+       if (cnt > 0) { 
+               dev->wait = &wait;
+                       current->state = TASK_UNINTERRUPTIBLE;
+                       schedule_timeout (HZ / 10);
+                       remove_wait_queue (&op_wakeup, &wait);
+               }
+       }
+       kfree (dev);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev) 
+{
+       ohci_t * ohci = usb_dev->bus->hcpriv;
+       
+       return le16_to_cpu (ohci->hcca.frame_no);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_operations sohci_device_operations = {
+       sohci_alloc_dev,
+       sohci_free_dev,
+       sohci_get_current_frame_number,
+       sohci_submit_urb,
+       sohci_unlink_urb
+};
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/  
+               
+/* search for the right branch to insert an interrupt ed into the int tree 
+ * do some load ballancing;
+ * returns the branch and 
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance (ohci_t * ohci, int interval, int load)
+{
+       int i, branch = 0;
+   
+       /* search for the least loaded interrupt endpoint branch of all 32 branches */
+       for (i = 0; i < 32; i++) 
+               if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i; 
+  
+       branch = branch % interval;
+       for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;
+
+       return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int( ld (inter)) */
+
+static int ep_2_n_interval (int inter)
+{      
+       int i;
+       for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); 
+       return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree 
+ * in order to process it sequentially the indexes of the branches have to be mapped 
+ * the mapping reverses the bits of a word of num_bits length */
+static int ep_rev (int num_bits, int word)
+{
+       int i, wout = 0;
+
+       for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
+       return wout;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t * ohci, ed_t * edi)
+{       
+       int int_branch;
+       int i;
+       int inter;
+       int interval;
+       int load;
+       __u32 * ed_p;
+       volatile ed_t * ed = edi;
+       
+       ed->state = ED_OPER;
+       
+       switch (ed->type) {
+       case CTRL:
+               ed->hwNextED = 0;
+               if (ohci->ed_controltail == NULL) {
+                       writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
+               } else {
+                       ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+               }
+               ed->ed_prev = ohci->ed_controltail;
+               ohci->ed_controltail = edi;       
+               break;
+               
+       case BULK:  
+               ed->hwNextED = 0;
+               if (ohci->ed_bulktail == NULL) {
+                       writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
+               } else {
+                       ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+               }
+               ed->ed_prev = ohci->ed_bulktail;
+               ohci->ed_bulktail = edi;          
+               break;
+               
+       case INT:
+               load = ed->int_load;
+               interval = ep_2_n_interval (ed->int_period);
+               ed->int_interval = interval;
+               int_branch = ep_int_ballance (ohci, interval, load);
+               ed->int_branch = int_branch;
+               
+               for (i = 0; i < ep_rev (6, interval); i += inter) {
+                       inter = 1;
+                       for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]); 
+                               (*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval >= interval); 
+                               ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
+                                       inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+                       ed->hwNextED = *ed_p; 
+                       *ed_p = cpu_to_le32 (virt_to_bus (ed));
+               }
+#ifdef DEBUG
+               ep_print_int_eds (ohci, "LINK_INT");
+#endif
+               break;
+               
+       case ISO:
+               ed->hwNextED = 0;
+               ed->int_interval = 1;
+               if (ohci->ed_isotail != NULL) {
+                       ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+                       ed->ed_prev = ohci->ed_isotail;
+               } else {
+                       for ( i = 0; i < 32; i += inter) {
+                               inter = 1;
+                               for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+                                       *ed_p != 0; 
+                                       ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
+                                               inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+                               *ed_p = cpu_to_le32 (virt_to_bus (ed)); 
+                       }       
+                       ed->ed_prev = NULL;
+               }       
+               ohci->ed_isotail = edi;  
+#ifdef DEBUG
+               ep_print_int_eds (ohci, "LINK_ISO");
+#endif
+               break;
+       }               
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains. 
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t * ohci, ed_t * ed) 
+{
+       int int_branch;
+       int i;
+       int inter;
+       int interval;
+       __u32 * ed_p;
+        
+    
+       switch (ed->type) {
+       case CTRL: 
+               if (ed->ed_prev == NULL) {
+                       writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
+               } else {
+                       ed->ed_prev->hwNextED = ed->hwNextED;
+               }
+               if(ohci->ed_controltail == ed) {
+                       ohci->ed_controltail = ed->ed_prev;
+               } else {
+                       ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+               }
+               break;
+      
+       case BULK: 
+               if (ed->ed_prev == NULL) {
+                       writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
+               } else {
+                       ed->ed_prev->hwNextED = ed->hwNextED;
+               }
+               if (ohci->ed_bulktail == ed) {
+                       ohci->ed_bulktail = ed->ed_prev;
+               } else {
+                       ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+               }
+               break;
+      
+    case INT: 
+       int_branch = ed->int_branch;
+               interval = ed->int_interval;
+
+               for (i = 0; i < ep_rev (6, interval); i += inter) {
+                       for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]), inter = 1; 
+                               (*ed_p != 0) && (*ed_p != ed->hwNextED); 
+                               ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED), 
+                               inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval)) {                               
+                                       if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+                                               *ed_p = ed->hwNextED;           
+                                               break;
+                                       }
+                         }
+               }
+               for (i = int_branch; i < 32; i += interval) ohci->ohci_int_load[i] -= ed->int_load;
+#ifdef DEBUG
+               ep_print_int_eds (ohci, "UNLINK_INT");
+#endif         break;
+               
+    case ISO:
+       if (ohci->ed_isotail == ed)
+                               ohci->ed_isotail = ed->ed_prev;
+               if (ed->hwNextED != 0) 
+                               ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+                               
+               if (ed->ed_prev != NULL) {
+                       ed->ed_prev->hwNextED = ed->hwNextED;
+               } else {
+                       for (i = 0; i < 32; i += inter) {
+                               inter = 1;
+                               for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+                                       *ed_p != 0; 
+                                       ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
+                                               inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+                                               if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+                                                       *ed_p = ed->hwNextED;           
+                                                       break;
+                                               }
+                               }
+                       }       
+               }       
+#ifdef DEBUG
+               ep_print_int_eds (ohci, "UNLINK_ISO");
+#endif
+               break;
+    }
+    ed->state = ED_UNLINK;
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless  so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load)
+{
+       ohci_t * ohci = usb_dev->bus->hcpriv;
+       td_t * td;
+       ed_t * ed_ret;
+       volatile ed_t * ed; 
+       
+       
+       spin_lock (&usb_ed_lock);
+
+       ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
+                       (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
+
+       if((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) 
+               return NULL; /* pending delete request */
+       
+       if (ed->state == ED_NEW) {
+               ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+               OHCI_ALLOC (td, sizeof (*td)); /* dummy td; end of td list for ed */
+               if(!td) return NULL; /* out of memory */
+               ed->hwTailP = cpu_to_le32 (virt_to_bus (td));
+               ed->hwHeadP = ed->hwTailP;      
+               ed->state = ED_UNLINK;
+               ed->type = usb_pipetype (pipe);
+               usb_to_ohci (usb_dev)->ed_cnt++;
+       }
+
+       ohci->dev[usb_pipedevice (pipe)] = usb_dev;
+       
+       ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
+                       | usb_pipeendpoint (pipe) << 7
+                       | (usb_pipeisoc (pipe)? 0x8000: 0)
+                       | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
+                       | usb_pipeslow (pipe) << 13
+                       | usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
+  
+       if (ed->type == INT && ed->state == ED_UNLINK) {
+               ed->int_period = interval;
+               ed->int_load = load;
+       }
+       
+       spin_unlock(&usb_ed_lock);
+       return ed_ret; 
+}
+
+/*-------------------------------------------------------------------------*/
+/* request the removal of an endpoint
+ * put the ep on the rm_list and request a stop of the bulk or ctrl list 
+ * real removal is done at the next start of frame (SOF) hardware interrupt */
+static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
+{    
+       unsigned int frame;
+       ohci_t * ohci = usb_dev->bus->hcpriv;
+
+       if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) return;
+       
+       ed->hwINFO  |=  cpu_to_le32 (OHCI_ED_SKIP);
+       
+       writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+       writel (OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
+
+       frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1;
+       ed->ed_rm_list = ohci->ed_rm_list[frame];
+       ohci->ed_rm_list[frame] = ed;
+
+       switch (ed->type) {
+               case CTRL: /* stop CTRL list */
+                       writel (ohci->hc_control &= ~(0x01 << 4), &ohci->regs->control); 
+                       break;
+               case BULK: /* stop BULK list */
+                       writel (ohci->hc_control &= ~(0x01 << 5), &ohci->regs->control); 
+                       break;
+       }
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* prepare a TD */
+
+static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int type, int index)
+{
+       volatile td_t  * td, * td_pt;
+       urb_priv_t * urb_priv = urb->hcpriv;
+
+       if (index >= urb_priv->length) {
+               err("internal OHCI error: TD index > length");
+               return;
+       }
+       
+       td_pt = urb_priv->td [index];
+       /* fill the old dummy TD */
+       td = urb_priv->td [index] = (td_t *) bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0);
+       td->ed = urb_priv->ed;
+       td->index = index;
+       td->urb = urb; 
+       td->hwINFO = cpu_to_le32 (info);
+       td->type = type;
+       if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
+               td->hwCBP = cpu_to_le32 (((!data || !len)? 
+                                                               0 : virt_to_bus (data)) & 0xFFFFF000);
+               td->ed->last_iso = info & 0xffff;
+       } else {
+               td->hwCBP = cpu_to_le32 (((!data || !len)? 0 : virt_to_bus (data))); 
+       }                       
+       td->hwBE = cpu_to_le32 ((!data || !len )? 0: virt_to_bus (data + len - 1));
+       td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt));
+       td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000);
+       td_pt->hwNextTD = 0;
+       td->ed->hwTailP = td->hwNextTD;
+   
+       td->next_dl_td = NULL; //td_pt;
+}
+
+/*-------------------------------------------------------------------------*/
+/* prepare all TDs of a transfer */
+
+static void td_submit_urb (urb_t * urb)
+{ 
+       urb_priv_t * urb_priv = urb->hcpriv;
+       ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
+       void * ctrl = urb->setup_packet;
+       void * data = urb->transfer_buffer;
+       int data_len = urb->transfer_buffer_length;
+       int cnt = 0; 
+       __u32 info = 0;
+  
+
+       urb_priv->td_cnt = 0;
+       
+       switch (usb_pipetype (urb->pipe)) {
+               case PIPE_BULK:
+                       info = usb_pipeout (urb->pipe)? 
+                               TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_DP_IN | TD_T_TOGGLE;
+                       while(data_len > 4096) {                
+                               td_fill (info, data, 4096, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+                               data += 4096; data_len -= 4096; cnt++;
+                       }
+                       info = usb_pipeout (urb->pipe)?
+                               TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE;
+                       td_fill (info, data, data_len, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt);
+                       cnt++;
+                       writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+                       break;
+
+               case PIPE_INTERRUPT:
+                       info = usb_pipeout (urb->pipe)? 
+                               TD_CC | TD_DP_OUT | TD_T_TOGGLE: TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE;
+                       td_fill (info, data, data_len, urb, ST_ADDR | ADD_LEN, cnt++);
+                       break;
+
+               case PIPE_CONTROL:
+                       info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+                       td_fill (info, ctrl, 8, urb, ST_ADDR, cnt++); 
+                       if (data_len > 0) {  
+                               info = usb_pipeout (urb->pipe)? 
+                                       TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+                               td_fill (info, data, data_len, urb, ADD_LEN, cnt++);  
+                       } 
+                       info = usb_pipeout (urb->pipe)? 
+                               TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+                       td_fill (info, NULL, 0, urb, 0, cnt++);
+                       writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+                       break;
+
+               case PIPE_ISOCHRONOUS:
+                       for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+                               td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
+                                       (__u8 *) data + urb->iso_frame_desc[cnt].offset, 
+                                       urb->iso_frame_desc[cnt].length, urb, (cnt? 0: ST_ADDR) | ADD_LEN, cnt); 
+                       }
+                       break;
+       } 
+       if (urb_priv->length != cnt) 
+               dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+static td_t * dl_reverse_done_list (ohci_t * ohci)
+{
+       __u32 td_list_hc;
+       td_t * td_rev = NULL;
+       td_t * td_list = NULL;
+       urb_priv_t * urb_priv = NULL;
+       unsigned long flags;
+       
+       spin_lock_irqsave (&usb_ed_lock, flags);
+       
+       td_list_hc = le32_to_cpup (&ohci->hcca.done_head) & 0xfffffff0;
+       ohci->hcca.done_head = 0;
+       
+       while (td_list_hc) {            
+               td_list = (td_t *) bus_to_virt (td_list_hc);
+
+               if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
+                       urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+                       dbg(" USB-error/status: %x : %p", 
+                                       TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
+                       if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
+                               if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
+                                       td_list->ed->hwHeadP = 
+                                               (urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
+                                                                       (td_list->ed->hwHeadP & cpu_to_le32 (0x2));
+                                       urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
+                               } else 
+                                       td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
+                       }
+               }
+
+               td_list->next_dl_td = td_rev;   
+               td_rev = td_list;
+               td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;    
+       }       
+       spin_unlock_irqrestore (&usb_ed_lock, flags);
+       return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* there are some pending requests to remove 
+ * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
+ * - some URBs/TDs if urb_priv->state == URB_DEL */
+static void dl_del_list (ohci_t  * ohci, unsigned int frame)
+{
+       unsigned long flags;
+       ed_t * ed;
+       __u32 edINFO;
+       td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
+       __u32 * td_p;
+       int ctrl = 0, bulk = 0;
+
+       spin_lock_irqsave (&usb_ed_lock, flags);
+       for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
+
+               tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+               tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+               edINFO = le32_to_cpup (&ed->hwINFO);
+               td_p = &ed->hwHeadP;
+                       
+               for (td = tdHeadP; td != tdTailP; td = td_next) { 
+                       urb_t * urb = td->urb;
+                       urb_priv_t * urb_priv = td->urb->hcpriv;
+                       
+                       td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+                       if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
+                               *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
+                               if(++ (urb_priv->td_cnt) == urb_priv->length) 
+                                       urb_rm_priv (urb);
+                       } else {
+                               td_p = &td->hwNextTD;
+                       }
+                       
+               }
+               if (ed->state & ED_DEL) { /* set by sohci_free_dev */
+                       struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
+                       OHCI_FREE (tdTailP); /* free dummy td */
+                       ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
+                       ed->state = ED_NEW; 
+                       /* if all eds are removed wake up sohci_free_dev */
+                       if ((! --dev->ed_cnt) && dev->wait) {
+                               add_wait_queue (&op_wakeup, dev->wait); 
+                               wake_up (&op_wakeup);
+                       }
+               }
+               else {
+                       ed->state &= ~ED_URB_DEL;
+                       ed->hwINFO  &=  ~cpu_to_le32 (OHCI_ED_SKIP);
+               }
+               
+               if ((ed->type & 3) == CTRL) ctrl |= 1;
+               if ((ed->type & 3) == BULK) bulk |= 1;  
+       }
+       
+       if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
+       if (bulk) writel (0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
+       if (!ohci->ed_rm_list[!frame])          /* start CTRL u. BULK list */ 
+               writel (ohci->hc_control |= (0x03<<4), &ohci->regs->control);   
+       ohci->ed_rm_list[frame] = NULL;
+
+       spin_unlock_irqrestore (&usb_ed_lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+
+static void dl_done_list (ohci_t * ohci, td_t * td_list)
+{
+       td_t * td_list_next = NULL;
+       ed_t * ed;
+       int dlen = 0;
+       int cc = 0;
+       urb_t * urb;
+       urb_priv_t * urb_priv;
+       __u32 tdINFO, tdBE, tdCBP, edHeadP, edTailP;
+       __u16 tdPSW;
+       unsigned long flags;
+       
+       while (td_list) {
+               td_list_next = td_list->next_dl_td;
+               
+               urb = td_list->urb;
+               urb_priv = urb->hcpriv;
+               tdINFO = le32_to_cpup (&td_list->hwINFO);
+               tdBE   = le32_to_cpup (&td_list->hwBE);
+               tdCBP  = le32_to_cpup (&td_list->hwCBP);
+               
+               ed = td_list->ed;
+               
+               if (td_list->type & ST_ADDR) 
+                       urb->actual_length = 0;
+                       
+               if (td_list->type & ADD_LEN) { /* accumulate length of multi td transfers */
+                       if (tdINFO & TD_ISO) {
+                               tdPSW = le16_to_cpu (td_list->hwPSW[0]);
+                               cc = (tdPSW >> 12) & 0xF;
+                               if (cc < 0xE)  {
+                                       if (usb_pipeout(urb->pipe)) {
+                                               dlen = urb->iso_frame_desc[td_list->index].length;
+                                       } else {
+                                               dlen = tdPSW & 0x3ff;
+                                       }
+                                       urb->actual_length += dlen;
+                                       urb->iso_frame_desc[td_list->index].actual_length = dlen;
+                                       if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
+                                               cc = TD_CC_NOERROR;
+                                        
+                                       urb->iso_frame_desc[td_list->index].status = cc_to_error[cc];
+                               }
+                       } else {
+                               if (tdBE != 0) {
+                                       dlen = (bus_to_virt (tdBE) - urb->transfer_buffer + 1);
+                                       if (td_list->hwCBP == 0)
+                                       urb->actual_length += dlen;
+                                       else
+                                       urb->actual_length += (bus_to_virt(tdCBP) - urb->transfer_buffer);
+                           }
+                       }
+               }
+               /* error code of transfer */
+               cc = TD_CC_GET (tdINFO);
+               if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
+                                               cc = TD_CC_NOERROR;
+               if (++(urb_priv->td_cnt) == urb_priv->length) {
+                       if (urb_priv->state != URB_DEL && !(ed->state & ED_DEL) && ed->state != ED_NEW) { 
+                               urb->status = cc_to_error[cc];
+                               sohci_return_urb (urb);
+                       } else {
+                               urb_rm_priv (urb);
+                       }
+               }
+               
+               spin_lock_irqsave (&usb_ed_lock, flags);
+               if (ed->state != ED_NEW) { 
+                       edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
+                       edTailP = le32_to_cpup (&ed->hwTailP);
+
+               if((edHeadP == edTailP) && (ed->state == ED_OPER)) 
+                       ep_unlink (ohci, ed); /* unlink eds if they are not busy */
+               
+       }       
+       spin_unlock_irqrestore (&usb_ed_lock, flags);
+       
+       td_list = td_list_next;
+       }  
+}
+
+
+
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+static __u8 root_hub_dev_des[] =
+{
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x00,       /*  __u16 bcdUSB; v1.0 */
+       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; */
+       0x00,       /*  __u8  iProduct; */
+       0x00,       /*  __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 */
+       0x08,       /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+       0x00,
+       0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* 
+For OHCI we need just the  2nd Byte, so we 
+don't need this constant byte-array 
+
+static __u8 root_hub_hub_des[] =
+{ 
+       0x00,       *  __u8  bLength; *
+       0x29,       *  __u8  bDescriptorType; Hub-descriptor *
+       0x02,       *  __u8  bNbrPorts; *
+       0x00,       * __u16  wHubCharacteristics; *
+       0x00,
+       0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
+       0x00,       *  __u8  bHubContrCurrent; 0 mA *
+       0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
+       0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
+};
+*/
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */ 
+static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
+{
+       int num_ports;
+       int i;
+       int ret;
+       int len;
+
+       __u8 data[8];
+
+       num_ports = readl (&ohci->regs->roothub.a) & 0xff; 
+       *(__u8 *) data = (readl (&ohci->regs->roothub.status) & 0x00030000) > 0? 1: 0;
+       ret = *(__u8 *) data;
+
+       for ( i = 0; i < num_ports; i++) {
+               *(__u8 *) (data + (i + 1) / 8) |= 
+                       ((readl (&ohci->regs->roothub.portstatus[i]) & 0x001f0000) > 0? 1: 0) << ((i + 1) % 8);
+               ret += *(__u8 *) (data + (i + 1) / 8);
+       }
+       len = i/8 + 1;
+  
+       if (ret > 0) { 
+               memcpy (rh_data, data, min (len, min (rh_len, sizeof(data))));
+               return len;
+       }
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+static void rh_int_timer_do (unsigned long ptr)
+{
+       int len; 
+
+       urb_t * urb = (urb_t *) ptr;
+       ohci_t * ohci = urb->dev->bus->hcpriv;
+       
+       if(ohci->rh.send) { 
+               len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
+               if (len > 0) {
+                       urb->actual_length = len;
+#ifdef DEBUG
+                       urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+#endif
+                       if (urb->complete) urb->complete (urb);
+               }
+       }       
+       rh_init_int_timer (urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Root Hub INTs are polled by this timer */
+
+static int rh_init_int_timer (urb_t * urb) 
+{
+       ohci_t * ohci = urb->dev->bus->hcpriv;
+
+       ohci->rh.interval = urb->interval;
+       init_timer (&ohci->rh.rh_int_timer);
+       ohci->rh.rh_int_timer.function = rh_int_timer_do;
+       ohci->rh.rh_int_timer.data = (unsigned long) urb;
+       ohci->rh.rh_int_timer.expires = 
+                       jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
+       add_timer (&ohci->rh.rh_int_timer);
+       
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x)                          len = (x); break
+#define WR_RH_STAT(x)          writel((x), &ohci->regs->roothub.status)
+#define WR_RH_PORTSTAT(x)      writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
+#define RD_RH_STAT                     readl(&ohci->regs->roothub.status)
+#define RD_RH_PORTSTAT         readl(&ohci->regs->roothub.portstatus[wIndex-1])
+
+/* request to virtual root hub */
+
+static int rh_submit_urb (urb_t * urb)
+{
+       struct usb_device * usb_dev = urb->dev;
+       ohci_t * ohci = usb_dev->bus->hcpriv;
+       unsigned int pipe = urb->pipe;
+       devrequest * cmd = (devrequest *) urb->setup_packet;
+       void * data = urb->transfer_buffer;
+       int leni = urb->transfer_buffer_length;
+       int len = 0;
+       int status = TD_CC_NOERROR;
+       
+       __u8 datab[16];
+       __u8  * data_buf = datab;
+       
+       __u16 bmRType_bReq;
+       __u16 wValue; 
+       __u16 wIndex;
+       __u16 wLength;
+
+       if (usb_pipeint(pipe)) {
+       
+               ohci->rh.urb =  urb;
+               ohci->rh.send = 1;
+               ohci->rh.interval = urb->interval;
+               rh_init_int_timer(urb);
+               urb->status = cc_to_error [TD_CC_NOERROR];
+               
+               return 0;
+       }
+
+       bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+       wValue        = le16_to_cpu (cmd->value);
+       wIndex        = le16_to_cpu (cmd->index);
+       wLength       = le16_to_cpu (cmd->length);
+       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 (RD_RH_STAT & 0x7fff7fff); OK (4);
+               case RH_GET_STATUS | RH_OTHER | RH_CLASS:       
+                               *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); 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): 
+                                               WR_RH_STAT(RH_HS_OCIC); OK (0);
+                       }
+                       break;
+               
+               case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+                       switch (wValue) {
+                               case (RH_PORT_ENABLE):                  
+                                               WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+                               case (RH_PORT_SUSPEND):                 
+                                               WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+                               case (RH_PORT_POWER):                   
+                                               WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+                               case (RH_C_PORT_CONNECTION):    
+                                               WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+                               case (RH_C_PORT_ENABLE):                
+                                               WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+                               case (RH_C_PORT_SUSPEND):               
+                                               WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+                               case (RH_C_PORT_OVER_CURRENT):  
+                                               WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+                               case (RH_C_PORT_RESET):                 
+                                               WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); 
+                       }
+                       break;
+               case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+                       switch (wValue) {
+                               case (RH_PORT_SUSPEND):                 
+                                               WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 
+                               case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+                                               if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PRS ); OK (0);
+                               case (RH_PORT_POWER):                   
+                                               WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 
+                               case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+                                               if((RD_RH_PORTSTAT &1) != 0)  WR_RH_PORTSTAT (RH_PS_PES ); OK (0);
+                       }
+                       break;
+
+               case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
+
+               case RH_GET_DESCRIPTOR:
+                       switch ((wValue & 0xff00) >> 8) {
+                               case (0x01): /* device descriptor */
+                                       len = min (leni, min (sizeof (root_hub_dev_des), wLength));
+                                       data_buf = root_hub_dev_des; OK(len);
+                               case (0x02): /* configuration descriptor */
+                                       len = min (leni, min (sizeof (root_hub_config_des), wLength));
+                                       data_buf = root_hub_config_des; OK(len);
+                               case (0x03): /* string descriptors */
+                               default: 
+                                       status = TD_CC_STALL;
+                       }
+                       break;
+               
+               case RH_GET_DESCRIPTOR | RH_CLASS:
+                       *(__u8 *)  (data_buf+1) = 0x29;
+                       *(__u32 *) (data_buf+2) = cpu_to_le32 (readl (&ohci->regs->roothub.a));  
+                       *(__u8 *)  data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */
+                                
+                       len = min (leni, min(*(__u8 *) data_buf, wLength));
+                       *(__u8 *) (data_buf+6) = 0; /* Root Hub needs no current from bus */
+                       if (*(__u8 *) (data_buf+2) < 8) { /* less than 8 Ports */
+                               *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff; 
+                               *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16; 
+                       } else {
+                               *(__u32 *) (data_buf+7) = cpu_to_le32 (readl(&ohci->regs->roothub.b)); 
+                       }
+                       OK (len); 
+               case RH_GET_CONFIGURATION:      *(__u8 *) data_buf = 0x01; OK (1);
+
+               case RH_SET_CONFIGURATION:      WR_RH_STAT (0x10000); OK (0);
+
+               default: 
+                       status = TD_CC_STALL;
+       }
+       
+       dbg("USB HC roothubstat1: %x", readl ( &(ohci->regs->roothub.portstatus[0]) ));
+       dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
+
+       len = min(len, leni);
+       memcpy (data, data_buf, len);
+       urb->actual_length = len;
+       urb->status = cc_to_error [status];
+       
+#ifdef DEBUG
+       urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+#endif
+
+       if (urb->complete) urb->complete (urb);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_unlink_urb (urb_t * urb)
+{
+       ohci_t * ohci = urb->dev->bus->hcpriv;
+       ohci->rh.send = 0;
+       del_timer (&ohci->rh.rh_int_timer);
+       return 0;
+}
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC not the BUS */
+
+static void hc_reset (ohci_t * ohci)
+{
+       int timeout = 30;
+       int smm_timeout = 50; /* 0,5 sec */
+               
+       if (readl (&ohci->regs->control) & 0x100) { /* SMM owns the HC */
+               writel (0x08, &ohci->regs->cmdstatus); /* request ownership */
+               dbg("USB HC TakeOver from SMM");
+               while (readl (&ohci->regs->control) & 0x100) {
+                       wait_ms (10);
+                       if (--smm_timeout == 0) {
+                               err("USB HC TakeOver failed!");
+                               break;
+                       }
+               }
+       }       
+               
+       writel ((1 << 31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+       dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
+       /* this seems to be needed for the lucent controller on powerbooks.. */
+       writel (0, &ohci->regs->control);           /* Move USB to reset state */
+       
+       writel (1,  &ohci->regs->cmdstatus);       /* HC Reset */
+       while ((readl (&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+               if (--timeout == 0) {
+                       err("USB HC reset timed out!");
+                       return;
+               }       
+               udelay (1);
+       }        
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts 
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+       unsigned int mask;
+       unsigned int fminterval;
+       struct usb_device  * usb_dev;
+       struct ohci_device * dev;
+       
+       /* Tell the controller where the control and bulk lists are
+        * The lists are empty now. */
+        
+       writel (0, &ohci->regs->ed_controlhead);
+       writel (0, &ohci->regs->ed_bulkhead);
+       
+       writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
+   
+       fminterval = 0x2edf;
+       writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+       fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 
+       writel (fminterval, &ohci->regs->fminterval);   
+       writel (0x628, &ohci->regs->lsthresh);
+
+       /* Choose the interrupts we care about now, others later on demand */
+       mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO;
+       
+       writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
+       writel (mask, &ohci->regs->intrenable);
+       writel (mask, &ohci->regs->intrstatus);
+
+#ifdef OHCI_USE_NPS
+       writel ((readl(&ohci->regs->roothub.a) | 0x200) & ~0x100,
+               &ohci->regs->roothub.a);
+       writel (0x10000, &ohci->regs->roothub.status);
+       mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
+#endif /* OHCI_USE_NPS */
+       /* connect the virtual root hub */
+       
+       usb_dev = usb_alloc_dev (NULL, ohci->bus);
+       if (!usb_dev) return -1;
+
+       dev = usb_to_ohci (usb_dev);
+       ohci->bus->root_hub = usb_dev;
+       usb_connect (usb_dev);
+       if (usb_new_device (usb_dev) != 0) {
+               usb_free_dev (usb_dev); 
+               return -1;
+       }
+       
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
+{
+       ohci_t * ohci = __ohci;
+       struct ohci_regs * regs = ohci->regs;
+       int ints; 
+
+       if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) {
+               ints =  OHCI_INTR_WDH;
+       } else { 
+               if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0)
+                       return;
+       } 
+
+       dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+       
+       if (ints & OHCI_INTR_WDH) {
+               writel (OHCI_INTR_WDH, &regs->intrdisable);     
+               dl_done_list (ohci, dl_reverse_done_list (ohci));
+               writel (OHCI_INTR_WDH, &regs->intrenable); 
+       }
+  
+       if (ints & OHCI_INTR_SO) {
+               dbg("USB Schedule overrun");
+               writel (OHCI_INTR_SO, &regs->intrenable);        
+       }
+
+       if (ints & OHCI_INTR_SF) { 
+               unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
+               writel (OHCI_INTR_SF, &regs->intrdisable);      
+               if (ohci->ed_rm_list[!frame] != NULL) {
+                       dl_del_list (ohci, !frame);
+               }
+               if (ohci->ed_rm_list[frame] != NULL) writel (OHCI_INTR_SF, &regs->intrenable);  
+       }
+       writel (ints, &regs->intrstatus);
+       writel (OHCI_INTR_MIE, &regs->intrenable);      
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* allocate OHCI */
+
+static ohci_t * hc_alloc_ohci (void * mem_base)
+{
+       int i;
+       ohci_t * ohci;
+       struct usb_bus * bus;
+
+       ohci = (ohci_t *) __get_free_pages (GFP_KERNEL, 1);
+       if (!ohci)
+               return NULL;
+               
+       memset (ohci, 0, sizeof (ohci_t));
+       
+       ohci->irq = -1;
+       ohci->regs = mem_base;   
+
+       /* for load ballancing of the interrupt branches */
+       for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+       for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
+       
+       /* end of control and bulk lists */      
+       ohci->ed_isotail     = NULL;
+       ohci->ed_controltail = NULL;
+       ohci->ed_bulktail    = NULL;
+
+       bus = usb_alloc_bus (&sohci_device_operations);
+       if (!bus) {
+               free_pages ((unsigned long) ohci, 1);
+               return NULL;
+       }
+
+       ohci->bus = bus;
+       bus->hcpriv = (void *) ohci;
+       return ohci;
+} 
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t * ohci)
+{      
+       dbg("USB HC release ohci");
+
+       /* disconnect all devices */    
+       if (ohci->bus->root_hub) usb_disconnect (&ohci->bus->root_hub);
+       
+       hc_reset (ohci);
+       writel (OHCI_USB_RESET, &ohci->regs->control);
+       wait_ms (10);
+       
+       if (ohci->irq >= 0) {
+               free_irq (ohci->irq, ohci);
+               ohci->irq = -1;
+       }
+
+       usb_deregister_bus (ohci->bus);
+       usb_free_bus (ohci->bus);
+    
+       /* unmap the IO address space */
+       iounmap (ohci->regs);
+       
+       free_pages ((unsigned long) ohci, 1);   
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Increment the module usage count, start the control thread and
+ * return success. */
+static int hc_found_ohci (int irq, void * mem_base)
+{
+       ohci_t * ohci;
+       dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base);
+    
+       ohci = hc_alloc_ohci (mem_base);
+       if (!ohci) {
+               return -ENOMEM;
+       }
+       
+       INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+       list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+       
+       hc_reset (ohci);
+       writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
+       wait_ms (10);
+       usb_register_bus (ohci->bus);
+       
+       if (request_irq (irq, hc_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+               ohci->irq = irq;     
+               hc_start (ohci);
+               return 0;
+       }       
+       err("request interrupt %d failed", irq);
+       hc_release_ohci (ohci);
+       return -EBUSY;
+}
+
+/*-------------------------------------------------------------------------*/
+static int hc_start_ohci (struct pci_dev * dev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+       unsigned long mem_base = dev->resource[0].start;
+#else
+       unsigned long mem_base = dev->base_address[0];
+       if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
+       mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+#endif
+       
+       pci_set_master (dev);
+       mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
+
+       if (!mem_base) {
+               err("Error mapping OHCI memory");
+               return -EFAULT;
+       }
+       return hc_found_ohci (dev->irq, (void *) mem_base);
+} 
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PMAC_PBOOK
+
+/* On Powerbooks, put the controller into suspend mode when going
+ * to sleep, and do a resume when waking up. */
+
+static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
+{
+       struct list_head * ohci_l;
+       ohci_t * ohci;
+       
+       for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
+       ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
+
+               switch (when) {
+               case PBOOK_SLEEP_NOW:
+                       disable_irq (ohci->irq);
+                       writel (ohci->hc_control = OHCI_USB_SUSPEND, &ohci->regs->control);
+                       wait_ms (10);
+                       break;
+               case PBOOK_WAKE:
+                       writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
+                       wait_ms (20);
+                       writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+                       enable_irq (ohci->irq);
+                       break;
+               }
+       }
+       return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier ohci_sleep_notifier = {
+       ohci_sleep_notify, SLEEP_LEVEL_MISC,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_APM
+static int handle_apm_event (apm_event_t event) 
+{
+       static int down = 0;
+       ohci_t * ohci;
+       struct list_head * ohci_l;
+       
+       switch (event) {
+       case APM_SYS_SUSPEND:
+       case APM_USER_SUSPEND:
+               if (down) {
+                       dbg("received extra suspend event");
+                       break;
+               }
+               for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
+                       ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
+                       dbg("USB-Bus suspend: %p", ohci);
+                       writel (ohci->hc_control = 0xFF, &ohci->regs->control);
+               }
+               wait_ms (10);
+               down = 1;
+               break;
+       case APM_NORMAL_RESUME:
+       case APM_CRITICAL_RESUME:
+               if (!down) {
+                       dbg("received bogus resume event");
+                       break;
+               }
+               for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
+                       ohci = list_entry(ohci_l, ohci_t, ohci_hcd_list);
+                       dbg("USB-Bus resume: %p", ohci);
+                       writel (ohci->hc_control = 0x7F, &ohci->regs->control);
+               }               
+               wait_ms (20);
+               for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
+                       ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
+                       writel (ohci->hc_control = 0xBF, &ohci->regs->control);
+               }
+               down = 0;
+               break;
+       }
+       return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
+int ohci_hcd_init (void) 
+{
+       int ret = -ENODEV;
+       struct pci_dev * dev = NULL;
+       while ((dev = pci_find_class (PCI_CLASS_SERIAL_USB_OHCI, dev))) { 
+               if (hc_start_ohci(dev) >= 0) ret = 0;
+       }
+    
+#ifdef CONFIG_APM
+       apm_register_callback (&handle_apm_event);
+#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+       pmu_register_sleep_notifier (&ohci_sleep_notifier);
+#endif  
+    return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef MODULE
+int init_module (void) 
+{
+       return ohci_hcd_init ();
+}
+
+/*-------------------------------------------------------------------------*/
+
+void cleanup_module (void) 
+{      
+       ohci_t * ohci;
+       
+#ifdef CONFIG_APM
+       apm_unregister_callback (&handle_apm_event);
+#endif
+
+#ifdef CONFIG_PMAC_PBOOK
+       pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
+#endif  
+
+       while (!list_empty (&ohci_hcd_list)) {
+               ohci = list_entry (ohci_hcd_list.next, ohci_t, ohci_hcd_list);
+               list_del (&ohci->ohci_hcd_list);
+               INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+               hc_release_ohci (ohci);
+       }               
+}
+#endif //MODULE
+
diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
new file mode 100644 (file)
index 0000000..6098f0b
--- /dev/null
@@ -0,0 +1,407 @@
+ /*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ * 
+ *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * 
+ * usb-ohci.h
+ * 
+ */
+
+#define MODSTR "ohci: "
+
+
+static int cc_to_error[16] = { 
+
+/* mapping of the OHCI CC status to error codes */ 
+#ifdef USB_ST_CRC /* status codes */
+       /* No  Error  */               USB_ST_NOERROR,
+       /* CRC Error  */               USB_ST_CRC,
+       /* Bit Stuff  */               USB_ST_BITSTUFF,
+       /* Data Togg  */               USB_ST_CRC,
+       /* Stall      */               USB_ST_STALL,
+       /* DevNotResp */               USB_ST_NORESPONSE,
+       /* PIDCheck   */               USB_ST_BITSTUFF,
+       /* UnExpPID   */               USB_ST_BITSTUFF,
+       /* DataOver   */               USB_ST_DATAOVERRUN,
+       /* DataUnder  */               USB_ST_DATAUNDERRUN,
+       /* reservd    */               USB_ST_NORESPONSE,
+       /* reservd    */               USB_ST_NORESPONSE,
+       /* BufferOver */               USB_ST_BUFFEROVERRUN,
+       /* BuffUnder  */               USB_ST_BUFFERUNDERRUN,
+       /* Not Access */               USB_ST_NORESPONSE,
+       /* Not Access */               USB_ST_NORESPONSE 
+};
+
+#else  /* error codes */
+       /* No  Error  */               0,
+       /* CRC Error  */               -EILSEQ,
+       /* Bit Stuff  */               -EPROTO,
+       /* Data Togg  */               -EILSEQ,
+       /* Stall      */               -EPIPE,
+       /* DevNotResp */               -ETIMEDOUT,
+       /* PIDCheck   */               -EPROTO,
+       /* UnExpPID   */               -EPROTO,
+       /* DataOver   */               -EOVERFLOW,
+       /* DataUnder  */               -EREMOTEIO,
+       /* reservd    */               -ETIMEDOUT,
+       /* reservd    */               -ETIMEDOUT,
+       /* BufferOver */               -ECOMM,
+       /* BuffUnder  */               -ECOMM,
+       /* Not Access */               -ETIMEDOUT,
+       /* Not Access */               -ETIMEDOUT  
+};
+#define USB_ST_URB_PENDING             -EINPROGRESS
+#endif
+
+
+struct ed;
+struct td;
+/* for ED and TD structures */
+
+/* ED States */
+
+#define ED_NEW                 0x00
+#define ED_UNLINK      0x01
+#define ED_OPER                0x02
+#define ED_DEL         0x04
+#define ED_URB_DEL  0x08
+
+/* usb_ohci_ed */
+typedef struct ed {
+       __u32 hwINFO;       
+       __u32 hwTailP;
+       __u32 hwHeadP;
+       __u32 hwNextED;
+
+       struct ed * ed_prev;  
+       __u8 int_period;
+       __u8 int_branch;
+       __u8 int_load; 
+       __u8 int_interval;
+       __u8 state;
+       __u8 type; 
+       __u16 last_iso;
+    struct ed * ed_rm_list;
+   
+} ed_t;
+
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO         0x00010000
+#define TD_DEL      0x00020000
+
+/* CC Codes */
+#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
+
+
+#define MAXPSW 1
+
+typedef struct td { 
+       __u32 hwINFO;
+       __u32 hwCBP;            /* Current Buffer Pointer */
+       __u32 hwNextTD;         /* Next TD Pointer */
+       __u32 hwBE;             /* Memory Buffer End Pointer */
+       __u16 hwPSW[MAXPSW];
+
+       __u8 type;
+       __u8 index;
+       struct ed * ed;
+       struct td * next_dl_td;
+       urb_t * urb;
+} td_t;
+
+
+/* TD types */
+#define BULK           0x03
+#define INT                    0x01
+#define CTRL           0x02
+#define ISO                    0x00
+#define SEND            0x01
+#define ST_ADDR         0x02
+#define ADD_LEN         0x04
+#define DEL             0x08
+
+
+#define OHCI_ED_SKIP   (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+#define NUM_INTS 32    /* part of the OHCI standard */
+struct ohci_hcca {
+    __u32      int_table[NUM_INTS];    /* Interrupt ED table */
+       __u16   frame_no;               /* current frame number */
+       __u16   pad1;                   /* set to 0 on each frame_no change */
+       __u32   done_head;              /* info returned for an interrupt */
+       u8              reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+  
+/*
+ * Maximum number of root hub ports.  
+ */
+#define MAX_ROOT_PORTS 15      /* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+       /* control and status registers */
+       __u32   revision;
+       __u32   control;
+       __u32   cmdstatus;
+       __u32   intrstatus;
+       __u32   intrenable;
+       __u32   intrdisable;
+       /* memory pointers */
+       __u32   hcca;
+       __u32   ed_periodcurrent;
+       __u32   ed_controlhead;
+       __u32   ed_controlcurrent;
+       __u32   ed_bulkhead;
+       __u32   ed_bulkcurrent;
+       __u32   donehead;
+       /* frame counters */
+       __u32   fminterval;
+       __u32   fmremaining;
+       __u32   fmnumber;
+       __u32   periodicstart;
+       __u32   lsthresh;
+       /* Root hub ports */
+       struct  ohci_roothub_regs {
+               __u32   a;
+               __u32   b;
+               __u32   status;
+               __u32   portstatus[MAX_ROOT_PORTS];
+       } roothub;
+} __attribute((aligned(32)));
+
+/*
+ * cmdstatus register */
+#define OHCI_CLF  0x02
+#define OHCI_BLF  0x04
+
+/*
+ * Interrupt register masks
+ */
+#define OHCI_INTR_SO   (1)
+#define OHCI_INTR_WDH  (1 << 1)
+#define OHCI_INTR_SF   (1 << 2)
+#define OHCI_INTR_RD   (1 << 3)
+#define OHCI_INTR_UE   (1 << 4)
+#define OHCI_INTR_FNO  (1 << 5)
+#define OHCI_INTR_RHSC (1 << 6)
+#define OHCI_INTR_OC   (1 << 30)
+#define OHCI_INTR_MIE  (1 << 31)
+
+/*
+ * Control register masks
+ */
+#define OHCI_USB_RESET         0
+#define OHCI_USB_RESUME     (1 << 6)
+#define OHCI_USB_OPER          (2 << 6)
+#define OHCI_USB_SUSPEND       (3 << 6)
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+       int devnum; /* Address of Root Hub endpoint */ 
+       void * urb;
+       void * int_addr;
+       int send;
+       int interval;
+       struct timer_list rh_int_timer;
+};
+/* 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
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+/* Root-Hub Register info */
+
+#define RH_PS_CCS            0x00000001   
+#define RH_PS_PES            0x00000002   
+#define RH_PS_PSS            0x00000004   
+#define RH_PS_POCI           0x00000008   
+#define RH_PS_PRS            0x00000010  
+#define RH_PS_PPS            0x00000100   
+#define RH_PS_LSDA           0x00000200    
+#define RH_PS_CSC            0x00010000 
+#define RH_PS_PESC           0x00020000   
+#define RH_PS_PSSC           0x00040000    
+#define RH_PS_OCIC           0x00080000    
+#define RH_PS_PRSC           0x00100000   
+
+/* Root hub status bits */
+#define RH_HS_LPS           0x00000001
+#define RH_HS_OCI           0x00000002
+#define RH_HS_DRWE          0x00008000
+#define RH_HS_LPSC          0x00010000
+#define RH_HS_OCIC          0x00020000
+#define RH_HS_CRWE          0x80000000
+
+#define min(a,b) (((a)<(b))?(a):(b))  
+
+/* urb */
+typedef struct 
+{
+       ed_t * ed;
+       __u16 length;   // number of tds associated with this request
+       __u16 td_cnt;   // number of tds already serviced
+       int   state;
+       void * wait;
+       td_t * td[0];   // list pointer to all corresponding TDs associated with this request
+
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+       struct ohci_hcca hcca;                                  /* hcca */                
+
+       int irq;
+       struct ohci_regs * regs;                                        /* OHCI controller's memory */  
+    struct list_head ohci_hcd_list;         /* list of all ohci_hcd */           
+
+       struct ohci * next;             // chain of uhci device contexts
+       struct list_head urb_list;      // list of all pending urbs
+       spinlock_t urb_list_lock;       // lock to keep consistency 
+  
+       int ohci_int_load[32];                  /* load of the 32 Interrupt Chains (for load ballancing)*/     
+       ed_t * ed_rm_list[2];     /* lists of all endpoints to be removed */
+       ed_t * ed_bulktail;       /* last endpoint of bulk list */
+       ed_t * ed_controltail;    /* last endpoint of control list */
+       ed_t * ed_isotail;        /* last endpoint of iso list */
+       int intrstatus;
+       __u32 hc_control;                                               /* copy of the hc control reg */  
+       struct usb_bus * bus;    
+       struct usb_device * dev[128];
+       struct virt_root_hub rh;
+} ohci_t;
+
+
+#define NUM_TDS        0               /* num of preallocated transfer descriptors */
+#define NUM_EDS 32             /* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+       ed_t    ed[NUM_EDS];
+       int ed_cnt;
+       void  * wait;
+};
+
+// #define ohci_to_usb(ohci)   ((ohci)->usb)
+#define usb_to_ohci(usb)       ((struct ohci_device *)(usb)->hcpriv)
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load);
+static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
+/* td */
+static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int type, int index);
+static void td_submit_urb(urb_t * urb);
+/* root hub */
+static int rh_submit_urb(urb_t * urb);
+static int rh_unlink_urb(urb_t * urb);
+static int rh_init_int_timer(urb_t * urb);
+
+#ifdef DEBUG
+#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d: %4x\n", -- __ohci_free_cnt, (unsigned int) x)
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); printk("OHCI ALLO: %d: %4x\n", ++ __ohci_free_cnt,(unsigned int) x)
+static int __ohci_free_cnt = 0;
+#else
+#define OHCI_FREE(x) kfree(x) 
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) 
+#endif
index 8826bc5221bf25af6796e7b7d45baf10ca4cd8e8..8b00c45be9e5ab61399eb160e6df9263b01769e5 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (01/21/2000) gkh
+ *     Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
+ *     Fixed get_serial_by_minor which was all messed up for multi port 
+ *     devices. Fixed multi port problem for generic devices. Now the number
+ *     of ports is determined by the number of bulk out endpoints for the
+ *     generic device.
+ *
  * (01/19/2000) gkh
  *     Removed lots of cruft that was around from the old (pre urb) driver 
  *     interface.
@@ -438,13 +445,19 @@ static struct usb_serial *get_serial_by_minor (int minor)
 
        dbg("get_serial_by_minor %d", minor);
 
-       for (i = 0; i < SERIAL_TTY_MINORS; ++i)
-               if (serial_table[i])
-                       if (serial_table[i] != SERIAL_PTR_EMPTY)
-                               if (serial_table[i]->minor == minor)
-                                       return (serial_table[i]);
+       if (serial_table[minor] == NULL)
+               return (NULL);
 
-       return (NULL);
+       if (serial_table[minor] != SERIAL_PTR_EMPTY)
+               return (serial_table[minor]);
+
+       i = minor;
+       while (serial_table[i] == SERIAL_PTR_EMPTY) {
+               if (i == 0)
+                       return (NULL);
+               --i;
+               }
+       return (serial_table[i]);
 }
 
 
@@ -538,6 +551,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
        
        dbg("serial_open");
 
+       /* initialize the pointer incase something fails */
+       tty->driver_data = NULL;
+
        /* get the serial object associated with this tty pointer */
        serial = get_serial_by_minor (MINOR(tty->device));
 
@@ -1079,6 +1095,7 @@ static int  visor_startup (struct usb_serial *serial)
 {
        /* send out two unknown commands that I found by looking at a Win98 trace */
        int response;
+       int i;
        unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
 
        if (!transfer_buffer) {
@@ -1091,18 +1108,22 @@ static int  visor_startup (struct usb_serial *serial)
        dbg("visor_setup: Set config to 1");
        usb_set_configuration (serial->dev, 1);
 
-       response = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x03, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+       response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 0x03, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
        if (response < 0) {
                err("visor_startup: error getting first vendor specific message");
        } else {
-               dbg("visor_startup: First vendor specific message successful");
+               dbg("visor_startup: First vendor specific message successful, data received:");
+               for (i = 0; i < response; ++i)
+                       dbg("    0x%.2x", transfer_buffer[i]);
        }
 
-       response = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x01, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
+       response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), 0x01, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
        if (response < 0) {
                err("visor_startup: error getting second vendor specific message");
        } else {
-               dbg("visor_startup: Second vendor specific message successful");
+               dbg("visor_startup: Second vendor specific message successful, data received:");
+               for (i = 0; i < response; ++i)
+                       dbg("    0x%.2x", transfer_buffer[i]);
        }
 
        kfree (transfer_buffer);
@@ -1260,6 +1281,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
        int num_interrupt_in = 0;
        int num_bulk_in = 0;
        int num_bulk_out = 0;
+       int num_ports;
        
        /* loop through our list of known serial converters, and see if this device matches */
        device_num = 0;
@@ -1317,7 +1339,14 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
                                /* found all that we need */
                                info("%s converter detected", type->name);
 
-                               serial = get_free_serial (type->num_ports, &minor);
+#ifdef CONFIG_USB_SERIAL_GENERIC
+                               if (type == &generic_device)
+                                       num_ports = num_bulk_out;
+                               else
+#endif
+                                       num_ports = type->num_ports;
+
+                               serial = get_free_serial (num_ports, &minor);
                                if (serial == NULL) {
                                        err("No more free serial devices");
                                        return NULL;
@@ -1326,7 +1355,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
                                serial->dev = dev;
                                serial->type = type;
                                serial->minor = minor;
-                               serial->num_ports = type->num_ports;
+                               serial->num_ports = num_ports;
                                serial->num_bulk_in = num_bulk_in;
                                serial->num_bulk_out = num_bulk_out;
                                serial->num_interrupt_in = num_interrupt_in;
diff --git a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
new file mode 100644 (file)
index 0000000..9a883f1
--- /dev/null
@@ -0,0 +1,2373 @@
+/* 
+ * Universal Host Controller Interface driver for USB (take II).
+ *
+ * (c) 1999 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ *          Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+ *          Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+ *          Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
+ *          
+ * HW-initalization based on material of
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * $Id: usb-uhci.c,v 1.169 2000/01/20 19:50:11 acher Exp $
+ */
+
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>   /* for in_interrupt() */
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "usb.h"
+#include "usb-uhci.h"
+
+//#define DEBUG
+#include "uhci-debug.h"
+
+#ifdef dbg
+       #undef dbg
+#endif
+#undef DEBUG
+#ifdef DEBUG
+#define dbg(format, arg...) printk(format, ## arg)
+#else
+#define dbg(format, arg...)
+#endif
+
+// Please leave the following intact, it makes debugging
+// (esp. after an hard oops crash) a lot easier!
+#define _static //static
+
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event (apm_event_t event);
+#endif
+
+/* We added an UHCI_SLAB slab support just for debugging purposes. In real 
+   life this compile option is NOT recommended, because slab caches are not 
+   suitable for modules.
+*/
+
+// #define _UHCI_SLAB 
+#ifdef _UHCI_SLAB
+static kmem_cache_t *uhci_desc_kmem;
+static kmem_cache_t *urb_priv_kmem;
+#endif
+
+static int rh_submit_urb (purb_t purb);
+static int rh_unlink_urb (purb_t purb);
+static puhci_t devs = NULL;
+
+/* used by userspace UHCI data structure dumper */
+puhci_t *uhci_devices = &devs;
+
+/*-------------------------------------------------------------------*/
+_static void queue_urb (puhci_t s, struct list_head *p, int do_lock)
+{
+       unsigned long flags=0;
+
+       if (do_lock) 
+               spin_lock_irqsave (&s->urb_list_lock, flags);
+               
+       list_add_tail (p, &s->urb_list);
+       
+       if (do_lock) 
+               spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+
+/*-------------------------------------------------------------------*/
+_static void dequeue_urb (puhci_t s, struct list_head *p, int do_lock)
+{
+       unsigned long flags=0;
+       
+       if (do_lock) 
+               spin_lock_irqsave (&s->urb_list_lock, flags);
+
+       list_del (p);
+
+       if (do_lock) 
+               spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+
+/*-------------------------------------------------------------------*/
+_static int alloc_td (puhci_desc_t * new, int flags)
+{
+#ifdef _UHCI_SLAB
+       *new= kmem_cache_alloc(uhci_desc_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL);
+#else
+       *new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
+#endif
+       if (!*new)
+               return -ENOMEM;
+       
+       memset (*new, 0, sizeof (uhci_desc_t));
+       (*new)->hw.td.link = UHCI_PTR_TERM | (flags & UHCI_PTR_BITS);   // last by default
+
+       (*new)->type = TD_TYPE;
+       mb();
+       INIT_LIST_HEAD (&(*new)->vertical);
+       INIT_LIST_HEAD (&(*new)->horizontal);
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+/* insert td at last position in td-list of qh (vertical) */
+_static int insert_td (puhci_t s, puhci_desc_t qh, puhci_desc_t new, int flags)
+{
+       uhci_desc_t *prev;
+       unsigned long xxx;
+       
+       spin_lock_irqsave (&s->td_lock, xxx);
+
+       list_add_tail (&new->vertical, &qh->vertical);
+
+       if (qh->hw.qh.element & UHCI_PTR_TERM) {
+               // virgin qh without any tds
+               qh->hw.qh.element = virt_to_bus (new);  /* QH's cannot have the DEPTH bit set */
+       }
+       else {
+               // already tds inserted 
+               prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
+               // implicitely remove TERM bit of prev
+               prev->hw.td.link = virt_to_bus (new) | (flags & UHCI_PTR_DEPTH);
+       }
+       mb();
+       spin_unlock_irqrestore (&s->td_lock, xxx);
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+/* insert new_td after td (horizontal) */
+_static int insert_td_horizontal (puhci_t s, puhci_desc_t td, puhci_desc_t new, int flags)
+{
+       uhci_desc_t *next;
+       unsigned long xxx;
+       
+       spin_lock_irqsave (&s->td_lock, xxx);
+
+       next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
+       new->hw.td.link = td->hw.td.link;
+       mb();
+       list_add (&new->horizontal, &td->horizontal);
+       td->hw.td.link = virt_to_bus (new);
+       mb();
+       spin_unlock_irqrestore (&s->td_lock, xxx);      
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int unlink_td (puhci_t s, puhci_desc_t element)
+{
+       uhci_desc_t *next, *prev;
+       int dir = 0;
+       unsigned long xxx;
+       
+       spin_lock_irqsave (&s->td_lock, xxx);
+       
+       next = list_entry (element->vertical.next, uhci_desc_t, vertical);
+       
+       if (next == element) {
+               dir = 1;
+               next = list_entry (element->horizontal.next, uhci_desc_t, horizontal);
+               prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+       }
+       else {
+               prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
+       }
+       
+       if (prev->type == TD_TYPE)
+               prev->hw.td.link = element->hw.td.link;
+       else
+               prev->hw.qh.element = element->hw.td.link;
+       
+       mb ();
+       
+       if (dir == 0)
+               list_del (&element->vertical);
+       else
+               list_del (&element->horizontal);
+       
+       spin_unlock_irqrestore (&s->td_lock, xxx);      
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int delete_desc (puhci_desc_t element)
+{
+#ifdef _UHCI_SLAB
+       kmem_cache_free(uhci_desc_kmem, element);
+#else
+       kfree (element);
+#endif
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+// Allocates qh element
+_static int alloc_qh (puhci_desc_t * new)
+{
+#ifdef _UHCI_SLAB
+       *new= kmem_cache_alloc(uhci_desc_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL);
+#else
+       *new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
+#endif 
+       if (!*new)
+               return -ENOMEM;
+       
+       memset (*new, 0, sizeof (uhci_desc_t));
+       (*new)->hw.qh.head = UHCI_PTR_TERM;
+       (*new)->hw.qh.element = UHCI_PTR_TERM;
+       (*new)->type = QH_TYPE;
+       mb();
+       INIT_LIST_HEAD (&(*new)->horizontal);
+       INIT_LIST_HEAD (&(*new)->vertical);
+       
+       dbg (KERN_DEBUG MODSTR "Allocated qh @ %p\n", *new);
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+// inserts new qh before/after the qh at pos
+// flags: 0: insert before pos, 1: insert after pos (for low speed transfers)
+_static int insert_qh (puhci_t s, puhci_desc_t pos, puhci_desc_t new, int flags)
+{
+       puhci_desc_t old;
+       unsigned long xxx;
+
+       spin_lock_irqsave (&s->qh_lock, xxx);
+
+       if (!flags) {
+               // (OLD) (POS) -> (OLD) (NEW) (POS)
+               old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
+               list_add_tail (&new->horizontal, &pos->horizontal);
+               new->hw.qh.head = MAKE_QH_ADDR (pos) ;
+               mb();
+               if (!(old->hw.qh.head & UHCI_PTR_TERM))
+                       old->hw.qh.head = MAKE_QH_ADDR (new) ;
+       }
+       else {
+               // (POS) (OLD) -> (POS) (NEW) (OLD)
+               old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
+               list_add (&new->horizontal, &pos->horizontal);
+               new->hw.qh.head = MAKE_QH_ADDR (old);
+               mb();
+               pos->hw.qh.head = MAKE_QH_ADDR (new) ;
+       }
+
+       mb ();
+       
+       spin_unlock_irqrestore (&s->qh_lock, xxx);
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int unlink_qh (puhci_t s, puhci_desc_t element)
+{
+       puhci_desc_t next, prev;
+       unsigned long xxx;
+
+       spin_lock_irqsave (&s->qh_lock, xxx);
+       
+       next = list_entry (element->horizontal.next, uhci_desc_t, horizontal);
+       prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+       prev->hw.qh.head = element->hw.qh.head;
+       mb ();
+       list_del (&element->horizontal);
+       
+       spin_unlock_irqrestore (&s->qh_lock, xxx);
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int delete_qh (puhci_t s, puhci_desc_t qh)
+{
+       puhci_desc_t td;
+       struct list_head *p;
+
+       list_del (&qh->horizontal);
+       
+       while ((p = qh->vertical.next) != &qh->vertical) {
+               td = list_entry (p, uhci_desc_t, vertical);
+               unlink_td (s, td);
+               delete_desc (td);
+       }
+       
+       delete_desc (qh);
+       
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+void clean_td_chain (puhci_desc_t td)
+{
+       struct list_head *p;
+       puhci_desc_t td1;
+
+       if (!td)
+               return;
+       
+       while ((p = td->horizontal.next) != &td->horizontal) {
+               td1 = list_entry (p, uhci_desc_t, horizontal);
+               delete_desc (td1);
+       }
+       
+       delete_desc (td);
+}
+/*-------------------------------------------------------------------*/
+// Removes ALL qhs in chain (paranoia!)
+_static void cleanup_skel (puhci_t s)
+{
+       unsigned int n;
+       puhci_desc_t td;
+
+       printk (KERN_DEBUG MODSTR "Cleanup_skel\n");
+       
+       for (n = 0; n < 8; n++) {
+               td = s->int_chain[n];
+               clean_td_chain (td);
+       }
+
+       if (s->iso_td) {
+               for (n = 0; n < 1024; n++) {
+                       td = s->iso_td[n];
+                       clean_td_chain (td);
+               }
+               kfree (s->iso_td);
+       }
+
+       if (s->framelist)
+               free_page ((unsigned long) s->framelist);
+
+       if (s->control_chain) {
+               // completed init_skel?
+               struct list_head *p;
+               puhci_desc_t qh, qh1;
+
+               qh = s->control_chain;
+               while ((p = qh->horizontal.next) != &qh->horizontal) {
+                       qh1 = list_entry (p, uhci_desc_t, horizontal);
+                       delete_qh (s, qh1);
+               }
+               delete_qh (s, qh);
+       }
+       else {
+               if (s->control_chain)
+                       kfree (s->control_chain);
+               if (s->bulk_chain)
+                       kfree (s->bulk_chain);
+               if (s->chain_end)
+                       kfree (s->chain_end);
+       }
+       printk (KERN_DEBUG MODSTR "Cleanup_skel finished\n");   
+}
+/*-------------------------------------------------------------------*/
+// allocates framelist and qh-skeletons
+// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
+_static int init_skel (puhci_t s)
+{
+       int n, ret;
+       puhci_desc_t qh, td;
+       
+       dbg (KERN_DEBUG MODSTR "init_skel\n");
+       
+       s->framelist = (__u32 *) get_free_page (GFP_KERNEL);
+
+       if (!s->framelist)
+               return -ENOMEM;
+
+       memset (s->framelist, 0, 4096);
+
+       dbg (KERN_DEBUG MODSTR "allocating iso desc pointer list\n");
+       s->iso_td = (puhci_desc_t *) kmalloc (1024 * sizeof (puhci_desc_t), GFP_KERNEL);
+       
+       if (!s->iso_td)
+               goto init_skel_cleanup;
+
+       s->control_chain = NULL;
+       s->bulk_chain = NULL;
+       s->chain_end = NULL;
+
+       dbg (KERN_DEBUG MODSTR "allocating iso descs\n");
+       for (n = 0; n < 1024; n++) {
+               // allocate skeleton iso/irq-tds
+               ret = alloc_td (&td, 0);
+               if (ret)
+                       goto init_skel_cleanup;
+               s->iso_td[n] = td;
+               s->framelist[n] = ((__u32) virt_to_bus (td));
+       }
+
+       dbg (KERN_DEBUG MODSTR "allocating qh: chain_end\n");
+       ret = alloc_qh (&qh);
+       
+       if (ret)
+               goto init_skel_cleanup;
+       
+       s->chain_end = qh;
+
+       dbg (KERN_DEBUG MODSTR "allocating qh: bulk_chain\n");
+       ret = alloc_qh (&qh);
+       
+       if (ret)
+               goto init_skel_cleanup;
+       
+       insert_qh (s, s->chain_end, qh, 0);
+       s->bulk_chain = qh;
+       dbg (KERN_DEBUG MODSTR "allocating qh: control_chain\n");
+       ret = alloc_qh (&qh);
+       
+       if (ret)
+               goto init_skel_cleanup;
+       
+       insert_qh (s, s->bulk_chain, qh, 0);
+       s->control_chain = qh;
+       for (n = 0; n < 8; n++)
+               s->int_chain[n] = 0;
+
+       dbg (KERN_DEBUG MODSTR "Allocating skeleton INT-TDs\n");
+       
+       for (n = 0; n < 8; n++) {
+               puhci_desc_t td;
+
+               alloc_td (&td, 0);
+               if (!td)
+                       goto init_skel_cleanup;
+               s->int_chain[n] = td;
+               if (n == 0) {
+                       s->int_chain[0]->hw.td.link = virt_to_bus (s->control_chain) | UHCI_PTR_QH;
+               }
+               else {
+                       s->int_chain[n]->hw.td.link = virt_to_bus (s->int_chain[0]);
+               }
+       }
+
+       dbg (KERN_DEBUG MODSTR "Linking skeleton INT-TDs\n");
+       
+       for (n = 0; n < 1024; n++) {
+               // link all iso-tds to the interrupt chains
+               int m, o;
+               dbg("framelist[%i]=%x\n",n,s->framelist[n]);
+               if ((n&127)==127) 
+                       ((puhci_desc_t) s->iso_td[n])->hw.td.link = virt_to_bus(s->int_chain[0]);
+               else {
+                       for (o = 1, m = 2; m <= 128; o++, m += m) {
+                               // n&(m-1) = n%m
+                               if ((n & (m - 1)) == ((m - 1) / 2)) {
+                                       ((puhci_desc_t) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]);
+                               }
+                       }
+               }
+       }
+
+       mb();
+       //uhci_show_queue(s->control_chain);   
+       dbg (KERN_DEBUG MODSTR "init_skel exit\n");
+       return 0;               // OK
+
+      init_skel_cleanup:
+       cleanup_skel (s);
+       return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------*/
+_static void fill_td (puhci_desc_t td, int status, int info, __u32 buffer)
+{
+       td->hw.td.status = status;
+       td->hw.td.info = info;
+       td->hw.td.buffer = buffer;
+}
+
+/*-------------------------------------------------------------------*/
+//                         LOW LEVEL STUFF
+//          assembles QHs und TDs for control, bulk and iso
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_control_urb (purb_t purb)
+{
+       puhci_desc_t qh, td;
+       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
+       purb_priv_t purb_priv = purb->hcpriv;
+       unsigned long destination, status;
+       int maxsze = usb_maxpacket (purb->dev, purb->pipe, usb_pipeout (purb->pipe));
+       unsigned long len, bytesrequested;
+       char *data;
+
+       dbg (KERN_DEBUG MODSTR "uhci_submit_control start\n");
+       alloc_qh (&qh);         // alloc qh for this request
+
+       if (!qh)
+               return -ENOMEM;
+
+       alloc_td (&td, UHCI_PTR_DEPTH);         // get td for setup stage
+
+       if (!td) {
+               delete_qh (s, qh);
+               return -ENOMEM;
+       }
+
+       /* The "pipe" thing contains the destination in bits 8--18 */
+       destination = (purb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+       /* 3 errors */
+       status = (purb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+               (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+       /*  Build the TD for the control request, try forever, 8 bytes of data */
+       fill_td (td, status, destination | (7 << 21), virt_to_bus (purb->setup_packet));
+
+       /* If direction is "send", change the frame from SETUP (0x2D)
+          to OUT (0xE1). Else change it from SETUP to IN (0x69). */
+
+       destination ^= (USB_PID_SETUP ^ USB_PID_IN);    /* SETUP -> IN */
+       
+       if (usb_pipeout (purb->pipe))
+               destination ^= (USB_PID_IN ^ USB_PID_OUT);      /* IN -> OUT */
+
+       insert_td (s, qh, td, 0);       // queue 'setup stage'-td in qh
+#if 0
+       printk ("SETUP to pipe %x: %x %x %x %x %x %x %x %x\n", purb->pipe,
+               purb->setup_packet[0], purb->setup_packet[1], purb->setup_packet[2], purb->setup_packet[3],
+               purb->setup_packet[4], purb->setup_packet[5], purb->setup_packet[6], purb->setup_packet[7]);
+       //uhci_show_td(td);
+#endif
+
+       /*  Build the DATA TD's */
+       len = purb->transfer_buffer_length;
+       bytesrequested = len;
+       data = purb->transfer_buffer;
+       
+       while (len > 0) {
+               int pktsze = len;
+
+               alloc_td (&td, UHCI_PTR_DEPTH);
+               if (!td) {
+                       delete_qh (s, qh);
+                       return -ENOMEM;
+               }
+
+               if (pktsze > maxsze)
+                       pktsze = maxsze;
+
+               destination ^= 1 << TD_TOKEN_TOGGLE;    // toggle DATA0/1
+
+               fill_td (td, status, destination | ((pktsze - 1) << 21),
+                        virt_to_bus (data));   // Status, pktsze bytes of data
+
+               insert_td (s, qh, td, UHCI_PTR_DEPTH);  // queue 'data stage'-td in qh
+
+               data += pktsze;
+               len -= pktsze;
+       }
+
+       /*  Build the final TD for control status */
+       /* It's only IN if the pipe is out AND we aren't expecting data */
+       destination &= ~0xFF;
+       
+       if (usb_pipeout (purb->pipe) | (bytesrequested == 0))
+               destination |= USB_PID_IN;
+       else
+               destination |= USB_PID_OUT;
+
+       destination |= 1 << TD_TOKEN_TOGGLE;    /* End in Data1 */
+
+       alloc_td (&td, UHCI_PTR_DEPTH);
+       
+       if (!td) {
+               delete_qh (s, qh);
+               return -ENOMEM;
+       }
+
+       /* no limit on errors on final packet , 0 bytes of data */
+       fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),
+                0);
+
+       insert_td (s, qh, td, UHCI_PTR_DEPTH);  // queue status td
+
+
+       list_add (&qh->desc_list, &purb_priv->desc_list);
+
+       purb->status = USB_ST_URB_PENDING;
+       queue_urb (s, &purb->urb_list,1);       // queue before inserting in desc chain
+
+       //uhci_show_queue(qh);
+
+       /* Start it up... put low speed first */
+       if (purb->pipe & TD_CTRL_LS)
+               insert_qh (s, s->control_chain, qh, 1); // insert after control chain
+       else
+               insert_qh (s, s->bulk_chain, qh, 0);    // insert before bulk chain
+       
+       //uhci_show_queue(qh);
+       dbg (KERN_DEBUG MODSTR "uhci_submit_control end\n");
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_bulk_urb (purb_t purb)
+{
+       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
+       purb_priv_t purb_priv = purb->hcpriv;
+       puhci_desc_t qh, td;
+       unsigned long destination, status;
+       char *data;
+       unsigned int pipe = purb->pipe;
+       int maxsze = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
+       int info, len;
+
+       /* shouldn't the clear_halt be done in the USB core or in the client driver? - Thomas */
+       if (usb_endpoint_halted (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) &&
+           usb_clear_halt (purb->dev, usb_pipeendpoint (pipe) | (pipe & USB_DIR_IN)))
+               return -EPIPE;
+
+       if (!maxsze)
+               return -EMSGSIZE;
+       /* FIXME: should tell the client that the endpoint is invalid, i.e. not in the descriptor */
+
+       alloc_qh (&qh);         // get qh for this request
+
+       if (!qh)
+               return -ENOMEM;
+
+       /* The "pipe" thing contains the destination in bits 8--18. */
+       destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+
+       /* 3 errors */
+       status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+               ((purb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+       /* Build the TDs for the bulk request */
+       len = purb->transfer_buffer_length;
+       data = purb->transfer_buffer;
+       dbg (KERN_DEBUG MODSTR "uhci_submit_bulk_urb: pipe %x, len %d\n", pipe, len);
+       
+       while (len > 0) {
+               int pktsze = len;
+
+               alloc_td (&td, UHCI_PTR_DEPTH);
+
+               if (!td) {
+                       delete_qh (s, qh);
+                       return -ENOMEM;
+               }
+
+               if (pktsze > maxsze)
+                       pktsze = maxsze;
+
+               // pktsze bytes of data 
+               info = destination | ((pktsze - 1) << 21) |
+                       (usb_gettoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+               fill_td (td, status, info, virt_to_bus (data));
+
+               data += pktsze;
+               len -= pktsze;
+
+               if (!len)
+                       td->hw.td.status |= TD_CTRL_IOC;        // last one generates INT
+               //dbg("insert td %p, len %i\n",td,pktsze);
+
+               insert_td (s, qh, td, UHCI_PTR_DEPTH);
+               
+               /* Alternate Data0/1 (start with Data0) */
+               usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+       }
+
+       list_add (&qh->desc_list, &purb_priv->desc_list);
+
+       purb->status = USB_ST_URB_PENDING;
+       queue_urb (s, &purb->urb_list,1);
+
+       insert_qh (s, s->chain_end, qh, 0);     // insert before end marker
+       //uhci_show_queue(s->bulk_chain);
+
+       dbg (KERN_DEBUG MODSTR "uhci_submit_bulk_urb: exit\n");
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+// unlinks an urb by dequeuing its qh, waits some frames and forgets it
+// Problem: unlinking in interrupt requires waiting for one frame (udelay)
+// to allow the whole structures to be safely removed
+_static int uhci_unlink_urb (purb_t purb)
+{
+       puhci_t s;
+       puhci_desc_t qh;
+       puhci_desc_t td;
+       purb_priv_t purb_priv;
+       unsigned long flags=0;
+       struct list_head *p;
+
+       if (!purb)              // you never know...
+               return -1;
+
+       s = (puhci_t) purb->dev->bus->hcpriv;   // get pointer to uhci struct
+
+       if (usb_pipedevice (purb->pipe) == s->rh.devnum)
+               return rh_unlink_urb (purb);
+
+       if(!in_interrupt()) {
+               spin_lock_irqsave (&s->unlink_urb_lock, flags);         // do not allow interrupts
+       }
+       
+       //dbg("unlink_urb called %p\n",purb);
+       if (purb->status == USB_ST_URB_PENDING) {
+               // URB probably still in work
+               purb_priv = purb->hcpriv;
+               dequeue_urb (s, &purb->urb_list,1);
+               purb->status = USB_ST_URB_KILLED;       // mark urb as killed
+               
+               if(!in_interrupt()) {
+                       spin_unlock_irqrestore (&s->unlink_urb_lock, flags);    // allow interrupts from here
+               }
+
+               switch (usb_pipetype (purb->pipe)) {
+               case PIPE_ISOCHRONOUS:
+               case PIPE_INTERRUPT:
+                       for (p = purb_priv->desc_list.next; p != &purb_priv->desc_list; p = p->next) {
+                               td = list_entry (p, uhci_desc_t, desc_list);
+                               unlink_td (s, td);
+                       }
+                       // wait at least 1 Frame
+                       if (in_interrupt ())
+                               udelay (1000);
+                       else
+                               wait_ms(1);
+                       while ((p = purb_priv->desc_list.next) != &purb_priv->desc_list) {
+                               td = list_entry (p, uhci_desc_t, desc_list);
+                               list_del (p);
+                               delete_desc (td);
+                       }
+                       break;
+
+               case PIPE_BULK:
+               case PIPE_CONTROL:
+                       qh = list_entry (purb_priv->desc_list.next, uhci_desc_t, desc_list);
+
+                       unlink_qh (s, qh);      // remove this qh from qh-list
+                       // wait at least 1 Frame
+
+                       if (in_interrupt ())
+                               udelay (1000);
+                       else
+                               wait_ms(1);
+                       delete_qh (s, qh);              // remove it physically
+
+               }
+               
+#ifdef _UHCI_SLAB
+               kmem_cache_free(urb_priv_kmem, purb->hcpriv);
+#else
+               kfree (purb->hcpriv);
+#endif
+               if (purb->complete) {
+                       dbg (KERN_DEBUG MODSTR "unlink_urb: calling completion\n");
+                       purb->complete ((struct urb *) purb);
+                       usb_dec_dev_use (purb->dev);
+               }
+               return 0;
+       }
+       else {
+               if(!in_interrupt())
+                       spin_unlock_irqrestore (&s->unlink_urb_lock, flags);    // allow interrupts from here
+       }
+
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+// In case of ASAP iso transfer, search the URB-list for already queued URBs
+// for this EP and calculate the earliest start frame for the new
+// URB (easy seamless URB continuation!)
+_static int find_iso_limits (purb_t purb, unsigned int *start, unsigned int *end)
+{
+       purb_t u, last_urb = NULL;
+       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
+       struct list_head *p = s->urb_list.next;
+       int ret=-1;
+       unsigned long flags;
+       
+       spin_lock_irqsave (&s->urb_list_lock, flags);
+
+       for (; p != &s->urb_list; p = p->next) {
+               u = list_entry (p, urb_t, urb_list);
+               // look for pending URBs with identical pipe handle
+               // works only because iso doesn't toggle the data bit!
+               if ((purb->pipe == u->pipe) && (purb->dev == u->dev) && (u->status == USB_ST_URB_PENDING)) {
+                       if (!last_urb)
+                               *start = u->start_frame;
+                       last_urb = u;
+               }
+       }
+       
+       if (last_urb) {
+               *end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+               ret=0;
+       }
+       
+       spin_unlock_irqrestore(&s->urb_list_lock, flags);
+       
+       return ret;     // no previous urb found
+
+}
+/*-------------------------------------------------------------------*/
+// adjust start_frame according to scheduling constraints (ASAP etc)
+
+_static int iso_find_start (purb_t purb)
+{
+       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
+       unsigned int now;
+       unsigned int start_limit = 0, stop_limit = 0, queued_size;
+       int limits;
+
+       now = UHCI_GET_CURRENT_FRAME (s) & 1023;
+
+       if ((unsigned) purb->number_of_packets > 900)
+               return -EFBIG;
+       
+       limits = find_iso_limits (purb, &start_limit, &stop_limit);
+       queued_size = (stop_limit - start_limit) & 1023;
+
+       if (purb->transfer_flags & USB_ISO_ASAP) {
+               // first iso
+               if (limits) {
+                       // 10ms setup should be enough //FIXME!
+                       purb->start_frame = (now + 10) & 1023;
+               }
+               else {
+                       purb->start_frame = stop_limit;         //seamless linkage
+
+                       if (((now - purb->start_frame) & 1023) <= (unsigned) purb->number_of_packets) {
+                               printk (KERN_DEBUG MODSTR "iso_find_start: warning, ASAP gap, should not happen\n");
+                               printk (KERN_DEBUG MODSTR "iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x\n",
+                                       now, purb->start_frame, purb->number_of_packets, purb->pipe);
+// The following code is only for debugging purposes...
+#if 0
+                               {
+                                       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
+                                       struct list_head *p;
+                                       purb_t u;
+                                       int a = -1, b = -1;
+                                       unsigned long flags;
+
+                                       spin_lock_irqsave (&s->urb_list_lock, flags);
+                                       p=s->urb_list.next;
+
+                                       for (; p != &s->urb_list; p = p->next) {
+                                               u = list_entry (p, urb_t, urb_list);
+                                               if (purb->dev != u->dev)
+                                                       continue;
+                                               printk (KERN_DEBUG MODSTR "urb: pipe 0x%08x status %d start_frame %u number_of_packets %u\n",
+                                                       u->pipe, u->status, u->start_frame, u->number_of_packets);
+                                               if (!usb_pipeisoc (u->pipe))
+                                                       continue;
+                                               if (a == -1)
+                                                       a = u->start_frame;
+                                               b = (u->start_frame + u->number_of_packets - 1) & 1023;
+                                       }
+                                       spin_unlock_irqrestore(&s->urb_list_lock, flags);
+                               }
+#endif
+                               purb->start_frame = (now + 5) & 1023;   // 5ms setup should be enough //FIXME!
+                               //return -EAGAIN; //FIXME
+                       }
+               }
+       }
+       else {
+               purb->start_frame &= 1023;
+               if (((now - purb->start_frame) & 1023) < (unsigned) purb->number_of_packets) {
+                       printk (KERN_DEBUG MODSTR "iso_find_start: now between start_frame and end\n");
+                       return -EAGAIN;
+               }
+       }
+
+       /* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */
+       if (limits)
+               return 0;
+
+       if (((purb->start_frame - start_limit) & 1023) < queued_size ||
+           ((purb->start_frame + purb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
+               printk (KERN_DEBUG MODSTR "iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u\n",
+                       purb->start_frame, purb->number_of_packets, start_limit, stop_limit);
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+// submits USB interrupt (ie. polling ;-) 
+// ASAP-flag set implicitely
+// if period==0, the the transfer is only done once (usb_scsi need this...)
+
+_static int uhci_submit_int_urb (purb_t purb)
+{
+       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
+       purb_priv_t purb_priv = purb->hcpriv;
+       int nint, n, ret;
+       puhci_desc_t td;
+       int status, destination;
+       int now;
+       int info;
+       unsigned int pipe = purb->pipe;
+
+       //printk("SUBMIT INT\n");
+
+       if (purb->interval < 0 || purb->interval >= 256)
+               return -EINVAL;
+
+       if (purb->interval == 0)
+               nint = 0;
+       else {
+               for (nint = 0, n = 1; nint <= 8; nint++, n += n)        // round interval down to 2^n
+                {
+                       if (purb->interval < n) {
+                               purb->interval = n / 2;
+                               break;
+                       }
+               }
+               nint--;
+       }
+       dbg(KERN_INFO "Rounded interval to %i, chain  %i\n", purb->interval, nint);
+
+       now = UHCI_GET_CURRENT_FRAME (s) & 1023;
+       purb->start_frame = now;        // remember start frame, just in case...
+
+       purb->number_of_packets = 1;
+
+       // INT allows only one packet
+       if (purb->transfer_buffer_length > usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)))
+               return -EINVAL;
+
+       ret = alloc_td (&td, UHCI_PTR_DEPTH);
+
+       if (ret)
+               return -ENOMEM;
+
+       status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+               (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+       destination = (purb->pipe & PIPE_DEVEP_MASK) | usb_packetid (purb->pipe) |
+               (((purb->transfer_buffer_length - 1) & 0x7ff) << 21);
+
+
+       info = destination | (usb_gettoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+       fill_td (td, status, info, virt_to_bus (purb->transfer_buffer));
+       list_add_tail (&td->desc_list, &purb_priv->desc_list);
+
+       purb->status = USB_ST_URB_PENDING;
+       queue_urb (s, &purb->urb_list,1);
+
+       insert_td_horizontal (s, s->int_chain[nint], td, UHCI_PTR_DEPTH);       // store in INT-TDs
+
+       usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+#if 0
+       td = tdm[purb->number_of_packets];
+       fill_td (td, TD_CTRL_IOC, 0, 0);
+       insert_td_horizontal (s, s->iso_td[(purb->start_frame + (purb->number_of_packets) * purb->interval + 1) & 1023], td, UHCI_PTR_DEPTH);
+       list_add_tail (&td->desc_list, &purb_priv->desc_list);
+#endif
+
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_iso_urb (purb_t purb)
+{
+       puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
+       purb_priv_t purb_priv = purb->hcpriv;
+       int pipe=purb->pipe;
+       int maxsze = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
+       int n, ret, last=0;
+       puhci_desc_t td, *tdm;
+       int status, destination;
+       unsigned long flags;
+       spinlock_t lock;
+
+       spin_lock_init (&lock);
+       spin_lock_irqsave (&lock, flags);       // Disable IRQs to schedule all ISO-TDs in time
+
+       ret = iso_find_start (purb);    // adjusts purb->start_frame for later use
+
+       if (ret)
+               goto err;
+
+       tdm = (puhci_desc_t *) kmalloc (purb->number_of_packets * sizeof (puhci_desc_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
+
+       if (!tdm) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       // First try to get all TDs
+       for (n = 0; n < purb->number_of_packets; n++) {
+               dbg (KERN_DEBUG MODSTR "n:%d purb->iso_frame_desc[n].length:%d\n", n, purb->iso_frame_desc[n].length);
+               if (!purb->iso_frame_desc[n].length) {
+                       // allows ISO striping by setting length to zero in iso_descriptor
+                       tdm[n] = 0;
+                       continue;
+               }
+               if(purb->iso_frame_desc[n].length > maxsze) {
+                       printk(KERN_ERR MODSTR"submit_iso: purb->iso_frame_desc[%d].length(%d)>%d",n , purb->iso_frame_desc[n].length, maxsze);
+                       tdm[n] = 0;
+                       continue;
+               }
+               ret = alloc_td (&td, UHCI_PTR_DEPTH);
+               if (ret) {
+                       int i;  // Cleanup allocated TDs
+
+                       for (i = 0; i < n; n++)
+                               if (tdm[i])
+                                       kfree (tdm[i]);
+                       kfree (tdm);
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               last=n;
+               tdm[n] = td;
+       }
+
+       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;  //| (purb->transfer_flags&USB_DISABLE_SPD?0:TD_CTRL_SPD);
+
+       destination = (purb->pipe & PIPE_DEVEP_MASK) | usb_packetid (purb->pipe);
+
+       
+       // Queue all allocated TDs
+       for (n = 0; n < purb->number_of_packets; n++) {
+               td = tdm[n];
+               if (!td)
+                       continue;
+                       
+               if (n  == last)
+                       status |= TD_CTRL_IOC;
+
+               fill_td (td, status, destination | (((purb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
+                        virt_to_bus (purb->transfer_buffer + purb->iso_frame_desc[n].offset));
+               list_add_tail (&td->desc_list, &purb_priv->desc_list);
+       
+               if (n == last) {
+                       purb->status = USB_ST_URB_PENDING;
+                       queue_urb (s, &purb->urb_list,1);
+               }
+               insert_td_horizontal (s, s->iso_td[(purb->start_frame + n) & 1023], td, UHCI_PTR_DEPTH);        // store in iso-tds
+               //uhci_show_td(td);
+
+       }
+
+       kfree (tdm);
+       dbg ("ISO-INT# %i, start %i, now %i\n", purb->number_of_packets, purb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
+       ret = 0;
+
+      err:
+       spin_unlock_irqrestore (&lock, flags);
+       return ret;
+
+}
+/*-------------------------------------------------------------------*/
+_static int search_dev_ep (puhci_t s, purb_t purb)
+{
+       unsigned long flags;
+       struct list_head *p = s->urb_list.next;
+       purb_t tmp;
+       unsigned int mask = usb_pipecontrol(purb->pipe) ? (~USB_DIR_IN) : (~0);
+
+       dbg (KERN_DEBUG MODSTR "search_dev_ep:\n");
+       spin_lock_irqsave (&s->urb_list_lock, flags);
+       for (; p != &s->urb_list; p = p->next) {
+               tmp = list_entry (p, urb_t, urb_list);
+               dbg (KERN_DEBUG MODSTR "urb: %p\n", tmp);
+               // we can accept this urb if it is not queued at this time 
+               // or if non-iso transfer requests should be scheduled for the same device and pipe
+               if ((!usb_pipeisoc(purb->pipe) && tmp->dev == purb->dev && !((tmp->pipe ^ purb->pipe) & mask)) ||
+                   (purb == tmp)) {
+                       spin_unlock_irqrestore (&s->urb_list_lock, flags);
+                       return 1;       // found another urb already queued for processing
+               }
+       }
+       spin_unlock_irqrestore (&s->urb_list_lock, flags);
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_urb (purb_t purb)
+{
+       puhci_t s;
+       purb_priv_t purb_priv;
+       int ret = 0;
+
+       if (!purb->dev || !purb->dev->bus)
+               return -ENODEV;
+
+       s = (puhci_t) purb->dev->bus->hcpriv;
+       //printk( MODSTR"submit_urb: %p type %d\n",purb,usb_pipetype(purb->pipe));
+
+       if (usb_pipedevice (purb->pipe) == s->rh.devnum)
+               return rh_submit_urb (purb);    /* virtual root hub */
+
+       usb_inc_dev_use (purb->dev);
+
+       if (search_dev_ep (s, purb)) {
+               usb_dec_dev_use (purb->dev);
+               return -ENXIO;  // urb already queued
+
+       }
+
+#ifdef _UHCI_SLAB
+       purb_priv = kmem_cache_alloc(urb_priv_kmem, in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL);
+#else
+       purb_priv = kmalloc (sizeof (urb_priv_t), in_interrupt ()? GFP_ATOMIC : GFP_KERNEL);
+#endif
+       if (!purb_priv) {
+               usb_dec_dev_use (purb->dev);
+               return -ENOMEM;
+       }
+
+       purb->hcpriv = purb_priv;
+       INIT_LIST_HEAD (&purb_priv->desc_list);
+       purb_priv->short_control_packet=0;
+       dbg (KERN_DEBUG MODSTR "submit_urb: scheduling %p\n", purb);
+
+       switch (usb_pipetype (purb->pipe)) {
+       case PIPE_ISOCHRONOUS:
+               ret = uhci_submit_iso_urb (purb);
+               break;
+       case PIPE_INTERRUPT:
+               ret = uhci_submit_int_urb (purb);
+               break;
+       case PIPE_CONTROL:
+               //dump_urb (purb);
+               ret = uhci_submit_control_urb (purb);
+               break;
+       case PIPE_BULK:
+               ret = uhci_submit_bulk_urb (purb);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       dbg (KERN_DEBUG MODSTR "submit_urb: scheduled with ret: %d\n", ret);
+
+       if (ret != USB_ST_NOERROR) {
+               usb_dec_dev_use (purb->dev);
+#ifdef _UHCI_SLAB
+               kmem_cache_free(urb_priv_kmem, purb_priv);
+#else
+               kfree (purb_priv);
+#endif
+               return ret;
+       }
+/*
+       purb->status = USB_ST_URB_PENDING;
+       queue_urb (s, &purb->urb_list,1);
+       dbg (KERN_DEBUG MODSTR "submit_urb: exit\n");
+*/
+       return 0;
+}
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+_static __u8 root_hub_dev_des[] =
+{
+       0x12,                   /*  __u8  bLength; */
+       0x01,                   /*  __u8  bDescriptorType; Device */
+       0x00,                   /*  __u16 bcdUSB; v1.0 */
+       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; */
+       0x00,                   /*  __u8  iProduct; */
+       0x00,                   /*  __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 */
+       0x08,                   /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+       0x00,
+       0xff                    /*  __u8  ep_bInterval; 255 ms */
+};
+
+
+_static __u8 root_hub_hub_des[] =
+{
+       0x09,                   /*  __u8  bLength; */
+       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
+       0x02,                   /*  __u8  bNbrPorts; */
+       0x00,                   /* __u16  wHubCharacteristics; */
+       0x00,
+       0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */
+       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
+       0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+       0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*-------------------------------------------------------------------------*/
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+_static int rh_send_irq (purb_t purb)
+{
+
+       int len = 1;
+       int i;
+       puhci_t uhci = purb->dev->bus->hcpriv;
+       unsigned int io_addr = uhci->io_addr;
+       __u16 data = 0;
+
+       for (i = 0; i < uhci->rh.numports; i++) {
+               data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+               len = (i + 1) / 8 + 1;
+       }
+
+       *(__u16 *) purb->transfer_buffer = cpu_to_le16 (data);
+       purb->actual_length = len;
+       purb->status = USB_ST_NOERROR;
+
+       if ((data > 0) && (uhci->rh.send != 0)) {
+               dbg (KERN_DEBUG MODSTR "Root-Hub INT complete: port1: %x port2: %x data: %x\n",
+                    inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
+               purb->complete (purb);
+
+       }
+       return USB_ST_NOERROR;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+_static int rh_init_int_timer (purb_t purb);
+
+_static void rh_int_timer_do (unsigned long ptr)
+{
+       int len;
+
+       purb_t purb = (purb_t) ptr;
+       puhci_t uhci = purb->dev->bus->hcpriv;
+
+       if (uhci->rh.send) {
+               len = rh_send_irq (purb);
+               if (len > 0) {
+                       purb->actual_length = len;
+                       if (purb->complete)
+                               purb->complete (purb);
+               }
+       }
+       rh_init_int_timer (purb);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Root Hub INTs are polled by this timer */
+_static int rh_init_int_timer (purb_t purb)
+{
+       puhci_t uhci = purb->dev->bus->hcpriv;
+
+       uhci->rh.interval = purb->interval;
+       init_timer (&uhci->rh.rh_int_timer);
+       uhci->rh.rh_int_timer.function = rh_int_timer_do;
+       uhci->rh.rh_int_timer.data = (unsigned long) purb;
+       uhci->rh.rh_int_timer.expires = jiffies + (HZ * (purb->interval < 30 ? 30 : purb->interval)) / 1000;
+       add_timer (&uhci->rh.rh_int_timer);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#define OK(x)                  len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+               status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+               status = (status & 0xfff5) & ~(x); \
+               outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+               status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+               status = (status & 0xfff5) | (x); \
+               outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+
+/*-------------------------------------------------------------------------*/
+/****
+ ** Root Hub Control Pipe
+ *************************/
+
+
+_static int rh_submit_urb (purb_t purb)
+{
+       struct usb_device *usb_dev = purb->dev;
+       puhci_t uhci = usb_dev->bus->hcpriv;
+       unsigned int pipe = purb->pipe;
+       devrequest *cmd = (devrequest *) purb->setup_packet;
+       void *data = purb->transfer_buffer;
+       int leni = purb->transfer_buffer_length;
+       int len = 0;
+       int status = 0;
+       int stat = USB_ST_NOERROR;
+       int i;
+       unsigned int io_addr = uhci->io_addr;
+       __u16 cstatus;
+
+       __u16 bmRType_bReq;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+
+       if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+               dbg (KERN_DEBUG MODSTR "Root-Hub submit IRQ: every %d ms\n", purb->interval);
+               uhci->rh.urb = purb;
+               uhci->rh.send = 1;
+               uhci->rh.interval = purb->interval;
+               rh_init_int_timer (purb);
+
+               return USB_ST_NOERROR;
+       }
+
+
+       bmRType_bReq = cmd->requesttype | cmd->request << 8;
+       wValue = le16_to_cpu (cmd->value);
+       wIndex = le16_to_cpu (cmd->index);
+       wLength = le16_to_cpu (cmd->length);
+
+       for (i = 0; i < 8; i++)
+               uhci->rh.c_p_r[i] = 0;
+
+       dbg(KERN_DEBUG MODSTR "Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x\n",
+            uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, 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 = cpu_to_le16 (1);
+               OK (2);
+       case RH_GET_STATUS | RH_INTERFACE:
+               *(__u16 *) data = cpu_to_le16 (0);
+               OK (2);
+       case RH_GET_STATUS | RH_ENDPOINT:
+               *(__u16 *) data = cpu_to_le16 (0);
+               OK (2);
+       case RH_GET_STATUS | RH_CLASS:
+               *(__u32 *) data = cpu_to_le32 (0);
+               OK (4);         /* hub power ** */
+       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+               status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+               cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+                       ((status & USBPORTSC_PEC) >> (3 - 1)) |
+                       (uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+               status = (status & USBPORTSC_CCS) |
+                       ((status & USBPORTSC_PE) >> (2 - 1)) |
+                       ((status & USBPORTSC_SUSP) >> (12 - 2)) |
+                       ((status & USBPORTSC_PR) >> (9 - 4)) |
+                       (1 << 8) |      /* power on ** */
+                       ((status & USBPORTSC_LSDA) << (-8 + 9));
+
+               *(__u16 *) data = cpu_to_le16 (status);
+               *(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
+               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_OVER_CURRENT):
+                       OK (0); /* hub power over current ** */
+               }
+               break;
+
+       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+               case (RH_PORT_ENABLE):
+                       CLR_RH_PORTSTAT (USBPORTSC_PE);
+                       OK (0);
+               case (RH_PORT_SUSPEND):
+                       CLR_RH_PORTSTAT (USBPORTSC_SUSP);
+                       OK (0);
+               case (RH_PORT_POWER):
+                       OK (0); /* port power ** */
+               case (RH_C_PORT_CONNECTION):
+                       SET_RH_PORTSTAT (USBPORTSC_CSC);
+                       OK (0);
+               case (RH_C_PORT_ENABLE):
+                       SET_RH_PORTSTAT (USBPORTSC_PEC);
+                       OK (0);
+               case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+                       OK (0);
+               case (RH_C_PORT_OVER_CURRENT):
+                       OK (0); /* port power over current ** */
+               case (RH_C_PORT_RESET):
+                       uhci->rh.c_p_r[wIndex - 1] = 0;
+                       OK (0);
+               }
+               break;
+
+       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+               case (RH_PORT_SUSPEND):
+                       SET_RH_PORTSTAT (USBPORTSC_SUSP);
+                       OK (0);
+               case (RH_PORT_RESET):
+                       SET_RH_PORTSTAT (USBPORTSC_PR);
+                       wait_ms (10);
+                       uhci->rh.c_p_r[wIndex - 1] = 1;
+                       CLR_RH_PORTSTAT (USBPORTSC_PR);
+                       udelay (10);
+                       SET_RH_PORTSTAT (USBPORTSC_PE);
+                       wait_ms (10);
+                       SET_RH_PORTSTAT (0xa);
+                       OK (0);
+               case (RH_PORT_POWER):
+                       OK (0); /* port power ** */
+               case (RH_PORT_ENABLE):
+                       SET_RH_PORTSTAT (USBPORTSC_PE);
+                       OK (0);
+               }
+               break;
+
+       case RH_SET_ADDRESS:
+               uhci->rh.devnum = wValue;
+               OK (0);
+
+       case RH_GET_DESCRIPTOR:
+               switch ((wValue & 0xff00) >> 8) {
+               case (0x01):    /* device descriptor */
+                       len = min (leni, min (sizeof (root_hub_dev_des), wLength));
+                       memcpy (data, root_hub_dev_des, len);
+                       OK (len);
+               case (0x02):    /* configuration descriptor */
+                       len = min (leni, min (sizeof (root_hub_config_des), wLength));
+                       memcpy (data, root_hub_config_des, len);
+                       OK (len);
+               case (0x03):    /*string descriptors */
+                       stat = -EPIPE;
+               }
+               break;
+
+       case RH_GET_DESCRIPTOR | RH_CLASS:
+               root_hub_hub_des[2] = uhci->rh.numports;
+               len = min (leni, min (sizeof (root_hub_hub_des), wLength));
+               memcpy (data, root_hub_hub_des, len);
+               OK (len);
+
+       case RH_GET_CONFIGURATION:
+               *(__u8 *) data = 0x01;
+               OK (1);
+
+       case RH_SET_CONFIGURATION:
+               OK (0);
+       default:
+               stat = -EPIPE;
+       }
+
+
+       printk (KERN_DEBUG MODSTR "Root-Hub stat port1: %x port2: %x \n",
+            inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
+
+       purb->actual_length = len;
+       purb->status = stat;
+       if (purb->complete)
+               purb->complete (purb);
+       return USB_ST_NOERROR;
+}
+/*-------------------------------------------------------------------------*/
+
+_static int rh_unlink_urb (purb_t purb)
+{
+       puhci_t uhci = purb->dev->bus->hcpriv;
+
+       dbg (KERN_DEBUG MODSTR "Root-Hub unlink IRQ\n");
+       uhci->rh.send = 0;
+       del_timer (&uhci->rh.rh_int_timer);
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+
+#define UHCI_DEBUG
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+_static int uhci_map_status (int status, int dir_out)
+{
+       if (!status)
+               return USB_ST_NOERROR;
+       if (status & TD_CTRL_BITSTUFF)  /* Bitstuff error */
+               return -EPROTO;
+       if (status & TD_CTRL_CRCTIMEO) {        /* CRC/Timeout */
+               if (dir_out)
+                       return -ETIMEDOUT;
+               else
+                       return -EILSEQ;
+       }
+       if (status & TD_CTRL_NAK)       /* NAK */
+               return -ETIMEDOUT;
+       if (status & TD_CTRL_BABBLE)    /* Babble */
+               return -EPIPE;
+       if (status & TD_CTRL_DBUFERR)   /* Buffer error */
+               return -ENOSR;
+       if (status & TD_CTRL_STALLED)   /* Stalled */
+               return -EPIPE;
+       if (status & TD_CTRL_ACTIVE)    /* Active */
+               return USB_ST_NOERROR;
+
+       return -EPROTO;
+}
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+_static int uhci_alloc_dev (struct usb_device *usb_dev)
+{
+       return 0;
+}
+
+_static int uhci_free_dev (struct usb_device *usb_dev)
+{
+       return 0;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+_static int uhci_get_current_frame_number (struct usb_device *usb_dev)
+{
+       return UHCI_GET_CURRENT_FRAME ((puhci_t) usb_dev->bus->hcpriv);
+}
+
+struct usb_operations uhci_device_operations =
+{
+       uhci_alloc_dev,
+       uhci_free_dev,
+       uhci_get_current_frame_number,
+       uhci_submit_urb,
+       uhci_unlink_urb
+};
+
+/* 
+ * For IN-control transfers, process_transfer gets a bit more complicated,
+ * since there are devices that return less data (eg. strings) than they
+ * have announced. This leads to a queue abort due to the short packet,
+ * the status stage is not executed. If this happens, the status stage
+ * is manually re-executed.
+ * FIXME: Stall-condition may override 'nearly' successful CTRL-IN-transfer
+ * when the transfered length fits exactly in maxsze-packets. A bit
+ * more intelligence is needed to detect this and finish without error.
+ */
+_static int process_transfer (puhci_t s, purb_t purb)
+{
+       int ret = USB_ST_NOERROR;
+       purb_priv_t purb_priv = purb->hcpriv;
+       struct list_head *qhl = purb_priv->desc_list.next;
+       puhci_desc_t qh = list_entry (qhl, uhci_desc_t, desc_list);
+       struct list_head *p = qh->vertical.next;
+       puhci_desc_t desc= list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list);
+       puhci_desc_t last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
+       int data_toggle = usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));   // save initial data_toggle
+
+
+       // extracted and remapped info from TD
+       int maxlength;
+       int actual_length;
+       int status = USB_ST_NOERROR;
+
+       dbg (KERN_DEBUG MODSTR "process_transfer: urb contains bulk/control request\n");
+
+
+       /* if the status phase has been retriggered and the
+          queue is empty or the last status-TD is inactive, the retriggered
+          status stage is completed
+        */
+#if 1
+       if (purb_priv->short_control_packet && 
+               ((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE)))) 
+               goto transfer_finished;
+#endif
+       purb->actual_length=0;
+
+       for (; p != &qh->vertical; p = p->next) {
+               desc = list_entry (p, uhci_desc_t, vertical);
+
+               if (desc->hw.td.status & TD_CTRL_ACTIVE)        // do not process active TDs
+                       return ret;
+
+               // extract transfer parameters from TD
+               actual_length = (desc->hw.td.status + 1) & 0x7ff;
+               maxlength = (((desc->hw.td.info >> 21) & 0x7ff) + 1) & 0x7ff;
+               status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe));
+
+               // see if EP is stalled
+               if (status == -EPIPE) {
+                       // set up stalled condition
+                       usb_endpoint_halt (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
+               }
+
+               // if any error occured stop processing of further TDs
+               if (status != USB_ST_NOERROR) {
+                       // only set ret if status returned an error
+                       uhci_show_td (desc);
+                       ret = status;
+                       purb->error_count++;
+                       break;
+               }
+               else if ((desc->hw.td.info & 0xff) != USB_PID_SETUP)
+                       purb->actual_length += actual_length;
+
+#if 0
+               //      if (i++==0)
+                       uhci_show_td (desc);    // show first TD of each transfer
+#endif
+
+               // got less data than requested
+               if ( (actual_length < maxlength)) {
+                       if (purb->transfer_flags & USB_DISABLE_SPD) {
+                               ret = USB_ST_SHORT_PACKET;      // treat as real error
+                               printk (KERN_DEBUG MODSTR "process_transfer: SPD!!\n");
+                               break;  // exit after this TD because SP was detected
+                       }
+
+                       // short read during control-IN: re-start status stage
+                       if ((usb_pipetype (purb->pipe) == PIPE_CONTROL)) {
+                               if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) {
+                       
+                                       qh->hw.qh.element = virt_to_bus (last_desc);  // re-trigger status stage
+                                       printk(KERN_DEBUG MODSTR "uhci: short packet during control transfer, retrigger status stage @ %p\n",last_desc);
+                                       uhci_show_td (desc);
+                                       uhci_show_td (last_desc);
+                                       purb_priv->short_control_packet=1;
+                                       return 0;
+                               }
+                       }
+                       // all other cases: short read is OK
+                       data_toggle = uhci_toggle (desc->hw.td.info);
+                       break;
+               }
+
+               data_toggle = uhci_toggle (desc->hw.td.info);
+               //printk(KERN_DEBUG MODSTR"process_transfer: len:%d status:%x mapped:%x toggle:%d\n", actual_length, desc->hw.td.status,status, data_toggle);      
+
+       }
+       usb_settoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe), !data_toggle);
+       transfer_finished:
+
+       /* APC BackUPS Pro kludge */     
+       /* It tries to send all of the descriptor instead of */
+       /*  the amount we requested */   
+       if (desc->hw.td.status & TD_CTRL_IOC &&  
+               status & TD_CTRL_ACTIVE &&   
+               status & TD_CTRL_NAK )
+       {
+               printk("APS WORKAROUND\n");
+               ret=0;
+               status=0;
+       }
+
+       unlink_qh (s, qh);
+       delete_qh (s, qh);
+
+       purb->status = status;
+                                                               
+       dbg(KERN_DEBUG MODSTR"process_transfer: urb %p, wanted len %d, len %d status %x err %d\n",
+               purb,purb->transfer_buffer_length,purb->actual_length, purb->status, purb->error_count);
+       //dbg(KERN_DEBUG MODSTR"process_transfer: exit\n");
+#if 0
+       if (purb->actual_length){
+               char *uu;
+               uu=purb->transfer_buffer;
+               dbg(KERN_DEBUG MODSTR"%x %x %x %x %x %x %x %x\n",
+                       *uu,*(uu+1),*(uu+2),*(uu+3),*(uu+4),*(uu+5),*(uu+6),*(uu+7));
+       }
+#endif
+       return ret;
+}
+
+_static int process_interrupt (puhci_t s, purb_t purb)
+{
+       int i, ret = USB_ST_URB_PENDING;
+       purb_priv_t purb_priv = purb->hcpriv;
+       struct list_head *p = purb_priv->desc_list.next;
+       puhci_desc_t desc = list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+       int actual_length;
+       int status = USB_ST_NOERROR;
+
+       //printk(KERN_DEBUG MODSTR"urb contains interrupt request\n");
+
+       for (i = 0; p != &purb_priv->desc_list; p = p->next, i++)       // Maybe we allow more than one TD later ;-)
+       {
+               desc = list_entry (p, uhci_desc_t, desc_list);
+
+               if (desc->hw.td.status & TD_CTRL_ACTIVE) {
+                       // do not process active TDs
+                       //printk("TD ACT Status @%p %08x\n",desc,desc->hw.td.status);
+                       break;
+               }
+
+               if (!desc->hw.td.status & TD_CTRL_IOC) {
+                       // do not process one-shot TDs, no recycling
+                       break;
+               }
+               // extract transfer parameters from TD
+
+               actual_length = (desc->hw.td.status + 1) & 0x7ff;
+               status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe));
+
+               // see if EP is stalled
+               if (status == -EPIPE) {
+                       // set up stalled condition
+                       usb_endpoint_halt (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
+               }
+
+               // if any error occured: ignore this td, and continue
+               if (status != USB_ST_NOERROR) {
+                       uhci_show_td (desc);
+                       purb->error_count++;
+                       goto recycle;
+               }
+               else
+                       purb->actual_length = actual_length;
+
+               // FIXME: SPD?
+
+       recycle:
+               if (purb->complete) {
+                       //printk (KERN_DEBUG MODSTR "process_interrupt: calling completion, status %i\n",status);
+                       purb->status = status;
+                       purb->complete ((struct urb *) purb);
+                       purb->status = USB_ST_URB_PENDING;
+               }
+
+               // Recycle INT-TD if interval!=0, else mark TD as one-shot
+               if (purb->interval) {
+                       desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
+                       if (status==0) {
+                               desc->hw.td.info |= (usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe),
+                                     usb_pipeout (purb->pipe)) << TD_TOKEN_TOGGLE);
+                               usb_dotoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
+                       } else {
+                               desc->hw.td.info |= (!usb_gettoggle (purb->dev, usb_pipeendpoint (purb->pipe),
+                                     usb_pipeout (purb->pipe)) << TD_TOKEN_TOGGLE);
+                       }
+                       desc->hw.td.status= (purb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+                               (purb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+                       wmb();
+               }
+               else {
+                       desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
+               }
+       }
+
+       return ret;
+}
+
+
+_static int process_iso (puhci_t s, purb_t purb)
+{
+       int i;
+       int ret = USB_ST_NOERROR;
+       purb_priv_t purb_priv = purb->hcpriv;
+       struct list_head *p = purb_priv->desc_list.next;
+       puhci_desc_t desc = list_entry (purb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+       dbg ( /*KERN_DEBUG */ MODSTR "urb contains iso request\n");
+       if (desc->hw.td.status & TD_CTRL_ACTIVE)
+               return USB_ST_PARTIAL_ERROR;    // last TD not finished
+
+       purb->error_count = 0;
+       purb->actual_length = 0;
+       purb->status = USB_ST_NOERROR;
+
+       for (i = 0; p != &purb_priv->desc_list; p = p->next, i++) {
+               desc = list_entry (p, uhci_desc_t, desc_list);
+
+               //uhci_show_td(desc);
+               if (desc->hw.td.status & TD_CTRL_ACTIVE) {
+                       // means we have completed the last TD, but not the TDs before
+                       desc->hw.td.status &= ~TD_CTRL_ACTIVE;
+                       printk (KERN_DEBUG MODSTR "TD still active (%x)- grrr. paranoia!\n", desc->hw.td.status);
+                       ret = USB_ST_PARTIAL_ERROR;
+                       purb->iso_frame_desc[i].status = ret;
+                       unlink_td (s, desc);
+                       // FIXME: immediate deletion may be dangerous
+                       goto err;
+               }
+
+               unlink_td (s, desc);
+
+               if (purb->number_of_packets <= i) {
+                       dbg (KERN_DEBUG MODSTR "purb->number_of_packets (%d)<=(%d)\n", purb->number_of_packets, i);
+                       ret = USB_ST_URB_INVALID_ERROR;
+                       goto err;
+               }
+
+               if (purb->iso_frame_desc[i].offset + purb->transfer_buffer != bus_to_virt (desc->hw.td.buffer)) {
+                       // Hm, something really weird is going on
+                       dbg (KERN_DEBUG MODSTR "Pointer Paranoia: %p!=%p\n", purb->iso_frame_desc[i].offset + purb->transfer_buffer, bus_to_virt (desc->hw.td.buffer));
+                       ret = USB_ST_URB_INVALID_ERROR;
+                       purb->iso_frame_desc[i].status = ret;
+                       goto err;
+               }
+               purb->iso_frame_desc[i].actual_length = (desc->hw.td.status + 1) & 0x7ff;
+               purb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (purb->pipe));
+               purb->actual_length += purb->iso_frame_desc[i].actual_length;
+
+             err:
+
+               if (purb->iso_frame_desc[i].status != USB_ST_NOERROR) {
+                       purb->error_count++;
+                       purb->status = purb->iso_frame_desc[i].status;
+               }
+               dbg (KERN_DEBUG MODSTR "process_iso: len:%d status:%x\n",
+                    purb->iso_frame_desc[i].length, purb->iso_frame_desc[i].status);
+
+               delete_desc (desc);
+               list_del (p);
+       }
+       dbg ( /*KERN_DEBUG */ MODSTR "process_iso: exit %i (%d)\n", i, ret);
+       return ret;
+}
+
+
+_static int process_urb (puhci_t s, struct list_head *p)
+{
+       int ret = USB_ST_NOERROR;
+       purb_t purb;
+
+       spin_lock(&s->urb_list_lock);
+       purb=list_entry (p, urb_t, urb_list);
+       dbg ( /*KERN_DEBUG */ MODSTR "found queued urb: %p\n", purb);
+
+       switch (usb_pipetype (purb->pipe)) {
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+               ret = process_transfer (s, purb);
+               break;
+       case PIPE_ISOCHRONOUS:
+               ret = process_iso (s, purb);
+               break;
+       case PIPE_INTERRUPT:
+               ret = process_interrupt (s, purb);
+               break;
+       }
+
+       spin_unlock(&s->urb_list_lock);
+
+       if (purb->status != USB_ST_URB_PENDING) {
+               int proceed = 0;
+               dbg ( /*KERN_DEBUG */ MODSTR "dequeued urb: %p\n", purb);
+               dequeue_urb (s, p, 1);
+
+#ifdef _UHCI_SLAB
+               kmem_cache_free(urb_priv_kmem, purb->hcpriv);
+#else
+               kfree (purb->hcpriv);
+#endif
+
+               if ((usb_pipetype (purb->pipe) != PIPE_INTERRUPT)) {
+                       purb_t tmp = purb->next;        // pointer to first urb
+                       int is_ring = 0;
+                       
+                       if (purb->next) {
+                               do {
+                                       if (tmp->status != USB_ST_URB_PENDING) {
+                                               proceed = 1;
+                                               break;
+                                       }
+                                       tmp = tmp->next;
+                               }
+                               while (tmp != NULL && tmp != purb->next);
+                               if (tmp == purb->next)
+                                       is_ring = 1;
+                       }
+
+                       // In case you need the current URB status for your completion handler
+                       if (purb->complete && (!proceed || (purb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
+                               dbg (KERN_DEBUG MODSTR "process_transfer: calling early completion\n");
+                               purb->complete ((struct urb *) purb);
+                               if (!proceed && is_ring && (purb->status != USB_ST_URB_KILLED))
+                                       uhci_submit_urb (purb);
+                       }
+
+                       if (proceed && purb->next) {
+                               // if there are linked urbs - handle submitting of them right now.
+                               tmp = purb->next;       // pointer to first urb
+
+                               do {
+                                       if ((tmp->status != USB_ST_URB_PENDING) && (tmp->status != USB_ST_URB_KILLED) && uhci_submit_urb (tmp) != USB_ST_NOERROR)
+                                               break;
+                                       tmp = tmp->next;
+                               }
+                               while (tmp != NULL && tmp != purb->next);       // submit until we reach NULL or our own pointer or submit fails
+
+                               if (purb->complete && !(purb->transfer_flags & USB_URB_EARLY_COMPLETE)) {
+                                       dbg ( /*KERN_DEBUG */ MODSTR "process_transfer: calling completion\n");
+                                       purb->complete ((struct urb *) purb);
+                               }
+                       }
+                       usb_dec_dev_use (purb->dev);
+               }
+       }
+
+       return ret;
+}
+
+_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
+{
+       puhci_t s = __uhci;
+       unsigned int io_addr = s->io_addr;
+       unsigned short status;
+       struct list_head *p, *p2;
+
+       /*
+        * Read the interrupt status, and write it back to clear the
+        * interrupt cause
+        */
+
+       status = inw (io_addr + USBSTS);
+
+       if (!status)            /* shared interrupt, not mine */
+               return;
+
+       dbg ("interrupt\n");
+
+       if (status != 1) {
+               printk (KERN_DEBUG MODSTR "interrupt, status %x\n", status);
+               
+               // remove host controller halted state
+               if ((status&0x20) && (s->running)) {
+                       // more to be done - check TDs for invalid entries
+                       // but TDs are only invalid if somewhere else is a (memory ?) problem
+                       outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
+               }
+               //uhci_show_status (s);
+       }
+       //beep(1000);           
+       /*
+        * the following is very subtle and was blatantly wrong before
+        * traverse the list in *reverse* direction, because new entries
+        * may be added at the end.
+        * also, because process_urb may unlink the current urb,
+        * we need to advance the list before
+        * - Thomas Sailer
+        */
+
+       spin_lock(&s->unlink_urb_lock);
+       spin_lock (&s->urb_list_lock);
+       p = s->urb_list.prev;
+       spin_unlock (&s->urb_list_lock);
+
+       while (p != &s->urb_list) {
+               p2 = p;
+               p = p->prev;
+               process_urb (s, p2);
+       }
+
+       spin_unlock(&s->unlink_urb_lock);       
+
+       outw (status, io_addr + USBSTS);
+#ifdef __alpha
+       mb ();                  // ?
+#endif
+       dbg ("done\n\n\n");
+}
+
+_static void reset_hc (puhci_t s)
+{
+       unsigned int io_addr = s->io_addr;
+
+       s->apm_state = 0;
+       /* Global reset for 50ms */
+       outw (USBCMD_GRESET, io_addr + USBCMD);
+       wait_ms (50);
+       outw (0, io_addr + USBCMD);
+       wait_ms (10);
+}
+
+_static void start_hc (puhci_t s)
+{
+       unsigned int io_addr = s->io_addr;
+       int timeout = 1000;
+
+       /*
+        * Reset the HC - this will force us to get a
+        * new notification of any already connected
+        * ports due to the virtual disconnect that it
+        * implies.
+        */
+       outw (USBCMD_HCRESET, io_addr + USBCMD);
+
+       while (inw (io_addr + USBCMD) & USBCMD_HCRESET) {
+               if (!--timeout) {
+                       printk (KERN_ERR MODSTR "USBCMD_HCRESET timed out!\n");
+                       break;
+               }
+       }
+
+       /* Turn on all interrupts */
+       outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+
+       /* Start at frame 0 */
+       outw (0, io_addr + USBFRNUM);
+       outl (virt_to_bus (s->framelist), io_addr + USBFLBASEADD);
+
+       /* Run and mark it configured with a 64-byte max packet */
+       outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+       s->apm_state = 1;
+       s->running = 1;
+}
+
+_static void __exit uhci_cleanup_dev(puhci_t s)
+{
+       struct usb_device *root_hub = s->bus->root_hub;
+       if (root_hub)
+               usb_disconnect (&root_hub);
+
+       usb_deregister_bus (s->bus);
+       s->running = 0;
+       reset_hc (s);
+       release_region (s->io_addr, s->io_size);
+       free_irq (s->irq, s);
+       usb_free_bus (s->bus);
+       cleanup_skel (s);
+       kfree (s);
+
+}
+
+_static int __init uhci_start_usb (puhci_t s)
+{                              /* start it up */
+       /* connect the virtual root hub */
+       struct usb_device *usb_dev;
+
+       usb_dev = usb_alloc_dev (NULL, s->bus);
+       if (!usb_dev)
+               return -1;
+
+       s->bus->root_hub = usb_dev;
+       usb_connect (usb_dev);
+
+       if (usb_new_device (usb_dev) != 0) {
+               usb_free_dev (usb_dev);
+               return -1;
+       }
+
+       return 0;
+}
+
+_static int __init alloc_uhci (int irq, unsigned int io_addr, unsigned int io_size)
+{
+       puhci_t s;
+       struct usb_bus *bus;
+
+       s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
+       if (!s)
+               return -1;
+
+       memset (s, 0, sizeof (uhci_t));
+       INIT_LIST_HEAD (&s->urb_list);
+       spin_lock_init (&s->urb_list_lock);
+       spin_lock_init (&s->qh_lock);
+       spin_lock_init (&s->td_lock);
+       spin_lock_init (&s->unlink_urb_lock);
+       s->irq = -1;
+       s->io_addr = io_addr;
+       s->io_size = io_size;
+       s->next = devs; //chain new uhci device into global list        
+
+       bus = usb_alloc_bus (&uhci_device_operations);
+       if (!bus) {
+               kfree (s);
+               return -1;
+       }
+
+       s->bus = bus;
+       bus->hcpriv = s;
+
+       /* UHCI specs says devices must have 2 ports, but goes on to say */
+       /* they may have more but give no way to determine how many they */
+       /* have, so default to 2 */
+       /* According to the UHCI spec, Bit 7 is always set to 1. So we try */
+       /* to use this to our advantage */
+
+       for (s->maxports = 0; s->maxports < (io_size - 0x10) / 2; s->maxports++) {
+               unsigned int portstatus;
+
+               portstatus = inw (io_addr + 0x10 + (s->maxports * 2));
+               printk ("port %i, adr %x status %x\n", s->maxports,
+                       io_addr + 0x10 + (s->maxports * 2), portstatus);
+               if (!(portstatus & 0x0080))
+                       break;
+       }
+       dbg (KERN_DEBUG MODSTR "Detected %d ports\n", s->maxports);
+
+       /* This is experimental so anything less than 2 or greater than 8 is */
+       /*  something weird and we'll ignore it */
+       if (s->maxports < 2 || s->maxports > 8) {
+               dbg (KERN_DEBUG "Port count misdetected, forcing to 2 ports\n");
+               s->maxports = 2;
+       }
+
+       s->rh.numports = s->maxports;
+
+       if (init_skel (s)) {
+               usb_free_bus (bus);
+               kfree(s);
+               return -1;
+       }
+
+       request_region (s->io_addr, io_size, MODNAME);
+       reset_hc (s);
+       usb_register_bus (s->bus);
+
+       start_hc (s);
+
+       if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
+               printk(MODSTR KERN_ERR"request_irq %d failed!\n",irq);
+               usb_free_bus (bus);
+               reset_hc (s);
+               release_region (s->io_addr, s->io_size);
+               cleanup_skel(s);
+               kfree(s);
+               return -1;
+       }
+
+       s->irq = irq;
+
+       if(uhci_start_usb (s) < 0) {
+               uhci_cleanup_dev(s);
+               return -1;
+       }
+       
+       //chain new uhci device into global list
+       devs = s;
+
+       return 0;
+}
+
+_static int __init start_uhci (struct pci_dev *dev)
+{
+       int i;
+
+       /* Search for the IO base address.. */
+       for (i = 0; i < 6; i++) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+               unsigned int io_addr = dev->resource[i].start;
+               unsigned int io_size =
+               dev->resource[i].end - dev->resource[i].start + 1;
+               if (!(dev->resource[i].flags & 1))
+                       continue;
+#else
+               unsigned int io_addr = dev->base_address[i];
+               unsigned int io_size = 0x14;
+               if (!(io_addr & 1))
+                       continue;
+               io_addr &= ~1;
+#endif
+
+               /* Is it already in use? */
+               if (check_region (io_addr, io_size))
+                       break;
+               /* disable legacy emulation */
+               pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+               return alloc_uhci(dev->irq, io_addr, io_size);
+       }
+       return -1;
+}
+
+#ifdef CONFIG_APM
+_static int handle_apm_event (apm_event_t event)
+{
+       static int down = 0;
+       puhci_t s = devs;
+       printk ("handle_apm_event(%d)\n", event);
+       switch (event) {
+       case APM_SYS_SUSPEND:
+       case APM_USER_SUSPEND:
+               if (down) {
+                       dbg (KERN_DEBUG MODSTR "received extra suspend event\n");
+                       break;
+               }
+               while (s) {
+                       reset_hc (s);
+                       s = s->next;
+               }
+               down = 1;
+               break;
+       case APM_NORMAL_RESUME:
+       case APM_CRITICAL_RESUME:
+               if (!down) {
+                       dbg (KERN_DEBUG MODSTR "received bogus resume event\n");
+                       break;
+               }
+               down = 0;
+               while (s) {
+                       start_hc (s);
+                       s = s->next;
+               }
+               break;
+       }
+       return 0;
+}
+#endif
+
+int __init uhci_init (void)
+{
+       int retval = -ENODEV;
+       struct pci_dev *dev = NULL;
+       u8 type;
+       int i=0;
+
+#ifdef _UHCI_SLAB
+       char *slabname=kmalloc(16, GFP_KERNEL);
+
+       if(!slabname)
+               return -ENOMEM;
+
+       strcpy(slabname, "uhci_desc");
+       uhci_desc_kmem = kmem_cache_create(slabname, sizeof(uhci_desc_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+       
+       if(!uhci_desc_kmem) {
+               printk(KERN_ERR MODSTR"kmem_cache_create for uhci_desc failed (out of memory)\n");
+               return -ENOMEM;
+       }
+
+       slabname=kmalloc(16, GFP_KERNEL);
+
+       if(!slabname)
+               return -ENOMEM;
+
+       strcpy(slabname, "urb_priv");   
+       urb_priv_kmem = kmem_cache_create(slabname, sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+       
+       if(!urb_priv_kmem) {
+               printk(KERN_ERR MODSTR"kmem_cache_create for urb_priv_t failed (out of memory)\n");
+               return -ENOMEM;
+       }
+#endif 
+       printk (KERN_INFO MODSTR VERSTR "\n");
+
+       for (;;) {
+               dev = pci_find_class (PCI_CLASS_SERIAL_USB << 8, dev);
+               if (!dev)
+                       break;
+
+               /* Is it UHCI */
+               pci_read_config_byte (dev, PCI_CLASS_PROG, &type);
+               if (type != 0)
+                       continue;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+               pci_enable_device (dev);
+#endif
+               if(!dev->irq)
+               {
+                       printk(KERN_ERR MODSTR"Found UHCI device with no IRQ assigned. Check BIOS settings!\n");
+                       continue;
+               }
+
+               /* Ok set it up */
+               retval = start_uhci (dev);
+       
+               if (!retval)
+                       i++;
+
+       }
+
+#ifdef CONFIG_APM
+       if(i)
+               apm_register_callback (&handle_apm_event);
+#endif
+       return retval;
+}
+
+void __exit uhci_cleanup (void)
+{
+       puhci_t s;
+       while ((s = devs)) {
+               devs = devs->next;
+               uhci_cleanup_dev(s);
+       }
+#ifdef _UHCI_SLAB
+       kmem_cache_shrink(uhci_desc_kmem);
+       kmem_cache_shrink(urb_priv_kmem);
+#endif
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+       return uhci_init ();
+}
+
+void cleanup_module (void)
+{
+#ifdef CONFIG_APM
+       apm_unregister_callback (&handle_apm_event);
+#endif
+       uhci_cleanup ();
+}
+
+#endif //MODULE
diff --git a/drivers/usb/usb-uhci.h b/drivers/usb/usb-uhci.h
new file mode 100644 (file)
index 0000000..a228794
--- /dev/null
@@ -0,0 +1,253 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+/*
+   $Id: usb-uhci.h,v 1.31 2000/01/15 22:02:30 acher Exp $
+ */
+#define MODNAME "usb-uhci"
+#define MODSTR MODNAME": "
+#define VERSTR "version v0.9 time " __TIME__ " " __DATE__
+
+/* Command register */
+#define USBCMD         0
+#define   USBCMD_RS            0x0001  /* Run/Stop */
+#define   USBCMD_HCRESET       0x0002  /* Host reset */
+#define   USBCMD_GRESET                0x0004  /* Global reset */
+#define   USBCMD_EGSM          0x0008  /* Global Suspend Mode */
+#define   USBCMD_FGR           0x0010  /* Force Global Resume */
+#define   USBCMD_SWDBG         0x0020  /* SW Debug mode */
+#define   USBCMD_CF            0x0040  /* Config Flag (sw only) */
+#define   USBCMD_MAXP          0x0080  /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS         2
+#define   USBSTS_USBINT                0x0001  /* Interrupt due to IOC */
+#define   USBSTS_ERROR         0x0002  /* Interrupt due to error */
+#define   USBSTS_RD            0x0004  /* Resume Detect */
+#define   USBSTS_HSE           0x0008  /* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE          0x0010  /* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH           0x0020  /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR                4
+#define   USBINTR_TIMEOUT      0x0001  /* Timeout/CRC error enable */
+#define   USBINTR_RESUME       0x0002  /* Resume interrupt enable */
+#define   USBINTR_IOC          0x0004  /* Interrupt On Complete enable */
+#define   USBINTR_SP           0x0008  /* Short packet interrupt enable */
+
+#define USBFRNUM       6
+#define USBFLBASEADD   8
+#define USBSOF         12
+
+/* USB port status and control registers */
+#define USBPORTSC1     16
+#define USBPORTSC2     18
+#define   USBPORTSC_CCS                0x0001  /* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC                0x0002  /* Connect Status Change */
+#define   USBPORTSC_PE         0x0004  /* Port Enable */
+#define   USBPORTSC_PEC                0x0008  /* Port Enable Change */
+#define   USBPORTSC_LS         0x0030  /* Line Status */
+#define   USBPORTSC_RD         0x0040  /* Resume Detect */
+#define   USBPORTSC_LSDA       0x0100  /* Low Speed Device Attached */
+#define   USBPORTSC_PR         0x0200  /* Port Reset */
+#define   USBPORTSC_SUSP       0x1000  /* Suspend */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT 0x2000       /* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE    0x7ff   /* for UHCI controller TD */
+
+#define UHCI_PTR_BITS          0x000F
+#define UHCI_PTR_TERM          0x0001
+#define UHCI_PTR_QH            0x0002
+#define UHCI_PTR_DEPTH         0x0004
+
+#define UHCI_NUMFRAMES         1024    /* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER    2047    /* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES    1000    /* how far future frames can be scheduled */
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD            (1 << 29)       /* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK     (3 << 27)       /* Error Counter bits */
+#define TD_CTRL_LS             (1 << 26)       /* Low Speed Device */
+#define TD_CTRL_IOS            (1 << 25)       /* Isochronous Select */
+#define TD_CTRL_IOC            (1 << 24)       /* Interrupt on Complete */
+#define TD_CTRL_ACTIVE         (1 << 23)       /* TD Active */
+#define TD_CTRL_STALLED                (1 << 22)       /* TD Stalled */
+#define TD_CTRL_DBUFERR                (1 << 21)       /* Data Buffer Error */
+#define TD_CTRL_BABBLE         (1 << 20)       /* Babble Detected */
+#define TD_CTRL_NAK            (1 << 19)       /* NAK Received */
+#define TD_CTRL_CRCTIMEO       (1 << 18)       /* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF       (1 << 17)       /* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK    0x7ff   /* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR      (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+                                TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts)     (ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts)   ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK)  /* 1-based */
+#define uhci_ptr_to_virt(x)    bus_to_virt(x & ~UHCI_PTR_BITS)
+
+/*
+ * for TD <flags>:
+ */
+#define UHCI_TD_REMOVE         0x0001  /* Remove when done */
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE                19
+
+#define uhci_maxlen(token)     ((token) >> 21)
+#define uhci_toggle(token)     (((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_endpoint(token)   (((token) >> 15) & 0xf)
+#define uhci_devaddr(token)    (((token) >> 8) & 0x7f)
+#define uhci_devep(token)      (((token) >> 8) & 0x7ff)
+#define uhci_packetid(token)   ((token) & 0xff)
+#define uhci_packetout(token)  (uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)   (uhci_packetid(token) == USB_PID_IN)
+
+/* ------------------------------------------------------------------------------------
+   New TD/QH-structures
+   ------------------------------------------------------------------------------------ */
+typedef enum {
+       TD_TYPE, QH_TYPE
+} uhci_desc_type_t;
+
+typedef struct {
+       __u32 link;
+       __u32 status;
+       __u32 info;
+       __u32 buffer;
+} uhci_td_t, *puhci_td_t;
+
+typedef struct {
+       __u32 head;
+       __u32 element;          /* Queue element pointer */
+} uhci_qh_t, *puhci_qh_t;
+
+typedef struct {
+       union {
+               uhci_td_t td;
+               uhci_qh_t qh;
+       } hw;
+       uhci_desc_type_t type;
+       struct list_head horizontal;
+       struct list_head vertical;
+       struct list_head desc_list;
+} uhci_desc_t, *puhci_desc_t;
+
+typedef struct {
+       struct list_head desc_list;     // list pointer to all corresponding TDs/QHs associated with this request
+       int short_control_packet;
+} urb_priv_t, *purb_priv_t;
+
+struct virt_root_hub {
+       int devnum;             /* Address of Root Hub endpoint */
+       void *urb;
+       void *int_addr;
+       int send;
+       int interval;
+       int numports;
+       int c_p_r[8];
+       struct timer_list rh_int_timer;
+};
+
+typedef struct uhci {
+       int irq;
+       unsigned int io_addr;
+       unsigned int io_size;
+       unsigned int maxports;
+       int running;
+
+       int apm_state;
+
+       struct uhci *next;      // chain of uhci device contexts
+
+       struct list_head urb_list;      // list of all pending urbs
+
+       spinlock_t urb_list_lock;       // lock to keep consistency 
+
+       struct usb_bus *bus;    // our bus
+
+       spinlock_t unlink_urb_lock;     // lock for unlink_urb
+
+       __u32 *framelist;
+       uhci_desc_t **iso_td;
+       uhci_desc_t *int_chain[8];
+       uhci_desc_t *control_chain;
+       uhci_desc_t *bulk_chain;
+       uhci_desc_t *chain_end;
+       spinlock_t qh_lock;
+       spinlock_t td_lock;
+       struct virt_root_hub rh;        //private data of the virtual root hub
+} uhci_t, *puhci_t;
+
+
+#define MAKE_TD_ADDR(a) (virt_to_bus(a)&~UHCI_PTR_QH)
+#define MAKE_QH_ADDR(a) (virt_to_bus(a)|UHCI_PTR_QH)
+#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
+
+/* ------------------------------------------------------------------------------------ 
+   Virtual Root HUB 
+   ------------------------------------------------------------------------------------ */
+/* 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
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+#endif
index 6b02641a98d0ddce10c48994a9db38b30870f0e2..7b582b3037d9371d6313c043fae0e65fbc59f911 100644 (file)
@@ -15,7 +15,7 @@
  * It should be considered a slave, with no callbacks. Callbacks
  * are evil.
  *
- * $Id: usb.c,v 1.39 1999/12/27 15:17:47 acher Exp $
+ * $Id: usb.c,v 1.53 2000/01/14 16:19:09 acher Exp $
  */
 
 #include <linux/config.h>
@@ -486,7 +486,8 @@ urb_t* usb_alloc_urb(int iso_packets)
 /*-------------------------------------------------------------------*/
 void usb_free_urb(urb_t* urb)
 {
-       kfree(urb);
+       if(urb)
+               kfree(urb);
 }
 /*-------------------------------------------------------------------*/
 int usb_submit_urb(urb_t *urb)
@@ -515,7 +516,7 @@ int usb_unlink_urb(urb_t *urb)
 static void usb_api_blocking_completion(urb_t *urb)
 {
        api_wrapper_data *awd = (api_wrapper_data *)urb->context;
-  
+
        if (waitqueue_active(awd->wakeup))
                wake_up(awd->wakeup);
 #if 0
@@ -541,7 +542,7 @@ static void usb_api_async_completion(urb_t *urb)
  *-------------------------------------------------------------------*/
 
 // Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, unsigned long* rval)
+static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
 { 
        DECLARE_WAITQUEUE(wait, current);
        DECLARE_WAIT_QUEUE_HEAD(wqh);
@@ -551,7 +552,7 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, unsigned long* rval)
        awd.wakeup=&wqh;
        awd.handler=0;
        init_waitqueue_head(&wqh);      
-       current->state = TASK_UNINTERRUPTIBLE;
+       current->state = TASK_INTERRUPTIBLE;
        add_wait_queue(&wqh, &wait);
        urb->context=&awd;
        status=usb_submit_urb(urb);
@@ -572,15 +573,15 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, unsigned long* rval)
 
        if (!status) {
                // timeout
-               dbg("usb_control/bulk_msg: timeout");
+               printk("usb_control/bulk_msg: timeout\n");
                usb_unlink_urb(urb);  // remove urb safely
                status=-ETIMEDOUT;
        }
        else
                status=urb->status;
 
-       if (rval)
-               *rval=urb->actual_length;
+       if (actual_length)
+               *actual_length=urb->actual_length;
 
        usb_free_urb(urb);
        return status;
@@ -593,7 +594,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
 {
        urb_t *urb;
        int retv;
-       unsigned long length;
+       int length;
 
        urb=usb_alloc_urb(0);
        if (!urb)
@@ -601,7 +602,7 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
   
        FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,    /* build urb */  
                   (usb_complete_t)usb_api_blocking_completion,0);
-       
+
        retv=usb_start_wait_urb(urb,timeout, &length);
        if (retv < 0)
                return retv;
@@ -613,15 +614,25 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
                         __u16 value, __u16 index, void *data, __u16 size, int timeout)
 {
-       devrequest dr;
-         
-       dr.requesttype = requesttype;
-       dr.request = request;
-       dr.value = cpu_to_le16p(&value);
-       dr.index = cpu_to_le16p(&index);
-       dr.length = cpu_to_le16p(&size);
+       devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+       int ret;
+       
+       if(!dr)
+               return -ENOMEM;
+
+       dr->requesttype = requesttype;
+       dr->request = request;
+       dr->value = cpu_to_le16p(&value);
+       dr->index = cpu_to_le16p(&index);
+       dr->length = cpu_to_le16p(&size);
+
        //dbg("usb_control_msg");       
-       return usb_internal_control_msg(dev, pipe, &dr, data, size, timeout);
+
+       ret=usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+
+       kfree(dr);
+
+       return ret;
 }
 
 /*-------------------------------------------------------------------*/
@@ -629,7 +640,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
 /* synchronous behavior */
 
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
-                       void *data, int len, unsigned long *rval, int timeout)
+                       void *data, int len, int *actual_length, int timeout)
 {
        urb_t *urb;
 
@@ -643,13 +654,15 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
        FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len,   /* build urb */
                        (usb_complete_t)usb_api_blocking_completion,0);
 
-       return usb_start_wait_urb(urb,timeout,rval);
+       return usb_start_wait_urb(urb,timeout,actual_length);
 }
 /*-------------------------------------------------------------------*/
 
 void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
 {
        urb_t *urb;
+       DECLARE_WAITQUEUE(wait, current);
+       DECLARE_WAIT_QUEUE_HEAD(wqh);
        api_wrapper_data *awd;
 
        if (!(urb=usb_alloc_urb(0)))
@@ -1087,7 +1100,7 @@ int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor
        
        for (i = 0; i < config->bNumInterfaces; i++) {
                header = (struct usb_descriptor_header *)buffer;
-               if (header->bLength > size) {
+               if ((header->bLength > size) || (header->bLength <= 2)) {
                        err("ran out of descriptors parsing");
                        return -1;
                }
@@ -1222,7 +1235,8 @@ void usb_disconnect(struct usb_device **pdev)
        /* Free up all the children.. */
        for (i = 0; i < USB_MAXCHILDREN; i++) {
                struct usb_device **child = dev->children + i;
-               usb_disconnect(child);
+               if (*child)
+                       usb_disconnect(child);
        }
 
        /* remove /proc/bus/usb entry */
@@ -1246,6 +1260,9 @@ void usb_connect(struct usb_device *dev)
 {
        int devnum;
        // FIXME needs locking for SMP!!
+       /* why? this is called only from the hub thread, 
+        * which hopefully doesn't run on multiple CPU's simulatenously 8-)
+        */
        dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */
        devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
        if (devnum < 128) {
@@ -1272,6 +1289,8 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
 {
        int i = 5;
        int result;
+       
+       memset(buf,0,size);     // Make sure we parse really received data
 
        while (i--) {
                if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -1373,10 +1392,11 @@ static void usb_set_maxpacket(struct usb_device *dev)
  * endp: endpoint number in bits 0-3;
  *     direction flag in bit 7 (1 = IN, 0 = OUT)
  */
-int usb_clear_halt(struct usb_device *dev, int endp)
+int usb_clear_halt(struct usb_device *dev, int pipe)
 {
        int result;
        __u16 status;
+       int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
 
 /*
        if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp)))
@@ -1399,11 +1419,11 @@ int usb_clear_halt(struct usb_device *dev, int endp)
        if (status & 1)
                return -EPIPE;          /* still halted */
 
-       usb_endpoint_running(dev, endp & 0x0f, usb_endpoint_out(endp));
+       usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
        /* toggle is reset on clear */
 
-       usb_settoggle(dev, endp & 0x0f, usb_endpoint_out(endp), 0);
+       usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
 
        return 0;
 }
@@ -1482,6 +1502,7 @@ int usb_get_configuration(struct usb_device *dev)
        unsigned int cfgno;
        unsigned char buffer[8];
        unsigned char *bigbuffer;
+       unsigned int tmp;
        struct usb_config_descriptor *desc =
                (struct usb_config_descriptor *)buffer;
 
@@ -1511,8 +1532,11 @@ int usb_get_configuration(struct usb_device *dev)
                /* We grab the first 8 bytes so we know how long the whole */
                /*  configuration is */
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
-               if (result < 0) {
-                       err("unable to get descriptor");
+               if (result < 8) {
+                       if (result < 0)
+                               err("unable to get descriptor");
+                       else
+                               err("config descriptor too short (expected %i, got %i)",8,result);
                        goto err;
                }
 
@@ -1525,13 +1549,19 @@ int usb_get_configuration(struct usb_device *dev)
                        result=-ENOMEM;
                        goto err;
                }
-
+               tmp=desc->wTotalLength;
                /* Now that we know the length, get the whole thing */
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength);
                if (result < 0) {
                        err("couldn't get all of config descriptors");
                        kfree(bigbuffer);
                        goto err;
+               }       
+       
+               if (result < tmp) {
+                       err("config descriptor too short (expected %i, got %i)",tmp,result);
+                       kfree(bigbuffer);
+                       goto err;
                }               
                result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
                kfree(bigbuffer);
@@ -1603,6 +1633,7 @@ int usb_new_device(struct usb_device *dev)
 {
        unsigned char *buf;
        int addr, err;
+       int tmp;
 
        info("USB new device connect, assigned device number %d", dev->devnum);
  
@@ -1615,13 +1646,15 @@ int usb_new_device(struct usb_device *dev)
        dev->devnum = 0;
 
        err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
-       if (err < 0) {
-               err("USB device not responding, giving up (error=%d)", err);
+       if (err < 8) {
+               if (err < 0)
+                       err("USB device not responding, giving up (error=%d)", err);
+               else
+                       err("USB device descriptor short read (expected %i, got %i)",8,err);
                clear_bit(addr, &dev->bus->devmap.devicemap);
                dev->devnum = -1;
                return 1;
        }
-
        dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
        dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
        switch (dev->descriptor.bMaxPacketSize0) {
@@ -1644,9 +1677,15 @@ int usb_new_device(struct usb_device *dev)
 
        wait_ms(10);    /* Let the SET_ADDRESS settle */
 
+       tmp = sizeof(dev->descriptor);
+
        err = usb_get_device_descriptor(dev);
-       if (err < 0) {
-               err("unable to get device descriptor (error=%d)",err);
+       if (err < tmp) {
+               if (err < 0)
+                       err("unable to get device descriptor (error=%d)",err);
+               else
+                       err("USB device descriptor short read (expected %i, got %i)",tmp,err);
+       
                clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
                dev->devnum = -1;
                return 1;
index c6f52047be3d60b02fce4ec453b53759eeb5d428..b51d4234c7280b264ffae0bb065069b9f4b848a1 100644 (file)
@@ -4,6 +4,9 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 #include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>   /* for in_interrupt() */
 
 /* USB constants */
 
@@ -159,8 +162,12 @@ typedef struct wait_queue *wait_queue_head_t;
 
 static __inline__ void wait_ms(unsigned int ms)
 {
-       current->state = TASK_UNINTERRUPTIBLE;
-       schedule_timeout(1 + ms * HZ / 1000);
+       if(!in_interrupt()) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(1 + ms * HZ / 1000);
+       }
+       else
+               mdelay(ms);
 }
 
 typedef struct {
@@ -263,6 +270,23 @@ struct usb_endpoint_descriptor {
        int extralen;
 } __attribute__ ((packed));
 
+/* HID descriptor */
+struct usb_hid_class_descriptor {
+        __u8  bDescriptorType;
+        __u16 wDescriptorLength;
+} __attribute__ ((packed));
+
+
+struct usb_hid_descriptor {
+        __u8  bLength;
+        __u8  bDescriptorType;
+        __u16 bcdHID;
+        __u8  bCountryCode;
+        __u8  bNumDescriptors;
+
+        struct usb_hid_class_descriptor desc[1];
+} __attribute__ ((packed));
+
 /* Interface descriptor */
 struct usb_interface_descriptor {
        __u8  bLength;
@@ -428,7 +452,7 @@ void usb_free_urb (purb_t purb);
 int usb_submit_urb(purb_t purb);
 int usb_unlink_urb(purb_t purb);
 int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd,  void *data, int len, int timeout);
-int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *rval, int timeout);
+int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout);
 
 /*-------------------------------------------------------------------*
  *                         COMPATIBILITY STUFF                       *
@@ -676,7 +700,7 @@ int usb_get_report(struct usb_device *dev, unsigned char type,
 int usb_set_report(struct usb_device *dev, unsigned char type,
        unsigned char id, unsigned char index, void *buf, int size);
 int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
-int usb_clear_halt(struct usb_device *dev, int endp);
+int usb_clear_halt(struct usb_device *dev, int pipe);
 
 #define usb_get_extra_descriptor(ifpoint,type,ptr)\
        __usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,type,(void**)ptr)
index 885cdac77b716ce6d4102d662a0b068f5238c515..04474cb930986495c1f39e7b9540a336a51a80e8 100644 (file)
@@ -143,8 +143,7 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
                        /* if we stall, we need to clear it before we go on */
                        if (result == USB_ST_STALL) {
                                US_DEBUGP("clearing endpoint halt for pipe %x\n", pipe);
-                               usb_clear_halt(us->pusb_dev,
-                                              usb_pipeendpoint(pipe) | (pipe & USB_DIR_IN));
+                               usb_clear_halt(us->pusb_dev,pipe);
                        }
 
                        /* we want to retry if the device reported NAK */
@@ -296,8 +295,8 @@ static int pop_CB_reset(struct us_data *us)
        schedule_timeout(HZ*6);
 
        US_DEBUGP("pop_CB_reset: clearing endpoint halt\n");
-       usb_clear_halt(us->pusb_dev, us->ep_in | USB_DIR_IN);
-       usb_clear_halt(us->pusb_dev, us->ep_out | USB_DIR_OUT);
+       usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+       usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out));
 
        US_DEBUGP("pop_CB_reset done\n");
        return 0;
@@ -522,8 +521,8 @@ static int pop_Bulk_reset(struct us_data *us)
                                 NULL, 0, HZ*5);
        if (result)
                US_DEBUGP("Bulk hard reset failed %d\n", result);
-       usb_clear_halt(us->pusb_dev, us->ep_in | USB_DIR_IN);
-       usb_clear_halt(us->pusb_dev, us->ep_out | USB_DIR_OUT);
+       usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+       usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out));
 
        /* long wait for reset */
 
index b8fef78918f57d46c10e570f22d0115b5c631e1b..fa2d1b46587c863a1db2cc41e5b4a7e5e93ee9b2 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *  wmforce.c  Version 0.1
  *
- *  Copyright (c) 1999 Vojtech Pavlik
+ *  Copyright (c) 2000 Vojtech Pavlik
  *
- *  USB Logitech WingMan Force tablet support
+ *  USB Logitech WingMan Force joystick support
  *
  *  Sponsored by SuSE
  */
index 4ffd51452b70dc55174c4631026be049e59fc0e4..c08847d3252dab9b52bc16cbc52bcb7d74dbd193 100644 (file)
@@ -24,8 +24,7 @@ typedef struct siginfo {
                /* kill() */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       old_uid_t _uid;         /* backwards compatibility */
-                       uid_t _uid32;           /* sender's uid */
+                       uid_t _uid;             /* sender's uid */
                } _kill;
 
                /* POSIX.1b timers */
@@ -37,19 +36,17 @@ typedef struct siginfo {
                /* POSIX.1b signals */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       old_uid_t _uid;         /* backwards compatibility */
+                       uid_t _uid;             /* sender's uid */
                        sigval_t _sigval;
-                       uid_t _uid32;           /* sender's uid */
                } _rt;
 
                /* SIGCHLD */
                struct {
                        pid_t _pid;             /* which child */
-                       old_uid_t _uid;         /* backwards compatibility */
+                       uid_t _uid;             /* sender's uid */
                        int _status;            /* exit code */
                        clock_t _utime;
                        clock_t _stime;
-                       uid_t _uid32;           /* sender's uid */
                } _sigchld;
 
                /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -65,18 +62,11 @@ typedef struct siginfo {
        } _sifields;
 } siginfo_t;
 
-#define UID16_SIGINFO_COMPAT_NEEDED
-
 /*
  * How these fields are to be accessed.
  */
 #define si_pid         _sifields._kill._pid
-#ifdef __KERNEL__
-#define si_uid         _sifields._kill._uid32
-#define si_uid16       _sifields._kill._uid
-#else
 #define si_uid         _sifields._kill._uid
-#endif /* __KERNEL__ */
 #define si_status      _sifields._sigchld._status
 #define si_utime       _sifields._sigchld._utime
 #define si_stime       _sifields._sigchld._stime
index 467aa9d3923da9152f7dd7dbdc6cd520b9179b80..7c805525c9e5143b47ec2d5361be679cbb13ee14 100644 (file)
@@ -24,8 +24,7 @@ typedef struct siginfo {
                /* kill() */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       old_uid_t _uid;         /* backwards compatibility */
-                       uid_t _uid32;           /* sender's uid */
+                       uid_t _uid;             /* sender's uid */
                } _kill;
 
                /* POSIX.1b timers */
@@ -37,19 +36,17 @@ typedef struct siginfo {
                /* POSIX.1b signals */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       old_uid_t _uid;         /* backwards compatibility */
+                       uid_t _uid;             /* sender's uid */
                        sigval_t _sigval;
-                       uid_t _uid32;           /* sender's uid */
                } _rt;
 
                /* SIGCHLD */
                struct {
                        pid_t _pid;             /* which child */
-                       old_uid_t _uid;         /* backwards compatibility */
+                       uid_t _uid;             /* sender's uid */
                        int _status;            /* exit code */
                        clock_t _utime;
                        clock_t _stime;
-                       uid_t _uid32;           /* sender's uid */
                } _sigchld;
 
                /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -65,18 +62,11 @@ typedef struct siginfo {
        } _sifields;
 } siginfo_t;
 
-#define UID16_SIGINFO_COMPAT_NEEDED
-
 /*
  * How these fields are to be accessed.
  */
 #define si_pid         _sifields._kill._pid
-#ifdef __KERNEL__
-#define si_uid         _sifields._kill._uid32
-#define si_uid16       _sifields._kill._uid
-#else
 #define si_uid         _sifields._kill._uid
-#endif /* __KERNEL__ */
 #define si_status      _sifields._sigchld._status
 #define si_utime       _sifields._sigchld._utime
 #define si_stime       _sifields._sigchld._stime
index 2dac2b06321932d53ec737339d4417678b604303..4061e6f72946dbb4b3e1fdaa58e3decc39ccb6a5 100644 (file)
@@ -24,8 +24,7 @@ typedef struct siginfo {
                /* kill() */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       old_uid_t _uid;         /* backwards compatibility */
-                       uid_t _uid32;           /* sender's uid */
+                       uid_t _uid;             /* sender's uid */
                } _kill;
 
                /* POSIX.1b timers */
@@ -37,19 +36,17 @@ typedef struct siginfo {
                /* POSIX.1b signals */
                struct {
                        pid_t _pid;             /* sender's pid */
-                       old_uid_t _uid;         /* backwards compatibility */
+                       uid_t _uid;             /* sender's uid */
                        sigval_t _sigval;
-                       uid_t _uid32;           /* sender's uid */
                } _rt;
 
                /* SIGCHLD */
                struct {
                        pid_t _pid;             /* which child */
-                       old_uid_t _uid;         /* backwards compatibility */
+                       uid_t _uid;             /* sender's uid */
                        int _status;            /* exit code */
                        clock_t _utime;
                        clock_t _stime;
-                       uid_t _uid32;           /* sender's uid */
                } _sigchld;
 
                /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -65,18 +62,11 @@ typedef struct siginfo {
        } _sifields;
 } siginfo_t;
 
-#define UID16_SIGINFO_COMPAT_NEEDED
-
 /*
  * How these fields are to be accessed.
  */
 #define si_pid         _sifields._kill._pid
-#ifdef __KERNEL__
-#define si_uid         _sifields._kill._uid32
-#define si_uid16       _sifields._kill._uid
-#else
 #define si_uid         _sifields._kill._uid
-#endif /* __KERNEL__ */
 #define si_status      _sifields._sigchld._status
 #define si_utime       _sifields._sigchld._utime
 #define si_stime       _sifields._sigchld._stime
index 40f121ca76e13314e49f60963db4e3a1fffb2162..5d287bbb3315b69fcbb0165839b166818f167617 100644 (file)
@@ -63,13 +63,6 @@ extern int overflowgid;
 #define SET_STAT_UID(stat, uid)                (stat).st_uid = high2lowuid(uid)
 #define SET_STAT_GID(stat, gid)                (stat).st_gid = high2lowgid(gid)
 
-/* specific to kernel/signal.c */
-#ifdef UID16_SIGINFO_COMPAT_NEEDED
-#define SET_SIGINFO_UID16(var, uid)    var = high2lowuid(uid)
-#else
-#define SET_SIGINFO_UID16(var, uid)    do { ; } while (0)
-#endif
-
 #else
 
 #define SET_UID16(var, uid)    do { ; } while (0)
@@ -82,8 +75,6 @@ extern int overflowgid;
 #define SET_STAT_UID(stat, uid)                (stat).st_uid = uid
 #define SET_STAT_GID(stat, gid)                (stat).st_gid = gid
 
-#define SET_SIGINFO_UID16(var, uid)    do { ; } while (0)
-
 #endif /* CONFIG_UID16 */
 
 
index 1e998c944cef31ba0712e288078577549afcb62b..fefc77b515708d4c9041228d3696e1e360b128b2 100644 (file)
@@ -285,11 +285,16 @@ struct input_event {
 #define BTN_MODE               0x13c
 
 #define BTN_DIGI               0x140
-#define BTN_PEN                        0x140
-#define BTN_RUBBER             0x141
-#define BTN_PEN_SIDE           0x142
-#define BTN_PEN_SIDE2          0x143
-#define BTN_NEAR               0x144
+#define BTN_TOOL_PEN           0x140
+#define BTN_TOOL_RUBBER                0x141
+#define BTN_TOOL_BRUSH         0x142
+#define BTN_TOOL_PENCIL                0x143
+#define BTN_TOOL_AIRBRUSH      0x144
+#define BTN_TOOL_FINGER                0x145
+#define BTN_TOOL_MOUSE         0x146
+#define BTN_TOUCH              0x147
+#define BTN_STYLUS             0x148
+#define BTN_STYLUS2            0x149
 
 #define KEY_MAX                        0x1ff
 
index 1c9ca4b659515b31c45efca4052b48c2a0b6bfc5..082fdbd475dc99ebef22dce0f8269408cb565a66 100644 (file)
@@ -451,24 +451,22 @@ extern struct page *filemap_nopage(struct vm_area_struct * area,
  * GFP bitmasks..
  */
 #define __GFP_WAIT     0x01
-#define __GFP_LOW      0x02
-#define __GFP_MED      0x04
-#define __GFP_HIGH     0x08
-#define __GFP_IO       0x10
-#define __GFP_SWAP     0x20
+#define __GFP_HIGH     0x02
+#define __GFP_IO       0x04
+#define __GFP_SWAP     0x08
 #ifdef CONFIG_HIGHMEM
-#define __GFP_HIGHMEM  0x40
+#define __GFP_HIGHMEM  0x10
 #else
 #define __GFP_HIGHMEM  0x0 /* noop */
 #endif
 
-#define __GFP_DMA      0x80
+#define __GFP_DMA      0x20
 
-#define GFP_BUFFER     (__GFP_LOW | __GFP_WAIT)
+#define GFP_BUFFER     (__GFP_WAIT)
 #define GFP_ATOMIC     (__GFP_HIGH)
-#define GFP_USER       (__GFP_LOW | __GFP_WAIT | __GFP_IO)
+#define GFP_USER       (__GFP_WAIT | __GFP_IO)
 #define GFP_HIGHUSER   (GFP_USER | __GFP_HIGHMEM)
-#define GFP_KERNEL     (__GFP_MED | __GFP_WAIT | __GFP_IO)
+#define GFP_KERNEL     (__GFP_HIGH | __GFP_WAIT | __GFP_IO)
 #define GFP_NFS                (__GFP_HIGH | __GFP_WAIT | __GFP_IO)
 #define GFP_KSWAPD     (__GFP_IO | __GFP_SWAP)
 
index 97f6923da66691cb973d88afa0a9c260426cc003..36f1a67186da3e5ea2b092fae0404bcad5c5ec93 100644 (file)
@@ -22,7 +22,8 @@ typedef struct kmem_cache_s kmem_cache_t;
 #define        SLAB_NFS                GFP_NFS
 #define        SLAB_DMA                GFP_DMA
 
-#define SLAB_LEVEL_MASK                0x0000007fUL
+#define SLAB_LEVEL_MASK                (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_SWAP| \
+                                                       __GFP_HIGHMEM)
 #define        SLAB_NO_GROW            0x00001000UL    /* don't grow a cache */
 
 /* flags to pass to kmem_cache_create().
index a2c2d3d4b94b58d28b6fd2433606a774b2119c62..b190669a11020ef0b41de35f969302742777d2dc 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/highuid.h>
 
 #include <asm/uaccess.h>
 
@@ -166,7 +165,6 @@ printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
                        info->si_code = 0;
                        info->si_pid = 0;
                        info->si_uid = 0;
-                       SET_SIGINFO_UID16(info->si_uid16, 0);
                }
 
                if (reset)
@@ -325,7 +323,6 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
                                q->info.si_code = SI_USER;
                                q->info.si_pid = current->pid;
                                q->info.si_uid = current->uid;
-                               SET_SIGINFO_UID16(q->info.si_uid16, current->uid);
                                break;
                        case 1:
                                q->info.si_signo = sig;
@@ -333,7 +330,6 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
                                q->info.si_code = SI_KERNEL;
                                q->info.si_pid = 0;
                                q->info.si_uid = 0;
-                               SET_SIGINFO_UID16(q->info.si_uid16, 0);
                                break;
                        default:
                                q->info = *info;
@@ -783,7 +779,6 @@ sys_kill(int pid, int sig)
        info.si_code = SI_USER;
        info.si_pid = current->pid;
        info.si_uid = current->uid;
-       SET_SIGINFO_UID16(info.si_uid16, current->uid);
 
        return kill_something_info(sig, &info, pid);
 }
index 1c6ced2beed52760b8a630f8e50b5988f86cb961..3826007c2b25664855c70573d23e09c63299e02e 100644 (file)
@@ -227,7 +227,7 @@ static inline int zone_balance_memory (zone_t *zone, int gfp_mask)
        freed = try_to_free_pages(gfp_mask, zone);
        current->flags &= ~PF_MEMALLOC;
 
-       if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
+       if (!freed && !(gfp_mask & __GFP_HIGH))
                return 0;
        return 1;
 }
@@ -267,7 +267,7 @@ static inline int balance_memory (zone_t *zone, int gfp_mask)
        freed = try_to_free_pages(gfp_mask, zone);
        current->flags &= ~PF_MEMALLOC;
 
-       if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
+       if (!freed && !(gfp_mask & __GFP_HIGH))
                return 0;
        return 1;
 }